/// /// Copyright (c) 2017-2020 Sensus Slovensko a.s. /// using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Printing; using System.IO; using Common; using GenCode128; using Gma.QrCodeNet.Encoding; using Results.Resources; namespace Results.Output.Printers.OnePerMeter { public class OnePerMeterPrintDocument : Common.Printers.PrintersCommon { const float GapBetweenTableColumns = 10; const float GapBetweenCommonColumns = 10; static QrEncoder encoder = new QrEncoder(); /// Size of the printed area without margins, after taking into account 'pageOrientation' readonly int printHeight; readonly int printWidth; readonly int topMargin; readonly int bottomMargin; readonly int leftMargin; readonly int TitleX; readonly int TitleY; /// Depends on the size of the header readonly int spacingOne; readonly int spacingOne4Header; float titleHeight; /// /// Property variable for the Font the user wishes to use /// Font titleFont; Font headerFont; Font font; Font footerFont; /// /// Data to print /// Results.Entities.Batch batch; OnePerMeterPrinterCfg cfg; Results.Entities.WaterMeter wm; /// /// Items to print /// string header; IList commonItems1; IList commonItems2; IList commonItems3; IList testItems; IList testItems2; IList belowItems1; IList belowItems2; IList belowItems3; string footer; int nrPages; int pageNr; /// Page number to be printed at the bottom of the page /// /// Constructor /// /// Text to be printed public OnePerMeterPrintDocument(Results.Entities.Batch batch, OnePerMeterPrinterCfg cfg, Results.Entities.WaterMeter wm, string documentName) { this.batch = batch; this.cfg = cfg; this.wm = wm; DocumentName = documentName; topMargin = cfg.TopMargin; bottomMargin = cfg.BottomMargin; leftMargin = cfg.LeftMargin; header = string.IsNullOrEmpty(cfg.Header) ? string.Empty : cfg.Header.Replace("~", Environment.NewLine); commonItems1 = Results.WMeterRsltItemSpec.FromStrArray(cfg.CommonItems1); commonItems2 = Results.WMeterRsltItemSpec.FromStrArray(cfg.CommonItems2); commonItems3 = Results.WMeterRsltItemSpec.FromStrArray(cfg.CommonItems3); testItems = Results.WMeterRsltItemSpec.FromStrArray(cfg.TestItems); /// TestID info will be overwritten later on testItems2 = Results.WMeterRsltItemSpec.FromStrArray(cfg.TestItems2); /// TestID info will be overwritten later on belowItems1 = Results.WMeterRsltItemSpec.FromStrArray(cfg.BelowItems1); belowItems2 = Results.WMeterRsltItemSpec.FromStrArray(cfg.BelowItems2); belowItems3 = Results.WMeterRsltItemSpec.FromStrArray(cfg.BelowItems3); footer = string.IsNullOrEmpty(cfg.Footer) ? string.Empty : cfg.Footer.Replace("~", Environment.NewLine); /// Initialize fonts titleFont = new Font((cfg.TitFntFml != null ? cfg.TitFntFml : "Arial"), (cfg.TitFntSz > 0 ? cfg.TitFntSz : 10), (FontStyle)cfg.TitFntSty); headerFont = new Font((cfg.HdrFntFml != null ? cfg.HdrFntFml : "Arial"), (cfg.HdrFntSz > 0 ? cfg.HdrFntSz : 10), (FontStyle)cfg.HdrFntSty); font = new Font((cfg.BodyFntFml != null ? cfg.BodyFntFml : "Arial"), (cfg.BodyFntSz > 0 ? cfg.BodyFntSz : 10), (FontStyle)cfg.BodyFntSty); footerFont = new Font((cfg.FooterFntFml != null ? cfg.FooterFntFml : "Arial"), (cfg.FooterFntSz > 0 ? cfg.FooterFntSz : 10), (FontStyle)cfg.FooterFntSty); /// Set print area size and margins (in dots using 100 dpi) DefaultPageSettings.Landscape = (cfg.PageOrientation == PageOrientation.Landscape); /// if (DefaultPageSettings.Landscape) { printHeight = base.DefaultPageSettings.PaperSize.Width - topMargin - bottomMargin; printWidth = base.DefaultPageSettings.PaperSize.Height - leftMargin - leftMargin; } else { printHeight = base.DefaultPageSettings.PaperSize.Height - topMargin - bottomMargin; printWidth = base.DefaultPageSettings.PaperSize.Width - leftMargin - leftMargin; } spacingOne = System.Windows.Forms.TextRenderer.MeasureText("Abcgq", font).Height; spacingOne4Header = System.Windows.Forms.TextRenderer.MeasureText("Abcgq", headerFont).Height; /// Prepare document outline TitleX = cfg.LeftMargin; TitleY = cfg.TopMargin; pageNr = 1; nrPages = (testItems2.Count != 0) ? 2 : 1; } /// /// Override the default onbeginPrint method of the PrintDocument Object /// /// /// protected override void OnBeginPrint(System.Drawing.Printing.PrintEventArgs e) { base.OnBeginPrint(e); } /// /// Override the default OnPrintPage method of the PrintDocument. /// /// /// This provides the print logic for our document protected override void OnPrintPage(System.Drawing.Printing.PrintPageEventArgs e) { /// Run base code base.OnPrintPage(e); if (!string.IsNullOrEmpty(cfg.Template)) { string templatePath = Path.Combine("C:\\TBF\\Templates\\", cfg.Template); if (File.Exists(templatePath)) { if (cfg.PageOrientation == PageOrientation.Portrait) e.Graphics.DrawImage(new Bitmap(Image.FromFile(templatePath), 827, 1169), new Rectangle(0, 0, 827, 1169)); else e.Graphics.DrawImage(new Bitmap(Image.FromFile(templatePath), 1169, 827), new Rectangle(0, 0, 1169, 827)); } } if ((cfg.GraphHgh != 0) && (cfg.GraphWid != 0)) { Rectangle pos = new Rectangle(cfg.GraphLeft, cfg.GraphTop, cfg.GraphWid, cfg.GraphHgh); WMChart.GetChart(wm, true).Printing.PrintPaint(e.Graphics, pos); } if (cfg.BarcodeType != BarcodeType.None && cfg.BarcodeType < BarcodeType.Count && !string.IsNullOrEmpty(wm.SerialNr)) { try { if (cfg.BarcodeType == BarcodeType.QR_Code) { QrCode qrCode = encoder.Encode(wm.SerialNr); DrawQR(e.Graphics, qrCode, cfg.BarcodeLeft, cfg.BarcodeTop, cfg.BarcodeWidth, cfg.BarcodeHeight); } else if (cfg.BarcodeType == BarcodeType.Code_128_Horizontally || cfg.BarcodeType == BarcodeType.Code_128_Vertically) { Image img = Code128Rendering.MakeBarcodeImage(wm.SerialNr, 1, true); if (cfg.BarcodeType == BarcodeType.Code_128_Vertically) { img.RotateFlip(RotateFlipType.Rotate90FlipNone); } e.Graphics.DrawImage(img, cfg.BarcodeLeft, cfg.BarcodeTop, cfg.BarcodeWidth, cfg.BarcodeHeight); } } catch (Exception) { } } float tableTop = cfg.TopMargin; if (pageNr == 1) { /// First page /// /// Print water meter picture /// if (cfg.ImgWid != 0 && cfg.ImgHgh != 0 && cfg.ImgFullPathName != null) { try { e.Graphics.DrawImage(new Bitmap(Image.FromFile(cfg.ImgFullPathName), cfg.ImgWid, cfg.ImgHgh), new Rectangle(cfg.ImgLeft, cfg.ImgTop, cfg.ImgWid, cfg.ImgHgh)); } catch (Exception) { } /// Cope with situations when file is missing or is not correct } /// /// Title /// RectangleF printArea = new RectangleF(TitleX, TitleY, printWidth, titleHeight); e.Graphics.DrawString(header, titleFont, Brushes.Black, printArea); titleHeight = System.Windows.Forms.TextRenderer.MeasureText(header, titleFont).Height; float commonTop = TitleY + titleHeight; ///---------------- /// Common items ///---------------- commonTop += spacingOne4Header; /// Space above common part float leftMarginCommon1 = leftMargin + printWidth * 0.01f * cfg.ColW0Pct; float leftMarginCommon2 = leftMargin + printWidth * 0.01f * (cfg.ColW0Pct + cfg.ColW1Pct); float leftMarginCommon3 = leftMargin + printWidth * 0.01f * (cfg.ColW0Pct + cfg.ColW1Pct + cfg.ColW2Pct); Alignment[] horizAlgn = new Alignment[] { Alignment.Left, Alignment.Left }; VertAlignment[] vertAlgn = new VertAlignment[] { VertAlignment.Top, VertAlignment.Top }; TableStyle commonTableStyle = new TableStyle { Font = font, MarginX = 5, MarginY = 3 }; Table table1 = new Table(2) { Style = commonTableStyle }; foreach (var item in commonItems1) { string[] row = new string[] { item.Caption, item.Print(wm).Split(new char[] { '|' })[0] }; table1.AddRow(row, horizAlgn, vertAlgn); } float bodyTop1 = table1.Draw(e, leftMarginCommon1, commonTop); table1 = new Table(2) { Style = commonTableStyle }; foreach (var item in commonItems2) { string[] row = new string[] { item.Caption, item.Print(wm).Split(new char[] { '|' })[0] }; table1.AddRow(row, horizAlgn, vertAlgn); } float bodyTop2 = table1.Draw(e, leftMarginCommon2, commonTop); table1 = new Table(2) { Style = commonTableStyle }; foreach (var item in commonItems3) { string[] row = new string[] { item.Caption, item.Print(wm).Split(new char[] { '|' })[0] }; table1.AddRow(row, horizAlgn, vertAlgn); } float bodyTop3 = table1.Draw(e, leftMarginCommon3, commonTop); float bodyTop12 = (bodyTop1 > bodyTop2) ? bodyTop1 : bodyTop2; tableTop = (bodyTop12 > bodyTop3) ? bodyTop12 : bodyTop3; /// Max. of all three bodyTop-s tableTop += spacingOne4Header; /// Space between the common part and the table } /// /// Draw table (on the 1st, as well as on the 2nd page) /// float belowTop; TableStyle style; Table table; switch (cfg.Form) { default: case TableForm.Rows: style = new TableStyle { Font = font, HeaderFont = headerFont, MarginX = 5, MarginY = 3, LineWidth = 1, TopHeadersCount = 1, HorizLines = TableLines.All, VertLines = TableLines.All }; table = Table.Create_TestsAreRows(wm, (pageNr == 1) ? testItems : testItems2, style); break; case TableForm.Columns: style = new TableStyle { Font = font, HeaderFont = headerFont, MarginX = 5, MarginY = 3, LineWidth = 1, LeftHeadersCount = 1, HorizLines = TableLines.FirstSecondAndLast, VertLines = TableLines.All }; table = Table.Create_TestsAreColumns(wm, (pageNr == 1) ? testItems : testItems2, style); break; case TableForm.ColumnsPL: style = new TableStyle { Font = font, HeaderFont = headerFont, MarginX = 5, MarginY = 3, LineWidth = 1, TopHeadersCount = 1, HorizLines = TableLines.FirstSecondAndLast, VertLines = TableLines.All }; table = Table.Create_TestsAreColumnsPL(wm, (pageNr == 1) ? testItems : testItems2, style); break; } SizeF size = table.Measure(e); float tableLeft = (float)leftMargin + ((float)printWidth - size.Width) / 2; belowTop = table.Draw(e, tableLeft, tableTop); if (pageNr == nrPages) { ///---------------- /// Common items ///---------------- belowTop += spacingOne4Header; /// Space between the table and the bottom common part float leftMarginBelow1 = leftMargin + printWidth * 0.01f * cfg.BelowW0Pct; float leftMarginBelow2 = leftMargin + printWidth * 0.01f * (cfg.BelowW0Pct + cfg.BelowW1Pct); float leftMarginBelow3 = leftMargin + printWidth * 0.01f * (cfg.BelowW0Pct + cfg.BelowW1Pct + cfg.BelowW2Pct); Alignment[] horizAlgn = new Alignment[] { Alignment.Left, Alignment.Left }; VertAlignment[] vertAlgn = new VertAlignment[] { VertAlignment.Top, VertAlignment.Top }; TableStyle commonTableStyle = new TableStyle { Font = font, MarginX = 5, MarginY = 3 }; Table table2 = new Table(2) { Style = commonTableStyle }; foreach (var item in belowItems1) { string[] row = new string[] { item.Caption, item.Print(wm).Split(new char[] { '|' })[0] }; table2.AddRow(row, horizAlgn, vertAlgn); } table2.Draw(e, leftMarginBelow1, belowTop); table2 = new Table(2) { Style = commonTableStyle }; foreach (var item in belowItems2) { string[] row = new string[] { item.Caption, item.Print(wm).Split(new char[] { '|' })[0] }; table2.AddRow(row, horizAlgn, vertAlgn); } table2.Draw(e, leftMarginBelow2, belowTop); table2 = new Table(2) { Style = commonTableStyle }; foreach (var item in belowItems3) { string[] row = new string[] { item.Caption, item.Print(wm).Split(new char[] { '|' })[0] }; table2.AddRow(row, horizAlgn, vertAlgn); } table2.Draw(e, leftMarginBelow3, belowTop); /// /// Footer on the last page /// float footerWidth = e.Graphics.MeasureString(footer, footerFont).Width; PrintAt(e, footer, footerFont, leftMargin, topMargin + printHeight - 2 * spacingOne, 0, 0, Alignment.Left, VertAlignment.Top); } /// /// Page number on each page /// string pageNrText = string.Format("{0} {1}/{2}", Strings.Page, pageNr, nrPages); float pageNrWidth = e.Graphics.MeasureString(pageNrText, font).Width; PrintAt(e, pageNrText, font, leftMargin + (printWidth - pageNrWidth) / 2, topMargin + printHeight - spacingOne, 0, 0, Alignment.Left, VertAlignment.Top); e.HasMorePages = !(pageNr == nrPages); pageNr++; } public static void DrawQR(Graphics g, QrCode qrCode, float left, float top, float width, float height) { /// Assuming 100 dpi (printer) g.SmoothingMode = SmoothingMode.AntiAlias; g.InterpolationMode = InterpolationMode.HighQualityBicubic; g.PixelOffsetMode = PixelOffsetMode.HighQuality; float qrPixWidth = width / qrCode.Matrix.Width; float qrPixHeight = height / qrCode.Matrix.Height; for (int i = 0; i < qrCode.Matrix.Height; i++) { for (int j = 0; j < qrCode.Matrix.Width; j++) { if (qrCode.Matrix[j, i]) { g.FillRectangle(Brushes.Black, new RectangleF(left + j * qrPixWidth, top + i * qrPixHeight, qrPixWidth, qrPixHeight)); } } } } } }