【问题标题】:XPS Print Quality C# vs. XPS viewerXPS 打印质量 C# 与 XPS 查看器
【发布时间】:2011-11-17 19:01:36
【问题描述】:

我的 C# 应用程序出现了一个奇怪的打印质量问题。我有一个 XPS 文件(它基本上只是一个 1 页图像,最初是扫描的黑白图像),我正在尝试通过 C# 应用程序打印到 IBM InfoPrint Mainframe 驱动程序。我已经打印到许多其他打印驱动程序并且从来没有遇到过问题,但是这个驱动程序给我它创建的 AFP 文件的质量很差。如果我在 Microsoft XPS 查看器应用程序中打开同一个文件并打印到同一个驱动程序,质量看起来不错。

尝试解决问题我已经尝试了 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)。

我还没有尝试过的一个领域是使用老式的底层打印 API,但我不确定为什么会有不同的行为。我还有一个选择,我的原始文档是 PDF,我有一个很好的第三方库,可以让我成为 EMF 文件。但是,每次我尝试将该 EMF 文件流式传输到我的打印机时,我都会收到乱码。

任何关于为什么失去这种质量、如何修复或如何将 EMF 文件流式传输到打印驱动程序的想法,将不胜感激!

更新: 另一个注意事项。这个不错的示例应用程序:http://wrb.home.xs4all.nl/Articles_2010/Article_XPSViewer_01.htm 经历了相同的质量损失。我现在还进行了测试,直接打开 PDF 并将位图渲染到打印文档,结果图像的模糊性相同。如果我在 Acrobat 中打开 PDF 并打印,它们看起来很好。

【问题讨论】:

  • 对不起,我对您的解决方案没有任何帮助,但是您的帖子提到了,并且被标记为 WCF。我相信这应该是 WPF,而不是 WCF。更改它可能会使您的帖子更容易被确实为您解答的人看到。

标签: c# wpf wcf printing


【解决方案1】:

因此,要关闭此问题,IBM Infoprint 驱动程序(至少在此处使用的方式)似乎具有完全不同的质量,具体取决于您在 C# 中的打印方式。

在这个问题中我使用的是:

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

我完全改变了我的方法,完全删除了 XPS,并获得了我的文档的 emf(Windows 元文件)再现,然后使用 Windows 打印事件处理程序将该 emf 文件发送到 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,它可以让您通过一个相对简单的调用从 PDF 生成 EMF 文件。

   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.");
            }
        }
    }
}

【讨论】:

  • 我猜 XPS 打印输出出于某种原因处于 ECO 模式。是否可以选择标准质量或生态(例如带票)?我有类似的问题,但无法迁移到 EMF(我得到 XPS 文件并且必须修改和打印它)。
  • 哇,这是一个倒退!值得庆幸的是,整个解决方案在几年前就被淘汰了,取而代之的是不需要通过古老的大型机打印驱动程序的东西。祝你好运!
  • OutputQuality 中有 PrintTicket 属性,但不确定它是否有帮助。 docs.microsoft.com/en-US/dotnet/api/…
猜你喜欢
  • 1970-01-01
  • 2011-02-17
  • 2011-11-30
  • 2014-10-18
  • 2012-12-05
  • 2011-09-21
  • 2017-11-21
  • 2011-07-08
  • 2010-10-04
相关资源
最近更新 更多