TextRendering.cs
  1. //
  2. // This code is part of Document Solutions for Imaging demos.
  3. // Copyright (c) MESCIUS inc. All rights reserved.
  4. //
  5. using System;
  6. using System.IO;
  7. using System.Drawing;
  8. using GrapeCity.Documents.Imaging;
  9. using GrapeCity.Documents.Text;
  10. using GrapeCity.Documents.Drawing;
  11. using GCTEXT = GrapeCity.Documents.Text;
  12. using GCDRAW = GrapeCity.Documents.Drawing;
  13.  
  14. namespace DsImagingWeb.Demos
  15. {
  16. // Demonstrates the basics of rendering text in DsImaging.
  17. // The two main approaches are:
  18. // - using the MeasureString/DrawString pair, or
  19. // - using the TextLayout directly.
  20. // While the first approach may be easier in simple cases,
  21. // the second approach (using TextLayout) is much more powerful
  22. // and generally speaking yields better performance.
  23. // Please read the comments in code below for more details.
  24. public class TextRendering
  25. {
  26. public GcBitmap GenerateImage(Size pixelSize, float dpi, bool opaque, string[] sampleParams = null)
  27. {
  28. var bmp = new GcBitmap(pixelSize.Width, pixelSize.Height, true, dpi, dpi);
  29. var Inch = dpi;
  30. const float fontSize = 14;
  31. using (var g = bmp.CreateGraphics(Color.White))
  32. {
  33. // TextFormat class is used throughout all DsImaging text rendering to specify
  34. // font and other character formatting:
  35. var tf = new TextFormat()
  36. {
  37. Font = GCTEXT.Font.FromFile(Path.Combine("Resources", "Fonts", "times.ttf")),
  38. FontSize = fontSize
  39. };
  40.  
  41. // 1.
  42. // The easiest way to render a short string on a page at an arbitrary location,
  43. // when you are 100% sure that the string will fit in the available space,
  44. // is to use the GcGraphics.DrawString() overload accepting just the point
  45. // at which to draw the string:
  46. g.DrawString(
  47. "1. Test string. Please read the extensive comments in this sample's code.\r\n" +
  48. "(Note that line breaks are allowed even in the simplest DrawString overload.)",
  49. tf, new PointF(Inch, Inch));
  50.  
  51. // 2.
  52. // Another overload taking a rectangle instead, plus alignment and wrapping
  53. // options, is also available and provides a bit more flexibility:
  54. g.DrawString(
  55. "2. A longer test string which will probably need more than the allocated " +
  56. "4 inches so quite possibly will wrap to show that DrawString can do that.",
  57. tf,
  58. new RectangleF(Inch, Inch * 2, Inch * 4, Inch), // the layout rectangle
  59. // The rest 3 args are optional, passing defaults here for illustration:
  60. TextAlignment.Leading, // leading (left for LTR languages) text align
  61. ParagraphAlignment.Near, // near (top for top-to-bottom flow) para align
  62. true); // word wrap
  63.  
  64. // 3.
  65. // Complementary to DrawString, a MeasureString() method is available
  66. // (with several different overloads), and can be used in pair with
  67. // DrawString when more control over text layout is needed:
  68. const string tstr3 = "3. Test string to demo MeasureString() used with DrawString().";
  69.  
  70. SizeF layoutSize = new SizeF(Inch * 3, Inch * 0.8f); // available size
  71. SizeF s = g.MeasureString(tstr3, tf, layoutSize, out int fitCharCount);
  72. // Show the passed in size in red, the measured size in blue,
  73. // and draw the string within the returned size as bounds:
  74. PointF pt = new PointF(Inch, Inch * 3);
  75. g.DrawRectangle(new RectangleF(pt, layoutSize), Color.Red);
  76. g.DrawRectangle(new RectangleF(pt, s), Color.Blue);
  77. g.DrawString(tstr3, tf, new RectangleF(pt, s));
  78.  
  79. // 4.
  80. // A much more powerful and with better performance, way to render text
  81. // is to use TextLayout. (TextLayout is used anyway by DrawString/MeasureString,
  82. // so when you use TextLayout directly, you basically cut the work in half.)
  83. // A TextLayout instance represents one or more paragraphs of text, with
  84. // the same paragraph formatting (character formats may be different,
  85. // see {MultiFormattedText}).
  86. var tl = g.CreateTextLayout();
  87. // To add text, use Append() or AppendLine() methods:
  88. tl.Append("4. First test string added to TextLayout. ", tf);
  89. tl.Append("Second test string added to TextLayout, continuing the same paragraph. ", tf);
  90. tl.AppendLine(); // Add a line break, effectively starting a new paragraph
  91. tl.Append("Third test string added to TextLayout, a new paragraph. ", tf);
  92. tl.Append("Fourth test string, with a different char formatting. ",
  93. new TextFormat(tf)
  94. {
  95. Font = GCTEXT.Font.FromFile(Path.Combine("Resources", "Fonts", "timesbi.ttf")),
  96. FontSize = fontSize,
  97. FontBold = true,
  98. FontItalic = true,
  99. ForeColor = Color.DarkSeaGreen,
  100. });
  101. // Text can be added to TextLayout without explicit TextFormat:
  102. tl.Append("Fifth test string, using the TextLayout's default format.");
  103. // ...but in that case at least the Font must be specified on the
  104. // TextLayout's DefaultFormat, otherwise PerformLayout (below) will fail:
  105. tl.DefaultFormat.Font = GCTEXT.Font.FromFile(Path.Combine("Resources", "Fonts", "timesi.ttf"));
  106. tl.DefaultFormat.FontSize = fontSize;
  107.  
  108. // Specify the layout, such as max available size etc.
  109. // Here we only provide the max width, but many more parameters can be set:
  110. tl.MaxWidth = g.Width - Inch * 2;
  111. // Paragraph formatting can also be set, here we set first line offset,
  112. // spacing between paragraphs and line spacing:
  113. tl.FirstLineIndent = Inch * 0.5f;
  114. tl.ParagraphSpacing = Inch * 0.05f;
  115. tl.LineSpacingScaleFactor = 0.8f;
  116.  
  117. // When all text has been added, and layout options specified,
  118. // the TextLayout needs to calculate the glyphs needed to render
  119. // the text, and perform the layout. This can be done with a
  120. // single call:
  121. tl.PerformLayout(true);
  122.  
  123. // Now we can draw it on the page:
  124. pt = new PointF(Inch, Inch * 4);
  125. g.DrawTextLayout(tl, pt);
  126. // TextLayout provides info about the text including the measured bounds
  127. // and much more. Here we draw the bounding box in orange red:
  128. g.DrawRectangle(new RectangleF(pt, tl.ContentRectangle.Size), Color.OrangeRed);
  129.  
  130. // 5.
  131. // TextLayout can be re-used to draw different paragraph(s), this can be useful
  132. // when you need to render a different text with the same paragraph formatting.
  133. // The Clear() call removes the text but preserves paragraph formatting:
  134. tl.Clear();
  135. tl.Append("5. This is text rendered re-using the same TextLayout. ");
  136. tl.Append("More text added to TextLayout being re-used, continuing the same paragraph. ", tf);
  137. tl.Append("And finally, some more text added.", tf);
  138. // The necessary call to calculate the glyphs and perform layout:
  139. tl.PerformLayout(true);
  140. // Render the text:
  141. g.DrawTextLayout(tl, new PointF(Inch, Inch * 5));
  142. // Draw border around the whole image:
  143. g.DrawRectangle(new RectangleF(0, 0, bmp.Width, bmp.Height), Color.DarkSlateBlue, 4);
  144. }
  145. // Done:
  146. return bmp;
  147. }
  148. }
  149. }
  150.