C# - 如何打印纵横比/整页

5

我在按钮点击时打印 CHART 控件:

chart1.SaveImage(ms, ChartImageFormat.Bmp);
Bitmap bm = new Bitmap(ms);

PrintDocument doc = new PrintDocument();
doc.PrintPage += (s, ev) =>
{
    ev.Graphics.DrawImage(bm, Point.Empty); // adjust this to put the image elsewhere
    ev.HasMorePages = false;
};
doc.DefaultPageSettings.Landscape = true;

doc.Print();

我该如何强制打印控件以适应页面大小(保持纵横比)?
2个回答

11

至少有两种不同的方法可以实现,其中都包括将要打印的图像缩放以适应所选打印机的页面大小:

1)使用.NET工具(我自己没有测试过,从这个帖子中借鉴了这个方法):

    private void printDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
    {
        Image i = pictureBox1.Image;

        float newWidth = i.Width * 100 / i.HorizontalResolution;
        float newHeight = i.Height * 100 / i.VerticalResolution;

        float widthFactor = newWidth / e.MarginBounds.Width;
        float heightFactor = newHeight / e.MarginBounds.Height;

        if(widthFactor>1 | heightFactor > 1)
        {
            if(widthFactor > heightFactor)
            {
                newWidth = newWidth / widthFactor;
                newHeight = newHeight / widthFactor;
            }
            else
            {
                newWidth = newWidth / heightFactor;
                newHeight = newHeight / heightFactor;
            }
        }
        e.Graphics.DrawImage(i, 0, 0, (int)newWidth, (int)newHeight);
    }
}

2) 从GDI和平面GDI中进行P/Invoke调用Windows API(这更加复杂但速度更快,可以传递位图文件的纯字节数组(将文件读取为byte[]),如果需要此代码,请提供电子邮件):

  private static extern bool ClosePrinter(IntPtr hPrinter);
  private static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPStr)] string szPrinter, out IntPtr hPrinter, IntPtr pd);
  private static extern int SetJob(IntPtr hPrinter, int JobId, int Level, ref byte pJob, int Command_Renamed);
  private static extern int GdiplusStartup(out IntPtr token, ref StartupInput input, out StartupOutput output);
  private static extern int GdiplusShutdown(IntPtr token);
  internal static extern int GdipLoadImageFromStream([In, MarshalAs(UnmanagedType.Interface)]IStream stream, out IntPtr image);
  internal static extern int GdipDisposeImage(IntPtr image);
  static internal extern int GdipCreateFromHDC2(IntPtr hDC, IntPtr hDevice, out IntPtr graphics);
  static internal extern int GdipDeleteGraphics(IntPtr graphics);
  static internal extern int GdipReleaseDC(IntPtr graphics, IntPtr hdc);
  internal static extern int GdipGetImageDimension(IntPtr image, out float width, out float height);
  internal static extern int GdipGetDpiX(IntPtr graphics, out float dpi);
  internal static extern int GdipGetDpiY(IntPtr graphics, out float dpi);
  static internal extern int GdipDrawImageRectI(IntPtr graphics, IntPtr image, int x, int y, int width, int height);
  private static extern IntPtr CreateDC([MarshalAs(UnmanagedType.LPStr)] string lpszDriver, [MarshalAs(UnmanagedType.LPStr)] string lpszDevice, [MarshalAs(UnmanagedType.LPStr)] string lpszOutput, IntPtr lpInitData);
  private static extern bool DeleteDC(IntPtr hdc);
  private static extern int StartDoc(IntPtr hdc, DOCINFO lpdi);
  private static extern int EndDoc(IntPtr hdc);
  private static extern int StartPage(IntPtr hdc);
  private static extern int EndPage(IntPtr hdc);
  private static extern int GetDeviceCaps(IntPtr hdc, int nIndex);

@我是一个女孩,当我需要做这个研究时,我的结论是没有使用 .Net 或 win32 提供的 API。我知道这很令人惊讶 - 在 .Net 中有很多事情可以做,但像这样的愚蠢的事情需要攀登一座山,但我非常确定这是事实。可能会有第三方库可以做到这一点,但我没有时间去研究。而且特别需要保留纵横比这一事实是一个逻辑问题,所以我猜这就是为什么微软从未提供易于执行此操作的函数,因为它是一个处理图像调整大小的函数,可以是任何大小,这种情况只是其中之一。 - user44298
@我是一个女孩,所以我也很长时间在寻找printFullPage()函数:) 但是没有这样的函数,所以我不得不自己写,如果您提供给我电子邮件,我可以将其发送给您,因为它太长且专有,所以我不想在此处发布(还必须允许我到明天剥离一些逻辑定制,这是我们公司的财产)。但是第一种方法,我认为,如果它能工作,那就不错了,它非常简短,请尝试一下。 - user44298
@ivo 非常感谢,我很欣赏您愿意帮助frumrecords GMAIL。 - Alex Gordon
@我是一个女孩完成了,检查一下。PS:我不知道为什么John Saunders编辑了这个问题的标题(标签没问题),但是为什么要编辑标题?联系他并告诉他你根本没有指定GDI+,我认为他的编辑是错误的。我没有权限自己编辑。 - user44298
@我是一个女孩,不要抱歉(无效再试)。请尝试第一个选项 :) - user44298
显示剩余7条评论

0
这是我为了让它工作所做的。令人烦恼的是,图表控件只会将其内容绘制为与屏幕上大小相同的尺寸。我发现唯一的解决方法是手动调整大小。然后,由于它可能不喜欢在表单上调整大小,这还涉及到暂时将其从表单中移除。
因此,经过所有这些步骤,最终得到了像这样的结果:
Chart ChartBox { get; private set; }

...

var oldParent = ChartBox.Parent;
var oldSize = ChartBox.Size;

ChartBox.Parent = null;
ChartBox.Size = new Size(width, height);

ChartBox.Printing.Print();

ChartBox.Parent = oldParent;
ChartBox.Size = oldSize;

根据您的表单,您可能还需要保存和恢复图表控件的其他属性。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接