(转)打印机设置一等分、二等分、三等分打印尺寸使用教程 | 您所在的位置:网站首页 › 打印机a4尺寸怎么设置方法 › (转)打印机设置一等分、二等分、三等分打印尺寸使用教程 |
前端实现打印预览功能以及page-break-inside属性解决打印换行问题(打印预览表格或文字被分割开) 崽崽的谷雨 于 2021-05-18 09:48:59 发布 2827 收藏 3分类专栏: 前端 js 文章标签: javascript版权 前端同时被 2 个专栏收录12 篇文章0 订阅订阅专栏 js45 篇文章0 订阅订阅专栏前言: 做项目的时候可能会遇到打印,不管是调用系统的(Ctrl+shift+p)或者浏览器里window.print(); 打印实现方案:1.调用系统的(Ctrl+shift+p); 2.调用浏览器里window.print(); window.print() api window.print():默认打印当前页面body里的所有内容。当然也可以打印局部。思路就是把要打印的临时赋值给body然后再重新赋值会原来的。 function doPrint2(){ //根据div标签ID拿到div中的局部内容 bdhtml=window.document.body.innerHTML; var jubuData = document.getElementById("printcontent").innerHTML; //把获取的 局部div内容赋给body标签, 相当于重置了 body里的内容 window.document.body.innerHTML= jubuData; //调用打印功能 window.print(); window.document.body.innerHTML=bdhtml;//重新给页面内容赋值; return false;}参考:window.print实现局部打印 window.onbeforeprint()--打印之前做的事 onbeforeprint api window.onafterprint()--打印之后做的事 nafterprint api 3.实际上转换成图片再打印也行或者截图打印(当然效果不太好,对于海报之类的可能会好些可以用)这个也是一个思路建议用上面的。 例如:html2Canvas html2Cavas遇到的问题及解决方案 html2Cavas官网 api 定义和用法onbeforeprint 事件在页面即将打印时触发 (在打印窗口出现前)。 提示: onbeforeprint 事件的相反事件为 onafterprint 。 遇到的问题:打印预览的时候表格被分割了,就是一共两页而其中一行显示在不同的两个页面(而不想让tr被隔开,很难看)。如下图:
代码如下:
Document tr { width: 500px; height: 500px; } table { /* width: 200px; */ border-top: 1px solid #999; border-left: 1px solid #999; border-spacing: 0; /*去掉单元格间隙*/ }
printthis page nmae age 33 33 33 33 33 33 function func() { window.print(); } 解决方案:给tr加上age-break-inside: avoid; tr { width: 500px; height: 500px; page-break-inside: avoid; /* page-break-before: avoid; page-break-after: avoid; */ }加上之后效果图
浏览器支持表格中的数字注明了完全支持该属性的首个浏览器版本。 属性 Chrome IE Firefox Safari Operapage-break-inside 1.0 8.0 19.0 1.3 7.0一、定义和用法 (page-break-inside)page-break-inside 属性设置元素内部的 page-breaking 行为。 尽管可以用 always 强制放上分页符,但是无法保证避免分页符的插入,创作人员最多只能要求用户代理尽可能避免插入分页。 应用于:position 值为 relative 或 static 的非浮动块级元素。 注释:请尽可能少地使用分页属性,并且避免在表格、浮动元素、带有边框的块元素中使用分页属性。 默认值: auto继承性: no版本: CSS2JavaScript 语法: object.style.pageBreakInside="avoid"可能的值值 描述auto 默认。如果必要则在元素内部插入分页符。avoid 避免在元素内部插入分页符。inherit 规定应该从父元素继承 page-break-inside 属性的设置。参考: w3c page-break-inside api 二、定义和用法(page-break-before)page-break-before 属性设置元素前的 page-breaking 行为。 尽管可以用 always 强制放上分页符,但是无法保证避免分页符的插入,创作人员最多只能要求用户代理尽可能避免插入分页。 应用于:position 值为 relative 或 static 的非浮动块级元素。 注释:请尽可能少地使用分页属性,并且避免在表格、浮动元素、带有边框的块元素中使用分页属性。 可能的值值 描述auto 默认值。如果必要则在元素前插入分页符。always 在元素前插入分页符。avoid 避免在元素前插入分页符。left 在元素之前足够的分页符,一直到一张空白的左页为止。right 在元素之前足够的分页符,一直到一张空白的右页为止。inherit 规定应该从父元素继承 page-break-before 属性的设置。参考: w3c page-break-before api 三、定义和用法(page-break-after)page-break-after 属性设置元素后的 page-breaking 行为。 尽管可以用 always 强制放上分页符,但是无法保证避免分页符的插入,创作人员最多只能要求用户代理尽可能避免插入分页。 应用于:position 值为 relative 或 static 的非浮动块级元素。 可能的值值 描述auto 默认。如果必要则在元素后插入分页符。always 在元素后插入分页符。avoid 避免在元素后插入分页符。left 在元素之后足够的分页符,一直到一张空白的左页为止。right 在元素之后足够的分页符,一直到一张空白的右页为止。inherit 规定应该从父元素继承 page-break-after 属性的设置。注释:请尽可能少地使用分页属性,并且避免在表格、浮动元素、带有边框的块元素中使用分页属性。 参考:w3c page-break-after api 其他用法: 这个只是其中一种用法,可以搭配另外两个属性组合成各种效果(根据自己的效果搭配)。 一、page-break-before 想要实现让h1独占一页 代码如下: 任何属性都没加
Document h1{ text-align: center; }
printthis page ttttt 5555555555555555555 function func() { window.print(); }解决方案: (1)给h1加page-break-after: right; h1{ text-align: center; page-break-after: right; } (2)给p加 page-break-before: right; h1{ text-align: center; /* page-break-after: right; */ } p{ page-break-before: right; } 本文部分参api考于:css-page-break 属性 vue和react中的插件vue: vue-printjs vue-printjshttps://codechina.csdn.net/mirrors/xyl66/vueplugs_printjs?utm_source=csdn_github_accelerator vue-print.js api地址当然github上也有只是,访问很慢 github print.js api react:react-to-print https://codechina.csdn.net/mirrors/gregnb/react-to-print?utm_source=csdn_github_accelerator react-to-print 地址 当然github上也有只是,访问很慢github react-to-print api 当然vue,react或者其他框架里也可以事用上面的浏览器自带的方案也行 ,请根据自己的需求择优选择。这些插件都事基于window.print封装的,有些api还是很方便的。 动态调整打印机纸张大小 江苏省昆山市地方税务局 信息管理系统中经常要提供各种打印功能,例如报表打印、凭证打印以及发票打印。在这些打印过程中所需要纸张的大小往往是不一致的,例如,打印报表有可能使用A4 纸或A3 纸,打印凭证或发票可能需要将打印纸张设置成自定义大小。如果在同一台打印机上打印这些内容,那么就应该针对不同的打印内容设置不同的纸张尺寸。显然如果用手动的方法来设置打印机的纸张尺寸是件很麻烦的事,最好的方法是让程序动态地修改打印机的纸张尺寸。 解决问题的思路 通过查阅API 函数技术文档可知,每个打印机都拥有唯一的一个叫做DevMode 的结构,与打印机相关的各项参数被存放在这个结构中。通过对DevMode 结构的分析,发现与设置打印机纸张大小有关的结构成员有四项:dmFields、dmPaperSize、dmPaperLength 以及dmPaperWidth。dmFields 是DevMode 的标志位初始化部分,如果要修改结构中的某些成员,那么dmFields 中相应位应被置位。dmPaperSize 表示打印机当前默认的打印纸张的大小,若要设置自定义纸张该项应为0(注,上述解释是根据微软提供的技术文档,但是在Delphi 中应将该成员设置成$100 即256)。dmPaperLength 和dmPaperWidth 只是在设置自定义大小纸张时使用,分别表示纸张的长度和宽度。如何对打印机的DevMode 结构进行修改呢?无非采用两种方法,一种是利用Delphi 提供的TPrinter 类中的某些方法,还有一种是调用与打印有关的API 函数。下面就以Delphi 为开发工具,以Epson 1600K 为默认打印机,用两种不同的方法来实现这一功能。 方法一:利用Delphi 的TPrinter 类 TPrinter 类是Delphi 对Windows 打印处理系统的封装,它能够帮助程序员在开发打印程序时尽可能地减少工作量。在程序中使用TPrinter,只要在单元的Use 子句后面添加Printers 即可。当前打印机的DevMode 结构的句柄可以通过调用Tprinter 类中的GetPrinter 方法来获取。当程序获得DevMode 结构的句柄后,就调用GlobalLock 函数来得到指向该结构的指针,随后可对结构中的某些成员进行修改。下面就举一个例子来说明这一问题:假设当前打印机的默认纸张尺寸是A3 纸,现在要打印长度为114mm、宽度为190mm 的纸张。为了简单起见,我们只在Form1 上放置一个Button1 按钮,增加一个OnClick 事件,在Use 子句后添加Printers。程序的代码如下: Procedure TForm1.Button1Click(Sender: TObject);var Device : array[0..cchDeviceName -1] of Char; Driver : array[0..(MAX_PATH -1)] of Char; Port : array[0..32]of Char; hDMode : THandle; pDMode : PDevMode;begin Printer.GetPrinter(Device,Driver,Port,hDMode);// 获取打印机DevMode 结构的句柄值, 存放在hDMode 中 if hDMode < > 0 then begin pDMode := GlobalLock(hDMode);// 获取指向打印机DevMode 结构的// 指针 if pDMode < > nil then begin pDMode^.dmPaperSize := 256;// 如果要将当前打印机纸张变为自定义dmPaperSize 必须设置成256 pDMode^.dmPaperLength := 1140; pDMode^.dmPaperWidth := 1900; pDMode^.dmFields := pDMode^.dmFields orDM_PAPERSIZE; pDMode^.dmFields := pDMode^.dmFields or DM_PAPERLENGTH; pDMode^.dmFields := pDMode^.dmFields or DM_PAPERWIDTH; { 以上三条语句是对相应 的dmFields 成员进行置位。} ResetDC(Printer.Handle,pDMode^);// 设置打印机设备环境句柄的值 GlobalUnlock(hDMode); end; end;{ 下面的代码是为了测试打印机是否 按190 *114 纸张大小来打印} with Printer do begin BeginDoc; Canvas.TextOut(10,10,'Hello, My Friend!'); EndDoc; end;end; 方法二:利用有关打印的Windows API 函数 解决问题的思路和第一种方法类似,首先要获取当前打印机的DevMode 结构的指针,然后再对该结构进行修改,从而修改打印机纸张大小。要完成上述功能,就得调用DocumentProperties 函数。利用该函数程序就可以获取并修改与当前打印机相关的DevMode 结构中的成员。DocumentProperties 函数申明如下: LONG DocumentProperties( HWND hWnd, HANDLE hPrinter, LPTSTR pDeviceName, PDEVMODE pDevModeOutput, PDEVMODE pDevModeInput, DWORD fMode); 六个参数中只有pDevModeOutput 是输出变量,其余五个参数必须由程序给出具体值。其中,hWnd 表征当前窗口的句柄值;hPrinter 表示当前打印机的句柄;pDeviceName 是对打印机设备的描述;pDevModeOutput 是指向句柄值为hPrinter 的打印机DevMode 结构的指针;pDevModeInput 是指向一个修改后的DevMode 结构的指针,该结构有待于被句柄值为hPrinter 的打印机接受;fMode 定义了该函数的具体功能,如果取值DM_IN_BUFFER 那么表示打印机接受由参数pDevModeInput 表示的由程序修改了的DevMode 值,如果取值DM_OUT_BUFFER 那么程序可以通过参数pDevModeOutput 来获取打印机的DevMode 值,如果fMode 为零,则函数返回的值表示结构DevMode 所需的字节数。承接上述例子,现在将190 *114 大小的纸张设成A4 纸。再往Form1 上放置按钮Button2,增加OnClick 事件,在Use 子句后面添加WinSpool。代码如下: Procedure TForm1.Button2Click(Sender: TObject);var PrnHd : THandle; PrnInfo : PPrinterInfo1; pcbNeeded : DWORD; PDevModeBytes : DWORD; DevMode: PDeviceMode; PrnHdc : HDC; DocInfo : PDocInfo;begin OpenPrinter('Epson LQ -1600K',PrnHd,nil); // 获得打印机句柄PrnHd GetMem(PrnInfo,1024); GetPrinter(PrnHd,1,PrnInfo,1024,@pcbNeeded); PDevModeBytes:= DocumentProperties( Handle,PrnHd,prninfo^. pDescription,DevMode^,DevMode^,0 );{ 获取DevMode 结构所需的字节数} GetMem(DevMode,PDevModeBytes);// 给结构DevMode 分配空间 DocumentProperties( Handle,PrnHd,PrnInfo^.p Description,DevMode^,DevMode^,DM_OUT_BUFFER );// 获取打印机的DevMode 结构 With DevMode^ do begin dmPaperSize := DMPAPER_A4 ;// 将纸张设置成A4 纸 dmFields := dmFields or DM_PAPERSIZE; end; DocumentProperties( Handle,PrnHd,PrnInfo^.pDescription,DevMode^,DevMode^,DM_OUT_BUFFER or DM_IN_BUFFER);// 修改DevMode 结构。 { 下面的代码是为了测试打印机 是否按A4 纸大小来打印 } PrnHdc := CreateDC( nil, 'Epson LQ -1600K',nil,DevMode ); GetMem( DocInfo, 100 ); With DocInfo^ do begin cbSize := sizeof(DocInfo); lpszDocName := nil; lpszOutput := nil; lpszDatatype := nil; fwType := DI_APPBANDING; end; StartDoc( PrnHdc, DocInfo^); StartPage(PrnHdc); TextOut( PrnHdc, 10, 10, 'Hello My Friend!',17); EndPage(PrnHdc); EndDoc(PrnHdc); DeleteDC(PrnHdc); FreeMem(DocInfo); FreeMem(PrnInfo); FreeMem(DevMode);end; 至此,程序实现了本文开头所提出的要求。需要指出的是,上述代码是在程序运行时,动态地改变打印机纸张大小,而不改变打印机默认纸张大小。也就是说当打印程序运行结束后,打印机还是会按照默认打印纸张大小来打印、走纸。动态调整打印机纸张尺寸也是因打印机而异,某些打印机基本不支持自定义纸张,例如惠普的HP DeskJet 1120C 喷墨打印机以及众多激光打印机。因此在这些打印机上,不能实现按任意纸张大小打印。对于一些针式打印机则没有上述问题。 上述程序是在Windows 95 环境下,用Delphi 4.0 为开发工具调试通过。
打印自定义纸张大小 长江支流说的办法保留太多了,结果不行,很多类都是他在程序集里自定义的,源码又没公开 不过还是要感谢他的提示 今天和小陈搞了一天,他在国外的论坛上看到了一篇文章得到了启示,最后我们在凌晨3点终于把自定义纸张的代码给写出来了,看来必须用API,微软的.NET对打印的支持太菜了 现公开我们工作室实现此功能的部分代码 using System; using System.Text; using System.Runtime.InteropServices; using System.Security; using System.ComponentModel; using System.Drawing.Printing; namespace MCCustomPrintForm { /// /// 成都微创工作室(电子科技大学微创工作室) /// Tell 028-82853098 /// Email [email protected] , [email protected] /// 打印机纸张的真正自定义部分代码 /// 2006-1-2 /// public class MCCustomPrintForm { // Make a static class private MCCustomPrintForm() { } [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)] internal struct structPrinterDefaults { [MarshalAs(UnmanagedType.LPTStr)] public String pDatatype; public IntPtr pDevMode; [MarshalAs(UnmanagedType.I4)] public int DesiredAccess; }; [DllImport("winspool.Drv", EntryPoint="OpenPrinter", SetLastError=true, CharSet=CharSet.Unicode, ExactSpelling=false,CallingConvention=CallingConvention.StdCall), SuppressUnmanagedCodeSecurityAttribute()] internal static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPTStr)] string printerName, out IntPtr phPrinter, ref structPrinterDefaults pd); [DllImport("winspool.Drv", EntryPoint="ClosePrinter", SetLastError=true, CharSet=CharSet.Unicode, ExactSpelling=false, CallingConvention=CallingConvention.StdCall),SuppressUnmanagedCodeSecurityAttribute()] internal static extern bool ClosePrinter(IntPtr phPrinter); [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)] internal struct structSize { public Int32 width; public Int32 height; } [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)] internal struct structRect { public Int32 left; public Int32 top; public Int32 right; public Int32 bottom; } [StructLayout(LayoutKind.Explicit, CharSet=CharSet.Unicode)] internal struct FormInfo1 { [FieldOffset(0), MarshalAs(UnmanagedType.I4)] public uint Flags; [FieldOffset(4), MarshalAs(UnmanagedType.LPWStr)] public String pName; [FieldOffset(8)] public structSize Size; [FieldOffset(16)] public structRect ImageableArea; }; [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi/* changed from CharSet=CharSet.Auto */)] internal struct structDevMode { [MarshalAs(UnmanagedType.ByValTStr, SizeConst=32)] public String dmDeviceName; [MarshalAs(UnmanagedType.U2)] public short dmSpecVersion; [MarshalAs(UnmanagedType.U2)] public short dmDriverVersion; [MarshalAs(UnmanagedType.U2)] public short dmSize; [MarshalAs(UnmanagedType.U2)] public short dmDriverExtra; [MarshalAs(UnmanagedType.U4)] public int dmFields; [MarshalAs(UnmanagedType.I2)] public short dmOrientation; [MarshalAs(UnmanagedType.I2)] public short dmPaperSize; [MarshalAs(UnmanagedType.I2)] public short dmPaperLength; [MarshalAs(UnmanagedType.I2)] public short dmPaperWidth; [MarshalAs(UnmanagedType.I2)] public short dmScale; [MarshalAs(UnmanagedType.I2)] public short dmCopies; [MarshalAs(UnmanagedType.I2)] public short dmDefaultSource; [MarshalAs(UnmanagedType.I2)] public short dmPrintQuality; [MarshalAs(UnmanagedType.I2)] public short dmColor; [MarshalAs(UnmanagedType.I2)] public short dmDuplex; [MarshalAs(UnmanagedType.I2)] public short dmYResolution; [MarshalAs(UnmanagedType.I2)] public short dmTTOption; [MarshalAs(UnmanagedType.I2)] public short dmCollate; [MarshalAs(UnmanagedType.ByValTStr, SizeConst=32)] public String dmFormName; [MarshalAs(UnmanagedType.U2)] public short dmLogPixels; [MarshalAs(UnmanagedType.U4)] public int dmBitsPerPel; [MarshalAs(UnmanagedType.U4)] public int dmPelsWidth; [MarshalAs(UnmanagedType.U4)] public int dmPelsHeight; [MarshalAs(UnmanagedType.U4)] public int dmNup; [MarshalAs(UnmanagedType.U4)] public int dmDisplayFrequency; [MarshalAs(UnmanagedType.U4)] public int dmICMMethod; [MarshalAs(UnmanagedType.U4)] public int dmICMIntent; [MarshalAs(UnmanagedType.U4)] public int dmMediaType; [MarshalAs(UnmanagedType.U4)] public int dmDitherType; [MarshalAs(UnmanagedType.U4)] public int dmReserved1; [MarshalAs(UnmanagedType.U4)] public int dmReserved2; } [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)] internal struct PRINTER_INFO_9 { public IntPtr pDevMode; } [DllImport("winspool.Drv", EntryPoint="AddFormW", SetLastError=true, CharSet=CharSet.Unicode, ExactSpelling=true, CallingConvention=CallingConvention.StdCall), SuppressUnmanagedCodeSecurityAttribute()] internal static extern bool AddForm( IntPtr phPrinter, [MarshalAs(UnmanagedType.I4)] int level, ref FormInfo1 form); /* This method is not used [DllImport("winspool.Drv", EntryPoint="SetForm", SetLastError=true, CharSet=CharSet.Unicode, ExactSpelling=false, CallingConvention=CallingConvention.StdCall), SuppressUnmanagedCodeSecurityAttribute()] internal static extern bool SetForm(IntPtr phPrinter, string paperName, [MarshalAs(UnmanagedType.I4)] int level, ref FormInfo1 form); */ [DllImport("winspool.Drv", EntryPoint="DeleteForm", SetLastError=true, CharSet=CharSet.Unicode, ExactSpelling=false,CallingConvention=CallingConvention.StdCall), SuppressUnmanagedCodeSecurityAttribute()] internal static extern bool DeleteForm( IntPtr phPrinter, [MarshalAs(UnmanagedType.LPTStr)] string pName); [DllImport("kernel32.dll", EntryPoint="GetLastError", SetLastError=false, ExactSpelling=true, CallingConvention=CallingConvention.StdCall), SuppressUnmanagedCodeSecurityAttribute()] internal static extern Int32 GetLastError(); [DllImport("GDI32.dll", EntryPoint="CreateDC", SetLastError=true, CharSet=CharSet.Unicode, ExactSpelling=false, CallingConvention=CallingConvention.StdCall), SuppressUnmanagedCodeSecurityAttribute()] internal static extern IntPtr CreateDC([MarshalAs(UnmanagedType.LPTStr)] string pDrive, [MarshalAs(UnmanagedType.LPTStr)] string pName, [MarshalAs(UnmanagedType.LPTStr)] string pOutput, ref structDevMode pDevMode); [DllImport("GDI32.dll", EntryPoint="ResetDC", SetLastError=true, CharSet=CharSet.Unicode, ExactSpelling=false, CallingConvention=CallingConvention.StdCall), SuppressUnmanagedCodeSecurityAttribute()] internal static extern IntPtr ResetDC( IntPtr hDC, ref structDevMode pDevMode); [DllImport("GDI32.dll", EntryPoint="DeleteDC", SetLastError=true, CharSet=CharSet.Unicode, ExactSpelling=false, CallingConvention=CallingConvention.StdCall), SuppressUnmanagedCodeSecurityAttribute()] internal static extern bool DeleteDC(IntPtr hDC); [DllImport("winspool.Drv", EntryPoint="SetPrinterA", SetLastError=true, CharSet=CharSet.Auto, ExactSpelling=true, CallingConvention=CallingConvention.StdCall), SuppressUnmanagedCodeSecurityAttribute()] internal static extern bool SetPrinter( IntPtr hPrinter, [MarshalAs(UnmanagedType.I4)] int level, IntPtr pPrinter, [MarshalAs(UnmanagedType.I4)] int command); /* LONG DocumentProperties( HWND hWnd, // handle to parent window HANDLE hPrinter, // handle to printer object LPTSTR pDeviceName, // device name PDEVMODE pDevModeOutput, // modified device mode PDEVMODE pDevModeInput, // original device mode DWORD fMode // mode options ); */ [DllImport("winspool.Drv", EntryPoint="DocumentPropertiesA", SetLastError=true, ExactSpelling=true, CallingConvention=CallingConvention.StdCall)] public static extern int DocumentProperties( IntPtr hwnd, IntPtr hPrinter, [MarshalAs(UnmanagedType.LPStr)] string pDeviceName /* changed from String to string */, IntPtr pDevModeOutput, IntPtr pDevModeInput, int fMode ); [DllImport("winspool.Drv", EntryPoint="GetPrinterA", SetLastError=true, ExactSpelling=true, CallingConvention=CallingConvention.StdCall)] public static extern bool GetPrinter( IntPtr hPrinter, int dwLevel /* changed type from Int32 */, IntPtr pPrinter, int dwBuf /* chagned from Int32*/, out int dwNeeded /* changed from Int32*/ ); // SendMessageTimeout tools [Flags] public enum SendMessageTimeoutFlags : uint { SMTO_NORMAL = 0x0000, SMTO_BLOCK = 0x0001, SMTO_ABORTIFHUNG = 0x0002, SMTO_NOTIMEOUTIFNOTHUNG = 0x0008 } const int WM_SETTINGCHANGE = 0x001A; const int HWND_BROADCAST = 0xffff; [DllImport("user32.dll", SetLastError=true, CharSet=CharSet.Auto)] public static extern IntPtr SendMessageTimeout( IntPtr windowHandle, uint Msg, IntPtr wParam, IntPtr lParam, SendMessageTimeoutFlags flags, uint timeout, out IntPtr result ); //打印纸张长宽设置 public static void AddMC80MmPaperSizeToDefaultPrinter() { AddCustomPaperSizeToDefaultPrinter("MC 80mm * Receipt Length", 80.1f, 4003.9f); } public static void AddMC104MmPaperSizeToDefaultPrinter() { AddCustomPaperSizeToDefaultPrinter("MC 104mm * Receipt Length", 104.1f, 4003.9f); } /// /// Adds the printer form to the default printer /// /// Name of the printer form /// Width given in millimeters /// Height given in millimeters public static void AddCustomPaperSizeToDefaultPrinter(string paperName, float widthMm, float heightMm) { PrintDocument pd = new PrintDocument(); string sPrinterName = pd.PrinterSettings.PrinterName; AddCustomPaperSize(sPrinterName, paperName, widthMm, heightMm); } /// /// Add the printer form to a printer /// /// The printer name /// Name of the printer form /// Width given in millimeters /// Height given in millimeters public static void AddCustomPaperSize(string printerName, string paperName, float widthMm, float heightMm) { if (PlatformID.Win32NT == Environment.OSVersion.Platform) { // The code to add a custom paper size is different for Windows NT then it is // for previous versions of windows const int PRINTER_ACCESS_USE = 0x00000008; const int PRINTER_ACCESS_ADMINISTER = 0x00000004; const int FORM_PRINTER = 0x00000002; structPrinterDefaults defaults = new structPrinterDefaults(); defaults.pDatatype = null; defaults.pDevMode = IntPtr.Zero; defaults.DesiredAccess = PRINTER_ACCESS_ADMINISTER | PRINTER_ACCESS_USE; IntPtr hPrinter = IntPtr.Zero; // Open the printer. if (OpenPrinter(printerName, out hPrinter, ref defaults)) { try { // delete the form incase it already exists DeleteForm(hPrinter, paperName); // create and initialize the FORM_INFO_1 structure FormInfo1 formInfo = new FormInfo1(); formInfo.Flags = 0; formInfo.pName = paperName; // all sizes in 1000ths of millimeters formInfo.Size.width = (int)(widthMm * 1000.0); formInfo.Size.height = (int)(heightMm * 1000.0); formInfo.ImageableArea.left = 0; formInfo.ImageableArea.right = formInfo.Size.width; formInfo.ImageableArea.top = 0; formInfo.ImageableArea.bottom = formInfo.Size.height; if (!AddForm(hPrinter, 1, ref formInfo)) { StringBuilder strBuilder = new StringBuilder(); strBuilder.AppendFormat("Failed to add the custom paper size {0} to the printer {1}, System error number: {2}", paperName, printerName, GetLastError()); throw new ApplicationException(strBuilder.ToString()); } // INIT const int DM_OUT_BUFFER = 2; const int DM_IN_BUFFER = 8; structDevMode devMode = new structDevMode(); IntPtr hPrinterInfo, hDummy; PRINTER_INFO_9 printerInfo; printerInfo.pDevMode = IntPtr.Zero; int iPrinterInfoSize, iDummyInt; // GET THE SIZE OF THE DEV_MODE BUFFER int iDevModeSize = DocumentProperties(IntPtr.Zero, hPrinter, printerName, IntPtr.Zero, IntPtr.Zero, 0); if(iDevModeSize < 0) throw new ApplicationException("Cannot get the size of the DEVMODE structure."); // ALLOCATE THE BUFFER IntPtr hDevMode = Marshal.AllocCoTaskMem(iDevModeSize + 100); // GET A POINTER TO THE DEV_MODE BUFFER int iRet = DocumentProperties(IntPtr.Zero, hPrinter, printerName, hDevMode, IntPtr.Zero, DM_OUT_BUFFER); if(iRet < 0) throw new ApplicationException("Cannot get the DEVMODE structure."); // FILL THE DEV_MODE STRUCTURE devMode = (structDevMode)Marshal.PtrToStructure(hDevMode, devMode.GetType()); // SET THE FORM NAME FIELDS TO INDICATE THAT THIS FIELD WILL BE MODIFIED devMode.dmFields = 0x10000; // DM_FORMNAME // SET THE FORM NAME devMode.dmFormName = paperName; // PUT THE DEV_MODE STRUCTURE BACK INTO THE POINTER Marshal.StructureToPtr(devMode, hDevMode, true); // MERGE THE NEW CHAGES WITH THE OLD iRet = DocumentProperties(IntPtr.Zero, hPrinter, printerName, printerInfo.pDevMode, printerInfo.pDevMode, DM_IN_BUFFER | DM_OUT_BUFFER); if(iRet < 0) throw new ApplicationException("Unable to set the orientation setting for this printer."); // GET THE PRINTER INFO SIZE GetPrinter(hPrinter, 9, IntPtr.Zero, 0, out iPrinterInfoSize); if(iPrinterInfoSize == 0) throw new ApplicationException("GetPrinter failed. Couldn't get the # bytes needed for shared PRINTER_INFO_9 structure"); // ALLOCATE THE BUFFER hPrinterInfo = Marshal.AllocCoTaskMem(iPrinterInfoSize + 100); // GET A POINTER TO THE PRINTER INFO BUFFER bool bSuccess = GetPrinter(hPrinter, 9, hPrinterInfo, iPrinterInfoSize, out iDummyInt); if(!bSuccess) throw new ApplicationException("GetPrinter failed. Couldn't get the shared PRINTER_INFO_9 structure"); // FILL THE PRINTER INFO STRUCTURE printerInfo = (PRINTER_INFO_9)Marshal.PtrToStructure(hPrinterInfo, printerInfo.GetType()); printerInfo.pDevMode = hDevMode; // GET A POINTER TO THE PRINTER INFO STRUCTURE Marshal.StructureToPtr(printerInfo, hPrinterInfo, true); // SET THE PRINTER SETTINGS bSuccess = SetPrinter(hPrinter, 9, hPrinterInfo, 0); if(!bSuccess) throw new Win32Exception(Marshal.GetLastWin32Error(), "SetPrinter() failed. Couldn't set the printer settings"); // Tell all open programs that this change occurred. SendMessageTimeout( new IntPtr(HWND_BROADCAST), WM_SETTINGCHANGE, IntPtr.Zero, IntPtr.Zero, MCCustomPrintForm.SendMessageTimeoutFlags.SMTO_NORMAL, 1000, out hDummy); } finally { ClosePrinter(hPrinter); } } else { StringBuilder strBuilder = new StringBuilder(); strBuilder.AppendFormat("Failed to open the {0} printer, System error number: {1}", printerName, GetLastError()); throw new ApplicationException(strBuilder.ToString()); } } else { structDevMode pDevMode = new structDevMode(); IntPtr hDC = CreateDC(null, printerName, null, ref pDevMode); if (hDC != IntPtr.Zero) { const long DM_PAPERSIZE = 0x00000002L; const long DM_PAPERLENGTH = 0x00000004L; const long DM_PAPERWIDTH = 0x00000008L; pDevMode.dmFields = (int)(DM_PAPERSIZE | DM_PAPERWIDTH | DM_PAPERLENGTH); pDevMode.dmPaperSize = 256; pDevMode.dmPaperWidth = (short)(widthMm * 1000.0); pDevMode.dmPaperLength = (short)(heightMm * 1000.0); ResetDC(hDC, ref pDevMode); DeleteDC(hDC); } } } } } C# PrintDocument打印 多页 打印预览 PrintDocument实例所有的订阅事件如下: 1.创建一个PrintDocument的实例.如下:System.Drawing.Printing.PrintDocument docToPrint = new System.Drawing.Printing.PrintDocument();2.设置打印机开始打印的事件处理函数.函数原形如下:void docToPrint_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)3.将事件处理函数添加到PrintDocument的PrintPage事件中。docToPrint.PrintPage+=new PrintPageEventHandler(docToPrint_PrintPage);4.设置PrintDocument的相关属性,如:PrintDialog1.AllowSomePages = true;PrintDialog1.ShowHelp = true;5.把PrintDialog的Document属性设为上面配置好的PrintDocument的实例:PrintDialog1.Document = docToPrint;6.调用PrintDialog的ShowDialog函数显示打印对话框:DialogResult result = PrintDialog1.ShowDialog();7.根据用户的选择,开始打印:if (result==DialogResult.OK) { docToPrint.Print(); }8.打印预览控件PrintPreviewDialog例子如下: 使用时先创建PrintService类的实例,然后调用void StartPrint(Stream streamToPrint,string streamType)函数开始打印。其中streamToPrint是要打印的内容(字节流),streamType是流的类型(txt表示普通文本,image表示图像); public partial class PrintTxt { private PrintPreviewDialog PrintPreview = new PrintPreviewDialog(); private string StreamType; private Image image = null; private Stream StreamToPrint = null; Font mainFont = new Font("宋体", 12);//打印的字体 public string Filename =null;
//1、实例化打印文档 PrintDocument pdDocument = new PrintDocument(); private string[] lines; private int linesPrinted;
public PrintTxt(string filepath,string filetype) {
Filename = Path.GetFileNameWithoutExtension(filepath);
//订阅BeginPrint事件 pdDocument.BeginPrint += new PrintEventHandler(pdDocument_BeginPrint); //訂閱EndPrint事件,释放资源
pdDocument.PrintPage += new PrintPageEventHandler(OnPrintPage);
//订阅Print打印事件,该方法必须放在订阅打印事件的最后 FileStream fs = new FileStream(filepath, FileMode.Open, FileAccess.Read); StartPrint(fs, filetype);
//打印结束 pdDocument.EndPrint += new PrintEventHandler(pdDocument_EndPrint);
} //2、启动Print打印方法 public void StartPrint(Stream streamToPrint, string streamType) { //返回值的PageSettings A4\A5 PageSettings ps = new PageSettings(); //显示设置打印页对话框 PageSetupDialog Psdl = new PageSetupDialog(); //打印多份设置,注意,该方法需放在printpage方法后面。 PrintDialog pt = new PrintDialog(); pt.AllowCurrentPage = true; pt.AllowSomePages = true; pt.AllowPrintToFile = true; StreamToPrint = streamToPrint;//打印的字节流 StreamType = streamType; //打印的类型 pdDocument.DocumentName = Filename; //打印的文件名 Psdl.Document = pdDocument; PrintPreview.Document = pdDocument; pt.Document = pdDocument; Psdl.PageSettings = pdDocument.DefaultPageSettings; try { //显示对话框 if (Psdl.ShowDialog() == DialogResult.OK) { ps = Psdl.PageSettings; pdDocument.DefaultPageSettings = Psdl.PageSettings; } if (pt.ShowDialog() == DialogResult.OK) { pdDocument.PrinterSettings.Copies = pt.PrinterSettings.Copies; pdDocument.Print(); } if(PrintPreview.ShowDialog()==DialogResult.OK ) //调用打印 pdDocument.Print(); * PrintDocument对象的Print()方法在PrintController类中执行PrintPage事件。 */ } catch (InvalidPrinterException ex) { MessageBox.Show(ex.Message, "Simple Editor", MessageBoxButtons.OK, MessageBoxIcon.Error); throw; } } /// /// 3、得到打印內容 /// 每个打印任务只调用OnBeginPrint()一次。 /// /// /// void pdDocument_BeginPrint(object sender, PrintEventArgs e) { char[] param = { '\n' }; char[] trimParam = { '\r' };//回车 switch (StreamType) { case "txt": StringBuilder text = new StringBuilder(); System.IO.StreamReader streamReader = new StreamReader(StreamToPrint, Encoding.Default); while (streamReader.Peek() >= 0) { lines = streamReader.ReadToEnd().Split(param); for (int i = 0; i < lines.Length; i++) { lines[i] = lines[i].TrimEnd(trimParam); } } break; case "image": image = System.Drawing.Image.FromStream(StreamToPrint); break; default: break; } } /// /// 4、绘制多个打印界面 /// printDocument的PrintPage事件 /// /// /// private void OnPrintPage(object sender, PrintPageEventArgs e) { int leftMargin = Convert.ToInt32((e.MarginBounds.Left) * 3 / 4); //左边距 int topMargin = Convert.ToInt32(e.MarginBounds.Top * 2 / 3); //顶边距 switch (StreamType) { case "txt": while (linesPrinted < lines.Length) { //向画布中填写内容 e.Graphics.DrawString(lines[linesPrinted++], new Font("Arial", 10), Brushes.Black, leftMargin, topMargin, new StringFormat()); topMargin += 55;//行高为55,可调整 //走纸换页 if (topMargin >= e.PageBounds.Height - 60)//页面累加的高度大于页面高度。根据自己需要,可以适当调整 { //如果大于设定的高 e.HasMorePages = true; /* * PrintPageEventArgs类的HaeMorePages属性为True时,通知控件器,必须再次調用OnPrintPage()方法,打印一个页面。 * PrintLoopI()有一个用於每个要打印的页面的序例。如果HasMorePages是False,PrintLoop()就会停止。 */ return; } } break; case "image"://一下涉及剪切图片, int width = image.Width; int height = image.Height; if ((width / e.MarginBounds.Width) > (height / e.MarginBounds.Height)) { width = e.MarginBounds.Width; height = image.Height * e.MarginBounds.Width / image.Width; } else { height = e.MarginBounds.Height; width = image.Width * e.MarginBounds.Height / image.Height; } System.Drawing.Rectangle destRect = new System.Drawing.Rectangle(topMargin, leftMargin, width, height); //向画布写入图片 for (int i = 0; i < Convert.ToInt32(Math.Floor((double)image.Height/ 820)) + 1; i++) { e.Graphics.DrawImage(image, destRect, i*820,i*1170 , image.Width, image.Height, System.Drawing.GraphicsUnit.Pixel); //走纸换页 if (i * 1170 >= e.PageBounds.Height - 60)//页面累加的高度大于页面高度。根据自己需要,可以适当调整 { //如果大于设定的高 e.HasMorePages = true; /* * PrintPageEventArgs类的HaeMorePages属性为True时,通知控件器,必须再次調用OnPrintPage()方法,打印一个页面。 * PrintLoopI()有一个用於每个要打印的页面的序例。如果HasMorePages是False,PrintLoop()就会停止。 */ return; } } break; } //打印完毕后,画线条,且注明打印日期 e.Graphics.DrawLine(new Pen(Color.Black), leftMargin, topMargin, e.MarginBounds.Right, topMargin); string strdatetime = DateTime.Now.ToLongDateString() + DateTime.Now.ToLongTimeString(); e.Graphics.DrawString(string.Format("打印时间:{0}", strdatetime), mainFont, Brushes.Black, e.MarginBounds.Right-240, topMargin+40, new StringFormat()); linesPrinted = 0; //绘制完成后,关闭多页打印功能 e.HasMorePages = false; } /// ///5、EndPrint事件,释放资源 /// /// /// void pdDocument_EndPrint(object sender, PrintEventArgs e) { //变量Lines占用和引用的字符串数组,现在释放 lines = null; } } //PrintTxt simple = new PrintTxt("D:\\Mainsoft\\12.txt", "txt"); C#学习笔记之PrintDocument打印 秋忆夏伤 于 2016-05-30 15:26:56 发布 8703 收藏 18分类专栏: C#学习笔记版权 C#学习笔记专栏收录该内容54 篇文章0 订阅订阅专栏using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Drawing.Printing;using System.Linq;using System.Management;using System.Text;using System.Threading.Tasks;using System.Windows.Forms; namespace PrintDocument控件{ public partial class Form1 : Form { public Form1() { InitializeComponent(); } /// /// PrintDocument:用于打印最重要的类,几乎所有的打印类都与这个类有关系。 /// // 1、打印页面设置 private void btnSetting_Click(object sender, EventArgs e) { // 打印页面设置对话框 PageSetupDialog page = new PageSetupDialog(); page.Document = printDocument1; page.AllowMargins = true; page.AllowOrientation = true; page.AllowPaper = true; page.AllowPrinter = true; page.ShowHelp = true; if (page.ShowDialog() == DialogResult.OK) { // 将设置好的打印页 用作 PrintDocument进行打印。 printDocument1.DefaultPageSettings = page.PageSettings; } } // 2、打印机设置 private void btnPrint_Click(object sender, EventArgs e) { // 打印机设置对话框 PrintDialog print = new PrintDialog(); print.Document = printDocument1; print.AllowCurrentPage = true; print.AllowPrintToFile = true; print.AllowSelection = true; print.AllowSomePages = true; print.ShowHelp = true; if (print.ShowDialog() == DialogResult.OK) { // 将设置好的打印机 用作 PrinDocument进行打印。 printDocument1.PrinterSettings = print.PrinterSettings; } } // 3、打印预览 private void btnPreview_Click(object sender, EventArgs e) { if (MessageBox.Show("是否要预览打印文件?", "打印预览", MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation) == DialogResult.OK) { // 设置要预览的文档 printPreviewDialog1.Document = printDocument1; // 开启操作系统的抗锯齿功能 printPreviewDialog1.UseAntiAlias = true; // 打开预览窗口 if (printPreviewDialog1.ShowDialog() == DialogResult.OK) { // 如果选择的是系统默认打印机,点击“打印”按钮之后,会跳出“文件另存为”窗口; // 如果选择别的打印机,点击“打印”之后,会直接打印,不会返回“OK”。 MessageBox.Show("开始打印"); } else { MessageBox.Show("关闭预览"); } } } // 4、开始打印 private void btnStart_Click(object sender, EventArgs e) { // PrintController:控制一个PrintDocument是如何打印的。 PrintController printController = new StandardPrintController(); printDocument1.PrintController = printController; printDocument1.DocumentName = "社保样卡"; printDocument1.PrinterSettings.PrinterName = "XID8600 U1"; printDocument1.Print(); // 触发Print_Page事件。 } // PrintDocument 三个事件中的第二个参数 e 有如下属性: // e.Cancel:设置为true,将取消这次打印作业。 // e.Griphics:所使用打印机的设备环境。 // e.HasMorePages:PrintPage事件打印一页后,如果仍有数据未打印,退出事件前设置 // HasMorePages=true;退出事件之后将再次出发PrintPage事件,打印下一页。 // e.MarginBounds:打印区域的大小,是Rectangle结构,元素包括左上角坐标(Left和Top), // 宽和高(Width和Height),单位为1/100英寸。 // e.PageSettings:PageSettings类对象,包含用对话框PageSetupDialog设置的页面打印方式的 // 全部信息, // 在调用 Print 方法后,在打印文档的第一页之前发生。 private void printDocument1_BeginPrint(object sender, System.Drawing.Printing.PrintEventArgs e) { } // 需要打印新的一页时发生,负责打印一页所需要的数据 // 打印预览会调用该事件,预览的内容就是此处设置好的内容。 private void printDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e) { Image iamge = Image.FromFile(@"D:\photo\test.jpg"); e.Graphics.DrawString("社保卡样卡", new Font("黑体", 35), Brushes.Black, new Point(400, 120)); e.Graphics.DrawString("姓名 张三", new Font("黑体", 25), Brushes.Black, new Point(480, 270)); e.Graphics.DrawString("社会保障号码 32032032302030230", new Font("黑体", 25), Brushes.Black, new Point(480, 360)); e.Graphics.DrawString("社会保障卡号 JS2018098", new Font("黑体", 25), Brushes.Black, new Point(480, 450)); e.Graphics.DrawString("制卡日期 2016年5月", new Font("黑体", 25), Brushes.Black, new Point(480, 540)); e.Graphics.DrawImage(iamge, new Point(100, 240)); } // 在打印完最后一页文档时发生。 private void printDocument1_EndPrint(object sender, System.Drawing.Printing.PrintEventArgs e) { } /// /// 打印机状态值 /// public enum PrinterStatus { 其他状态 = 1, 未知, 空闲, 正在打印, 预热, 停止打印, 打印中, 离线 } // 获取指定打印机的状态 private void btnState_Click(object sender, EventArgs e) { string strPrinter = "win32_printer.DeviceId='XID8300 U1'"; // 用指定的打印机实例化一个打印机对象。 ManagementObject printer = new ManagementObject(strPrinter); // 获取打印机信息。 printer.Get(); // 获取打印机状态属性 string str = printer.Properties["PrinterStatus"].Value.ToString(); textBox1.Text = str; } // 获取本地所有打印机信息 private void button1_Click(object sender, EventArgs e) { string strPrinter = "win32_printer"; // 获取本地所有打印机 ManagementClass mc = new ManagementClass(strPrinter); // 获取所有打印机实例的集合 ManagementObjectCollection moc = mc.GetInstances(); // 遍历本地所有打印机 foreach (ManagementObject printer in moc) { // 打印机名字 string strName = printer.Properties["DeviceId"].Value.ToString(); // 打印机状态 string strState = printer.Properties["PrinterStatus"].Value.ToString(); comboBox1.Items.Add(strName); } } }} 秋忆夏伤关注 ————————————————版权声明:本文为CSDN博主「秋忆夏伤」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/qq_29331365/article/details/51538369 |
CopyRight 2018-2019 实验室设备网 版权所有 |