//// This code is part of Document Solutions for Imaging demos.// Copyright (c) MESCIUS inc. All rights reserved.//usingSystem;usingSystem.IO;usingSystem.Drawing;usingGrapeCity.Documents.Text;usingGrapeCity.Documents.Imaging.Skia;usingGCTEXT = GrapeCity.Documents.Text; namespaceDsImagingWeb.Demos{ // This example is essentially the same as in TextRendering,// but uses DsImaging.Skia library (GcSkiaBitmap / GcSkiaGraphics)// to create and render the resulting image.publicclassSkiaTextRendering {publicstaticboolIsSkiaOnly => true; publicStreamGenerateImageStream(string targetMime, Size pixelSize, float dpi, bool opaque, string[] sampleParams = null) {switch (targetMime) {caseCommon.Util.MimeTypes.JPEG:caseCommon.Util.MimeTypes.PNG:caseCommon.Util.MimeTypes.WEBP:break;default:thrownewException("This sample uses Skia to create the image, and only supports JPEG, PNG and WEBP output formats."); } usingvar bmp = newGcSkiaBitmap(pixelSize.Width, pixelSize.Height, opaque); var Inch = dpi;constfloatfontSize = 14;using (var g = bmp.CreateGraphics(Color.White)) {// TextFormat class is used throughout all DsImaging text rendering to specify// font and other character formatting:var tf = newTextFormat() {Font = GCTEXT.Font.FromFile(Path.Combine("Resources", "Fonts", "FreeSerif.ttf")),FontSize = fontSize }; // 1.// The easiest way to render a short string on a page at an arbitrary location,// when you are 100% sure that the string will fit in the available space,// is to use the GcGraphics.DrawString() overload accepting just the point// at which to draw the string: g.DrawString("1. Test string. Please read the extensive comments in this sample's code.\r\n" +"(Note that line breaks are allowed even in the simplest DrawString overload.)", tf, newPointF(Inch, Inch)); // 2.// Another overload taking a rectangle instead, plus alignment and wrapping// options, is also available and provides a bit more flexibility: g.DrawString("2. A longer test string which will probably need more than the allocated " +"4 inches so quite possibly will wrap to show that DrawString can do that.", tf,newRectangleF(Inch, Inch * 2, Inch * 4, Inch), // the layout rectangle// The rest 3 args are optional, passing defaults here for illustration:TextAlignment.Leading, // leading (left for LTR languages) text alignParagraphAlignment.Near, // near (top for top-to-bottom flow) para aligntrue); // word wrap // 3.// Complementary to DrawString, a MeasureString() method is available// (with several different overloads), and can be used in pair with// DrawString when more control over text layout is needed:conststringtstr3 = "3. Test string to demo MeasureString() used with DrawString()."; SizeF layoutSize = newSizeF(Inch * 3, Inch * 0.8f); // available sizeSizeF s = g.MeasureString(tstr3, tf, layoutSize, outint fitCharCount);// Show the passed in size in red, the measured size in blue,// and draw the string within the returned size as bounds:PointF pt = newPointF(Inch, Inch * 3); g.DrawRectangle(newRectangleF(pt, layoutSize), Color.Red); g.DrawRectangle(newRectangleF(pt, s), Color.Blue); g.DrawString(tstr3, tf, newRectangleF(pt, s)); // 4.// A much more powerful and with better performance, way to render text// is to use TextLayout. (TextLayout is used anyway by DrawString/MeasureString,// so when you use TextLayout directly, you basically cut the work in half.)// A TextLayout instance represents one or more paragraphs of text, with // the same paragraph formatting (character formats may be different,// see {MultiFormattedText}).var tl = g.CreateTextLayout();// To add text, use Append() or AppendLine() methods: tl.Append("4. First test string added to TextLayout. ", tf); tl.Append("Second test string added to TextLayout, continuing the same paragraph. ", tf); tl.AppendLine(); // Add a line break, effectively starting a new paragraph tl.Append("Third test string added to TextLayout, a new paragraph. ", tf); tl.Append("Fourth test string, with a different char formatting. ",newTextFormat(tf) {Font = GCTEXT.Font.FromFile(Path.Combine("Resources", "Fonts", "FreeSerifBoldItalic.ttf")),FontSize = fontSize,FontBold = true,FontItalic = true,ForeColor = Color.DarkSeaGreen, });// Text can be added to TextLayout without explicit TextFormat: tl.Append("Fifth test string, using the TextLayout's default format.");// ...but in that case at least the Font must be specified on the// TextLayout's DefaultFormat, otherwise PerformLayout (below) will fail: tl.DefaultFormat.Font = GCTEXT.Font.FromFile(Path.Combine("Resources", "Fonts", "FreeSerifItalic.ttf")); tl.DefaultFormat.FontSize = fontSize; // Specify the layout, such as max available size etc.// Here we only provide the max width, but many more parameters can be set: tl.MaxWidth = g.Width - Inch * 2;// Paragraph formatting can also be set, here we set first line offset,// spacing between paragraphs and line spacing: tl.FirstLineIndent = Inch * 0.5f; tl.ParagraphSpacing = Inch * 0.05f; tl.LineSpacingScaleFactor = 0.8f; // When all text has been added, and layout options specified,// the TextLayout needs to calculate the glyphs needed to render// the text, and perform the layout. This can be done with a // single call: tl.PerformLayout(true); // Now we can draw it on the page: pt = newPointF(Inch, Inch * 4); g.DrawTextLayout(tl, pt);// TextLayout provides info about the text including the measured bounds// and much more. Here we draw the bounding box in orange red: g.DrawRectangle(newRectangleF(pt, tl.ContentRectangle.Size), Color.OrangeRed); // 5.// TextLayout can be re-used to draw different paragraph(s), this can be useful// when you need to render a different text with the same paragraph formatting.// The Clear() call removes the text but preserves paragraph formatting: tl.Clear(); tl.Append("5. This is text rendered re-using the same TextLayout. "); tl.Append("More text added to TextLayout being re-used, continuing the same paragraph. ", tf); tl.Append("And finally, some more text added.", tf);// The necessary call to calculate the glyphs and perform layout: tl.PerformLayout(true);// Render the text: g.DrawTextLayout(tl, newPointF(Inch, Inch * 5));// Draw border around the whole image: g.DrawRectangle(newRectangleF(0, 0, bmp.PixelWidth, bmp.PixelHeight), Color.DarkSlateBlue, 4); }// Done:var ms = newMemoryStream();switch (targetMime) {caseCommon.Util.MimeTypes.JPEG: bmp.SaveAsJpeg(ms);break;caseCommon.Util.MimeTypes.PNG: bmp.SaveAsPng(ms);break;caseCommon.Util.MimeTypes.WEBP: bmp.SaveAsWebp(ms);break;default:System.Diagnostics.Debug.Assert(false);break; }return ms; } }}