我遇到的问题是使用DrawImageUnscaled()
PrinterDocument
事件中的PrintPage
使新的Bitmap与打印机输出的大小正确同步。
我有想法将图像作为页面集合从另一篇文章的评论中呈现出来,在那里我询问如何以更传统的方式使用打印机(NewPage
,之前绘制项目 调用Print
等)在.NET框架中不存在。在我第一次尝试使用Image集合时,我注意到即使在将Bitmap Dpi设置为与打印机对象相同的Dpi之后使用.DrawImage()
时它们也有些颗粒感,我发现它是不可使用{{1图形对象通过反复试验(很多错误。
到目前为止,这项努力的结果是以下课程(它有一些我已经玩过的测试代码,但我已经清理了大部分内容,所以这里更具代表性)
PrinterSettings.CreateMeasurementGraphics()
正如您所看到的,我的类中的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>
如果您使用以下代码(代替上面的p.Print()
代码),它在功能上等同于类中的Dpi缩放,那么所有内容都会在pictureBox
中正确显示(只是很多更大,因为我的&#39;高&#39;设置解析为600 DPI,其中新创建的位图为72 DPI,然后在图像上调用pictureBox
方法。
SetResolution()
答案 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++;
}