2015-08-06 3 views
1

Я пытаюсь напечатать главное окно как для принтера, так и для файла (с помощью PrintDialog). Я пробовал следующие три решения, но есть проблемы с каждым из них (объясняется ниже). Кто-нибудь знает о хорошем решении или может улучшить существующие?Как распечатать окно (или экран) с помощью 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"); 
} 

ответ

0

Ниже приведен пример сохранения элемента управления Наследование от FrameworkElement в файл растрового изображения с использованием изображения RenderTargetBitmap:

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(); 
} 
+0

Спасибо, но это не то, что я ищу. Я хочу напечатать изображение на принтере, используя PrintDialog (или эквивалент). Отредактировано название, чтобы избежать путаницы. – Godspark

+0

Он показывает другой способ визуализации, который затем можно использовать для печати. Вероятно, ваша проблема связана с использованием PrintDialog.PrintVisual. Вы можете попробовать выполнить рендеринг с помощью RenderTargetBitmap, а затем распечатать растровое изображение. –

+0

Что именно следует вводить для метода printDialog.PrintVisual()? – Godspark

0

Вот реализация метода, который может печатать 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; 
} 
+0

Это много кода, есть ли способ сократить его? Я полагаю, что часть кода, связанного с Command, может быть опущена, так как печать в моем случае срабатывает нажатием клавиши. – Godspark

+0

Я удалил команду. Для его работы требуется все остальное. –

+0

Хорошо, спасибо. Я попытался использовать его, но я все еще получаю некоторые проблемы, похожие на решение №2. – Godspark

Смежные вопросы