PrintHelper.cs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563
  1. using ComPDFKit.Import;
  2. using ComPDFKit.PDFPage;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Drawing;
  6. using System.Drawing.Imaging;
  7. using System.Drawing.Printing;
  8. using System.Linq;
  9. using System.Printing;
  10. using System.Reflection;
  11. using System.Runtime.InteropServices;
  12. using System.Text;
  13. using System.Threading.Tasks;
  14. using System.Windows.Forms;
  15. namespace ComPDFKit.Controls.Printer
  16. {
  17. public enum DuplexingStage
  18. {
  19. None,
  20. FontSide,
  21. BackSide
  22. }
  23. public static class PrintHelper
  24. {
  25. private static PrintSettingsInfo printSettingsInfo;
  26. private static int MaxCopies = 1;
  27. private static bool FinishedFrontSide = false;
  28. private static bool isManualDuplex = false;
  29. private static List<OutputColor> outputColors;
  30. private static List<Duplexing> duplexings;
  31. private static Bitmap blankPageBitmapForPrint;
  32. private static int PrintIndex;
  33. public static PrintQueue printQueue;
  34. public static void InitPrint()
  35. {
  36. MaxCopies = 1;
  37. FinishedFrontSide = false;
  38. isManualDuplex = false;
  39. outputColors = new List<OutputColor>();
  40. duplexings = new List<Duplexing>();
  41. blankPageBitmapForPrint = null;
  42. PrintIndex = 0;
  43. }
  44. private static void SetPrinterLimits()
  45. {
  46. MaxCopies = printQueue.GetPrintCapabilities().MaxCopyCount.HasValue ? printQueue.GetPrintCapabilities().MaxCopyCount.Value : 1;
  47. outputColors = new List<OutputColor>(printQueue.GetPrintCapabilities().OutputColorCapability);
  48. duplexings = new List<Duplexing>(printQueue.GetPrintCapabilities().DuplexingCapability);
  49. }
  50. public static PrintQueue GetPrintQueue(PrintServer server, string printerName)
  51. {
  52. return server.GetPrintQueue(printerName);
  53. }
  54. public static void PrintDocument(PrintSettingsInfo printSettings)
  55. {
  56. printSettingsInfo = printSettings;
  57. SetPrinterLimits();
  58. if (printSettings.DuplexPrintMod == DuplexPrintMod.None ||
  59. (printSettings.PrintMode is BookletModeInfo bookletModeInfo && bookletModeInfo.Subset != BookletSubset.BothSides))
  60. {
  61. HandlePrintQueue(DuplexingStage.None);
  62. }
  63. else if (printSettings.DuplexPrintMod > 0 ||
  64. (printSettings.PrintMode is BookletModeInfo bookletModeInfo1 && bookletModeInfo1.Subset == BookletSubset.BothSides))
  65. {
  66. if (duplexings.Contains(Duplexing.TwoSidedShortEdge) || duplexings.Contains(Duplexing.TwoSidedLongEdge))
  67. {
  68. HandlePrintQueue(DuplexingStage.None);
  69. }
  70. else
  71. {
  72. if (OnlyOnePage())
  73. {
  74. HandlePrintQueue(DuplexingStage.None);
  75. }
  76. else
  77. {
  78. HandlePrintQueue(DuplexingStage.FontSide);
  79. if (FinishedFrontSide)
  80. {
  81. DialogResult dialogResult = MessageBox.Show("Print the back side.", "Print", MessageBoxButtons.YesNo);
  82. if (dialogResult == DialogResult.Yes)
  83. {
  84. HandlePrintQueue(DuplexingStage.BackSide);
  85. }
  86. }
  87. }
  88. }
  89. }
  90. bool OnlyOnePage()
  91. {
  92. return ((printSettings.PrintMode is SizeModeInfo || printSettings.PrintMode is PosterModeInfo) &&
  93. printSettings.PageRangeList.Count == 1) ||
  94. (printSettings.PrintMode is MultipleModeInfo multipleModeInfo &&
  95. (int)Math.Ceiling(printSettings.PageRangeList.Count / (double)(multipleModeInfo.Sheet.TotalPageNumber)) == 1);
  96. }
  97. }
  98. private static void HandlePrintQueue(DuplexingStage stage)
  99. {
  100. if (printQueue != null)
  101. {
  102. using (var printDocument = new PrintDocument())
  103. {
  104. var printTicket = new PrintTicket();
  105. printDocument.PrinterSettings.PrinterName = printQueue.Name;
  106. printDocument.DefaultPageSettings.Color = !printSettingsInfo.IsGrayscale && outputColors.Contains(OutputColor.Color);
  107. printTicket.PageOrientation = printSettingsInfo.PrintOrientation;
  108. if (printSettingsInfo.DuplexPrintMod > 0 || printSettingsInfo.PrintMode is BookletModeInfo)
  109. {
  110. if (stage == DuplexingStage.None)
  111. {
  112. if (printSettingsInfo.DuplexPrintMod == DuplexPrintMod.FlipLongEdge)
  113. {
  114. printDocument.PrinterSettings.Duplex = Duplex.Horizontal;
  115. }
  116. else
  117. {
  118. printDocument.PrinterSettings.Duplex = Duplex.Vertical;
  119. }
  120. PrintIndex = 0;
  121. }
  122. else
  123. {
  124. printDocument.PrinterSettings.Duplex = Duplex.Simplex;
  125. isManualDuplex = true;
  126. PrintIndex = stage == DuplexingStage.FontSide ? 0 : 1;
  127. }
  128. }
  129. else
  130. {
  131. printDocument.PrinterSettings.Duplex = Duplex.Simplex;
  132. PrintIndex = 0;
  133. }
  134. printQueue.DefaultPrintTicket = printTicket;
  135. printDocument.DefaultPageSettings.PaperSize = printSettingsInfo.PaperSize;
  136. printDocument.DefaultPageSettings.Landscape = (printSettingsInfo.PrintOrientation == PageOrientation.Landscape);
  137. List<PaperSource> paperSources;
  138. if (printDocument.PrinterSettings.PaperSources.Count > 0)
  139. {
  140. paperSources = Enumerable.Range(0, printDocument.PrinterSettings.PaperSources.Count).
  141. Select(i => printDocument.PrinterSettings.PaperSources[i]).ToList();
  142. }
  143. else
  144. {
  145. PaperSource defaultPaperSource = new PaperSource();
  146. defaultPaperSource.SourceName = "Default";
  147. paperSources = new List<PaperSource> { defaultPaperSource };
  148. }
  149. printDocument.DefaultPageSettings.Margins = new Margins() { Left = (int)printSettingsInfo.Margins.Left, Bottom = (int)printSettingsInfo.Margins.Bottom, Right = (int)printSettingsInfo.Margins.Right, Top = (int)printSettingsInfo.Margins.Top};
  150. if (printSettingsInfo.Copies >= printQueue.GetPrintCapabilities().MaxCopyCount)
  151. {
  152. printDocument.PrinterSettings.Copies = (short)MaxCopies;
  153. }
  154. else
  155. {
  156. printDocument.PrinterSettings.Copies = (short)printSettingsInfo.Copies;
  157. }
  158. printDocument.PrintPage -= PrintDocument_PrintPage;
  159. printDocument.PrintPage += PrintDocument_PrintPage;
  160. printDocument.PrinterSettings.PrintFileName = printSettingsInfo.Document.FileName;
  161. try
  162. {
  163. printDocument.Print();
  164. if(stage == DuplexingStage.FontSide)
  165. {
  166. FinishedFrontSide = true;
  167. }
  168. }
  169. catch (Exception ex)
  170. {
  171. MessageBox.Show(ex.Message);
  172. }
  173. }
  174. }
  175. }
  176. public static Bitmap ToGray(Bitmap bmp, int mode)
  177. {
  178. if (bmp == null)
  179. {
  180. return null;
  181. }
  182. int w = bmp.Width;
  183. int h = bmp.Height;
  184. try
  185. {
  186. byte newColor = 0;
  187. BitmapData srcData = bmp.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
  188. unsafe
  189. {
  190. byte* p = (byte*)srcData.Scan0.ToPointer();
  191. for (int y = 0; y < h; y++)
  192. {
  193. for (int x = 0; x < w; x++)
  194. {
  195. if (mode == 0)
  196. {
  197. newColor = (byte)((float)p[0] * 0.114f + (float)p[1] * 0.587f + (float)p[2] * 0.299f);
  198. }
  199. else
  200. {
  201. newColor = (byte)((float)(p[0] + p[1] + p[2]) / 3.0f);
  202. }
  203. p[0] = newColor;
  204. p[1] = newColor;
  205. p[2] = newColor;
  206. p += 3;
  207. }
  208. p += srcData.Stride - w * 3;
  209. }
  210. bmp.UnlockBits(srcData);
  211. return bmp;
  212. }
  213. }
  214. catch
  215. {
  216. return null;
  217. }
  218. }
  219. public static Bitmap BuildBmp(int width, int height, byte[] imgBytes)
  220. {
  221. // Check if the byte array length matches the expected size
  222. int expectedLength = width * height * 4;
  223. if (imgBytes.Length != expectedLength)
  224. {
  225. throw new ArgumentException("The length of imgBytes does not match the expected size.");
  226. }
  227. // Create a new bitmap with the specified width, height, and pixel format
  228. Bitmap bitmap = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
  229. // Lock the bitmap's bits for writing
  230. BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, bitmap.PixelFormat);
  231. try
  232. {
  233. // Copy the byte array to the bitmap's scan0 pointer
  234. Marshal.Copy(imgBytes, 0, bmpData.Scan0, imgBytes.Length);
  235. }
  236. finally
  237. {
  238. // Ensure that the bitmap is always unlocked, even if an exception occurs
  239. bitmap.UnlockBits(bmpData);
  240. }
  241. return bitmap;
  242. }
  243. public static int CaculatePrintedPageCount(PrintSettingsInfo printSettingsInfo)
  244. {
  245. int tempCount = printSettingsInfo.PageRangeList.Count;
  246. if (printSettingsInfo.PrintMode is MultipleModeInfo multipleModeInfo)
  247. {
  248. tempCount = (int)Math.Ceiling((double)tempCount /
  249. multipleModeInfo.Sheet.TotalPageNumber);
  250. }
  251. else if (printSettingsInfo.PrintMode is BookletModeInfo bookletInfo)
  252. {
  253. if (tempCount != 1)
  254. {
  255. tempCount = (bookletInfo.EndPageIndex - bookletInfo.BeginPageIndex + 1) / 2;
  256. if (bookletInfo.Subset != BookletSubset.BothSides)
  257. {
  258. tempCount /= 2;
  259. }
  260. }
  261. }
  262. return tempCount;
  263. }
  264. public static Bitmap CombineBitmap(Bitmap background, Bitmap foreground, System.Drawing.Point point)
  265. {
  266. if (background == null)
  267. {
  268. return null;
  269. }
  270. int bgWidth = background.Width;
  271. int bgHeight = background.Height;
  272. Bitmap newMap = new Bitmap(bgWidth, bgHeight);
  273. Graphics graphics = Graphics.FromImage(newMap);
  274. graphics.DrawImage(background, new System.Drawing.Point(0, 0));
  275. graphics.DrawImage(foreground, point);
  276. graphics.Dispose();
  277. return newMap;
  278. }
  279. private static void PrintDocumentModSize(PrintPageEventArgs e)
  280. {
  281. int PrintedPageCount = CaculatePrintedPageCount(printSettingsInfo);
  282. int widthDpiRatio = (int)e.Graphics.DpiX / 100;
  283. int heightDpiRatio = (int)e.Graphics.DpiY / 100;
  284. if (printSettingsInfo.PrintMode is SizeModeInfo sizeMode)
  285. {
  286. CPDFPage page = printSettingsInfo.Document.PageAtIndex(printSettingsInfo.TargetPaperList[PrintIndex]);
  287. Rectangle realBound = e.PageBounds;
  288. if (!printSettingsInfo.IsBorderless)
  289. {
  290. realBound.Width = realBound.Width - (int)printSettingsInfo.Margins.Left - (int)printSettingsInfo.Margins.Right;
  291. realBound.Height = realBound.Height - (int)printSettingsInfo.Margins.Top - (int)printSettingsInfo.Margins.Bottom;
  292. }
  293. Margins margins = e.PageSettings.Margins;
  294. Point point = new Point(0, 0);
  295. if (page != null)
  296. {
  297. CSize cSize = page.PageSize;
  298. System.Drawing.Size pageSize = new System.Drawing.Size((int)cSize.width * widthDpiRatio, (int)cSize.height * heightDpiRatio);
  299. byte[] bmpData = new byte[(int)(pageSize.Width * pageSize.Height * 4)];
  300. page.RenderPageBitmap(0, 0, pageSize.Width, pageSize.Height, 0xFFFFFFFF, bmpData, printSettingsInfo.IsPrintAnnot ? 1 : 0, printSettingsInfo.IsPrintForm);
  301. Bitmap bitmap = BuildBmp((int)pageSize.Width, (int)pageSize.Height, bmpData);
  302. if (printSettingsInfo.IsGrayscale)
  303. {
  304. bitmap = ToGray(bitmap, 0);
  305. }
  306. if (sizeMode.SizeType == SizeType.Adaptive)
  307. {
  308. int resizeHeight;
  309. int resizeWidth;
  310. if (bitmap.Height / bitmap.Width >= (printSettingsInfo.ActualHeight / printSettingsInfo.ActualWidth))
  311. {
  312. if (printSettingsInfo.PrintOrientation == PageOrientation.Portrait)
  313. {
  314. resizeHeight = (int)printSettingsInfo.ActualHeight;
  315. resizeWidth = (int)(printSettingsInfo.ActualHeight / bitmap.Height * bitmap.Width);
  316. }
  317. else
  318. {
  319. resizeWidth = (int)printSettingsInfo.ActualHeight;
  320. resizeHeight = (int)(printSettingsInfo.ActualHeight / bitmap.Height * bitmap.Width);
  321. }
  322. }
  323. else
  324. {
  325. if (printSettingsInfo.PrintOrientation == PageOrientation.Portrait)
  326. {
  327. resizeWidth = (int)printSettingsInfo.ActualWidth;
  328. resizeHeight = (int)(printSettingsInfo.ActualWidth / bitmap.Width * bitmap.Height);
  329. }
  330. else
  331. {
  332. resizeHeight = (int)printSettingsInfo.ActualWidth;
  333. resizeWidth = (int)(printSettingsInfo.ActualWidth / bitmap.Height * bitmap.Width);
  334. }
  335. }
  336. using (Bitmap resizedBitmap = new Bitmap(bitmap, resizeWidth * widthDpiRatio, resizeHeight * heightDpiRatio))
  337. {
  338. if (isManualDuplex && PrintIndex % 2 == 1 && printSettingsInfo.DuplexPrintMod == DuplexPrintMod.FlipShortEdge)
  339. {
  340. resizedBitmap.RotateFlip(RotateFlipType.RotateNoneFlipY);
  341. }
  342. float aspectRatioResizedBitmap = (float)resizedBitmap.Width / resizedBitmap.Height;
  343. float aspectRatioRealBound = (float)realBound.Width / realBound.Height;
  344. if (aspectRatioResizedBitmap != aspectRatioRealBound)
  345. {
  346. if (realBound.Width / aspectRatioResizedBitmap <= realBound.Height)
  347. {
  348. realBound.Height = (int)(realBound.Width / aspectRatioResizedBitmap);
  349. }
  350. else
  351. {
  352. realBound.Width = (int)(realBound.Height * aspectRatioResizedBitmap);
  353. }
  354. }
  355. int originX = (e.PageBounds.Width - realBound.Width)/2;
  356. int originY = (e.PageBounds.Height - realBound.Height)/2;
  357. if (!printSettingsInfo.IsBorderless)
  358. {
  359. if (originX < printSettingsInfo.Margins.Left)
  360. {
  361. originX = (int)printSettingsInfo.Margins.Left;
  362. }
  363. if (originY < printSettingsInfo.Margins.Top)
  364. {
  365. originY = (int)printSettingsInfo.Margins.Top;
  366. }
  367. }
  368. e.Graphics.DrawImage(resizedBitmap, new Rectangle(originX, originY, realBound.Width, realBound.Height), new Rectangle(0, 0, resizedBitmap.Width, resizedBitmap.Height), GraphicsUnit.Pixel);
  369. }
  370. }
  371. else if (sizeMode.SizeType == SizeType.Actural)
  372. {
  373. using (Bitmap resizedBitmap = ResizeBitmap(bitmap, 100))
  374. {
  375. if (isManualDuplex && PrintIndex % 2 == 1 && printSettingsInfo.DuplexPrintMod == DuplexPrintMod.FlipShortEdge)
  376. {
  377. resizedBitmap.RotateFlip(RotateFlipType.RotateNoneFlipY);
  378. }
  379. float aspectRatioResizedBitmap = (float)resizedBitmap.Width / resizedBitmap.Height;
  380. float aspectRatioRealBound = (float)realBound.Width / realBound.Height;
  381. if (aspectRatioResizedBitmap != aspectRatioRealBound)
  382. {
  383. if (realBound.Width / aspectRatioResizedBitmap <= realBound.Height)
  384. {
  385. realBound.Height = (int)(realBound.Width / aspectRatioResizedBitmap);
  386. }
  387. else
  388. {
  389. realBound.Width = (int)(realBound.Height * aspectRatioResizedBitmap);
  390. }
  391. }
  392. int originX = (e.PageBounds.Width - realBound.Width) / 2;
  393. int originY = (e.PageBounds.Height - realBound.Height) / 2;
  394. if (!printSettingsInfo.IsBorderless)
  395. {
  396. if (originX < printSettingsInfo.Margins.Left)
  397. {
  398. originX = (int)printSettingsInfo.Margins.Left;
  399. }
  400. if (originY < printSettingsInfo.Margins.Top)
  401. {
  402. originY = (int)printSettingsInfo.Margins.Top;
  403. }
  404. }
  405. e.Graphics.DrawImage(resizedBitmap, new Rectangle(originX, originY, realBound.Width, realBound.Height), new Rectangle(0, 0, resizedBitmap.Width, resizedBitmap.Height), GraphicsUnit.Pixel);
  406. }
  407. }
  408. else if (sizeMode.SizeType == SizeType.Customized)
  409. {
  410. using (Bitmap resizedBitmap = ResizeBitmap(bitmap, (printSettingsInfo.PrintMode as SizeModeInfo).Scale))
  411. {
  412. if (isManualDuplex && PrintIndex % 2 == 1 && printSettingsInfo.DuplexPrintMod == DuplexPrintMod.FlipShortEdge)
  413. {
  414. resizedBitmap.RotateFlip(RotateFlipType.RotateNoneFlipY);
  415. }
  416. float aspectRatioResizedBitmap = (float)resizedBitmap.Width / resizedBitmap.Height;
  417. float aspectRatioRealBound = (float)realBound.Width / realBound.Height;
  418. realBound.Width = (int)(realBound.Width * (printSettingsInfo.PrintMode as SizeModeInfo).Scale / 100.0);
  419. realBound.Height = (int)(realBound.Height * (printSettingsInfo.PrintMode as SizeModeInfo).Scale / 100.0);
  420. if (aspectRatioResizedBitmap != aspectRatioRealBound)
  421. {
  422. if (realBound.Width / aspectRatioResizedBitmap <= realBound.Height)
  423. {
  424. realBound.Height = (int)(realBound.Width / aspectRatioResizedBitmap);
  425. }
  426. else
  427. {
  428. realBound.Width = (int)(realBound.Height * aspectRatioResizedBitmap);
  429. }
  430. }
  431. int originX = (e.PageBounds.Width - realBound.Width) / 2;
  432. int originY = (e.PageBounds.Height - realBound.Height) / 2;
  433. if (!printSettingsInfo.IsBorderless)
  434. {
  435. if (originX < printSettingsInfo.Margins.Left)
  436. {
  437. originX = (int)printSettingsInfo.Margins.Left;
  438. }
  439. if (originY < printSettingsInfo.Margins.Top)
  440. {
  441. originY = (int)printSettingsInfo.Margins.Top;
  442. }
  443. }
  444. e.Graphics.DrawImage(resizedBitmap, new Rectangle(originX, originY, realBound.Width, realBound.Height), new Rectangle(0, 0, resizedBitmap.Width, resizedBitmap.Height), GraphicsUnit.Pixel);
  445. }
  446. }
  447. bitmap.Dispose();
  448. GC.Collect();
  449. if (isManualDuplex && PrintedPageCount != 1)
  450. {
  451. if (PrintIndex < PrintedPageCount - 2)
  452. {
  453. PrintIndex += 2;
  454. e.HasMorePages = true;
  455. }
  456. else
  457. {
  458. e.HasMorePages = false;
  459. if (PrintIndex % 2 == 0)
  460. {
  461. //
  462. }
  463. }
  464. }
  465. else
  466. {
  467. if (PrintIndex < PrintedPageCount - 1)
  468. {
  469. PrintIndex++;
  470. e.HasMorePages = true;
  471. }
  472. else
  473. {
  474. e.HasMorePages = false;
  475. }
  476. }
  477. }
  478. }
  479. }
  480. private static void PrintDocument_PrintPage(object sender, PrintPageEventArgs e)
  481. {
  482. switch (printSettingsInfo.PrintMode)
  483. {
  484. case SizeModeInfo _:
  485. PrintDocumentModSize(e);
  486. break;
  487. case PosterModeInfo _:
  488. break;
  489. case MultipleModeInfo _:
  490. break;
  491. case BookletModeInfo _:
  492. break;
  493. }
  494. }
  495. internal static Bitmap ResizeBitmap(Bitmap bitmap, float scale)
  496. {
  497. int newWidth = (int)(bitmap.Width * scale / 72);
  498. int newHeight = (int)(bitmap.Height * scale / 72);
  499. Bitmap newBitmap = new Bitmap(newWidth, newHeight);
  500. using (Graphics g = Graphics.FromImage(newBitmap))
  501. {
  502. g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
  503. g.DrawImage(bitmap, 0, 0, newWidth, newHeight);
  504. }
  505. return newBitmap;
  506. }
  507. }
  508. }