【问题标题】:Reading a Printer Device Context in C#在 C# 中读取打印机设备上下文
【发布时间】:2011-12-14 12:47:26
【问题描述】:

我能够显示屏幕设备并将其保存到 DIB 位图,并且我想对打印机设备上下文执行相同的操作。我可以得到一个非空位图,但它总是纯黑色。

这是允许我处理屏幕设备上下文的代码。

        //In size variable we shall keep the size of the window.
        SIZE size;

        //Win32 API functions are imported in classes
        //PlatformInvokeGDI32
        //PlatformInvokeUSER32

        //Get handle of calc.exe window.
        IntPtr hwnd = PlatformInvokeUSER32.FindWindow("SciCalc", "Calculator");

        //Get window dimensions
        PlatformInvokeUSER32.RECT rect;
        PlatformInvokeUSER32.GetWindowRect(hwnd, out rect);
        size.cx = rect._Right - rect._Left;
        size.cy = rect._Bottom - rect._Top;

        //Get the device context of Calculator.
        IntPtr hDC = PlatformInvokeUSER32.GetDC(hwnd);

        //Draw on the Calculator surface.
        Graphics CalculatorGraphics = Graphics.FromHdc(hDC);
        Color colorRed = Color.FromName("Red");
        Pen penRed = new Pen(colorRed);
        CalculatorGraphics.DrawEllipse(penRed, 50, 50, 50, 50);
        CalculatorGraphics.Save();

        //Here we make a compatible device context in memory for screen device context.
        IntPtr hMemDC = PlatformInvokeGDI32.CreateCompatibleDC(hDC);

        //Create a compatible bitmap of window size and using screen device context.
        m_HBitmap = PlatformInvokeGDI32.CreateCompatibleBitmap(hDC, size.cx, size.cy);

        //As m_HBitmap is IntPtr we can not check it against null. For this purspose IntPtr.Zero is used.
        if (m_HBitmap != IntPtr.Zero)
        {
            //Here we select the compatible bitmap in memeory device context and keeps the refrence to Old bitmap.
            IntPtr hOld = (IntPtr)PlatformInvokeGDI32.SelectObject(hMemDC, m_HBitmap);
            //We copy the Bitmap to the memory device context.
            PlatformInvokeGDI32.BitBlt(hMemDC, 0, 0, size.cx, size.cy, hDC, 0, 0, PlatformInvokeGDI32.SRCCOPY);
            //We select the old bitmap back to the memory device context.
            PlatformInvokeGDI32.SelectObject(hMemDC, hOld);
            //We delete the memory device context.
            PlatformInvokeGDI32.DeleteDC(hMemDC);
            //We release the screen device context.
            PlatformInvokeUSER32.ReleaseDC(hwnd, hDC);
            //Image is created by Image bitmap handle and returned.
            return System.Drawing.Image.FromHbitmap(m_HBitmap);
        }
        //If m_HBitmap is null retunrn null.
        return null;

这是我获取打印机设备上下文的方法:

        //In size variable we shall keep the size of the window.
        SIZE size;
        size.cx = 1000;
        size.cy = 1000;

        //Get Printer Handle
        IntPtr PrinterHandle;
        PlatformInvokeGDI32.PRINTER_DEFAULTSW defaults = new PlatformInvokeGDI32.PRINTER_DEFAULTSW();
        PlatformInvokeGDI32.OpenPrinterW("Bullzip PDF Printer", out PrinterHandle, defaults);

        //Get Printer Device context
        IntPtr PrinterHDC = PlatformInvokeGDI32.CreateDCW("", "Bullzip PDF Printer", "", IntPtr.Zero);

        //Initialize DocInfo structure.
        PlatformInvokeGDI32.DOCINFOW docInfo = new PlatformInvokeGDI32.DOCINFOW();

        //Start printing.
        PlatformInvokeGDI32.StartDocW(PrinterHDC, ref docInfo);
        PlatformInvokeGDI32.StartPage(PrinterHDC);
        Graphics graphics = Graphics.FromHdc(PrinterHDC, PrinterHandle);

        Color theColor = Color.FromName("Red");
        Pen pen = new Pen(theColor);
        graphics.DrawRectangle(pen, 50, 50, 50, 50);
        graphics.DrawEllipse(pen, 50, 50, 50, 50);
        graphics.Save();

        //Here we make a compatible device context in memory for screen device context.
        IntPtr hMemDC = PlatformInvokeGDI32.CreateCompatibleDC(PrinterHDC);

        //Create a compatible bitmap of window size and using screen device context.
        m_HBitmap = PlatformInvokeGDI32.CreateCompatibleBitmap(PrinterHDC, size.cx, size.cy);

        //As m_HBitmap is IntPtr we can not check it against null. For this purspose IntPtr.Zero is used.
        if (m_HBitmap != IntPtr.Zero)
        {
            //Here we select the compatible bitmap in memeory device context and keeps the refrence to Old bitmap.
            IntPtr hOld = (IntPtr)PlatformInvokeGDI32.SelectObject(hMemDC, m_HBitmap);
            //We copy the Bitmap to the memory device context.
            PlatformInvokeGDI32.BitBlt(hMemDC, 0, 0, size.cx, size.cy, PrinterHDC, 0, 0, PlatformInvokeGDI32.SRCCOPY);
            //We select the old bitmap back to the memory device context.
            PlatformInvokeGDI32.SelectObject(hMemDC, hOld);
            //We delete the memory device context.
            PlatformInvokeGDI32.DeleteDC(hMemDC);
            //We release the screen device context.
            //PlatformInvokeUSER32.ReleaseDC(hwnd, PrinterHDC);
            //Image is created by Image bitmap handle and returned.

            PlatformInvokeGDI32.EndPage(PrinterHDC);
            PlatformInvokeGDI32.EndDoc(PrinterHDC);
            PlatformInvokeGDI32.ClosePrinter(PrinterHandle);
            pen.Dispose();
            graphics.Dispose();


            return System.Drawing.Image.FromHbitmap(m_HBitmap);
        }
        //If m_HBitmap is null retunrn null.
        return null;

如何使用打印机设备上下文? 如何将打印机设备上下文保存到 DIB?

谢谢,

雅各布

【问题讨论】:

  • 这是一件非常不寻常的事情。一个名为“Bullzip PDF Printer”的假打印机驱动程序无疑不支持它。像光栅设备一样工作,而不是位图设备。
  • 我现在已经在其他物理和软件打印机上尝试了相同的代码并收到了相同的结果:图形打印成功,但 DC 没有像我希望的那样转换为位图。打印机:HP LaserJet 4100 系列 PCL、Apple Color LaserWriter 12/600、Bullzip PDF 打印机、DOXPrinter801 和 LaserWriter Personal NT v51.8。打印机 Ricoh Aficio MP C4000 PCL6 在 PlatformInvokeGDI32.StartPage(PrinterHDC); 处出现 AccessViolationException;。

标签: c# winapi printing bitmap gdi


【解决方案1】:

打印机设备上下文是只写的。

例如,假设您要打印到 PostScript 打印机。您创建一个打印机设备上下文并在其上绘制一些文本。打印机设备驱动程序不会呈现包含您的文本的位图。相反,它会创建一系列 PostScript 命令来绘制文本并将命令发送到打印机。换句话说,没有要复制的位图。

你想达到什么目的?

【讨论】:

  • 我以编程方式将大量文档打印到 TIFF。有时文档是基于 HTML 的电子邮件,其中包含的表格太宽而无法在页面上打印,这意味着某些内容无法打印。我希望保存一个位图,然后确定是否有任何非白色像素超出了可以打印到页面的区域。
  • 能否将电子邮件加载到 HTML 渲染器中并询问文档宽度?
  • 电子邮件存储在 Outlook PST 中。提交电子邮件以进行打印的应用程序是一个名为 DiscoveryCracker 的现成应用程序,它将电子邮件提交到 Outlook 2007 进行打印。我不知道在这个过程中我可以将文档发送到 HTML 渲染器的哪个位置。我想使用设备上下文的原因是我可以将一个 DLL 注入 DiscoveryCracker 或 Outlook 并挂钩使用 hDC 的 StartPage。
  • 我不是 Outlook 专家,但似乎可以编写一个宏以在加载邮件时运行。但是,如果只打印正在打开的消息的子集,那么这将没有多大用处。与 Excel 不同,在打印文档时似乎无法运行宏。或者,如果您要挂接 GDI,您可以挂接文本和线条绘制函数并检查它们的边界。尽管如果您需要考虑映射模式,这可能会变得复杂。或者可能有一种更清洁的方式连接到打印管道。
  • 获取 ExtTextOut 和其他文本方法的坐标是我想到的另一种方式。我同意必须考虑映射模式会使事情变得具有挑战性。如果有更清洁的方法可以连接到打印管道,我还没有找到。你有什么想法?宏观的想法不是我想到的。我会考虑一下的。
猜你喜欢
  • 1970-01-01
  • 2012-05-31
  • 2020-04-07
  • 2014-12-21
  • 1970-01-01
  • 1970-01-01
  • 2011-04-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多