InvoiceLayoutPrinter.cs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557
  1. 
  2. using System;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using System.Data;
  6. using System.Drawing;
  7. using System.Drawing.Printing;
  8. using System.IO;
  9. using System.Runtime.Serialization.Formatters.Binary;
  10. using System.Security.Cryptography;
  11. using Curtain.Log;
  12. namespace Dongke.WinForm.Controls.InvoiceLayout
  13. {
  14. public class InvoiceLayoutPrinter
  15. {
  16. #region 常量
  17. #region 保存、读取相关
  18. // TODO 加密保存 解密读取
  19. private static byte[] KEY = new byte[] { 106, 240, 243, 74, 29, 163, 145, 29, 39, 65, 118, 96, 247, 237, 40, 121, 116, 10, 14, 50, 139, 117, 244, 163, 193, 190, 184, 66, 8, 185, 78, 73 };
  20. private static byte[] IV = new byte[] { 26, 122, 25, 28, 97, 211, 152, 32, 223, 110, 120, 242, 170, 35, 96, 93 };
  21. //private static ICryptoTransform _decryptor = null;
  22. #endregion 保存、读取相关
  23. #endregion
  24. #region 成员变量
  25. private PropertyOfLayoutBox Property = null;
  26. private GridItem OneGridItem = null;
  27. private List<LayoutItem> LayoutItems = null;
  28. private int PageWidthPixel = 0;
  29. private int PageHeightPixel = 0;
  30. private RectangleF BackImgRectangleF = RectangleF.Empty;
  31. private float _allOffsetX = 0;
  32. private float _allOffsetY = 0;
  33. private int _printPageNum = 1; // 打印页的当前页码
  34. private int _printTotalPageNum = 1; // 总页数
  35. private DataRow _printData = null;
  36. private DataTable _printGridData = null;
  37. private PrintDocument _printDocument = new PrintDocument();
  38. #endregion
  39. #region 构造函数
  40. static InvoiceLayoutPrinter()
  41. {
  42. //Rijndael age = Rijndael.Create();
  43. //_decryptor = age.CreateDecryptor(KEY, IV);
  44. }
  45. private InvoiceLayoutPrinter()
  46. {
  47. _printDocument.DocumentName = "LayoutDocument";
  48. _printDocument.BeginPrint += new PrintEventHandler(this.printDocument_BeginPrint);
  49. _printDocument.PrintPage += new PrintPageEventHandler(this.PrintDocument_PrintPage);
  50. }
  51. #endregion
  52. private void printDocument_BeginPrint(object sender, PrintEventArgs e)
  53. {
  54. }
  55. private void PrintDocument_PrintPage(object sender, PrintPageEventArgs e)
  56. {
  57. try
  58. {
  59. e.Graphics.PageUnit = GraphicsUnit.Millimeter;
  60. e.HasMorePages = DrawPage(e.Graphics);
  61. }
  62. catch (Exception ex)
  63. {
  64. Logger.Error(ex);
  65. }
  66. }
  67. public static List<Image> Print(byte[] layout, DataRow data, DataTable detail)
  68. {
  69. if (layout == null || layout.Length == 0)
  70. {
  71. throw new System.ArgumentNullException("layout");
  72. }
  73. if (data == null)
  74. {
  75. throw new System.ArgumentNullException("data");
  76. }
  77. //if (detail == null || detail.Rows.Count == 0)
  78. //{
  79. // throw new System.ArgumentNullException("detail");
  80. //}
  81. try
  82. {
  83. InvoiceLayoutPrinter printer = new InvoiceLayoutPrinter();
  84. printer.LayoutItems = new List<LayoutItem>();
  85. printer.ReadLayout(layout);
  86. printer._printData = data;
  87. printer._printGridData = detail;
  88. //return printer.DrawImages().ToArray();
  89. return printer.DrawImages();
  90. }
  91. catch (Exception ex)
  92. {
  93. throw ex;
  94. }
  95. }
  96. public static void Print(string printerName, short copies, byte[] layout, DataRow data, DataTable detail)
  97. {
  98. if (layout == null || layout.Length == 0)
  99. {
  100. throw new System.ArgumentNullException("layout");
  101. }
  102. if (data == null)
  103. {
  104. throw new System.ArgumentNullException("data");
  105. }
  106. //if (detail == null || detail.Rows.Count == 0)
  107. //{
  108. // throw new System.ArgumentNullException("detail");
  109. //}
  110. try
  111. {
  112. InvoiceLayoutPrinter printer = new InvoiceLayoutPrinter();
  113. printer.LayoutItems = new List<LayoutItem>();
  114. printer.ReadLayout(layout);
  115. printer._printData = data;
  116. printer._printGridData = detail;
  117. printer._printDocument.PrinterSettings.PrinterName = printerName;
  118. printer._printDocument.PrinterSettings.Copies = copies;
  119. printer._printDocument.Print();
  120. //return printer.DrawImages().ToArray();
  121. //return printer.DrawImages();
  122. }
  123. catch (Exception ex)
  124. {
  125. throw ex;
  126. }
  127. }
  128. #region 票据打印
  129. private void ReadLayout(byte[] layout)
  130. {
  131. try
  132. {
  133. using (MemoryStream stream = new MemoryStream(layout))
  134. {
  135. stream.Position = 0;
  136. // 反序列化
  137. BinaryFormatter formatter = new BinaryFormatter();
  138. // TODO 解密读取
  139. //if (CryptoStream)
  140. if (true)
  141. {
  142. //using (CryptoStream cStream = new CryptoStream(stream, _decryptor, CryptoStreamMode.Read))
  143. Rijndael age = Rijndael.Create();
  144. using (CryptoStream cStream = new CryptoStream(stream, age.CreateDecryptor(KEY, IV), CryptoStreamMode.Read))
  145. {
  146. this.Property = (PropertyOfLayoutBox)formatter.Deserialize(cStream);
  147. }
  148. }
  149. else
  150. {
  151. this.Property = (PropertyOfLayoutBox)formatter.Deserialize(stream);
  152. }
  153. //_lastItemRF = propertyOflayoutBox.LastItemRF;
  154. //_newItemID = propertyOflayoutBox.NewItemID;
  155. //_paperHeight = propertyOflayoutBox.PaperHeight;
  156. //_paperWidth = propertyOflayoutBox.PaperWidth;
  157. //if (_zoomType != ZoomType.Whole)
  158. //{
  159. // ChangePaperSize();
  160. //}
  161. //else
  162. //{
  163. // InitializeZoom();
  164. //}
  165. //paperArea.BackgroundImage = propertyOflayoutBox.BackgroundImage;
  166. //_backgroundImageName = propertyOflayoutBox.BackgroundImageName;
  167. //_isPrintBackground = propertyOflayoutBox.PrintBackground;
  168. //_isPrintAreaVisible = propertyOflayoutBox.PrintAreaVisible;
  169. ArrayList items = this.Property.Items;
  170. if (items != null && 0 < items.Count)
  171. {
  172. foreach (LayoutItem item in items)
  173. {
  174. //item.Init(this, false);
  175. //item.Init();
  176. this.LayoutItems.Add(item);
  177. if (item.ItemType == ItemType.Grid)
  178. {
  179. this.OneGridItem = item as GridItem;
  180. if (this.OneGridItem.HeadRowsHeight == 0)
  181. {
  182. this.OneGridItem.HeadRowsHeight = this.OneGridItem.RowsHeight;
  183. }
  184. }
  185. }
  186. }
  187. //paperArea.Select();
  188. //RefreshItemsBound();
  189. ////paperArea.Refresh();
  190. //return true;
  191. }
  192. }
  193. catch (Exception ex)
  194. {
  195. throw ex;
  196. }
  197. }
  198. private List<Image> DrawImages()
  199. {
  200. this.PageWidthPixel = LayoutCommon.MillimeterToPixel(this.Property.PaperWidth);
  201. this.PageHeightPixel = LayoutCommon.MillimeterToPixel(this.Property.PaperHeight);
  202. this._printPageNum = 1;
  203. this._printTotalPageNum = 1;
  204. //if (this.OneGridItem != null)
  205. //{
  206. // foreach (LayoutItem item in this.LayoutItems)
  207. // {
  208. // if (item.ItemType == ItemType.Grid)
  209. // {
  210. // GridItem gItem = (item as GridItem);
  211. // gItem.PrintGridSource = this._printGridData;
  212. // _printTotalPageNum = Math.Max(_printTotalPageNum, gItem.PrintTotalPageNum);
  213. // }
  214. // }
  215. //}
  216. List<Image> images = new List<Image>();
  217. //Bitmap pageImage = null;
  218. //Graphics pageGraphics = null;
  219. bool hasNextPage = true;
  220. while (hasNextPage)
  221. {
  222. Bitmap pageImage = new Bitmap(this.PageWidthPixel, this.PageHeightPixel);
  223. pageImage.SetResolution(LayoutCommon.DPI, LayoutCommon.DPI);
  224. using (Graphics pageGraphics = Graphics.FromImage(pageImage))
  225. {
  226. // TODO 白色背景
  227. pageGraphics.Clear(Color.White);
  228. //pageGraphics.FillRectangle(Brushes.White, pageGraphics.ClipBounds);
  229. pageGraphics.PageUnit = GraphicsUnit.Millimeter;
  230. hasNextPage = DrawPage(pageGraphics);
  231. images.Add(pageImage);
  232. }
  233. }
  234. return images;
  235. }
  236. private bool DrawPage(Graphics graphics)
  237. {
  238. //try
  239. {
  240. // 背景打印
  241. if (this.Property.PrintBackground)
  242. {
  243. PrintBackgroundImage(graphics);
  244. }
  245. // Item打印
  246. foreach (LayoutItem layoutItem in this.LayoutItems)
  247. {
  248. switch (layoutItem.ItemType)
  249. {
  250. case ItemType.Text:
  251. DrawTextItem(graphics, (TextItem)layoutItem);
  252. break;
  253. case ItemType.Image:
  254. DrawImageItem(graphics, (ImageItem)layoutItem);
  255. break;
  256. case ItemType.Rectangle:
  257. DrawRectangleItem(graphics, (RectangleItem)layoutItem);
  258. break;
  259. case ItemType.Ellipse:
  260. DrawEllipseItem(graphics, (EllipseItem)layoutItem);
  261. break;
  262. //case ItemType.Line:
  263. // DrawLineItem(graphics, (LineItem)layoutItem);
  264. // break;
  265. case ItemType.Grid:
  266. DrawGridItem(graphics, (GridItem)layoutItem);
  267. break;
  268. case ItemType.PageNum:
  269. DrawPageNumItem(graphics, (PageNumItem)layoutItem);
  270. break;
  271. case ItemType.TotalText:
  272. DrawTotalTextItem(graphics, (TotalTextItem)layoutItem);
  273. break;
  274. default:
  275. //throw new NotImplementedException();
  276. break;
  277. }
  278. }
  279. // 表格Item是否有下一页
  280. if (_printPageNum < _printTotalPageNum)
  281. {
  282. _printPageNum++;
  283. //e.HasMorePages = true;
  284. return true;
  285. }
  286. return false;
  287. }
  288. //catch (Exception ex)
  289. //{
  290. // throw ex;
  291. //}
  292. }
  293. #region 绘制
  294. /// <summary>
  295. /// 打印背景图片
  296. /// </summary>
  297. /// <param name="graphics">用于绘制的System.Drawing.Graphics</param>
  298. private void PrintBackgroundImage(Graphics graphics)
  299. {
  300. if (this.Property.BackgroundImage != null)
  301. {
  302. if (this.BackImgRectangleF.IsEmpty)
  303. {
  304. // 背景图片的高宽比例
  305. float imgWHRate = (float)this.Property.BackgroundImage.Width / (float)this.Property.BackgroundImage.Height;
  306. // 打印纸张的高宽比例
  307. float paperWHRate = this.Property.PaperWidth / this.Property.PaperHeight;
  308. // 缩放背景图片,但保持图片高宽比例
  309. if (imgWHRate > paperWHRate)
  310. {
  311. BackImgRectangleF.Width = this.Property.PaperWidth;
  312. BackImgRectangleF.Height = this.Property.PaperWidth / imgWHRate;
  313. BackImgRectangleF.X = 0;
  314. BackImgRectangleF.Y = (this.Property.PaperHeight - BackImgRectangleF.Height) / 2 + 0;
  315. }
  316. else
  317. {
  318. BackImgRectangleF.Width = this.Property.PaperHeight * imgWHRate;
  319. BackImgRectangleF.Height = this.Property.PaperHeight;
  320. BackImgRectangleF.X = (this.Property.PaperWidth - BackImgRectangleF.Width) / 2 + 0;
  321. BackImgRectangleF.Y = 0;
  322. }
  323. }
  324. // 在指定的范围绘制背景图片
  325. graphics.DrawImage(this.Property.BackgroundImage, BackImgRectangleF);
  326. }
  327. }
  328. /// <summary>
  329. /// 打印文本Item
  330. /// </summary>
  331. /// <param name="graphics">用于绘制的System.Drawing.Graphics</param>
  332. /// <param name="textItem">文本Item</param>
  333. private void DrawTextItem(Graphics graphics, TextItem textItem)
  334. {
  335. // 文本Item打印范围
  336. RectangleF rectangleFM = new RectangleF(
  337. _allOffsetX + textItem.Left,
  338. _allOffsetY + textItem.Top,
  339. textItem.Width,
  340. textItem.Height);
  341. RectangleF rectangleF = rectangleFM;
  342. rectangleF.Inflate(0 - LayoutConsts.TEXT_MARGIN, 0 - LayoutConsts.TEXT_MARGIN);
  343. rectangleFM.Height -= LayoutConsts.TEXT_MARGIN;
  344. object value = null;
  345. if (this._printData.Table.Columns.Contains(textItem.DataMember))
  346. {
  347. value = this._printData[textItem.DataMember];
  348. }
  349. textItem.PrintTextItem(value, graphics, rectangleFM, rectangleF);
  350. }
  351. /// <summary>
  352. /// 打印图片Item
  353. /// </summary>
  354. /// <param name="graphics">用于绘制的System.Drawing.Graphics</param>
  355. /// <param name="imageItem">图片Item</param>
  356. private void DrawImageItem(Graphics graphics, ImageItem imageItem)
  357. {
  358. // 图片Item打印范围
  359. RectangleF rectangleF = new RectangleF(
  360. _allOffsetX + imageItem.Left,
  361. _allOffsetY + imageItem.Top,
  362. imageItem.Width,
  363. imageItem.Height);
  364. // 在指定的范围绘制图片Item
  365. LayoutUtility.DrawImage(graphics, rectangleF, imageItem.Image);
  366. }
  367. /// <summary>
  368. /// 打印矩形Item
  369. /// </summary>
  370. /// <param name="graphics">用于绘制的System.Drawing.Graphics</param>
  371. /// <param name="rectangleItem">矩形Item</param>
  372. private void DrawRectangleItem(Graphics graphics, RectangleItem rectangleItem)
  373. {
  374. // 矩形Item打印范围
  375. RectangleF rectangleF = new RectangleF(
  376. _allOffsetX + rectangleItem.Left,
  377. _allOffsetY + rectangleItem.Top,
  378. rectangleItem.Width,
  379. rectangleItem.Height);
  380. float lineWidthDraw = rectangleItem.LineWidth;
  381. // 在指定的范围绘制矩形Item
  382. LayoutUtility.DrawRectangle(graphics, rectangleF, rectangleItem.LineColor,
  383. rectangleItem.FillColor, lineWidthDraw, rectangleItem.Transparent);
  384. }
  385. /// <summary>
  386. /// 打印椭圆Item
  387. /// </summary>
  388. /// <param name="graphics">用于绘制的System.Drawing.Graphics</param>
  389. /// <param name="ellipseItem">椭圆Item</param>
  390. private void DrawEllipseItem(Graphics graphics, EllipseItem ellipseItem)
  391. {
  392. // 椭圆Item打印范围
  393. RectangleF rectangleF = new RectangleF(
  394. _allOffsetX + ellipseItem.Left,
  395. _allOffsetY + ellipseItem.Top,
  396. ellipseItem.Width,
  397. ellipseItem.Height);
  398. float lineWidthDraw = ellipseItem.LineWidth;
  399. // 在指定的范围绘制椭圆Item
  400. LayoutUtility.DrawEllipse(graphics, rectangleF, ellipseItem.LineColor,
  401. ellipseItem.FillColor, lineWidthDraw, ellipseItem.Transparent);
  402. }
  403. /// <summary>
  404. /// 打印表格Item
  405. /// </summary>
  406. /// <param name="graphics">用于绘制的System.Drawing.Graphics</param>
  407. /// <param name="gridItem">表格Item</param>
  408. private void DrawGridItem(Graphics graphics, GridItem gridItem)
  409. {
  410. // 表格Item打印范围
  411. RectangleF rectangleF = new RectangleF(
  412. _allOffsetX + gridItem.Left,
  413. _allOffsetY + gridItem.Top,
  414. gridItem.Width,
  415. gridItem.Height);
  416. // 在指定的范围绘制表格Item
  417. //gridItem.DrawGridItem(graphics, rectangleF, 1, _printPageNum);
  418. gridItem.PrintGridItem(graphics, rectangleF, _printPageNum);
  419. }
  420. /// <summary>
  421. /// 打印页码Item
  422. /// </summary>
  423. /// <param name="graphics">用于绘制的System.Drawing.Graphics</param>
  424. /// <param name="pageNumItem">页码Item</param>
  425. private void DrawPageNumItem(Graphics graphics, PageNumItem pageNumItem)
  426. {
  427. // 文本Item打印范围
  428. RectangleF rectangleFM = new RectangleF(
  429. _allOffsetX + pageNumItem.Left,
  430. _allOffsetY + pageNumItem.Top,
  431. pageNumItem.Width,
  432. pageNumItem.Height);
  433. RectangleF rectangleF = rectangleFM;
  434. rectangleF.Inflate(0 - LayoutConsts.TEXT_MARGIN, 0 - LayoutConsts.TEXT_MARGIN);
  435. rectangleFM.Height -= LayoutConsts.TEXT_MARGIN;
  436. // 在指定的范围绘制文本Item
  437. LayoutUtility.DrawText(graphics,
  438. rectangleFM,
  439. rectangleF,
  440. pageNumItem.GetPrintText(this._printPageNum, this._printTotalPageNum),
  441. pageNumItem.Font,
  442. pageNumItem.TextColor,
  443. 0,
  444. 0,
  445. 0,
  446. pageNumItem.TextAlign,
  447. pageNumItem.TextAlignVertical,
  448. false,
  449. false,
  450. false);
  451. }
  452. /// <summary>
  453. /// 打印合计Item
  454. /// </summary>
  455. /// <param name="graphics">用于绘制的System.Drawing.Graphics</param>
  456. /// <param name="totalTextItem">合计Item</param>
  457. private void DrawTotalTextItem(Graphics graphics, TotalTextItem totalTextItem)
  458. {
  459. // 文本Item打印范围
  460. RectangleF rectangleFM = new RectangleF(
  461. _allOffsetX + totalTextItem.Left,
  462. _allOffsetY + totalTextItem.Top,
  463. totalTextItem.Width,
  464. totalTextItem.Height);
  465. RectangleF rectangleF = rectangleFM;
  466. rectangleF.Inflate(0 - LayoutConsts.TEXT_MARGIN, 0 - LayoutConsts.TEXT_MARGIN);
  467. rectangleFM.Height -= LayoutConsts.TEXT_MARGIN;
  468. if (_printPageNum != _printTotalPageNum && totalTextItem.NotTotalValue != "[#合计值#]")
  469. {
  470. LayoutUtility.DrawText(graphics,
  471. rectangleFM,
  472. rectangleF,
  473. totalTextItem.NotTotalValue,
  474. totalTextItem.NotTotalFont,
  475. totalTextItem.NotTotalColor,
  476. totalTextItem.LineSpace,
  477. totalTextItem.CharacterSpace,
  478. totalTextItem.CharacterCount,
  479. totalTextItem.NotTotalAlign,
  480. totalTextItem.NotTotalAlignVertical,
  481. totalTextItem.Wrap,
  482. totalTextItem.Clip,
  483. false);
  484. return;
  485. }
  486. // 在指定的范围绘制文本Item
  487. object value = null;
  488. if (this._printData.Table.Columns.Contains(totalTextItem.DataMember))
  489. {
  490. value = this._printData[totalTextItem.DataMember];
  491. }
  492. value = totalTextItem.ResetTextValue(value, true);
  493. LayoutUtility.DrawText(graphics,
  494. rectangleFM,
  495. rectangleF,
  496. (value == null? "": value.ToString()),
  497. totalTextItem.Font,
  498. totalTextItem.TextColor,
  499. totalTextItem.LineSpace,
  500. totalTextItem.CharacterSpace,
  501. totalTextItem.CharacterCount,
  502. totalTextItem.TextAlign,
  503. totalTextItem.NotTotalAlignVertical,
  504. totalTextItem.Wrap,
  505. totalTextItem.Clip,
  506. false);
  507. }
  508. #endregion
  509. #endregion
  510. }
  511. }