/// <summary> /// Initializes a new SDUFormattedString object with given string and /// initial CharacterFormat.<br/> /// Format string definition is at documentation for /// <see cref="CharacterFormat.Formatted"/> member. /// </summary> /// <param name="str"></param> /// <param name="initFmt"></param> public SDUFormattedString(string str, CharacterFormat initFmt) { if(sdu==null) sdu=StringDrawUtils.GetInstance(); m_strings=new ArrayList(); m_formats=new ArrayList(); m_softbreaks=new Hashtable(); m_initialFormat=initFmt; Debug.Assert(initFmt.Angle==0); CharacterFormat curfmt=initFmt.ShallowCopy(); curfmt.Angle=0; curfmt.Formatted=false; if(!initFmt.Formatted) { AddFormattedPiece(str,curfmt); } else { Stack brushes=new Stack(); string curstr=""; for (int i = 0; i < str.Length; i++) { if(str[i]!='#') curstr+=str[i]; else if(str[i+1]=='#') { curstr+='#'; i++; } else { if(curstr.Length>0) { AddFormattedPiece(curstr,curfmt); curstr=""; curfmt=curfmt.ShallowCopy(); } switch(str[i+1]) { case 'C': if(str.Length > i + 2 && str[i+2]=='-') { if(!initFmt.IgnoreColorFormatting) { if(brushes.Count==0) throw new ArgumentException("Invalid format string","str"); curfmt.Brush=(Brush) brushes.Pop(); } i+=2; } else if(str.Length > i + 7) { string colstr=str.Substring(i+2,6); if(colstr.Length<6) throw new ArgumentException("Invalid format string","str"); int colint; try { colint=Int32.Parse(colstr,NumberStyles.HexNumber); } catch(FormatException) { throw new ArgumentException("Invalid format string","str"); } Color clr=Color.FromArgb( (255<<24) + colint ); if(!initFmt.IgnoreColorFormatting) { brushes.Push(curfmt.Brush); curfmt.Brush=new SolidBrush(clr); } i+=7; } break; case 'B': switch(str[i+2]) { case '+': curfmt.Font=new Font(curfmt.Font,curfmt.Font.Style|FontStyle.Bold); break; case '-': curfmt.Font=new Font(curfmt.Font,curfmt.Font.Style & ~FontStyle.Bold); break; default: throw new ArgumentException("Invalid format string","str"); } i+=2; break; case 'I': switch(str[i+2]) { case '+': curfmt.Font=new Font(curfmt.Font,curfmt.Font.Style|FontStyle.Italic); break; case '-': curfmt.Font=new Font(curfmt.Font,curfmt.Font.Style & ~FontStyle.Italic); break; default: throw new ArgumentException("Invalid format string","str"); } i+=2; break; case 'U': switch(str[i+2]) { case '+': curfmt.Font=new Font(curfmt.Font,curfmt.Font.Style|FontStyle.Underline); break; case '-': curfmt.Font=new Font(curfmt.Font,curfmt.Font.Style & ~FontStyle.Underline); break; default: throw new ArgumentException("Invalid format string","str"); } i+=2; break; default: throw new ArgumentException("Invalid format string","str"); } } } if(curstr.Length>0) AddFormattedPiece(curstr,curfmt); } }
/// <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> /// 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 string with given character format and alignment at given <see cref="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="pnt"><see cref="Point"/> where the string will be drawn.</param> /// <param name="fmt"><see cref="CharacterFormat"/> used to draw the <see cref="string"/>. </param> /// <param name="align">Specifies whether the <paramref name="pnt"/> is at left, right /// or in the center of the string. (<see cref="ParagraphAlignment.Full"/> means the same /// as <see cref="ParagraphAlignment.Left"/>.)</param> public void DrawString(Graphics gr, string str, PointF pnt, CharacterFormat fmt, ParagraphAlignment align) { StringFormat sf = (StringFormat) StringFormat.GenericDefault.Clone(); sf.Alignment = ParAl2StrAl(align); sf.HotkeyPrefix = fmt.HotkeyPrefix; Matrix trOld = null; if (fmt.Angle != 0) { trOld = gr.Transform.Clone(); gr.TranslateTransform(pnt.X, pnt.Y); gr.RotateTransform(fmt.Angle); gr.TranslateTransform(-pnt.X, -pnt.Y); } if (fmt.Formatted) { CharacterFormat cf = fmt.ShallowCopy(); cf.Angle = 0; SDUFormattedString fs = new SDUFormattedString(str, cf); SizeF sz = fs.Measure(gr, true); sz.Height += GetMeasureStringVerticalGap(gr, cf.Font); PointF ofs = pnt; switch (align) { case ParagraphAlignment.Right: ofs.X -= sz.Width; break; case ParagraphAlignment.Center: ofs.X -= sz.Width/2; break; } ParagraphFormat pf = new ParagraphFormat(); pf.MultiLine = false; pf.Alignment = align; fs.DrawStringInRectangle(gr, new RectangleF(ofs, sz), pf); } else if (fmt.FilledBounds) { ParagraphFormat pf = new ParagraphFormat(); //pf.Alignment=align; SizeF sz = MeasureStringExactly(gr, str, fmt, pf, false); sz.Width += GetMeasureStringHorizontalGap(gr, fmt.Font); pnt.X += GetMeasureStringHorizontalGap(gr, fmt.Font)/2; pnt.Y += GetMeasureStringVerticalGap(gr, fmt.Font); gr.FillRectangle(fmt.Brush, new RectangleF(pnt, sz)); } else gr.DrawString(str, fmt.Font, fmt.Brush, pnt, sf); if (trOld != null) gr.Transform = trOld; }
/// <summary> /// Returns height of the text when wrapping to given <paramref name="width"/> is performed. /// </summary> /// <param name="gr">Graphics object used for measurement.</param> /// <param name="str">String to be measured.</param> /// <param name="cf"><see cref="CharacterFormat"/> of given string.</param> /// <param name="width">Maximum width of resulting text.</param> /// <returns>Returns height of the text when wrapping to given <paramref name="width"/> /// is performed.</returns> public float GetWrappedHeight(Graphics gr, string str, CharacterFormat cf, float width) { CharacterFormat cf2=cf.ShallowCopy(); cf2.Angle=0; SDUFormattedString fmts = new SDUFormattedString(str, cf); fmts.WrapLines(gr, width); return fmts.GetTotalHeight(gr); }