///<summary>Since Graphics doesn't have a line height property. ///Our rendering algorithm focuses on wrapping the text on the same character on each line for all printing options (screen, printer, pdf), ///as well as making the text exactly fix vertically within the bounds given in order to properly support sheet vertical growth behavior. ///Since all printing options have slightly different implementations within their drivers, the same font when used in each option is slightly ///different. As a result, the printed text width will vary depending on which printing option is used. We return a rectangle representing the ///actual drawn area of the output string for use in special cases such as the TreatmentPlan.Note, which has a border drawn around it always. ///</summary> public static RectangleF DrawString(Graphics g, string str, Font font, Brush brush, Rectangle bounds, HorizontalAlignment align) { if (str.Trim() == "") { return(bounds); //Nothing to draw. } StringFormat sf = StringFormat.GenericTypographic; //The overload for DrawString that takes a StringFormat will cause the tabs '\t' to be ignored. //In order for the tabs to not get ignored, we have to tell StringFormat how many pixels each tab should be. //50.0f is the closest to our Fill Sheet Edit preview. sf.SetTabStops(0.0f, new float[1] { 50.0f }); RichTextBox textbox = CreateTextBoxForSheetDisplay(str, font, bounds.Width, bounds.Height, align); List <RichTextLineInfo> listTextLines = GetTextSheetDisplayLines(textbox); float deviceLineHeight = g.MeasureString(str.Replace("\r", "").Replace("\n", ""), font, int.MaxValue, sf).Height; float scale = deviceLineHeight / textbox.Font.Height;//(size when printed)/(size on screen) font = new Font(font.FontFamily, font.Size * scale, font.Style); float maxLineWidth = 0; for (int i = 0; i < listTextLines.Count; i++) { string line = RichTextLineInfo.GetTextForLine(textbox.Text, listTextLines, i); if (line.Trim().Length > 0) { float textWidth = g.MeasureString(line, font, int.MaxValue, sf).Width; float x; if (align == HorizontalAlignment.Left) { x = bounds.X + listTextLines[i].Left * scale; } else if (align == HorizontalAlignment.Center) { x = bounds.X + ((bounds.Width - (textWidth * scale)) / 2); } else //Right { x = bounds.X + bounds.Width - (textWidth * scale); } float y = bounds.Y + listTextLines[i].Top * scale; g.DrawString(line, font, brush, x, y, sf); maxLineWidth = Math.Max(maxLineWidth, (listTextLines[i].Left * scale) + textWidth); } } textbox.Font.Dispose(); //This font was dynamically created when the textbox was created. textbox.Dispose(); sf.Dispose(); font.Dispose(); return(new RectangleF(bounds.X, bounds.Y, maxLineWidth, bounds.Height)); }
///<summary>The PdfSharp version of Graphics.DrawString(). scaleToPix scales xObjects to pixels. ///Our rendering algorithm focuses on wrapping the text on the same character on each line for all printing options (screen, printer, pdf), ///as well as making the text exactly fix vertically within the bounds given in order to properly support sheet vertical growth behavior. ///Since all printing options have slightly different implementations within their drivers, the same font when used in each option is slightly ///different. As a result, the printed text width will vary depending on which printing option is used. We return a rectangle representing the ///actual drawn area of the output string for use in special cases such as the TreatmentPlan.Note, which has a border drawn around it always. ///</summary> public static RectangleF DrawStringX(XGraphics xg, string str, XFont xfont, XBrush xbrush, RectangleF bounds, HorizontalAlignment align) { if (str.Trim() == "") { return(bounds); //Nothing to draw. } XStringFormat sf = XStringFormats.Default; //There are two coordinate systems here: pixels (used by us) and points (used by PdfSharp). //MeasureString and ALL related measurement functions must use pixels. //DrawString is the ONLY function that uses points. //pixels: FontStyle fontstyle = FontStyle.Regular; if (xfont.Style == XFontStyle.Bold) { fontstyle = FontStyle.Bold; } //pixels: (except Size is em-size) Font font = new Font(xfont.Name, (float)xfont.Size, fontstyle); RichTextBox textbox = CreateTextBoxForSheetDisplay(str, font, (int)Math.Ceiling(bounds.Width), (int)Math.Ceiling(bounds.Height), align); List <RichTextLineInfo> listTextLines = GetTextSheetDisplayLines(textbox); float deviceLineHeight = PointsToPixels((float)xg.MeasureString(str.Replace("\r", "").Replace("\n", ""), xfont, sf).Height); float scale = deviceLineHeight / textbox.Font.Height;//(size when printed)/(size on screen) font.Dispose(); xfont = new XFont(xfont.Name, xfont.Size * scale, xfont.Style); double maxLineWidth = 0; for (int i = 0; i < listTextLines.Count; i++) { string line = RichTextLineInfo.GetTextForLine(textbox.Text, listTextLines, i); if (line.Trim().Length > 0) { float x = PixelsToPoints(bounds.X + listTextLines[i].Left * scale); //The +11 was arrived at via trial an error. Without this, the first line of each page after the first is halfway on the previous page. float y = PixelsToPoints(bounds.Y + listTextLines[i].Bottom * scale); //There is currently a problem with printing the tab character '\t' when using XStringFormat. //C#'s StringFormat has a method called SetTabStops() which can be used to get the tabs to be drawn (see regular printing above). //We're doing nothing for now because the current complaint is only for printing, not PDF creation. //A workaround is to not use tabs and to instead use separate static text fields that are spaced out as desired. xg.DrawString(line, xfont, xbrush, x, y, sf); maxLineWidth = Math.Max(maxLineWidth, PixelsToPoints(listTextLines[i].Left * scale) + xg.MeasureString(line, xfont, sf).Width); } } textbox.Font.Dispose(); //This font was dynamically created when the textbox was created. textbox.Dispose(); //sf.Dispose();//Does not exist for PDF. //xfont.Dispose();//Does not exist for PDF fonts. return(new RectangleF(bounds.X, bounds.Y, PointsToPixels((float)maxLineWidth), bounds.Height)); }