• 在WPF中打印A4纸


    本文使用PrintDialog. PrintVisual方法进行打印,参考“在WPF中使用PrintDialog.PrintVisual方法进行打印”。

    1、A4纸的分辨率

    本节文字摘录于打印A4纸图片需要多少像素和分辨率?”,算是相关介绍里比较早的一篇文章了。

    一般来说,给铜版纸使用的300dpi就够用了,太小打印出来不一定清晰,太大的话耗费内存和CPU处理起来十分慢,所以300dpi是一个很好的分界线。

    A4物理大小是21厘米×29.7厘米。

    具体换算成像素还要看用的多大的分辨率:

    分辨率是72像素/英寸时,A4纸的尺寸的图像的像素是595×842;

    分辨率是96像素/英寸时,A4纸的尺寸的图像的像素是794×1123;

    分辨率是120像素/英寸时,A4纸的尺寸的图像的像素是1487×2105;

    分辨率是150像素/英寸时,A4纸的尺寸的图像的像素是1240×1754;

    分辨率是300像素/英寸时,A4纸的尺寸的图像的像素是2480×3508;

    其他的大小,一般标准印刷300dpi时:

    A4纸的尺寸的图像的像素是2480×3508;

    A3纸的尺寸的图像的像素是4960×3508;

    B3纸的尺寸的图像的像素是3248×4300;

    B4纸的尺寸的图像的像素是3248×2150。

    2、打印分辨率

    在WPF中打印A4纸时,由于一般电脑不缩放时的分辨率为96dpi,假设打印机使用的分辨率是300dpi,1 英寸=2.54厘米,因此对应的控件像素是:21 / 2.54 * 96 = 793.7,29.7 / 2.54 * 96 = 1122.52。

    3、打印控件

    在WPF中,将需要打印的控件宽高分别设置为793.7、1122.52,然后在此控件上添加布局,并进行数据绑定,将其作为参数传递给PrintDialog. PrintVisual方法,即可打印出A4大小的纸张。

    4、连续打印

    对于数据比较多的情况,需要进行连续打印。可以将打印控件放在容器中(比如StackPanel),然后使用ScrollViewer进行预览。这时候如果直接将StackPanel中的打印控件传递给PrintDialog. PrintVisual方法,则会从第2张开始打印空白页。很可能是由于打印是异步的,要打印的控件没有及时刷新,或者刷新后又会被StackPanel重新排列,导致没有显示的控件打印不出来。

    无论上述猜想正确与否,使用控件构建DrawingVisual对象一定能够打印出控件的内容,代码如下所示。

    //通过控件构建DrawingVisual
    private static DrawingVisual GetDrawingVisual(FrameworkElement element, int dpi = 96)
    {
        //强制刷新控件
        var size = element.ActualWidth > 0
            ? new Size(element.ActualWidth, element.ActualHeight)
            : new Size(element.Width, element.Height);
        element.Measure(size);
        element.Arrange(new Rect(new Point(0, 0), size));
    
        //构造内存渲染图像
        var bitmap = new RenderTargetBitmap(
            (int) size.Width, //width
            (int) size.Height, //height
            dpi, //dpi x
            dpi, //dpi y
            PixelFormats.Pbgra32 // pixelformat
        );
        bitmap.Render(element);
    
        //构建DrawingVisual
        var drawingVisual = new DrawingVisual();
        using (var drawingContext = drawingVisual.RenderOpen())
        {
            drawingContext.DrawImage(bitmap.Clone(), new Rect {Width = size.Width, Height = size.Height});
        }
    
        return drawingVisual;
    }

    需要注意的是,上述方法将打印控件通过图片的形式封装为DrawingVisual对象,本质上是对图片的打印,因此打印时候会比较模糊。通过对控件遍历的改进,可以通过直接打印控件,使得打印质量得到保证。

    for (var i = 0; i < StackPanelMain.Children.Count; i++)
    {
        if (StackPanelMain.Children[i] is PrintControl printControl)
        {
            //移除控件
            StackPanelMain.Children.RemoveAt(i--);
    
            //强制刷新控件
            var size = printControl.ActualWidth > 0
                ? new Size(printControl.ActualWidth, printControl.ActualHeight)
                : new Size(printControl.Width, printControl.Height);
            printControl.Measure(size);
            printControl.Arrange(new Rect(new Point(0, 0), size));
    
            //通知打印
            PrintEvent?.Invoke(printControl);
        }
    }

    打印方法也需要做细微调整。

    /// <summary>
    /// 打印
    /// </summary>
    /// <param name="visual">要打印的元素</param>
    /// <param name="printer">打印机名称</param>
    /// <param name="description">打印描述</param>
    /// <param name="copyCount">打印个数</param>
    public void Print(Visual visual, string printer, string description, int copyCount = 1)
    {
        var localPrintServer = new LocalPrintServer();
        var printQueue = localPrintServer.GetPrintQueue(printer);
        if (printQueue.IsInError)
        {
            throw new Exception("打印机处于错误状态");
        }
    
        var printDialog = new PrintDialog
        {
            PrintQueue = printQueue, //打印队列
            PrintTicket = {CopyCount = copyCount} //打印个数
        };
    
        //设置纸张大小
        var pageWidth = (int) Math.Ceiling(printDialog.PrintableAreaWidth);
        var pageHeight = (int) Math.Ceiling(printDialog.PrintableAreaHeight);
        printDialog.PrintTicket.PageMediaSize = new PageMediaSize(pageWidth, pageHeight);
    
        //打印
        printDialog.PrintVisual(visual, description);
    }

    5、总结

    使用PrintDialog. PrintVisual进行A4纸打印时,首先需要设置打印控件的宽高,然后通过打印数据动态创建打印控件(可能有多个),之后从打印控件构建DrawingVisual对象,最后遍历所有控件执行打印操作。

  • 相关阅读:
    hdu 3037 Saving Beans fzu 2020 组合 hit 2813 Garden visiting hrbeu 组合数 fzu 1564 Combination
    PKU 2429 GCD & LCM Inverse
    Discrete Logging hunnu10590 pku2417 fzu 1352 hit 1928 zoj 1898
    HDUBased Game Theory
    Perfect Pth Powers zoj 2124 pku1730 hunnu10585
    More Divisors zoj 2562
    服务器的安全配置技巧总结
    sql server中datetime字段只取年月日如20060421,默认值如何设置?getdate()得到的是包含时分秒的时间
    获取当前打印机的名称、驱动程序、打印端口信息
    如何使用Delphi设计强大的服务器程序
  • 原文地址:https://www.cnblogs.com/xhubobo/p/15266892.html
Copyright © 2020-2023  润新知