Качество печати XPS C # против просмотра XPS - PullRequest
0 голосов
/ 17 ноября 2011

У меня странная проблема с качеством печати в приложении C #. У меня есть файл XPS (в основном это всего лишь одностраничное изображение, которое изначально было отсканированным черно-белым изображением), который я пытаюсь распечатать в драйвере мейнфрейма IBM InfoPrint через приложение C #. Я печатал на многих других драйверах печати и никогда не сталкивался с проблемой, но этот драйвер дает мне ужасное качество с файлом AFP, который он создает. Если я открою один и тот же файл в приложении Microsoft XPS Viewer и напечатаю в том же драйвере, качество будет хорошим.

Попытка работать, хотя проблема Я пробовал 3 или 4 различных подхода к печати в приложении C #. Оригинальный код сделал что-то вроде этого (обрезано для краткости):

        System.Windows.Xps.XpsDocumentWriter writer = PrintQueue.CreateXpsDocumentWriter(mPrintQueue);
        mCollator = writer.CreateVisualsCollator();
        mCollator.BeginBatchWrite();
        ContainerVisual v = getContainerVisual(xpsFilePath);
        //tried all sorts of different options on the print ticket, no effect
        mCollator.Write(v,mDefaultTicket);

Этот код (который я урезал), безусловно, мог иметь некоторые странные проблемы, поэтому я попробовал кое-что намного более простое:

            LocalPrintServer localPrintServer = new LocalPrintServer();
            PrintQueue defaultPrintQueue = LocalPrintServer.GetDefaultPrintQueue();
            PrintSystemJobInfo xpsPrintJob = defaultPrintQueue.AddJob("title", xpsDocPath, false);

Те же результаты.

Я даже пытался использовать диалоговое окно печати WCF, такое же низкое качество (http://msdn.microsoft.com/en-us/library/ms742418.aspx).

Одна область, в которой я еще не пробовал, - это использование старых программных интерфейсов печати, но я не уверен, почему это будет вести себя по-другому. Еще один вариант, который у меня есть, это мой оригинальный документ в формате PDF, и у меня есть хорошая сторонняя библиотека, которая может сделать меня EMF-файлом. Однако каждый раз, когда я пытаюсь передать этот файл EMF на принтер, я получаю искаженный текст.

Будем весьма благодарны за любые идеи о том, почему это качество потеряно, как его исправить или как передать файл EMF в драйвер принтера!

UPDATE: Еще одно примечание. Этот хороший пример приложения: http://wrb.home.xs4all.nl/Articles_2010/Article_XPSViewer_01.htm испытывает ту же потерю качества. Я также выполнил тесты, в которых я открываю PDF-файл напрямую и рендеринг растровых изображений в печатный документ, с той же нечеткостью получаемых изображений. Если я открою PDF-файлы в Acrobat и распечатаю их, они будут выглядеть нормально.

1 Ответ

1 голос
/ 29 ноября 2012

Итак, чтобы закрыть эту проблему, кажется, что драйвер IBM Infoprint (по крайней мере, как он используется здесь) имеет совершенно разное качество в зависимости от того, как вы печатаете в C #.

В этом вопросе я использовал:

System.Windows.Documents.Serialization.Write(Visual, PrintTicket);

Я полностью изменил свой подход, полностью удалив XPS и получил представление моего документа в формате emf (windows-метафайл), а затем отправил этот файл emf на принтер Windows с помощью обработчика событий печати windows:

using (PrintDocument pd = new PrintDocument())
{
    pd.DocumentName = this.mJobName;
    pd.PrinterSettings.PrinterName = this.mPrinterName;
    pd.PrintController = new StandardPrintController();
    pd.PrintPage += new PrintPageEventHandler(DoPrintPage);
    pd.Print();
}

(Я, очевидно, опустил много кода здесь, но вы можете найти примеры того, как использовать этот подход относительно легко)

В моем тестировании большинство драйверов печати были одинаково довольны любым подходом к печати, но драйвер IBM Infoprint был ЧРЕЗВЫЧАЙНО чувствителен к качеству. Одно из возможных объяснений состоит в том, что принтер Infoprint должен был быть настроен со странным фиксированным DPI, и он может выполнять относительно плохую конвертацию.

РЕДАКТИРОВАТЬ: Был запрошен более подробный пример кода, так что пошли. Обратите внимание, что получение файла EMF является предварительным требованием для этого подхода. В этом случае я использую ABC PDF, который позволяет вам генерировать файл EMF из вашего PDF с помощью относительно простого вызова.

   class AbcPrintEmf
{
    private Doc mDoc;
    private string mJobName;
    private string mPrinterName;
    private string mTempFilePath;
    private bool mRenderTextAsPolygon;
    public AbcPdfPrinterApproach(Doc printMe, string jobName, string printerName, bool debug, string tempFilePath, bool renderTextAsPolygon)
    {
        mDoc = printMe;
        mDoc.PageNumber = 1;
        mJobName = jobName;
        mPrinterName = printerName;
        mRenderTextAsPolygon = renderTextAsPolygon;
        if (debug)
            mTempFilePath = tempFilePath;
    }

    public void print()
    {
        using (PrintDocument pd = new PrintDocument())
        {
            pd.DocumentName = this.mJobName;
            pd.PrinterSettings.PrinterName = this.mPrinterName;
            pd.PrintController = new StandardPrintController();
            pd.PrintPage += new PrintPageEventHandler(DoPrintPage);
            pd.Print();
        }
    }

    private void DoPrintPage(object sender, PrintPageEventArgs e)
    {
        using (Graphics g = e.Graphics)
        {
            if (mDoc.PageCount == 0) return;
            if (mDoc.Page == 0) return;

            XRect cropBox = mDoc.CropBox;
            double srcWidth = (cropBox.Width / 72) * 100;
            double srcHeight = (cropBox.Height / 72) * 100;
            double pageWidth = e.PageBounds.Width;
            double pageHeight = e.PageBounds.Height;
            double marginX = e.PageSettings.HardMarginX;
            double marginY = e.PageSettings.HardMarginY;
            double dstWidth = pageWidth - (marginX * 2);
            double dstHeight = pageHeight - (marginY * 2);

            // if source bigger than destination then scale
            if ((srcWidth > dstWidth) || (srcHeight > dstHeight))
            {
                double sx = dstWidth / srcWidth;
                double sy = dstHeight / srcHeight;
                double s = Math.Min(sx, sy);
                srcWidth *= s;
                srcHeight *= s;
            }

            // now center
            double x = (pageWidth - srcWidth) / 2;
            double y = (pageHeight - srcHeight) / 2;

            // save state
            RectangleF theRect = new RectangleF((float)x, (float)y, (float)srcWidth, (float)srcHeight);

            int theRez = e.PageSettings.PrinterResolution.X;

            // draw content
            mDoc.Rect.SetRect(cropBox);
            mDoc.Rendering.DotsPerInch = theRez;
            mDoc.Rendering.ColorSpace = "RGB";
            mDoc.Rendering.BitsPerChannel = 8;

            if (mRenderTextAsPolygon)
            {
                //i.e. render text as polygon (non default)
                mDoc.SetInfo(0, "RenderTextAsText", "0");
            }

            byte[] theData = mDoc.Rendering.GetData(".emf");
            if (mTempFilePath != null)
            {
                File.WriteAllBytes(mTempFilePath + @"\" + mDoc.PageNumber + ".emf", theData);
            }
            using (MemoryStream theStream = new MemoryStream(theData))
            {
                using (Metafile theEMF = new Metafile(theStream))
                {
                    g.DrawImage(theEMF, theRect);
                }
            }

            e.HasMorePages = mDoc.PageNumber < mDoc.PageCount;
            if (!e.HasMorePages) return;

            //increment to next page, corrupted PDF's have occasionally failed to increment
            //which would otherwise put us in a spooling infinite loop, which is bad, so this check avoids it
            int oldPageNumber = mDoc.PageNumber;
            ++mDoc.PageNumber;
            int newPageNumber = mDoc.PageNumber;
            if ((oldPageNumber + 1) != newPageNumber)
            {
                throw new Exception("PDF cannot be printed as it is corrupt, pageNumbers will not increment properly.");
            }
        }
    }
}
...