/// <summary> /// Returns Image with <paramref name="str"/> drawn into rectangle of given size. /// </summary> /// <param name="str"><see cref="string"/> to be drawn.</param> /// <param name="size">Size of rectangle string will be drawn into and also of the /// returned image.</param> /// <param name="fmtCharacter"><see cref="CharacterFormat"/> used to draw the <paramref name="str"/>. </param> /// <param name="fmtParagraph"><see cref="ParagraphFormat"/> used to draw the <paramref name="str"/>. </param> /// <param name="topLeftOffset">Out parameter which receives top-left point of the rotated string. </param> /// <returns><see cref="Image"/> with given <paramref name="str"/> drawn.</returns> public Image DrawStringInRectangle(string str, SizeF size, CharacterFormat fmtCharacter, ParagraphFormat fmtParagraph, out PointF topLeftOffset) { //Prepare mask CharacterFormat mcf = fmtCharacter.ShallowCopy(); ParagraphFormat mpf = fmtParagraph.ShallowCopy(); mcf.Brush = new SolidBrush(Color.Black); mpf.BackgroundBrush = new SolidBrush(Color.White); mcf.IgnoreColorFormatting = true; Bitmap bMask = (Bitmap) DrawSolidBackgroundStringInRectangle(str, size, mcf, mpf, out topLeftOffset); //Prepare foreground CharacterFormat fgcf = fmtCharacter.ShallowCopy(); ParagraphFormat fgpf = fmtParagraph.ShallowCopy(); fgcf.FilledBounds = true; fgpf.BackgroundBrush = null; Bitmap bFg = (Bitmap) DrawSolidBackgroundStringInRectangle(str, size, fgcf, fgpf, out topLeftOffset); //And blend it together CopyIntensityAsAlpha(bMask, bFg); bMask.Dispose(); //Using background if (fmtParagraph.BackgroundBrush != null) { Bitmap bRes = new Bitmap(bFg.Width, bFg.Height); Graphics rsgr = Graphics.FromImage(bRes); //resulting bitmap's graphics if (fmtCharacter.Angle == 0) rsgr.FillRectangle(fmtParagraph.BackgroundBrush, 0, 0, size.Width, size.Height); else { Matrix trOld = rsgr.Transform.Clone(); rsgr.TranslateTransform(topLeftOffset.X, topLeftOffset.Y); rsgr.RotateTransform(fmtCharacter.Angle); rsgr.FillRectangle(fmtParagraph.BackgroundBrush, 0, 0, size.Width, size.Height); rsgr.Transform = trOld; } rsgr.DrawImage(bFg, 0, 0); rsgr.Dispose(); bFg.Dispose(); return bRes; } else { return bFg; } }
/// <summary> /// Returns Image with <paramref name="str"/> drawn wrapped to given <paramref name="width"/>. /// </summary> /// <param name="str"><see cref="string"/> to be drawn.</param> /// <param name="width">Width that string will be wrapped to.</param> /// <param name="fmtCharacter"><see cref="CharacterFormat"/> used to draw the <see cref="string"/>. </param> /// <param name="fmtParagraph"><see cref="ParagraphFormat"/> used to draw the <see cref="string"/>. </param> /// <returns><see cref="Image"/> with given <paramref name="str"/> drawn.</returns> public Image DrawWrappedString(string str, float width, CharacterFormat fmtCharacter, ParagraphFormat fmtParagraph) { float height = GetWrappedHeight(DummyGraphics, str, fmtCharacter, width); ParagraphFormat pf2 = fmtParagraph.ShallowCopy(); pf2.MultiLine = true; pf2.ShowIncompleteLines = true; pf2.VerticalAlignment = ParagraphVerticalAlignment.Top; return DrawStringInRectangle(str, new SizeF(width, height), fmtCharacter, fmtParagraph); }
/// <summary> /// Draws string with given formating and width at specified point. /// </summary> /// <param name="gr"><see cref="Graphics"/> object to draw into.</param> /// <param name="str"><see cref="string"/> to be drawn.</param> /// <param name="width">Width that string will be wrapped to.</param> /// <param name="ofs">Top-left point of the drawn string.</param> /// <param name="fmtCharacter"><see cref="CharacterFormat"/> used to draw the <see cref="string"/>. </param> /// <param name="fmtParagraph"><see cref="ParagraphFormat"/> used to draw the <see cref="string"/>. </param> public void DrawWrappedString(Graphics gr, string str, PointF ofs, float width, CharacterFormat fmtCharacter, ParagraphFormat fmtParagraph) { float height=GetWrappedHeight(gr, str, fmtCharacter, width); ParagraphFormat pf2=fmtParagraph.ShallowCopy(); pf2.MultiLine=true; pf2.ShowIncompleteLines=true; pf2.VerticalAlignment=ParagraphVerticalAlignment.Top; DrawStringInRectangle(gr, str, new RectangleF(ofs, new SizeF(width, height)),fmtCharacter, fmtParagraph); }
/// <summary> /// Draws string with given formating into given <paramref name="rectangle"/>. /// </summary> /// <param name="gr"><see cref="Graphics"/> object to draw into.</param> /// <param name="str"><see cref="string"/> to be drawn.</param> /// <param name="rectangle"><see cref="Rectangle"/> that string is drawn into.</param> /// <param name="fmtCharacter"><see cref="CharacterFormat"/> used to draw the <see cref="string"/>. </param> /// <param name="fmtParagraph"><see cref="ParagraphFormat"/> used to draw the <see cref="string"/>. </param> public void DrawStringInRectangle(Graphics gr, string str, RectangleF rectangle, CharacterFormat fmtCharacter, ParagraphFormat fmtParagraph) { Matrix trOld = gr.Transform.Clone(); gr.TranslateTransform(rectangle.X, rectangle.Y); gr.RotateTransform(fmtCharacter.Angle); gr.TranslateTransform(-rectangle.X, -rectangle.Y); if (fmtParagraph.BackgroundBrush != null) gr.FillRectangle(fmtParagraph.BackgroundBrush, rectangle); CharacterFormat cf = fmtCharacter.ShallowCopy(); cf.Angle = 0; ParagraphFormat pf = fmtParagraph.ShallowCopy(); pf.BackgroundBrush = null; if (fmtCharacter.Formatted) { SDUFormattedString fmts = new SDUFormattedString(str, cf); if (pf.MultiLine) fmts.WrapLines(gr, rectangle.Width); fmts.DrawStringInRectangle(gr, rectangle, pf); } else if (fmtCharacter.FilledBounds) gr.FillRectangle(fmtCharacter.Brush, rectangle); else { if (fmtParagraph.Alignment == ParagraphAlignment.Full && fmtParagraph.MultiLine && rectangle.Width > 0) { DrawFullAlignedStringInRectangle(gr, str, rectangle, cf, fmtParagraph); } else { StringFormat sf = GetStringFormat(fmtCharacter, fmtParagraph); gr.DrawString(str, fmtCharacter.Font, fmtCharacter.Brush, rectangle, sf); } } gr.Transform = trOld; }
/// <summary> /// Draws full aligned string into given rectangle. /// </summary> /// <param name="gr"><see cref="Graphics"/> object to draw into.</param> /// <param name="str"><see cref="string"/> to be drawn.</param> /// <param name="rect"><see cref="Rectangle"/> that string is drawn into.</param> /// <param name="cf"><see cref="CharacterFormat"/> used to draw the <paramref name="str"/>. </param> /// <param name="pf"><see cref="ParagraphFormat"/> used to draw the <paramref name="str"/>. </param> /// <remarks>As this method isn't to be exposed as public, there are /// several limitations:<br/> /// <see cref="Rectangle.Width"/> has to be non-zero.<br/> /// <see cref="CharacterFormat.Angle"/> has to be zero.<br/> /// <see cref="ParagraphFormat.MultiLine"/> has to be false.<br/> /// <see cref="ParagraphFormat.Alignment"/> has to be <see cref="ParagraphAlignment.Full"/>.<br/> /// <see cref="ParagraphFormat.BackgroundBrush"/> has to be null.<br/> /// If not satisfied, results might be not as expected.</remarks> private void DrawFullAlignedStringInRectangle(Graphics gr, string str, RectangleF rect, CharacterFormat cf, ParagraphFormat pf) { Region oldClip = gr.Clip.Clone(); gr.IntersectClip(rect); float yofs = rect.Y; StringFormat sfLeft; //StringFormat for drawing left-aligned lines { ParagraphFormat pf2 = pf.ShallowCopy(); pf2.Alignment = ParagraphAlignment.Left; pf2.VerticalAlignment = ParagraphVerticalAlignment.Top; pf2.MultiLine = false; pf2.ShowIncompleteLines = true; sfLeft = GetStringFormat(cf, pf2); } //lineHeight & borders retrieving float lineHeight = GetLineHeight(gr, cf.Font); int lineCount; //lineCount retrieving { StringFormat sf = GetStringFormat(cf, pf); int charfit; gr.MeasureString(str, cf.Font, new SizeF(rect.Width, rect.Height), sf, out charfit, out lineCount); } //VerticalAlignment business switch (pf.VerticalAlignment) { case ParagraphVerticalAlignment.Bottom: yofs += rect.Height - lineHeight*lineCount; break; case ParagraphVerticalAlignment.Center: yofs += (rect.Height - lineHeight*lineCount)/2; break; } int flc = 0; //first line character int llc = flc; //last line character (actually the one after last) int lineIndex = 0; while (lineIndex < lineCount - 1 && flc < str.Length) { lineIndex++; llc = flc; //add spaces at the beginneing while (llc < str.Length && Char.IsWhiteSpace(str, llc)) llc++; //add words until the line is full int pllc = llc; //potential last line character while (llc == pllc && llc < str.Length) { pllc++; while (pllc < str.Length && !Char.IsWhiteSpace(str, pllc)) pllc++; if (gr.MeasureString(str.Substring(flc, pllc - flc), cf.Font).Width < rect.Width) llc = pllc; } //If nothing was added before, add single characters (rect.Width is too small) if (llc == flc) do { //always at least one character per line llc++; } while (llc < str.Length && gr.MeasureString(str.Substring(flc, llc - flc + 1), cf.Font).Width < rect.Width); string line = str.Substring(flc, llc - flc); //Newline fotmatting int nlindex = line.IndexOf('\n'); if (nlindex >= 0) { //Newline may be just "\n" or "\r\n" if (nlindex > 1 && line[nlindex - 1] == '\r') line = line.Substring(0, nlindex - 1); else line = line.Substring(0, nlindex); DrawString(gr, line, new PointF(rect.X, yofs), cf); flc += nlindex + 1; } else { DrawFullAlignedLine(gr, line, new PointF(rect.X, yofs), rect.Width, cf); flc = llc; //skip spaces at the end of line (just like Graphics.DrawString does) while (flc < str.Length && Char.IsWhiteSpace(str, flc)) flc++; } yofs += lineHeight; } //And here comes the last line - it's always drawn left-aligned //(also, we have to get rid of newlines or they will sometimes show //in the bottom) gr.DrawString(str.Substring(flc), cf.Font, cf.Brush, new RectangleF(rect.X, yofs, rect.Width, lineHeight), sfLeft); //Set back the original clipping region gr.Clip = oldClip; }