Можно ли преобразовать PDF в формат векторного изображения, который можно распечатать из .NET?

У нас есть приложение .NET, которое печатает как на реальные принтеры, так и в PDF, в настоящее время используется PDFsharp, хотя эту часть можно изменить, если есть лучший вариант. Большая часть вывода представляет собой сгенерированный текст или изображения, но может быть одна или несколько страниц, которые добавляются в конец. Эти страницы предоставляются конечным пользователем в формате PDF.

При печати на бумаге наши пользователи используют предварительно распечатанную бумагу, но в случае экспортированного PDF мы объединяем эти страницы в конец, поскольку они уже в формате PDF.

Мы хотим иметь возможность встраивать эти PDF-файлы непосредственно в поток печати, чтобы они не нуждались в предварительно напечатанной бумаге. Однако на самом деле нет хороших вариантов для рендеринга PDF на страницу GDI (System.Drawing.Graphics).

Существует ли векторный формат, в который PDF может быть преобразован какой-либо внешней программой, которая может отображаться на странице GDI + без ухудшения качества путем предварительного преобразования в растровое изображение?


person Bryce Wagner    schedule 18.08.2011    source источник
comment
мы делаем что-то подобное, но сначала визуализируем PDF в растровое изображение - проблема качества может быть решена при рендеринге с использованием высококачественной библиотеки плюс высокое значение dpi (минимум 305, лучшее 1200), что требует некоторой памяти/производительности...   -  person Yahia    schedule 19.08.2011
comment
На днях я заметил, что PDFCreator (sourceforge.net/projects/pdfcreator), несмотря на то, при создании PDF можно использовать для печати PDF-документов в широком диапазоне форматов, включая SVG и растровые изображения. Может стоит посмотреть.   -  person Dave Cluderay    schedule 19.08.2011
comment
Эти PDF-файлы, как правило, представляют собой текст с некоторыми штриховыми рисунками. Они также будут напечатаны более 1000 раз подряд. Преобразование PDF-файла размером 30 КБ в растровое изображение размером 5 МБ, вероятно, поставит на колени всю очередь печати.   -  person Bryce Wagner    schedule 19.08.2011


Ответы (4)


В статье под названием «Как преобразовать PDF в EMF в .NET" я показали, как это сделать с помощью нашего продукта PDFOne .NET. EMF — это векторная графика, и вы можете отображать их на холсте принтера.

Более простой альтернативой для вас является наложение PDF, описанное в другой статье под названием «Наложение PDF — объединение страниц PDF вместе. в .NET". PDFOne допускает смещения x-y в наложениях, что позволяет сшивать страницы по краям. В цитируемой здесь статье я наложил страницы одну на другую, установив смещения равными нулю. Вы установите ширину и высоту страницы.

ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: Я работаю на Gnostice.

person BZ1    schedule 19.08.2011
comment
На самом деле мы уже используем инструментарий Gnostice PDF в Delphi для соединения двух PDF-файлов вместе, но мы переносим печать на .NET, поэтому доступно больше возможностей. Я не вижу GetPageMetafile() в компоненте Delphi, это новое дополнение или оно характерно для версии .NET? - person Bryce Wagner; 19.08.2011
comment
Другой вопрос, действительно ли это создает автономные файлы .EMF? На самом деле в прошлом мы пытались использовать продукт, который должен был позволить вам печатать в .EMF, но выходной файл работал только до тех пор, пока была открыта программа печати, потому что у нее были обратные вызовы к исходной программе, которые исчезали при закрытии этой программы. . Если PDFOne.NET может гарантировать рабочие файлы .EMF, это звучит как решение, которое я ищу. - person Bryce Wagner; 19.08.2011
comment
PDFtoolkit имеет два метода — RenderToDC (которому вы можете передать холст принтера) и RenderToStream (которому вы передаете поток EMF). Эти методы генерируют EMF аналогично GetPageMetafile PDFOne .NET. В PDFOne .NET GetPageMetaFile доступен только в версии ProPlus. - person BZ1; 22.08.2011
comment
В первой статье, приведенной выше, я показал скриншот файла EMF, который был открыт в Windows Picture and Fax Viewer. Это отдельный файл EMF. PDFOne также имеет компонент принтера, который может напрямую печатать страницы PDF на принтере. Вам не нужно использовать файлы EMF. Однако файлы EMF можно воспроизводить непосредственно на холсте принтера. Оба будут работать. - person BZ1; 22.08.2011

Ghostscript может выводить PostScript (векторный файл), который можно напрямую отправить на некоторые типы принтеров. Например, если вы используете принтер с поддержкой LPR, PS-файл можно напрямую настроить для этого принтера, используя что-то вроде этого проекта: http://www.codeproject.com/KB/printing/lpr.aspx

Есть также некоторые коммерческие варианты, которые могут печатать PDF (хотя я не уверен, является ли внутренний механизм векторным или растровым), например http://www.tallcomponents.com/pdfcontrols2-features.aspx или http://www.tallcomponents.com/pdfrasterizer3.aspx

person userx    schedule 18.08.2011
comment
У меня нет прямого контроля над принтером, который они используют, я думаю, что большинство из них настроены как PCL, а не как Postscript. Другая проблема заключается в том, что они хотят, чтобы PDF-файл был на обратной стороне одной из страниц (таким образом, это была предварительно напечатанная бумага), поэтому его нельзя отправить как отдельное задание на печать. - person Bryce Wagner; 19.08.2011

Наконец-то я понял, что есть вариант, отвечающий моему общему требованию по внедрению векторного формата в задание на печать, но он не работает с печатью на основе GDI.

Формат файла XPS, созданный драйвером печати Microsoft XPS Writer, можно распечатать из WPF с помощью библиотеки ReachFramework.dll, включенной в .NET. Используя для печати WPF вместо GDI, можно встроить страницу документа XPS в более крупный документ для печати.

Недостатком является то, что печать WPF работает немного по-другому, поэтому весь код поддержки, который напрямую использует материал в пространстве имен System.Drawing, должен быть переписан.

Вот основная схема того, как встроить документ XPS:

Откройте документ:

XpsDocument xpsDoc = new XpsDocument(filename, System.IO.FileAccess.Read);
var document = xpsDoc.GetFixedDocumentSequence().DocumentPaginator;

// pass the document into a custom DocumentPaginator that will decide
// what order to print the pages:
var mypaginator = new myDocumentPaginator(new DocumentPaginator[] { document });

// pass the paginator into PrintDialog.PrintDocument() to do the actual printing:
new PrintDialog().PrintDocument(mypaginator, "printjobname");

Затем создайте потомок DocumentPaginator, который будет выполнять фактическую печать. Переопределите абстрактные методы, в частности, GetPage должен возвращать DocumentPages в правильном порядке. Вот мое доказательство концептуального кода, демонстрирующего, как добавить пользовательский контент в список документов XPS:

public override DocumentPage GetPage(int pageNumber)
{
    for (int i = 0; i < children.Count; i++)
    {
        if (pageNumber >= pageCounts[i])
            pageNumber -= pageCounts[i];
        else
            return FixFixedPage(children[i].GetPage(pageNumber));
    }
    if (pageNumber < PageCount)
    {
        DrawingVisual dv = new DrawingVisual();
        var dc = dv.Drawing.Append();
        dc = dv.RenderOpen();
        DoRender(pageNumber, dc); // some method to render stuff to the DrawingContext
        dc.Close();
        return new DocumentPage(dv);
    }
    return null;
}

При попытке печати в другой документ XPS выдается исключение «FixedPage не может содержать другую FixedPage», и сообщение H.Alipourian демонстрирует, как это исправить: http://social.msdn.microsoft.com/Forums/da/wpf/thread/841e804b-9130-4476-8709-0d2854c11582

private DocumentPage FixFixedPage(DocumentPage page)
{
    if (!(page.Visual is FixedPage))
        return page;

    // Create a new ContainerVisual as a new parent for page children
    var cv = new ContainerVisual();
    foreach (var child in ((FixedPage)page.Visual).Children)
    {
        // Make a shallow clone of the child using reflection
        var childClone = (UIElement)child.GetType().GetMethod(
            "MemberwiseClone", BindingFlags.Instance | BindingFlags.NonPublic
            ).Invoke(child, null);

        // Setting the parent of the cloned child to the created ContainerVisual
        // by using Reflection.
        // WARNING: If we use Add and Remove methods on the FixedPage.Children,
        // for some reason it will throw an exception concerning event handlers
        // after the printing job has finished.
        var parentField = childClone.GetType().GetField(
            "_parent", BindingFlags.Instance | BindingFlags.NonPublic);
        if (parentField != null)
        {
            parentField.SetValue(childClone, null);
            cv.Children.Add(childClone);
        }
    }

    return new DocumentPage(cv, page.Size, page.BleedBox, page.ContentBox);
}

Извините, что это не совсем компиляция кода, я просто хотел предоставить обзор фрагментов кода, необходимых для того, чтобы заставить его работать, чтобы дать другим людям преимущество во всех разрозненных фрагментах, которые должны собраться вместе, чтобы заставить его работать. Попытка создать более обобщенное решение будет намного сложнее, чем объем этого ответа.

person Bryce Wagner    schedule 13.11.2012

Хотя это не открытый исходный код и не собственный .NET (я полагаю, на основе Delphi, но предлагает предварительно скомпилированную библиотеку .NET), Quick PDF может отображать PDF в файл EMF, который вы можете загрузить в свой объект Graphics.

person userx    schedule 22.08.2011