PrintDocument页面分辨率的位图与

时间:2016-04-06 04:09:10

标签: c# printing graphics bitmap dpi

我遇到的问题是使用DrawImageUnscaled() PrinterDocument事件中的PrintPage使新的Bitmap与打印机输出的大小正确同步。

我有想法将图像作为页面集合从另一篇文章的评论中呈现出来,在那里我询问如何以更传统的方式使用打印机(NewPage,之前绘制项目 调用Print等)在.NET框架中不存在。在我第一次尝试使用Image集合时,我注意到即使在将Bitmap Dpi设置为与打印机对象相同的Dpi之后使用.DrawImage()时它们也有些颗粒感,我发现它是不可使用{{1图形对象通过反复试验(很多错误。

到目前为止,这项努力的结果是以下课程(它有一些我已经玩过的测试代码,但我已经清理了大部分内容,所以这里更具代表性)

PrinterSettings.CreateMeasurementGraphics()

PDF输出的插图

Demonstration of Dpi

正如您所看到的,我的类中的canvas(using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Drawing; using System.Drawing.Drawing2D; using System.Windows.Forms; using System.Windows.Forms.Design; using PdfFileWriter; using System.Drawing.Printing; using System.ComponentModel; using System.IO; class PDF : PrintDocument { /// <summary> /// Logo to display on invoice /// </summary> public Image Logo { get; set; } /// <summary> /// Current X position on canvas /// </summary> public int X { get; set; } /// <summary> /// Current Y position on canvas /// </summary> public int Y { get; set; } /// <summary> /// Set the folder where backups, downloads, etc will be stored or retrieved from /// </summary> [Editor( typeof( System.Windows.Forms.Design.FolderNameEditor ), typeof( System.Drawing.Design.UITypeEditor ) )] public string Folder { get { return directory; } set { directory=value; } } /// <summary> /// Current font used to print /// </summary> public Font Font { get; set; } /// <summary> /// Current font color /// </summary> public Color ForeColor { get; set; } private int CurrentPagePrinting { get; set; } /// <summary> /// Set printer margins /// </summary> public Margins PrintMargins { get { return DefaultPageSettings.Margins; } set { DefaultPageSettings.Margins = value; } } /// <summary> /// Pages drawn in document /// </summary> private List<Image> Pages; /// <summary> /// The current selected page number. 0 if nothing selected /// </summary> private int CurrentPage; /// <summary> /// The current working directory to save files to /// </summary> private string directory; /// <summary> /// The currently chosen filename /// </summary> private string file; /// <summary> /// Public acceisble object to all paperSizes as set /// </summary> public List<PrintPaperSize> paperSizes { get; private set; } /// <summary> /// Object for holding papersizes /// </summary> public class PrintPaperSize { public string Name { get; set; } public double Height { get; set; } public double Width { get; set; } public PrintPaperSize() { Height = 0; Width = 0; Name = ""; } } /// <summary> /// Current papersize selected. used for some calculations /// </summary> public PrintPaperSize CurrentPaperSize { get; private set; } public PDF() { // set the file name without extension to something safe file = (string)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds.ToString(); // set the save directory to MyDocuments directory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); CurrentPage = 0; // initialize pages array Pages = new List<Image>(); // Set the initial font and color Font = new System.Drawing.Font("Arial", (float)11.25); ForeColor = Color.Black; // set the printer to Microsoft's PDF printer and generate and ensure it will save to a file PrinterSettings = new PrinterSettings() { PrinterName = "Microsoft Print to PDF", PrintToFile = true, PrintFileName = Path.Combine(directory, file + ".pdf"), }; // hide the notice 'printing' while spooling job. PrintController = new StandardPrintController(); // set the printer quality to maximum so we can use this for getting the dpi at this setting DefaultPageSettings.PrinterResolution.Kind = PrinterResolutionKind.High; // store all paper sizes at 1 dpi [ reference: https://social.msdn.microsoft.com/Forums/vstudio/en-US/05169a47-04d5-4890-9b0a-7ad11a6a87f2/need-pixel-width-for-paper-sizes-a4-a5-executive-letter-legal-executive?forum=csharpgeneral ] paperSizes = new List<PrintPaperSize>(); foreach ( PaperSize P in PrinterSettings.PaperSizes ) { double W=P.Width/100.0; double H=P.Height/100.0; paperSizes.Add( new PrintPaperSize() { Height = H, Width = W, Name = P.PaperName } ); if ( P.PaperName=="Letter" ) { CurrentPaperSize = paperSizes[paperSizes.Count-1]; } } // setup the initial page type, orientation, margins, using ( Graphics g=PrinterSettings.CreateMeasurementGraphics() ) { DefaultPageSettings = new PageSettings(PrinterSettings) { PaperSize=new PaperSize( CurrentPaperSize.Name, (Int32)(CurrentPaperSize.Width*g.DpiX), (Int32)(CurrentPaperSize.Height*g.DpiY) ), Landscape = false, Margins = new Margins(left: 10, right: 10, top: 10, bottom: 10), PrinterResolution=new PrinterResolution() { Kind = PrinterResolutionKind.High } }; } // constrain print within margins OriginAtMargins = true; } public void SetPaperSize( PaperKind paperSize ) { // TODO: Use Linq on } /// <summary> /// Get specific page /// </summary> /// <param name="page">page number. 1 based array</param> /// <returns></returns> public Image GetPage( int page ) { int p = page - 1; if ( p<0||p>Pages.Count ) { return null; } return Pages[p]; } /// <summary> /// Get the current page /// </summary> /// <returns>Image</returns> public Image GetCurrentPage() { return GetPage(CurrentPage); } /// <summary> /// Before printing starts /// </summary> /// <param name="e">PrintEventArgs</param> protected override void OnBeginPrint( PrintEventArgs e ) { CurrentPagePrinting=0; base.OnBeginPrint( e ); } /// <summary> /// Print page event /// </summary> /// <param name="e">PrintPageEventArgs</param> protected override void OnPrintPage( PrintPageEventArgs e ) { CurrentPagePrinting++; // if page count is max exit print routine if ( CurrentPagePrinting>=Pages.Count ) { e.HasMorePages=false; base.OnPrintPage( e ); return; } // ensure high resolution / clarity of image so text doesn't fuzz e.Graphics.CompositingMode=CompositingMode.SourceOver; e.Graphics.CompositingQuality=CompositingQuality.HighQuality; // Draw image and respect margins (unscaled in addition to the above so text doesn't fuzz) e.Graphics.DrawImageUnscaled( Pages[CurrentPagePrinting-1], new Point( DefaultPageSettings.Margins.Top, DefaultPageSettings.Margins.Left ) ); base.OnPrintPage( e ); } /// <summary> /// After printing has been completed /// </summary> /// <param name="e">PrintEventArgs</param> protected override void OnEndPrint( PrintEventArgs e ) { base.OnEndPrint( e ); } /// <summary> /// Add a new page to the document /// </summary> public void NewPage() { // Add a new page to the page collection and set it as the current page Bitmap bmp; using(Graphics g = PrinterSettings.CreateMeasurementGraphics()) { float dpiscaleX; float dpiscaleY; // measure default bitmap dpi on this system and use to calculate print dpi using ( Bitmap b=new Bitmap( 1, 1 ) ) { dpiscaleX = b.HorizontalResolution; dpiscaleY = b.VerticalResolution; }; bmp = new Bitmap( (Int32)(((DefaultPageSettings.PrintableArea.Width-( DefaultPageSettings.Margins.Left+DefaultPageSettings.Margins.Right )) / dpiscaleX) * g.DpiX), (Int32)(((DefaultPageSettings.PrintableArea.Height-( DefaultPageSettings.Margins.Top+DefaultPageSettings.Margins.Bottom )) / dpiscaleY) * g.DpiY) ); bmp.SetResolution(g.DpiX, g.DpiY); } Pages.Add( bmp ); CurrentPage++; } /// <summary> /// Add a new string to the current page /// </summary> /// <param name="text">The string to print</param> /// <param name="align">Optional alignment of the string</param> public void DrawString(string text, System.Windows.TextAlignment align = System.Windows.TextAlignment.Left ) { // add string to document using ( Graphics g=Graphics.FromImage( Pages[CurrentPage - 1] ) ) { g.CompositingQuality = CompositingQuality.HighQuality; switch ( align ) { case System.Windows.TextAlignment.Left: case System.Windows.TextAlignment.Justify: g.DrawString( text, Font, new SolidBrush( ForeColor ), new PointF( X, Y ) ); Y+=(Int32)g.MeasureString( "X", Font ).Height; break; case System.Windows.TextAlignment.Right: g.DrawString( text, Font, new SolidBrush( ForeColor ), new PointF( Pages[CurrentPage - 1].Width - g.MeasureString( text, Font ).Width, Y ) ); Y += (Int32)g.MeasureString( "X", Font ).Height; break; case System.Windows.TextAlignment.Center: g.DrawString( text, Font, new SolidBrush( ForeColor ), new PointF( ( Pages[CurrentPage-1].Width+g.MeasureString( text, Font ).Width )/2, Y ) ); Y+=(Int32)g.MeasureString( "X", Font ).Height; break; } } } } 属性)超出了界限。如果我仅使用Page绘制图像,缩放会拉伸它并且它看起来有颗粒感,所以我必须使用.DrawImage()

上面的行按顺序是以下代码的结果:

.DrawImageUnscaled()

如果您取消注释// Initialize the custom print class PDF p = new PDF(); // Add a new page to the document p.NewPage(); // Draw some strings. p.Y value is automatically incremented p.DrawString( "Hello" ); p.DrawString( "Hello", System.Windows.TextAlignment.Right ); p.DrawString( "Hello", System.Windows.TextAlignment.Center ); p.DrawString( "Hello pure awesomeness" ); // Uncomment the following and add a picture box to the form // pictureBox1.Height = 1100; // pictureBox1.Width = 850; // pictureBox1.SizeMode = PictureBoxSizeMode.Zoom; // pictureBox1.Image = p.GetCurrentPage(); // Send all pages to the "printer" p.Print(); 行并注释掉pictureBox1,则结果是正确的(请记住,由于为页面设置了边距,图像小于printdocument页面。< / p>

PictureBox输出的插图

Demonstration of Dpi in PictureBox

如果您使用以下代码(代替上面的p.Print()代码),它在功能上等同于类中的Dpi缩放,那么所有内容都会在pictureBox中正确显示(只是很多更大,因为我的&#39;高&#39;设置解析为600 DPI,其中新创建的位图为72 DPI,然后在图像上调用pictureBox方法。

SetResolution()

1 个答案:

答案 0 :(得分:0)

衡量DefaultPageSettings.Margins的计算错误,因为Margins以100英寸according to this MSDN document表示。调整此方法的正确方法是除以100。

x = DefaultPageSettings.Margins/100

以下是OP的NewPage()方法,用正确的计算重写:

/// <summary>
/// Add a new page to the document
/// </summary>
public void NewPage() {
    // Add a new page to the page collection and set it as the current page

    Bitmap bmp;
    using(Graphics g = PrinterSettings.CreateMeasurementGraphics()) {
        int w=(Int32)( CurrentPaperSize.Width*g.DpiX )-(Int32)( ( ( DefaultPageSettings.Margins.Left+DefaultPageSettings.Margins.Right )/100 )*g.DpiX );
        int h=(Int32)( CurrentPaperSize.Height*g.DpiY )-(Int32)( ( ( DefaultPageSettings.Margins.Top+DefaultPageSettings.Margins.Bottom )/100 )*g.DpiY );
        bmp = new Bitmap( w, h );
        bmp.SetResolution(g.DpiX, g.DpiY);
    }

    // reset X and Y positions
    Y=0;
    X=0;

    // Add new page to the collection
    Pages.Add( bmp );
    CurrentPage++;
}