【问题标题】:How do I print a window (or screen) by using PrintDialog (or equivalent)?如何使用 PrintDialog(或等效项)打印窗口(或屏幕)?
【发布时间】:2015-08-12 16:47:19
【问题描述】:

我正在尝试将主窗口打印到打印机和文件(通过使用 PrintDialog)。我尝试了以下三种解决方案,但每种解决方案都存在一些问题(如下所述)。有谁知道一个好的解决方案,或者改进现有的解决方案?

1。 https://social.msdn.microsoft.com/Forums/vstudio/en-US/df305a6c-4546-4665-a9fb-1b190ea47ec6/how-to-print-bitmapsource?forum=wpf

此解决方案会剪切最终文档/打印,因此不会显示整个屏幕。

private void PrintBitmapSource(BitmapSource inBms)
{
    var pd = new PrintDialog();
    var ret = pd.ShowDialog();
    if (ret.Value)
    {
        var dv = new DrawingVisual();
        using (var dc = dv.RenderOpen())
        {
            dc.DrawImage(inBms, new Rect(0, 0, inBms.Width, inBms.Height));
        }
        pd.PrintVisual(dv, "document image");
    }
}

2。 http://www.a2zdotnet.com/View.aspx?id=66#.VcMld_ntlBc

这个解决方案创建了一个完整的打印,但有一些奇怪的伪影,它似乎混合了调整大小之前和之后的元素。同时调整屏幕大小。

PrintDialog printDlg = new System.Windows.Controls.PrintDialog();
if (printDlg.ShowDialog() == true)
{
    //get selected printer capabilities
    System.Printing.PrintCapabilities capabilities = printDlg.PrintQueue.GetPrintCapabilities(printDlg.PrintTicket);

    //get scale of the print wrt to screen of WPF visual
 double scale = Math.Min(capabilities.PageImageableArea.ExtentWidth / this.ActualWidth, capabilities.PageImageableArea.ExtentHeight /
                this.ActualHeight);

    //Transform the Visual to scale
    this.LayoutTransform = new ScaleTransform(scale, scale);

    //get the size of the printer page
    Size sz = new Size(capabilities.PageImageableArea.ExtentWidth, capabilities.PageImageableArea.ExtentHeight);

    //update the layout of the visual to the printer page size.
    this.Measure(sz);
    this.Arrange(new Rect(new Point(capabilities.PageImageableArea.OriginWidth, capabilities.PageImageableArea.OriginHeight), sz));

    //now print the visual to printer to fit on the one page.
    printDlg.PrintVisual(this, "First Fit to Page WPF Print"); 
}

3。 将 PageMediaSize 设置为屏幕分辨率(硬编码用于测试目的)。

这个解决方案几乎是完美的,但右侧有一个黑色区域,但在这个黑色区域的顶部正确显示了一些元素。看起来黑色区域从解决方案 #1 的中断处开始。

var pd = new System.Windows.Controls.PrintDialog();
var ret = pd.ShowDialog();
if (ret.Value)
{
    pd.PrintTicket.PageMediaSize = new PageMediaSize(1920, 1080);
    pd.PrintTicket.PageOrientation = System.Printing.PageOrientation.Landscape;
    pd.PrintVisual(ApplicationGlobal.MainWindow as Window, "testprint");
}

【问题讨论】:

    标签: c# wpf printing


    【解决方案1】:

    这是一个使用RenderTargetBitmap将继承自FrameworkElement的控件保存到位图图像文件的示例:

    private void SaveFrameworkElementToBitmap(FrameworkElement gridinput, string filepath)
    {
        gridinput.Measure(new System.Windows.Size(double.PositiveInfinity, double.PositiveInfinity));
        int grid1Width = (int)Math.Round(gridinput.ActualWidth);
        int grid1Height = (int)Math.Round(gridinput.ActualHeight);
        grid1Width = grid1Width == 0 ? 1 : grid1Width;
        grid1Height = grid1Height == 0 ? 1 : grid1Height;
    
        RenderTargetBitmap rtbmp = new RenderTargetBitmap(grid1Width, grid1Height, 96d, 96d, PixelFormats.Default);
        rtbmp.Render(gridinput);
        BmpBitmapEncoder encoder = new BmpBitmapEncoder();
        encoder.Frames.Add(BitmapFrame.Create(rtbmp));
        FileStream gridbmpfilestrm = File.Create(filepath);
        encoder.Save(gridbmpfilestrm);
        gridbmpfilestrm.Close();
        rtbmp.Clear();
    }
    

    【讨论】:

    • 谢谢,但这不是我想要的。我想通过使用 PrintDialog(或等效项)将图像打印到打印机。编辑标题以避免混淆。
    • 它展示了一种不同的视觉呈现方式,然后您可以使用它来打印。您的问题可能是由于使用了 PrintDialog.PrintVisual。您可以尝试使用 RenderTargetBitmap 进行渲染,然后打印渲染的位图。
    • 我应该向 printDialog.PrintVisual() 方法输入什么?
    • 没什么。您将不再使用 PrintDialog 来打印 Visual,而是打印渲染的位图。
    • 好的,这是否意味着我无法使用此解决方案打印到打印机?
    【解决方案2】:

    这是一个可以打印 FrameworkElement 的方法的实现。您需要在项目上设置允许不安全代码属性。

    using System;
    using System.IO;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    
    public void Print(FrameworkElement objectToPrint)
    {
        PrintDialog printDialog = new PrintDialog();
        if ((bool)printDialog.ShowDialog().GetValueOrDefault())
        {
            Mouse.OverrideCursor = Cursors.Wait;
            System.Printing.PrintCapabilities capabilities =
                printDialog.PrintQueue.GetPrintCapabilities(printDialog.PrintTicket);
            double dpiScale = 300.0 / 96.0;
            FixedDocument document = new FixedDocument();
            try
            {
                // Change the layout of the UI Control to match the width of the printer page
                objectToPrint.Width = capabilities.PageImageableArea.ExtentWidth;
                objectToPrint.UpdateLayout();
                objectToPrint.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
                Size size = new Size(capabilities.PageImageableArea.ExtentWidth, objectToPrint.DesiredSize.Height);
                objectToPrint.Measure(size);
                size = new Size(capabilities.PageImageableArea.ExtentWidth, objectToPrint.DesiredSize.Height);
                objectToPrint.Measure(size);
                objectToPrint.Arrange(new Rect(size));
    
                // Convert the UI control into a bitmap at 300 dpi
                double dpiX = 300;
                double dpiY = 300;
                RenderTargetBitmap bmp =
                    new RenderTargetBitmap(
                        Convert.ToInt32(capabilities.PageImageableArea.ExtentWidth * dpiScale),
                        Convert.ToInt32(objectToPrint.ActualHeight * dpiScale),
                        dpiX,
                        dpiY,
                        PixelFormats.Pbgra32);
                bmp.Render(objectToPrint);
    
                // Convert the RenderTargetBitmap into a bitmap we can more readily use
                PngBitmapEncoder png = new PngBitmapEncoder();
                png.Frames.Add(BitmapFrame.Create(bmp));
                System.Drawing.Bitmap bmp2;
                using (MemoryStream memoryStream = new MemoryStream())
                {
                    png.Save(memoryStream);
                    bmp2 = new System.Drawing.Bitmap(memoryStream);
                }
                document.DocumentPaginator.PageSize = new Size(
                    printDialog.PrintableAreaWidth,
                    printDialog.PrintableAreaHeight);
    
                // break the bitmap down into pages
                int pageBreak = 0;
                int previousPageBreak = 0;
                int pageHeight = Convert.ToInt32(capabilities.PageImageableArea.ExtentHeight * dpiScale);
                while (pageBreak < bmp2.Height - pageHeight)
                {
                    pageBreak += pageHeight; // Where we thing the end of the page should be
    
                    // Keep moving up a row until we find a good place to break the page
                    while (!IsRowGoodBreakingPoint(bmp2, pageBreak)) pageBreak--;
    
                    PageContent pageContent = this.GeneratePageContent(
                        bmp2,
                        previousPageBreak,
                        pageBreak,
                        document.DocumentPaginator.PageSize.Width,
                        document.DocumentPaginator.PageSize.Height,
                        capabilities);
                    document.Pages.Add(pageContent);
                    previousPageBreak = pageBreak;
                }
    
                // Last Page
                PageContent lastPageContent = this.GeneratePageContent(
                    bmp2,
                    previousPageBreak,
                    bmp2.Height,
                    document.DocumentPaginator.PageSize.Width,
                    document.DocumentPaginator.PageSize.Height,
                    capabilities);
                document.Pages.Add(lastPageContent);
            }
            finally
            {
                // Scale UI control back to the original so we don't effect what is on the screen 
                objectToPrint.Width = double.NaN;
                objectToPrint.UpdateLayout();
                objectToPrint.LayoutTransform = new ScaleTransform(1, 1);
                Size size = new Size(
                    capabilities.PageImageableArea.ExtentWidth,
                    capabilities.PageImageableArea.ExtentHeight);
                objectToPrint.Measure(size);
                objectToPrint.Arrange(
                    new Rect(
                        new Point(
                            capabilities.PageImageableArea.OriginWidth,
                            capabilities.PageImageableArea.OriginHeight),
                        size));
                Mouse.OverrideCursor = null;
            }
            printDialog.PrintDocument(document.DocumentPaginator, "Print Document Name");
        }
    }
    
    private PageContent GeneratePageContent(System.Drawing.Bitmap bmp, int top,
        int bottom, double pageWidth, double PageHeight,
        System.Printing.PrintCapabilities capabilities)
    {
        FixedPage printDocumentPage = new FixedPage();
        printDocumentPage.Width = pageWidth;
        printDocumentPage.Height = PageHeight;
    
        int newImageHeight = bottom - top;
        System.Drawing.Bitmap bmpPage = bmp.Clone(new System.Drawing.Rectangle(0, top,
                bmp.Width, newImageHeight), System.Drawing.Imaging.PixelFormat.Format32bppArgb);
    
        // Create a new bitmap for the contents of this page
        Image pageImage = new Image();
        BitmapSource bmpSource =
            System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
                bmpPage.GetHbitmap(),
                IntPtr.Zero,
                System.Windows.Int32Rect.Empty,
                BitmapSizeOptions.FromWidthAndHeight(bmp.Width, newImageHeight));
    
        pageImage.Source = bmpSource;
        pageImage.VerticalAlignment = VerticalAlignment.Top;
    
        // Place the bitmap on the page
        printDocumentPage.Children.Add(pageImage);
    
        PageContent pageContent = new PageContent();
        ((System.Windows.Markup.IAddChild)pageContent).AddChild(printDocumentPage);
    
        FixedPage.SetLeft(pageImage, capabilities.PageImageableArea.OriginWidth);
        FixedPage.SetTop(pageImage, capabilities.PageImageableArea.OriginHeight);
    
        pageImage.Width = capabilities.PageImageableArea.ExtentWidth;
        pageImage.Height = capabilities.PageImageableArea.ExtentHeight;
        return pageContent;
    }
    
    private bool IsRowGoodBreakingPoint(System.Drawing.Bitmap bmp, int row)
    {
        double maxDeviationForEmptyLine = 1627500;
        bool goodBreakingPoint = false;
    
        if (rowPixelDeviation(bmp, row) < maxDeviationForEmptyLine)
            goodBreakingPoint = true;
    
        return goodBreakingPoint;
    }
    
    private double rowPixelDeviation(System.Drawing.Bitmap bmp, int row)
    {
        int count = 0;
        double total = 0;
        double totalVariance = 0;
        double standardDeviation = 0;
        System.Drawing.Imaging.BitmapData bmpData =
            bmp.LockBits(
                new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height),
                System.Drawing.Imaging.ImageLockMode.ReadOnly,
                bmp.PixelFormat);
        int stride = bmpData.Stride;
        IntPtr firstPixelInImage = bmpData.Scan0;
    
        unsafe
        {
            byte* p = (byte*)(void*)firstPixelInImage;
            p += stride * row; // find starting pixel of the specified row
            for (int column = 0; column < bmp.Width; column++)
            {
                count++; //count the pixels
    
                byte blue = p[0];
                byte green = p[1];
                byte red = p[3];
    
                int pixelValue = System.Drawing.Color.FromArgb(0, red, green, blue).ToArgb();
                total += pixelValue;
                double average = total / count;
                totalVariance += Math.Pow(pixelValue - average, 2);
                standardDeviation = Math.Sqrt(totalVariance / count);
    
                // go to next pixel
                p += 3;
            }
        }
        bmp.UnlockBits(bmpData);
    
        return standardDeviation;
    }
    

    【讨论】:

    • 这么多代码,有没有办法缩短呢?我想一些与命令相关的代码可以省略,因为在我的情况下打印是由按键触发的。
    • 我已删除该命令。它需要其他一切才能正常工作。
    • 好的,谢谢。我尝试使用它,但仍然收到与解决方案 #2 类似的一些问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-15
    • 1970-01-01
    • 1970-01-01
    • 2021-09-25
    相关资源
    最近更新 更多