using System; using System.Collections.Generic; using System.Text; using iTextSharp.text; using iTextSharp.text.pdf; using iTextSharp.text.factories; using Itenso.Rtf; using Itenso.Rtf.Parser; using Itenso.Rtf.Interpreter; using Itenso.Rtf.Support; using System.IO; using VEPROMS.CSLA.Library; namespace Volian.Print.Library { [Flags] // TableScrunching is used to allow for turning off/on various parts of the table scrunch test & data manipulation public enum TableScrunching:short // RHM20150507 Table Scrunch { None=0, Phase1=1, // Checks if height of table greater than what will fit on current page. (in setup) Phase2=2, // Remove any blank space between bottom of text & line in a table cell. (in setup) Phase3=4, // Removes new lines at end of text. (in setup) Phase4=8, // Determines height of content, i.e. text in cell, uses leading (height of line). (in setup) Phase5=16, // Make contents of the row a little bigger than max (max may be for merged cells). (in setup) Phase6=32, // Has no affect - YAdjust_h is set to 0. May have been used for testing/trying options. (in ToPdf) Phase7 =64, // Adjust y location of text: by 0 or by 1 if printing 7LPI Phase8=128, // not used Phase9=256, // not used Phase10=512, // not used AllPhases=1+2+4+8+16+32+64+128+256+512 // The default, and always used unless printing from UI list of items } public class Rtf2Pdf { #region Log4Net private static readonly log4net.ILog _MyLog = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); #endregion private string _Rtf; public string Rtf { get { return _Rtf; } set { _Rtf = value; } } private string _FileName; public string FileName { get { return _FileName; } set { _FileName = value; } } public Rtf2Pdf(string rtf, string fileName) { _Rtf = rtf; _FileName = fileName; } public void Process() { iTextSharp.text.Document document = new iTextSharp.text.Document(PaperSizeRec); // C2020-002 paper size is now set in the format files int paperSizePoints = PDFPageSize.PaperSizePoints(PaperSize); // C2020-002 paper size is now set in the format files PdfWriter writer = PdfWriter.GetInstance(document, new FileStream(FileName, FileMode.Create)); document.Open(); // Open RTF Document IRtfDocument rtfDoc = RtfInterpreterTool.BuildDoc(Rtf); Rtf2iTextSharp rtf2IText = new Rtf2iTextSharp(rtfDoc); Paragraph para = rtf2IText.Convert(); para.SetLeading(12F, 0); PdfContentByte cb = writer.DirectContent; SampleParagraphs(para, cb, paperSizePoints - 36, 252, 36); // C2020-002 paper size is now set in the format files para.Add(new Chunk(" (continued)", para.Font)); SampleParagraphs(para, cb, paperSizePoints - 36, 252, 324); // C2020-002 paper size is now set in the format files // Close the document document.Close(); } private static void SampleParagraphs(Paragraph para, PdfContentByte cb, float yTop, float width, float x) { while (yTop > 0) { float newYTop = TextAt(cb, para, x, yTop - 12F, width, 100,"",36); width -= 16; yTop = newYTop; } } private static string _PaperSize = "LETTER"; // default paper size public static string PaperSize // C2020-002 paper size is now set in the format files { get { return Rtf2Pdf._PaperSize; } set { Rtf2Pdf._PaperSize = value; } } private Rectangle _PaperSizeRec = PageSize.LETTER; // default paper size public Rectangle PaperSizeRec { get { return PDFPageSize.UsePaperSize(PaperSize); } } private static bool _PdfDebug = true; public static bool PdfDebug { get { return Rtf2Pdf._PdfDebug; } set { Rtf2Pdf._PdfDebug = value; } } private static System.Drawing.PointF _Offset = new System.Drawing.PointF(0, 0); public static System.Drawing.PointF Offset { get { return Rtf2Pdf._Offset; } set { Rtf2Pdf._Offset = value; } } public static float FillWidth = 0; // max text width (used in autoToc code) private static int _TextAtCounter = 0; public static int TextAtCounter { get { return Rtf2Pdf._TextAtCounter; } set { Rtf2Pdf._TextAtCounter = value; } } private static int NextTextAtCounter { get { int retval = ++TextAtCounter; //if (InList(retval, 17)) Console.WriteLine("TextAt {0}", retval); return retval; } } public class VlnSplitCharacter : ISplitCharacter { public bool IsSplitCharacter(int start, int current, int end, char[] cc, PdfChunk[] ck) { return (cc[current] == ' '); } public bool IsSplitCharacter(char c) { return (c == ' '); } } private static TableScrunching _AllowTableScrunching = TableScrunching.AllPhases; // RHM20150507 Table Scrunch public static TableScrunching AllowTableScrunching { get { return Rtf2Pdf._AllowTableScrunching; } set { Rtf2Pdf._AllowTableScrunching = value; } } public static bool GetTableScrunchingStatus(TableScrunching val) { return (val & _AllowTableScrunching) == val; } public static VlnSplitCharacter mySplitter = new VlnSplitCharacter(); public static string ChunkTextAttributesInfo(Chunk chk1) // C2018-004 create meta file for baseline compares { string rtnval = "Atrbs:"; if (chk1.HasAttributes()) { float? subsup = (float?)chk1.Attributes["SUBSUPSCRIPT"]; if (subsup != null) { if (subsup > 0.0) rtnval += " SUPERSCRIPT |"; else if (subsup < 0.0) rtnval += " SUBSCRIPT |"; } if (chk1.Attributes["UNDERLINE"] != null) rtnval += " UNDERLINE |"; } if (chk1.Font.BaseFont != null) { if (chk1.Font.BaseFont.PostscriptFontName.ToUpper().Contains("BOLD")) rtnval += " BOLD |"; // B2018-066 Support alternative Bold Font Style else if ((chk1.Font.Style & iTextSharp.text.Font.BOLD) == iTextSharp.text.Font.BOLD) rtnval += " Bold |"; if (chk1.Font.BaseFont.PostscriptFontName.ToUpper().Contains("ITALIC")) rtnval += " ITALICS |"; // B2018-066 Support alternative Italic Font Style else if ((chk1.Font.Style & iTextSharp.text.Font.ITALIC) == iTextSharp.text.Font.ITALIC) rtnval += " Italics |"; } if (rtnval.Length == 6) rtnval += " none"; else rtnval = rtnval.Substring(0, rtnval.Length - 2); return rtnval; } public static int _lastPageNum = 0; // C2018-004 create meta file for baseline compares public static float TextAt(PdfContentByte cb, Paragraph iParagraph, float x, float y, float width, float height, string debugText, float yBottomMargin) { return TextAt(cb, iParagraph, x, y, width, height, debugText, yBottomMargin, null); } public static float TextAt(PdfContentByte cb, Paragraph iParagraph, float x, float y, float width, float height, string debugText, float yBottomMargin, int? itmID) { if (cb.PdfDocument.PageNumber != _lastPageNum) // C2018-004 create meta file for baseline compares { Volian.Base.Library.BaselineMetaFile.WriteLine("Page Change from {0} to {1}", _lastPageNum, cb.PdfDocument.PageNumber); _lastPageNum = cb.PdfDocument.PageNumber; } VlnSvgPageHelper _MyPageHelper = cb.PdfWriter.PageEvent as VlnSvgPageHelper; PdfLayer textLayer = _MyPageHelper == null ? null : _MyPageHelper.TextLayer; float left = x + Offset.X; float top = y + Offset.Y; // B2020-059 - Barakah 1T4-OP-EOP-AC-0001 Instructions and Contingency Actions section step 6 last table in RNO is compressed - cause first bullet substep in AER to print on top HLS text // AdjustedTable and AdjustedTableYtop are set in vlnParagraph.cs DrawGrid() if (_MyPageHelper.AdjustedTable != null && _MyPageHelper.AdjustedTableYtop > y) top += _MyPageHelper.TableAdjustment;// RHM20150525 - Table Scrunch //B2020-059 if (iParagraph.Chunks.Count > 0) { if (itmID == null) Volian.Base.Library.BaselineMetaFile.WriteLine("TX x={0} Y={1} W={2} H={3}", left-Offset.X, top-Offset.Y, width, height); else Volian.Base.Library.BaselineMetaFile.WriteLine("TX x={0} Y={1} W={2} H={3} ItmID={4}", left - Offset.X, top - Offset.Y, width, height, itmID); foreach (Chunk chk1 in iParagraph) { //Object obj = chk1.Attributes["UNDERLINE"]; //Console.WriteLine("\t{0},{1},{2},{3},\"{4}\"", chk1.Font.Familyname, chk1.Font.Size, chk1.Font.Style, obj != null ? "Underline" : "", FixText(chk1.Content)); string ctai = ChunkTextAttributesInfo(chk1); Volian.Base.Library.BaselineMetaFile.WriteLine(" {0} {1} {2} {3} \"{4}\"", chk1.Font.Familyname, chk1.Font.Size, chk1.Font.Style, ctai,TextForBaseline.FixText(chk1.Content)); //Console.WriteLine("\t{0},{1},{2},{3},\"{4}\"", chk1.Font.Familyname, chk1.Font.Size, chk1.Font.Style, ctai, FixText(chk1.Content)); } } // Change the chunks to only split on spaces rather than spaces and hyphens foreach (Chunk chk in iParagraph) { if (chk.Attributes == null || !chk.Attributes.ContainsKey("NoSplit")) { if (chk.Attributes == null) chk.Attributes = new System.Collections.Hashtable(); chk.SetSplitCharacter(mySplitter); chk.Attributes.Add("NoSplit", false); } } float right = left + width; float bottom = top - height; ColumnText myColumnText = new ColumnText(cb); myColumnText.SetSimpleColumn(left, top, left + width, yBottomMargin); myColumnText.AddElement(iParagraph); float pos = myColumnText.YLine; // Save the position to be used if the paragraph fits int status = myColumnText.Go(true); // Check to see if it will fit on the page. if (ColumnText.HasMoreText(status)) return 0;// Paragraph won't fit. Return 0; myColumnText.YLine = pos; // restore the location on the page myColumnText.AddElement(iParagraph); // add in paragraph if (textLayer != null) cb.BeginLayer(textLayer); myColumnText.Go(false); // Draw the paragraph FillWidth = myColumnText.FilledWidth; if (textLayer != null) cb.EndLayer(); // Approximate Descent by using Leading divided by 5. float yDescent = iParagraph.Leading / 5; // If the BaseFont is available, calculate yAdj on the basis of the Descent if (iParagraph.Font.BaseFont != null) yDescent = -iParagraph.Font.BaseFont.GetDescentPoint("Almg", iParagraph.Font.Size); if (PdfDebug) { // be very careful around the following line, if the cursor 'touches' // NextTextAtCounter, it is incremented and the 'next' value may not be what // was seen as the UniqueNumber in the pdf. int next = NextTextAtCounter; // buffer (unnecessary comments) so // that cursor does NOT touch 'NextTextAtCounter' // as easily //if (InList(next,2958, 2961)) Console.WriteLine("Stop at UniqueNumber"); string dbt = string.Format("[{0}]{1}", next, debugText ?? ""); DrawPdfDebug(cb, left, top, left + width, myColumnText.YLine, dbt, yDescent); } return myColumnText.YLine; } private static bool InList(int value, params int [] examples) { foreach (int ex in examples) if (ex == value) return true; return false; } public static float FigureAt(PdfContentByte cb, iTextSharp.text.Image image, float x, float y, float width, float height, string debugText, float yBottommargin, bool hasBorder, int itmID, float sixLinesPerInch) { if (cb.PdfDocument.PageNumber != _lastPageNum) // C2018-004 create meta file for baseline compares { Volian.Base.Library.BaselineMetaFile.WriteLine("Page Change from {0} to {1}", _lastPageNum, cb.PdfDocument.PageNumber); _lastPageNum = cb.PdfDocument.PageNumber; } VlnSvgPageHelper _MyPageHelper = cb.PdfWriter.PageEvent as VlnSvgPageHelper; PdfLayer textLayer = _MyPageHelper == null ? null : _MyPageHelper.TextLayer; float left = x + Offset.X; float top = y + Offset.Y + sixLinesPerInch; float bottom = top - height; image.ScaleAbsoluteWidth(width); image.ScaleAbsoluteHeight(height); image.SetAbsolutePosition(left, bottom); if (textLayer != null) cb.BeginLayer(textLayer); // C2018-004 create meta file for baseline compares Volian.Base.Library.BaselineMetaFile.WriteLine("FG left={0} top={1} bottom={2} Height={3} Width={4} ItmID={5}", left, top, bottom, height, width, itmID); cb.AddImage(image); if (hasBorder) { iTextSharp.text.Color boxColor = new iTextSharp.text.Color(System.Drawing.Color.Black); // (PrintOverride.OverrideBoxColor(System.Drawing.Color.Black)); cb.SetColorStroke(boxColor); cb.SetLineWidth(.85F); cb.Rectangle(left-1.5F, bottom-1.5F, width+3, height+3); cb.Stroke(); } if (textLayer != null) cb.EndLayer(); if (PdfDebug) { // be very careful around the following line, if the cursor 'touches' // NextTextAtCounter, it is incremented and the 'next' value may not be what // was seen as the UniqueNumber in the pdf. int next = NextTextAtCounter; // buffer (unnecessary comments) so // that cursor does NOT touch 'NextTextAtCounter' // as easily //if (InList(next,2958, 2961)) Console.WriteLine("Stop at UniqueNumber"); string dbt = string.Format("[{0}]{1}", next, debugText ?? ""); DrawPdfDebug(cb, left, top, left + width, top-height, dbt, 0); } return bottom; } private static float _GridTopAdjust = -10; public static float GridTopAdjust { get { return _GridTopAdjust; } set { _GridTopAdjust = value; } } public static float GridAt(PdfContentByte cb, vlnTable myGrid, float x, float y, float width, float height, string debugText, float yBottomMargin, bool hasBorder) { if (cb.PdfDocument.PageNumber != _lastPageNum) // C2018-004 create meta file for baseline compares { Volian.Base.Library.BaselineMetaFile.WriteLine("Page Change from {0} to {1}", _lastPageNum, cb.PdfDocument.PageNumber); _lastPageNum = cb.PdfDocument.PageNumber; } //VlnSvgPageHelper _MyPageHelper = cb.PdfWriter.PageEvent as VlnSvgPageHelper; // RHM20150507 Table Scrunch //PdfLayer textLayer = _MyPageHelper == null ? null : _MyPageHelper.TextLayer; // RHM20150507 Table Scrunch float left = x + Offset.X; float top = y + Offset.Y; float right = left + width; float bottom = top - height; int paperSizePoints = PDFPageSize.PaperSizePoints(myGrid.MyFlexGrid.MyDVI.ActiveFormat.PlantFormat.FormatData.PDFPageSize.PaperSize); // C2020-002 paper size is now set in the format files ColumnText myColumnText = new ColumnText(cb); myColumnText.SetSimpleColumn(left, top, left + width, yBottomMargin); //if (textLayer != null) cb.BeginLayer(textLayer); // RHM20150507 Table Scrunch // C2018-004 create meta file for baseline compares if (top + GridTopAdjust > paperSizePoints) // B2019-110 Table continued on the next page - off the top of page { _MyLog.ErrorFormat("\r\n===> Table Printing Off the Top of Page"); Volian.Base.Library.BaselineMetaFile.WriteLine("## Error - Grid Off the Top of Page"); } Volian.Base.Library.BaselineMetaFile.WriteLine("GD left={0} top={1} right={2} bottom={3} Mygrid.ItmID={4}", left, top + GridTopAdjust, right, bottom, myGrid.ItemID); myGrid.ToPdf(myColumnText, left, top + GridTopAdjust); //if (textLayer != null) cb.EndLayer(); // RHM20150507 Table Scrunch return bottom; } internal static void DrawPdfDebug(PdfContentByte cb, float left, float top, float right, float bottom, string debugText, float yDescent) { VlnSvgPageHelper _MyPageHelper = cb.PdfWriter.PageEvent as VlnSvgPageHelper; PdfLayer debugLayer = _MyPageHelper == null ? null : _MyPageHelper.DebugLayer; if (debugLayer == null) return; System.Drawing.Color sysColor = PrintOverride.OverrideDebugColor(System.Drawing.Color.Gray); cb.SaveState(); cb.BeginLayer(debugLayer); cb.SetColorStroke(new Color(sysColor)); cb.SetLineWidth(.1F); cb.MoveTo(left, top - yDescent); cb.LineTo(right, top - yDescent); cb.LineTo(right, bottom - yDescent); cb.LineTo(left, bottom - yDescent); cb.LineTo(left, top - yDescent); cb.Stroke(); if (debugText != "") { ColumnText ct = new ColumnText(cb); ct.SetSimpleColumn(left, 4 + top - yDescent, right, top - yDescent - 50); iTextSharp.text.Font font = FontFactory.GetFont("Arial", BaseFont.IDENTITY_H, BaseFont.EMBEDDED, 2); Chunk chk = new Chunk(debugText + string.Format(", Top = {0}",top), font); Phrase ph = new Phrase(chk); ct.AddElement(ph); cb.SetColorFill(new Color(sysColor)); ct.Go(); } cb.EndLayer(); cb.RestoreState(); } internal static float RtfRawAt(PdfContentByte cb, System.Drawing.Image image, float XOffset, float yLocation, float Width, float Height, string debug, float yBottomMargin, bool hasBorder) { VlnSvgPageHelper _MyPageHelper = cb.PdfWriter.PageEvent as VlnSvgPageHelper; PdfLayer textLayer = _MyPageHelper == null ? null : _MyPageHelper.TextLayer; float left = XOffset + Offset.X; float top = yLocation + Offset.Y; float bottom = top - Height; float scale = .6f; iTextSharp.text.Image it_image=null; try { it_image = iTextSharp.text.Image.GetInstance(image,iTextSharp.text.Color.WHITE); float itxtWid = scale * Width * 300 / 72; float itxtHt = scale * Height * 300 / 72; it_image.ScaleAbsoluteWidth(scale * Width); it_image.ScaleAbsoluteHeight(scale * Height); it_image.SetAbsolutePosition(left, top-(scale*Height)); cb.AddImage(it_image); } catch (Exception ex) { Console.WriteLine("Exception {0}", ex.Message); } if (hasBorder) { iTextSharp.text.Color boxColor = new iTextSharp.text.Color(System.Drawing.Color.Black); cb.SetColorStroke(boxColor); cb.SetLineWidth(.85F); cb.Rectangle(left - 1.5F, top - (scale * Height) - 1.5F, (scale * Width) + 3, (scale * Height) + 3); cb.Stroke(); } if (textLayer != null) cb.EndLayer(); if (PdfDebug) { // be very careful around the following line, if the cursor 'touches' // NextTextAtCounter, it is incremented and the 'next' value may not be what // was seen as the UniqueNumber in the pdf. int next = NextTextAtCounter; // buffer (unnecessary comments) so // that cursor does NOT touch 'NextTextAtCounter' // as easily string dbt = string.Format("[{0}]{1}", next, debug ?? ""); DrawPdfDebug(cb, left, top, left + (scale*Width), top-(scale*Height), dbt, 0); } return bottom; } } }