SplitPrintController.cs 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. using System;
  2. using System.Drawing.Printing;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using FastReport.Utils;
  6. using System.Drawing;
  7. namespace FastReport.Print
  8. {
  9. internal class SplitPrintController : PrintControllerBase
  10. {
  11. #region Fields
  12. private List<SplittedPage> splittedPages;
  13. private float addX = 5;
  14. private float addY = 5;
  15. private float offsetX;
  16. private float offsetY;
  17. private bool landscape;
  18. #endregion
  19. #region Private methods
  20. private ReportPage GetNextSplittedPage()
  21. {
  22. if (splittedPages.Count == 0)
  23. return null;
  24. PageNo = splittedPages[0].pageNo;
  25. offsetX = splittedPages[0].offsetX;
  26. offsetY = splittedPages[0].offsetY;
  27. landscape = splittedPages[0].landscape;
  28. splittedPages.RemoveAt(0);
  29. return Report.PreparedPages.GetPage(PageNo);
  30. }
  31. private bool HasMoreSplittedPages()
  32. {
  33. return splittedPages.Count > 0;
  34. }
  35. private void TrySplit(float a, float b, float c, float d, out int x, out int y)
  36. {
  37. x = Math.Abs(Math.Truncate(a / c) * c - a) < 11 ?
  38. (int)Math.Round(a / c) : (int)Math.Truncate(a / c) + 1;
  39. y = Math.Abs(Math.Truncate(b / d) * d - b) < 11 ?
  40. (int)Math.Round(b / d) : (int)Math.Truncate(b / d) + 1;
  41. }
  42. private void SplitPage(float a, float b, float c, float d, out int x, out int y, out bool needRotate)
  43. {
  44. needRotate = false;
  45. TrySplit(a, b, c, d, out x, out y);
  46. int tempX = x;
  47. int tempY = y;
  48. float tempC = c;
  49. c = d;
  50. d = tempC;
  51. TrySplit(a, b, c, d, out x, out y);
  52. if (x * y >= tempX * tempY)
  53. {
  54. x = tempX;
  55. y = tempY;
  56. }
  57. else
  58. needRotate = true;
  59. }
  60. #endregion
  61. #region Public methods
  62. public override void QueryPageSettings(object sender, QueryPageSettingsEventArgs e)
  63. {
  64. Page = GetNextSplittedPage();
  65. if (Page != null)
  66. {
  67. SetPaperSize(Report.PrintSettings.PrintOnSheetWidth, Report.PrintSettings.PrintOnSheetHeight,
  68. Report.PrintSettings.PrintOnSheetRawPaperSize, e);
  69. e.PageSettings.Landscape = landscape;
  70. SetPaperSource(Page, e);
  71. Duplex duplex = Page.Duplex;
  72. if (duplex != Duplex.Default)
  73. e.PageSettings.PrinterSettings.Duplex = duplex;
  74. }
  75. }
  76. public override void PrintPage(object sender, PrintPageEventArgs e)
  77. {
  78. StartPage(e);
  79. Graphics g = e.Graphics;
  80. FRPaintEventArgs paintArgs;
  81. IGraphics gr = GdiGraphics.FromGraphics(g);
  82. if (Config.IsRunningOnMono)
  83. {
  84. // Point is the only right thing to use in mono. Pixel unit produces weird layout
  85. g.PageUnit = GraphicsUnit.Point;
  86. g.ResetTransform();
  87. g.TranslateTransform(offsetX * Units.Millimeters * 72f / 96f, offsetY * Units.Millimeters * 72f / 96f);
  88. // workaround different pango/cairo rendering behavior
  89. if (DrawUtils.GetMonoRendering(g) == MonoRendering.Pango)
  90. {
  91. g.ScaleTransform(72f / 96f, 72f / 96f);
  92. paintArgs = new FRPaintEventArgs(gr, 1, 1, Report.GraphicCache);
  93. }
  94. else
  95. {
  96. paintArgs = new FRPaintEventArgs(gr, 72f / 96f, 72f / 96f, Report.GraphicCache);
  97. }
  98. }
  99. else
  100. {
  101. g.PageUnit = GraphicsUnit.Pixel;
  102. g.TranslateTransform(offsetX * Units.Millimeters * g.DpiX / 96, offsetY * Units.Millimeters * g.DpiY / 96);
  103. paintArgs = new FRPaintEventArgs(gr, g.DpiX / 96, g.DpiY / 96, Report.GraphicCache);
  104. }
  105. Page.Print(paintArgs);
  106. Page.Dispose();
  107. FinishPage(e);
  108. e.HasMorePages = HasMoreSplittedPages();
  109. }
  110. #endregion
  111. public SplitPrintController(Report report, PrintDocument doc, int curPage) : base(report, doc, curPage)
  112. {
  113. splittedPages = new List<SplittedPage>();
  114. // get hard margins
  115. float leftMargin = doc.PrinterSettings.DefaultPageSettings.HardMarginX / 100f * 25.4f;
  116. float topMargin = doc.PrinterSettings.DefaultPageSettings.HardMarginY / 100f * 25.4f;
  117. float rightMargin = leftMargin;
  118. float bottomMargin = topMargin;
  119. int countX;
  120. int countY;
  121. bool needChangeOrientation;
  122. while (true)
  123. {
  124. Page = GetNextPage();
  125. if (Page == null)
  126. break;
  127. if (!Page.UnlimitedHeight && !Page.UnlimitedWidth)
  128. {
  129. SplitPage(Page.PaperWidth, Page.PaperHeight,
  130. Report.PrintSettings.PrintOnSheetWidth, Report.PrintSettings.PrintOnSheetHeight,
  131. out countX, out countY, out needChangeOrientation);
  132. }
  133. else
  134. {
  135. SplitPage(Page.WidthInPixels / Units.Millimeters, Page.HeightInPixels / Units.Millimeters,
  136. Report.PrintSettings.PrintOnSheetWidth, Report.PrintSettings.PrintOnSheetHeight,
  137. out countX, out countY, out needChangeOrientation);
  138. }
  139. bool landscape = false;
  140. if (needChangeOrientation)
  141. landscape = true;
  142. float pieceX = landscape ? Report.PrintSettings.PrintOnSheetHeight : Report.PrintSettings.PrintOnSheetWidth;
  143. float pieceY = landscape ? Report.PrintSettings.PrintOnSheetWidth : Report.PrintSettings.PrintOnSheetHeight;
  144. float marginY = 0;
  145. float printedY = 0;
  146. float offsY = -topMargin;
  147. for (int y = 1; y <= countY; y++)
  148. {
  149. float marginX = 0;
  150. float printedX = 0;
  151. float offsX = -leftMargin;
  152. for (int x = 1; x <= countX; x++)
  153. {
  154. splittedPages.Add(new SplittedPage(PageNo, offsX, offsY, landscape));
  155. printedX += (pieceX - marginX - rightMargin) - addX;
  156. offsX = -printedX;
  157. marginX = leftMargin;
  158. }
  159. printedY += (pieceY - marginY - bottomMargin) - addY;
  160. offsY = -printedY;
  161. marginY = topMargin;
  162. }
  163. Page.Dispose();
  164. }
  165. }
  166. private class SplittedPage
  167. {
  168. // physical pageno
  169. public int pageNo;
  170. // offsetx, in mm
  171. public float offsetX;
  172. // offsety, in mm
  173. public float offsetY;
  174. // determines if we should rotate the output page
  175. public bool landscape;
  176. public SplittedPage(int pageNo, float ofsX, float ofsY, bool landscape)
  177. {
  178. this.pageNo = pageNo;
  179. offsetX = ofsX;
  180. offsetY = ofsY;
  181. this.landscape = landscape;
  182. }
  183. }
  184. }
  185. }