public int CreatePDF(Stream stream) { const int NPAR = 40; var doc = new GcPdfDocument(); var tl = new TextLayout(72) { FirstLineIndent = 72 / 2, MaxWidth = doc.PageSize.Width, MaxHeight = doc.PageSize.Height, MarginAll = 72, }; tl.DefaultFormat.Font = StandardFonts.Times; tl.DefaultFormat.FontSize = 12; // Text format for paragraphs kept together with next one: var tf = new TextFormat(tl.DefaultFormat) { FontSize = tl.DefaultFormat.FontSize + 2, FontBold = true }; // We add a number of random 'lorem ipsum' paragraphs to this document, // adding a 'caption' before each paragraph which is kept together // with the following 'lorem ipsum' paragraph: for (int i = 0; i < NPAR; i++) { // 'Caption' kept together with the next paragraph: tl.Append("Caption kept together with the next paragraph. No page break after this.", tf); // AppendParagraphBreak adds a paragraph break but prevents a page break between the two paragraphs: tl.AppendParagraphBreak(); // Random paragraph after 'caption': tl.Append(Common.Util.LoremIpsum(1)); } tl.PerformLayout(true); // We force all paragraph lines to stay on the same page, // this makes it more obvious that 'caption' and following paragraph // are kept on the same page: TextSplitOptions to = new TextSplitOptions(tl) { KeepParagraphLinesTogether = true, }; // In a loop, split and render the text: while (true) { // 'rest' will accept the text that did not fit: var splitResult = tl.Split(to, out TextLayout rest); doc.Pages.Add().Graphics.DrawTextLayout(tl, PointF.Empty); if (splitResult != SplitResult.Split) { break; } tl = rest; } // Done: doc.Save(stream); return(doc.Pages.Count); }
public void Chat() { var layout = new TextLayout(645, 400, 25); layout.Append(_rasterizer, Regular("ナイトハルト:\"パンモロ")); layout.Append(_rasterizer, Regular("\"より\"はいてない")); layout.Append(_rasterizer, Regular("\"の方がいいだろ? それと同じことさ")); Assert.Equal(2, layout.Lines.Length); }
public int CreatePDF(Stream stream) { // Number of pages to generate: const int N = Common.Util.LargeDocumentIterations; var doc = new GcPdfDocument(); // Start creating the document by this call: doc.StartDoc(stream); // Prep a TextLayout to hold/format the text: var tl = new TextLayout(72) { MaxWidth = doc.PageSize.Width, MaxHeight = doc.PageSize.Height, MarginAll = 72, }; tl.DefaultFormat.Font = StandardFonts.Times; tl.DefaultFormat.FontSize = 12; // Start with a title page: tl.FirstLineIndent = 0; var fnt = Font.FromFile(Path.Combine("Resources", "Fonts", "yumin.ttf")); var tf0 = new TextFormat() { FontSize = 24, FontBold = true, Font = fnt }; tl.Append(string.Format("Large Document\n{0} Pages of Lorem Ipsum\n\n", N), tf0); var tf1 = new TextFormat(tf0) { FontSize = 14, FontItalic = true }; tl.Append(string.Format("Generated on {0}.", DateTime.Now), tf1); tl.TextAlignment = TextAlignment.Center; tl.PerformLayout(true); doc.Pages.Add().Graphics.DrawTextLayout(tl, PointF.Empty); tl.Clear(); tl.FirstLineIndent = 36; tl.TextAlignment = TextAlignment.Leading; // Generate the document: for (int pageIdx = 0; pageIdx < N; ++pageIdx) { tl.Append(Common.Util.LoremIpsum(1)); tl.PerformLayout(true); doc.NewPage().Graphics.DrawTextLayout(tl, PointF.Empty); tl.Clear(); } // NOTE: Certain operations (e.g. the one below) will throw an error when using StartDoc/EndDoc: // doc.Pages.Insert(0); // // Done - call EndDoc instead of Save(): doc.EndDoc(); return(doc.Pages.Count); }
// Creates a sample document with 100 pages of 'lorem ipsum': private string MakeDocumentToIndex() { const int N = 100; string tfile = Path.GetTempFileName(); using (var fsOut = new FileStream(tfile, FileMode.Open, FileAccess.ReadWrite)) { var tdoc = new GcPdfDocument(); // See StartEndDoc for details on StartDoc/EndDoc mode: tdoc.StartDoc(fsOut); // Prep a TextLayout to hold/format the text: var tl = new TextLayout(72); tl.FontCollection = _fc; tl.DefaultFormat.FontName = _fontFamily; tl.DefaultFormat.FontSize = 12; // Use TextLayout to layout the whole page including margins: tl.MaxHeight = tdoc.PageSize.Height; tl.MaxWidth = tdoc.PageSize.Width; tl.MarginAll = 72; tl.FirstLineIndent = 72 / 2; // Generate the document: for (int pageIdx = 0; pageIdx < N; ++pageIdx) { tl.Append(Common.Util.LoremIpsum(1)); tl.PerformLayout(true); tdoc.NewPage().Graphics.DrawTextLayout(tl, PointF.Empty); tl.Clear(); } tdoc.EndDoc(); } return(tfile); }
private Task <GcBitmap> LayerTexts(GcBitmap bmp, List <TextElement> textElements) { var g = bmp.CreateGraphics(); foreach (var item in textElements) { var jsonStringProduct = JsonConvert.SerializeObject(product); TextLayout tl = g.CreateTextLayout(); tl.DefaultFormat.FontSize = item.FontSize; tl.DefaultFormat.FontBold = item.isBold; tl.DefaultFormat.FontItalic = item.IsItalic; tl.DefaultFormat.UprightInVerticalText = item.isVertical; tl.MaxWidth = item.Width; tl.MaxHeight = item.Height; tl.WrapMode = WrapMode.WordWrap; tl.DefaultFormat.ForeColor = Color.FromName(item.Color); if (!string.IsNullOrEmpty(item.BackgroundColor)) { tl.DefaultFormat.BackColor = Color.FromName(item.BackgroundColor); } tl.DefaultFormat.Underline = item.isUnderLine; tl.DefaultFormat.Font = Font.FromFile(Path.Combine("Resources", "Fonts", $"{ item.FontFamily }.ttf")); tl.Append(BuildDynamicText(jsonStringProduct, item.Text)); tl.TextAlignment = TextAlignment.Justified; g.DrawTextLayout(tl, new PointF(item.X, item.Y)); } //Save the image rendering different shapes return(Task.FromResult(bmp)); }
private RectangleF DrawText(string text, TextStyle ts) { var page = CurrPage; TextLayout tl = page.Graphics.CreateTextLayout(); tl.MaxWidth = page.Size.Width - MarginRight - _ip.X; if (ts.FontSize == TsTitle.FontSize) // patch { tl.TextAlignment = TextAlignment.Center; } tl.DefaultFormat.Font = ts.Font; tl.DefaultFormat.FontSize = ts.FontSize; tl.DefaultFormat.GlyphAdvanceFactor = ts.GlyphAdvanceFactor; tl.DefaultFormat.ForeColor = ts.ForeColor; tl.Append(text); tl.PerformLayout(true); var line = tl.Lines[tl.Lines.Count - 1]; var run = line.GlyphRuns[0]; var baselineOffset = run.BaselineOffset; var p = _lastBaselineOffset.HasValue ? new PointF(_ip.X, _ip.Y + _lastBaselineOffset.Value - baselineOffset) : _ip; page.Graphics.DrawTextLayout(tl, p); if (!_lastBaselineOffset.HasValue) { _lastBaselineOffset = baselineOffset; // within one 'line', keep using the first offset } return(new RectangleF(_ip.X + tl.ContentX, _ip.Y + tl.ContentY, tl.ContentWidth, tl.ContentHeight)); }
public void CreatePDF(Stream stream) { // Rotation angle, degrees clockwise: float angle = -45; // var doc = new GcPdfDocument(); var g = doc.NewPage().Graphics; // Create a text layout, pick a font and font size: TextLayout tl = g.CreateTextLayout(); tl.DefaultFormat.Font = StandardFonts.Times; tl.DefaultFormat.FontSize = 24; // Add a text, and perform layout: tl.Append("Rotated text."); tl.PerformLayout(true); // Text insertion point at (1",1"): var ip = new PointF(72, 72); // Now that we have text size, create text rectangle with top left at insertion point: var rect = new RectangleF(ip.X, ip.Y, tl.ContentWidth, tl.ContentHeight); // Rotate the text around its bounding rect's center: // we now have the text size, and can rotate it about its center: g.Transform = Matrix3x2.CreateRotation((float)(angle * Math.PI) / 180f, new Vector2(ip.X + tl.ContentWidth / 2, ip.Y + tl.ContentHeight / 2)); // Draw rotated text and bounding rectangle: g.DrawTextLayout(tl, ip); g.DrawRectangle(rect, Color.Black, 1); // Remove rotation and draw the bounding rectangle where the non-rotated text would have been: g.Transform = Matrix3x2.Identity; g.DrawRectangle(rect, Color.ForestGreen, 1); // doc.Save(stream); }
public int CreatePDF(Stream stream) { // Number of pages to generate: const int N = Common.Util.LargeDocumentIterations; var start = DateTime.Now; var doc = new GcPdfDocument(); // Prep a TextLayout to hold/format the text: var tl = new TextLayout(72) { MaxWidth = doc.PageSize.Width, MaxHeight = doc.PageSize.Height, MarginAll = 72, FirstLineIndent = 36, }; tl.DefaultFormat.Font = StandardFonts.Times; tl.DefaultFormat.FontSize = 12; // Generate the document: for (int pageIdx = 0; pageIdx < N; ++pageIdx) { tl.Append(Common.Util.LoremIpsum(1)); tl.PerformLayout(true); doc.NewPage().Graphics.DrawTextLayout(tl, PointF.Empty); tl.Clear(); } // Insert a title page (cannot be done if using StartDoc/EndDoc): tl.FirstLineIndent = 0; var fnt = Font.FromFile(Path.Combine("Resources", "Fonts", "yumin.ttf")); var tf0 = new TextFormat() { Font = fnt, FontSize = 24, FontBold = true }; tl.Append(string.Format("Large Document\n{0} Pages of Lorem Ipsum\n\n", N), tf0); var tf1 = new TextFormat(tf0) { FontSize = 14, FontItalic = true }; tl.Append(string.Format("Generated on {0} in {1:m\\m\\ s\\s\\ fff\\m\\s}.", DateTime.Now, DateTime.Now - start), tf1); tl.TextAlignment = TextAlignment.Center; tl.PerformLayout(true); doc.Pages.Insert(0).Graphics.DrawTextLayout(tl, PointF.Empty); // Done: doc.Save(stream); return(doc.Pages.Count); }
// Static ctor: static GoodsReturnForm() { // Init Textbox: TextLayout tl = new TextLayout(72); tl.Append("Qwerty"); tl.DefaultFormat.Font = Textbox.Font; tl.DefaultFormat.FontSize = Textbox.FontSize; tl.PerformLayout(true); Textbox.Height = tl.ContentHeight; Textbox.BaselineOffset = tl.Lines[0].GlyphRuns[0].BaselineOffset; // Init Checkbox: tl.Clear(); tl.Append("Qwerty"); tl.DefaultFormat.Font = Checkbox.Font; tl.DefaultFormat.FontSize = Checkbox.FontSize; tl.PerformLayout(true); Checkbox.Height = tl.ContentHeight; Checkbox.BaselineOffset = tl.Lines[0].GlyphRuns[0].BaselineOffset; }
public void CreatePDF(Stream stream) { var doc = new GcPdfDocument(); // Use TextLayout to render text: var tl = new TextLayout(72); // If not specifying formats for individual runs, we MUST provide // font and font size on TextLayout.DefaultFormat: tl.DefaultFormat.Font = StandardFonts.Times; tl.DefaultFormat.FontSize = 12; // First line offset 1/2": tl.FirstLineIndent = 72 / 2; // // All other formatting properties are left at their default values. // In particular, TextLayout's default resolution is 72 dpi - // the same as GcPdf's, and WordWrap is true. // // Set TextLayout's area to the whole page: tl.MaxWidth = doc.PageSize.Width; tl.MaxHeight = doc.PageSize.Height; // ...and have it manage the page margins (1" all around): tl.MarginAll = tl.Resolution; // // Append the text (20 paragraphs so they would not fit on a single page) // (note that TextLayout interprets "\r\n" as paragraph delimiter): tl.Append(Common.Util.LoremIpsum(20)); // // When all text has been added, we must calculate the glyphs needed to render the text, // and perform the layout. This can be done by a single call to PerformLayout, passing true to // recalculate glyphs first (even though the text won't all fit in the specified max size, // we only need to call PerformLayout once): tl.PerformLayout(true); // Use split options to provide widow/orphan control: TextSplitOptions to = new TextSplitOptions(tl); to.MinLinesInFirstParagraph = 2; to.MinLinesInLastParagraph = 2; // In a loop, split and render the text: while (true) { // 'rest' will accept the text that did not fit: var splitResult = tl.Split(to, out TextLayout rest); doc.Pages.Add().Graphics.DrawTextLayout(tl, PointF.Empty); if (splitResult != SplitResult.Split) { break; } tl = rest; } // Done: doc.Save(stream); }
// Main entry point: public void CreatePDF(Stream stream) { var doc = new GcPdfDocument(); var ip = new PointF(Layout.Margin, Layout.Margin); // Use TextLayout.MarginLeft to reserve space for list numbers/bullets: var tl = new TextLayout(72) { MaxWidth = doc.PageSize.Width - Layout.Margin * 2, MaxHeight = doc.PageSize.Height - Layout.Margin * 2, ParagraphSpacing = 8, MarginLeft = Layout.ListOffset, }; tl.DefaultFormat.Font = StandardFonts.Times; // Add 20 paragraphs of text that will render as a numbered list of 20 items: tl.Append(Common.Util.LoremIpsum(20, 1, 6)); // Perform layout: tl.PerformLayout(true); // Use split options to provide widow/orphan control: TextSplitOptions to = new TextSplitOptions(tl); to.MinLinesInFirstParagraph = 2; to.MinLinesInLastParagraph = 2; // In a loop, split and render the text (see PaginatedText), // and add list numbers: int itemNo = 1; while (true) { // 'rest' will accept the text that did not fit: var splitResult = tl.Split(to, out TextLayout rest); var g = doc.Pages.Add().Graphics; g.DrawTextLayout(tl, ip); AddBullets(g, ip, tl, ref itemNo); if (splitResult != SplitResult.Split) { break; } tl = rest; } // Done: doc.Save(stream); }
// Renders a list of nodes as a numbered list. private PointF RenderNodes(ref Page page, PointF pt, List <Node> nodes, int level) { TextLayout tlBullet = new TextLayout(72); tlBullet.DefaultFormat.Font = StandardFonts.Times; tlBullet.MarginLeft = Layout.ListIndent * level; TextLayout tlText = new TextLayout(72); tlText.DefaultFormat.Font = StandardFonts.Times; tlText.MarginLeft = Layout.ListOffset + Layout.ListIndent * level; for (int i = 0; i < nodes.Count; ++i) { var g = page.Graphics; // Prep item text: tlText.Clear(); tlText.Append(nodes[i].Text); tlText.PerformLayout(true); if (pt.Y + tlText.ContentHeight > page.Size.Height - Layout.Margin) { page = page.Doc.NewPage(); g = page.Graphics; pt.Y = Layout.Margin; } // Prep item number: tlBullet.Clear(); tlBullet.Append(ItemIdxToString(i, level, tlBullet)); tlBullet.PerformLayout(true); // Render item: g.DrawTextLayout(tlBullet, pt); g.DrawTextLayout(tlText, pt); // Advance insertion point: pt.Y += tlText.ContentHeight; // Render children: if (nodes[i].Children.Count > 0) { pt = RenderNodes(ref page, pt, nodes[i].Children, level + 1); } } return(pt); }
public void CreatePDF(Stream stream) { // Rotation angle, degrees clockwise: float angle = -45; // var doc = new GcPdfDocument(); var g = doc.NewPage().Graphics; // Create a text layout, pick a font and font size: TextLayout tl = g.CreateTextLayout(); tl.DefaultFormat.Font = StandardFonts.Times; tl.DefaultFormat.FontSize = 24; // Add a text, and perform layout: tl.Append("Rotated text."); tl.PerformLayout(true); // Text insertion point at (1",1"): var ip = new PointF(72, 72); // Now that we have text size, create text rectangle with top left at insertion point: var rect = new RectangleF(ip.X, ip.Y, tl.ContentWidth, tl.ContentHeight); // Rotation center point in the middel of text bounding rectangle: var center = new PointF(ip.X + tl.ContentWidth / 2, ip.Y + tl.ContentHeight / 2); // Transformations can be combined by multiplying matrices. // Note that matrix multiplication is not commutative - // the sequence of operands is important, and is applied from last to first // matrices being multiplied: // 3) Translate the origin back to (0,0): // 2) Rotate around new origin by the specified angle: // 1) Translate the origin from default (0,0) to rotation center: g.Transform = Matrix3x2.CreateTranslation(-center.X, -center.Y) * Matrix3x2.CreateRotation((float)(angle * Math.PI) / 180f) * Matrix3x2.CreateTranslation(center.X, center.Y); // Draw rotated text and bounding rectangle: g.DrawTextLayout(tl, ip); g.DrawRectangle(rect, Color.Black, 1); // Remove transformation and draw the bounding rectangle where the non-rotated text would have been: g.Transform = Matrix3x2.Identity; g.DrawRectangle(rect, Color.ForestGreen, 1); // Done: doc.Save(stream); }
// Method drawing a language's caption and test text: private void DrawText(string caption, string text, Font font, bool rtl) { _captionLayout.Clear(); _captionLayout.Append(caption); _captionLayout.PerformLayout(true); _textLayout.Clear(); _textLayout.DefaultFormat.Font = font; _textLayout.RightToLeft = rtl; _textLayout.Append(text); _textLayout.PerformLayout(true); // Add new page if needed: GcGraphics g; if (_doc.Pages.Count == 0 || _ipY + tlHeight(_captionLayout) + tlHeight(_textLayout) + c_CaptionToText > _doc.PageSize.Height - c_Margin) { _ipY = c_Margin; g = _doc.Pages.Add().Graphics; } else { g = _doc.Pages.Last.Graphics; } // Draw caption: g.FillRectangle(new RectangleF(c_Margin, _ipY, _captionLayout.MaxWidth.Value, tlHeight(_captionLayout)), Color.SteelBlue); g.DrawTextLayout(_captionLayout, new PointF(c_Margin, _ipY)); _ipY += tlHeight(_captionLayout); _ipY += c_CaptionToText; // Draw test text: g.DrawRectangle(new RectangleF(c_Margin, _ipY, _textLayout.MaxWidth.Value, tlHeight(_textLayout)), Color.LightSteelBlue, 0.5f); g.DrawTextLayout(_textLayout, new PointF(c_Margin, _ipY)); _ipY += tlHeight(_textLayout); _ipY += c_TextToCaption; return; float tlHeight(TextLayout tl) { return(tl.MarginTop + tl.ContentHeight + tl.MarginBottom); } }
// Utility method to draw a part of a page header or footer. // Parameters: // - text: The part's text. // - tf: The text format to use. // - pageIdx: The page index. // - header: True if this is a header, false if a footer. // - horzAlign: Horizontal alignment (left/center/right). private void RenderHeader(string text, TextFormat tf, int pageIdx, bool header, TextAlignment horzAlign) { var page = _doc.Pages[pageIdx]; TextLayout tl = new TextLayout(page.Graphics.Resolution); tl.MaxWidth = page.Size.Width; tl.MaxHeight = page.Size.Height; // 1" margins, adjust as needed: tl.MarginLeft = tl.MarginRight = 72; // 1/3" spacing above top/below bottom header, adjust as needed: tl.MarginTop = tl.MarginBottom = 72 / 3; // Vertical alignment: tl.ParagraphAlignment = header ? ParagraphAlignment.Near : ParagraphAlignment.Far; // Horizontal alignment: tl.TextAlignment = horzAlign; tl.Append(text, tf); // NOTE: if some part of a header or footer is static, we could cache the corresponding TextLayout // object and save some cycles by just drawing that cached TextLayout on each page w/out anything else: tl.PerformLayout(true); // Draw the header at (0,0) (header located by margins and alignment): page.Graphics.DrawTextLayout(tl, PointF.Empty); }
// Replaces any text fields in the document with regular text: private void FlattenDoc(GcPdfDocument doc) { foreach (var f in doc.AcroForm.Fields) { if (f is TextField fld) { var w = fld.Widget; var g = w.Page.Graphics; _inputTl.Clear(); _inputTl.Append(fld.Value, _inputTf); _inputTl.MaxHeight = w.Rect.Height; _inputTl.PerformLayout(true); g.DrawTextLayout(_inputTl, w.Rect.Location); } } for (int i = doc.AcroForm.Fields.Count - 1; i >= 0; --i) { if (doc.AcroForm.Fields[i] is TextField) { doc.AcroForm.Fields.RemoveAt(i); } } }
public void CreatePDF(Stream stream) { var doc = new GcPdfDocument(); var page = doc.NewPage(); var g = page.Graphics; // As in the Surrogates sample, we specify a standard font // (which lacks many of the glyphs we will be rendering), // and will rely on font fallback support provided by FontCollection: var font = StandardFonts.Helvetica; // Set up text formats for captions, "interesting chars" and spacing: TextFormat tf = new TextFormat() { Font = font, FontSize = 12 }; TextFormat tf1 = new TextFormat(tf) { FontSize = 14 }; TextFormat tfs = new TextFormat(tf) { FontSize = 6 }; // Create a font collection to use: FontCollection fc = new FontCollection(); // Add our own fallback fonts to use (note that order is imortant here, // first come first found): fc.AppendFallbackFonts( Font.FromFile(Path.Combine("Resources", "Fonts", "arialuni.ttf")), Font.FromFile(Path.Combine("Resources", "Fonts", "l_10646.ttf")), Font.FromFile(Path.Combine("Resources", "Fonts", "seguiemj.ttf")), Font.FromFile(Path.Combine("Resources", "Fonts", "seguisym.ttf")), Font.FromFile(Path.Combine("Resources", "Fonts", "simsun.ttc")), Font.FromFile(Path.Combine("Resources", "Fonts", "times.ttf")), Font.FromFile(Path.Combine("Resources", "Fonts", "YuGothR.ttc")) ); // Restricting default font lookup is done in the TextLayout, so unlike the // {Surrogates} sample, here we cannot use DrawString, but must use // TextLayout and DrawTextLayout directly: // - specify the font collection to use; // - restrict default fonts/fallbacks lookup to the specified collection only; // - set up other props to render the text. TextLayout tl = new TextLayout(72) { FontCollection = fc, RestrictedFontLookup = true, FontFallbackScope = FontFallbackScope.FontCollectionOnly, MaxWidth = page.Size.Width, MaxHeight = page.Size.Height, MarginLeft = 72, MarginRight = 72, MarginTop = 36, MarginBottom = 36, TextAlignment = TextAlignment.Center, }; tl.Append("Some Interesting Unicode Characters (system-independent)", new TextFormat(tf) { Underline = true, FontSize = tf.FontSize + 2 }); tl.PerformLayout(true); g.DrawTextLayout(tl, PointF.Empty); tl.MarginTop = tl.ContentRectangle.Bottom + 20; tl.Clear(); tl.TextAlignment = TextAlignment.Leading; // Draw the strings: tl.Append("Surrogate Pairs:\n", tf); tl.Append("\uD867\uDEDB \uD840\uDC0B \uD834\uDD1E \uD834\uDD61 \uD83D\uDC04\n", tf1); tl.Append("\n", tfs); tl.Append("Currency Symbols:\n", tf); tl.Append("\u0024 \u20A0 \u20A1 \u20A2 \u20A3 \u20A4 \u20AC \u20B9 \x20BD\n", tf1); tl.Append("\n", tfs); tl.Append("Mathematical Operators:\n", tf); tl.Append("\u221A \u222B \u2211 \u2210 \u2264 \u2265 \u2202 \u2208\n", tf1); tl.Append("\n", tfs); tl.Append("CJK Ideographs Extension A:\n", tf); tl.Append("\u3400 \u3401 \u3402 \u3403 \u3404 \u3405 \u3406 \u3407\n", tf1); tl.Append("\n", tfs); tl.Append("Letterlike Symbols:\n", tf); tl.Append("\u2110 \u2111 \u2112 \u2113 \u2114 \u2115 \u211B \u211C\n", tf1); tl.Append("\n", tfs); tl.Append("Private Use Area:\n", tf); tl.Append("\uE000 \uE001 \uE010 \uE011 \uE012 \uE013 \uE014 \uE015\n", tf1); tl.Append("\n", tfs); tl.Append("Arrows:\n", tf); tl.Append("\u2190 \u2191 \u2192 \u2193 \u21B0 \u21E6 \u21CB \u21A9\n", tf1); tl.Append("\n", tfs); tl.Append("Dingbats:\n", tf); tl.Append("\u2714 \u2717 \u275B \u275C \u2706 \u2707 \u2708 \u2709\n", tf1); tl.Append("\n", tfs); tl.Append("Braille Patterns:\n", tf); tl.Append("\u2830 \u2831 \u2832 \u2833 \u2834 \u2835 \u2836 \u2837\n", tf1); tl.Append("\n", tfs); tl.Append("Geometric Shapes:\n", tf); tl.Append("\u25D0 \u25D1 \u25D2 \u25D3 \u25A4 \u25F0 \u25BC \u25CE\n", tf1); tl.Append("\n", tfs); tl.Append("Latin Extended A:\n", tf); tl.Append("\u0100 \u0101 \u0102 \u0103 \u0104 \u0105 \u0106 \u0107\n", tf1); tl.Append("\n", tfs); tl.Append("Miscellaneous Symbols:\n", tf); tl.Append("\u2600 \u2601 \u2602 \u2603 \u2604 \u2605 \u2606 \u2607 \u2608 \u2609 \u2614 \u2615 \u26F0\n", tf1); tl.Append("\n", tfs); tl.PerformLayout(true); g.DrawTextLayout(tl, PointF.Empty); // Done: doc.Save(stream); }
public void CreatePDF(Stream stream) { GcPdfDocument doc = new GcPdfDocument(); // The original file stream must be kept open while working with the loaded PDF, see LoadPDF for details: using (var fs = new FileStream(Path.Combine("Resources", "PDFs", "FormFields.pdf"), FileMode.Open, FileAccess.Read)) { doc.Load(fs); var page = doc.Pages.Last; StringBuilder sb = new StringBuilder(); sb.AppendLine("Log of updates made by the FillForm sample:\r\n"); foreach (Field fld in doc.AcroForm.Fields) { if (fld is CombTextField ctfld) { sb.Append($"CombTextField.Value was '{ctfld.Value}', "); ctfld.Value = "Comb text"; sb.AppendLine($"now '{ctfld.Value}'."); } else if (fld is TextField tfld) { sb.Append($"TextField.Value was '{tfld.Value}', "); tfld.Value = $"Text updated on {DateTime.Now}"; sb.AppendLine($"now '{tfld.Value}'."); } else if (fld is CheckBoxField cfld) { sb.Append($"CheckBoxField.Value was '{cfld.Value}', "); cfld.Value = !cfld.Value; sb.AppendLine($"now '{cfld.Value}'."); } else if (fld is RadioButtonField rbfld) { sb.Append($"RadioButtonField.Value was '{rbfld.Value}', "); rbfld.Value = rbfld.Widgets.Count - 1; sb.AppendLine($"now '{rbfld.Value}'."); } else if (fld is ComboBoxField cmbfld) { sb.Append($"ComboBoxField selection was '{cmbfld.Items[cmbfld.SelectedIndex].Text}', "); cmbfld.SelectedIndex = cmbfld.Items.Count - 1; sb.AppendLine($"now '{cmbfld.Items[cmbfld.SelectedIndex].Text}'."); } else if (fld is ListBoxField lbfld) { sb.Append($"ListBoxField selection was '{lbfld.Items[lbfld.SelectedIndex].Text}', "); lbfld.SelectedIndex = lbfld.Items.Count - 1; sb.AppendLine($"now '{lbfld.Items[lbfld.SelectedIndex].Text}'."); } else if (fld is SignatureField sfld) { sb.AppendLine("SignatureField found."); } else if (fld is PushButtonField btnfld) { sb.AppendLine($"PushButtonField '{btnfld.Widget.ButtonAppearance.Caption}' found."); } else { sb.AppendLine($"Field '{fld}' found/"); } } // Add a log of what we did at the bottom of the page: var tl = new TextLayout(72) { MaxWidth = page.Size.Width, MaxHeight = page.Size.Height, MarginLeft = 80, MarginRight = 80, MarginBottom = 80, ParagraphAlignment = ParagraphAlignment.Far }; tl.Append(sb.ToString(), new TextFormat() { Font = StandardFonts.Times, FontSize = 12 }); tl.PerformLayout(true); var rc = tl.ContentRectangle; rc.Inflate(8, 8); page.Graphics.FillRectangle(rc, Color.LightYellow); page.Graphics.DrawRectangle(rc, Color.Orange); page.Graphics.DrawTextLayout(tl, PointF.Empty); // Done: doc.Save(stream); } }
public int CreatePDF(Stream stream) { using (var clouds = Image.FromFile(Path.Combine("Resources", "Images", "clouds.jpg"))) using (var firth = Image.FromFile(Path.Combine("Resources", "Images", "firth.jpg"))) using (var lavender = Image.FromFile(Path.Combine("Resources", "Images", "lavender.jpg"))) { var yumin = Font.FromFile(Path.Combine("Resources", "Fonts", "yumin.ttf")); var ia = new ImageAlign(ImageAlignHorz.Left, ImageAlignVert.Top, true, true, true, false, false); var doc = new GcPdfDocument(); // The TextLayout that will hold and render the text: var tl = new TextLayout(72); tl.FirstLineIndent = 18; tl.ParagraphSpacing = 6; tl.FlowDirection = FlowDirection.VerticalRightToLeft; tl.TextAlignment = TextAlignment.Justified; tl.AlignmentDelayToSplit = true; var tf = new TextFormat() { Font = yumin, FontSize = 12 }; // Repeat test text to fill a few pages: for (int i = 0; i < 25; ++i) { tl.Append(text, tf); tl.AppendLine(); } // Layout text in 4 horizontal columns: // (The logic/code in this sample is identical to ArabicColumns): const int NCOLS = 4; var margin = 36f; var gap = 18f; var page = doc.NewPage(); page.Landscape = true; var colHeight = (page.Size.Height - margin * 2 - gap * (NCOLS - 1)) / NCOLS; tl.MaxWidth = page.Size.Width; tl.MaxHeight = page.Size.Height; tl.MarginLeft = tl.MarginRight = margin; tl.MarginTop = margin; tl.MarginBottom = margin + (colHeight + gap) * (NCOLS - 1); // We can specify arbitrary rectangles for the text to flow around. // In this case, we add 3 areas to draw some images: tl.ObjectRects = new List <ObjectRect>() { new ObjectRect(page.Size.Width - margin - 267, margin, 267, 200), new ObjectRect(margin + 100, margin + 60, 133, 100), new ObjectRect(margin, page.Size.Height - margin - 301, 200, 301), }; // Convert object rects to image areas, adjust to provide nice looking padding: var rClouds = tl.ObjectRects[0].ToRectangleF(); rClouds.Inflate(-4, -3); var rFirth = tl.ObjectRects[1].ToRectangleF(); rFirth.Inflate(-4, -3); var rLavender = tl.ObjectRects[2].ToRectangleF(); rLavender.Inflate(-4, -3); page.Graphics.DrawImage(clouds, rClouds, null, ia); page.Graphics.DrawImage(firth, rFirth, null, ia); page.Graphics.DrawImage(lavender, rLavender, null, ia); // THE call: it calculates the glyphs needed to draw the text, and lays it out: tl.PerformLayout(true); // Loop while there is still text to render: bool done = false; while (!done) { for (int col = 0; col < NCOLS; ++col) { int nextcol = (col < NCOLS - 1) ? col + 1 : 0; // TextSplitOptions tell TextLayout.Split() how to layout the remaining text. // In this case we advance from column to column by updating top and bottom margins: var tso = new TextSplitOptions(tl) { RestMarginTop = margin + (colHeight + gap) * nextcol, RestMarginBottom = margin + (colHeight + gap) * (NCOLS - 1 - nextcol) }; var split = tl.Split(tso, out TextLayout rest); page.Graphics.DrawTextLayout(tl, PointF.Empty); if (split != SplitResult.Split) { done = true; break; } tl = rest; } if (!done) { page = doc.NewPage(); page.Landscape = true; // We only want to render images on the first page, so clear ObjectRect: if (tl.ObjectRects != null) { tl.ObjectRects = null; // We need to redo the layout, but no need to recalculate the glyphs: tl.PerformLayout(false); } } } // Done: doc.Save(stream); return(doc.Pages.Count); } }
// Creates the Time Sheet form: private GcPdfDocument MakeTimeSheetForm() { const float marginH = 72, marginV = 48; var doc = new GcPdfDocument(); var page = doc.NewPage(); var g = page.Graphics; var ip = new PointF(marginH, marginV); var tl = new TextLayout(g.Resolution) { FontCollection = _fc }; tl.Append("TIME SHEET", new TextFormat() { FontName = "Segoe UI", FontSize = 18 }); tl.PerformLayout(true); g.DrawTextLayout(tl, ip); ip.Y += tl.ContentHeight + 15; var logo = Image.FromFile(Path.Combine("Resources", "ImagesBis", "AcmeLogo-vertical-250px.png")); _disposables.Add(logo); var s = new SizeF(250f * 0.75f, 64f * 0.75f); g.DrawImage(logo, new RectangleF(ip, s), null, ImageAlign.Default); ip.Y += s.Height + 5; tl.Clear(); tl.Append("Where Business meets Technology", new TextFormat() { FontName = "Segoe UI", FontItalic = true, FontSize = 10 }); tl.PerformLayout(true); g.DrawTextLayout(tl, ip); ip.Y += tl.ContentHeight + 15; tl.Clear(); tl.Append("1901, Halford Avenue,\r\nSanta Clara, California – 95051-2553,\r\nUnited States", new TextFormat() { FontName = "Segoe UI", FontSize = 9 }); tl.MaxWidth = page.Size.Width - marginH * 2; tl.TextAlignment = TextAlignment.Trailing; tl.PerformLayout(true); g.DrawTextLayout(tl, ip); ip.Y += tl.ContentHeight + 25; var pen = new Pen(Color.Gray, 0.5f); var colw = (page.Size.Width - marginH * 2) / 2; var fields1 = DrawTable(ip, new float[] { colw, colw }, new float[] { 30, 30, 30 }, g, pen); var tf = new TextFormat() { FontName = "Segoe UI", FontSize = 9 }; tl.ParagraphAlignment = ParagraphAlignment.Center; tl.TextAlignment = TextAlignment.Leading; tl.MarginLeft = tl.MarginRight = tl.MarginTop = tl.MarginBottom = 4; // t_ - caption // b_ - bounds // f_ - field name, null means no field Action <string, RectangleF, string> drawField = (t_, b_, f_) => { float tWidth; if (!string.IsNullOrEmpty(t_)) { tl.Clear(); tl.MaxHeight = b_.Height; tl.MaxWidth = b_.Width; tl.Append(t_, tf); tl.PerformLayout(true); g.DrawTextLayout(tl, b_.Location); tWidth = tl.ContentRectangle.Right; } else { tWidth = 0; } if (!string.IsNullOrEmpty(f_)) { var fld = new TextField() { Name = f_ }; fld.Widget.Page = page; fld.Widget.Rect = new RectangleF( b_.X + tWidth + _inputMargin, b_.Y + _inputMargin, b_.Width - tWidth - _inputMargin * 2, b_.Height - _inputMargin * 2); fld.Widget.TextFormat = _inputTf; fld.Widget.Border.Color = Color.LightSlateGray; fld.Widget.Border.Width = 0.5f; doc.AcroForm.Fields.Add(fld); } }; drawField("EMPLOYEE NAME: ", fields1[0, 0], _Names.EmpName); drawField("TITLE: ", fields1[1, 0], _Names.EmpTitle); drawField("EMPLOYEE NUMBER: ", fields1[0, 1], _Names.EmpNum); drawField("STATUS: ", fields1[1, 1], _Names.EmpStatus); drawField("DEPARTMENT: ", fields1[0, 2], _Names.EmpDep); drawField("SUPERVISOR: ", fields1[1, 2], _Names.EmpSuper); ip.Y = fields1[0, 2].Bottom; float col0 = 100; colw = (page.Size.Width - marginH * 2 - col0) / 5; float rowh = 25; var fields2 = DrawTable(ip, new float[] { col0, colw, colw, colw, colw, colw }, new float[] { 50, rowh, rowh, rowh, rowh, rowh, rowh, rowh, rowh }, g, pen); tl.ParagraphAlignment = ParagraphAlignment.Far; drawField("DATE", fields2[0, 0], null); drawField("START TIME", fields2[1, 0], null); drawField("END TIME", fields2[2, 0], null); drawField("REGULAR HOURS", fields2[3, 0], null); drawField("OVERTIME HOURS", fields2[4, 0], null); tf.FontBold = true; drawField("TOTAL HOURS", fields2[5, 0], null); tf.FontBold = false; tl.ParagraphAlignment = ParagraphAlignment.Center; tf.ForeColor = Color.Gray; for (int i = 0; i < 7; ++i) { drawField(_Names.Dows[i], fields2[0, i + 1], _Names.DtNames[_Names.Dows[i]][0]); } tf.ForeColor = Color.Black; for (int row = 1; row <= 7; ++row) { for (int col = 1; col <= 5; ++col) { drawField(null, fields2[col, row], _Names.DtNames[_Names.Dows[row - 1]][col]); } } tf.FontBold = true; drawField("WEEKLY TOTALS", fields2[0, 8], null); tf.FontBold = false; drawField(null, fields2[3, 8], _Names.TotalReg); drawField(null, fields2[4, 8], _Names.TotalOvr); drawField(null, fields2[5, 8], _Names.TotalHours); ip.Y = fields2[0, 8].Bottom; col0 = 72 * 4; colw = page.Size.Width - marginH * 2 - col0; var fields3 = DrawTable(ip, new float[] { col0, colw }, new float[] { rowh + 10, rowh, rowh }, g, pen); drawField("EMPLOYEE SIGNATURE: ", fields3[0, 1], null); var r = fields3[0, 1]; _empSignRect = new RectangleF(r.X + r.Width / 2, r.Y, r.Width / 2 - _inputMargin * 2, r.Height); // For a digital employee signature, uncomment this code: /* * SignatureField sf = new SignatureField(); * sf.Name = _Names.EmpSign; * sf.Widget.Rect = new RectangleF(r.X + r.Width / 2, r.Y + _inputMargin, r.Width / 2 - _inputMargin * 2, r.Height - _inputMargin * 2); * sf.Widget.Page = page; * sf.Widget.BackColor = Color.LightSeaGreen; * doc.AcroForm.Fields.Add(sf); */ drawField("DATE: ", fields3[1, 1], _Names.EmpSignDate); drawField("SUPERVISOR SIGNATURE: ", fields3[0, 2], null); // Supervisor signature: r = fields3[0, 2]; SignatureField sf = new SignatureField(); sf.Name = _Names.SupSign; sf.Widget.Rect = new RectangleF(r.X + r.Width / 2, r.Y + _inputMargin, r.Width / 2 - _inputMargin * 2, r.Height - _inputMargin * 2); sf.Widget.Page = page; sf.Widget.BackColor = Color.LightYellow; doc.AcroForm.Fields.Add(sf); drawField("DATE: ", fields3[1, 2], _Names.SupSignDate); // Done: return(doc); }
public int CreatePDF(Stream stream) { GcPdfDocument doc = new GcPdfDocument(); var page = doc.NewPage(); var rc = Common.Util.AddNote( "This sample loads the PDF created by the TimeSheet sample into a temporary GcPdfDocument, " + "gets the text map for the first page, and prints out the coordinates and texts of all " + "line fragments in the map. " + "It also uses the map's HitTest method to find the text at specific coordinates in the PDF " + "and prints the result. " + "The original TimeSheet.pdf used by this sample (consisting of 1 page) is appended for reference.", page); // Setup text formatting and layout: var tf = new TextFormat() { Font = StandardFonts.Times, FontSize = 13 }; var tfFound = new TextFormat() { Font = StandardFonts.TimesBold, FontSize = 14, ForeColor = Color.DarkBlue }; var tl = new TextLayout(72) { MaxWidth = doc.PageSize.Width, MaxHeight = doc.PageSize.Height, MarginAll = rc.Left, MarginTop = rc.Bottom + 36, TabStops = new List <TabStop>() { new TabStop(72 * 2) }, }; TextSplitOptions to = new TextSplitOptions(tl) { MinLinesInFirstParagraph = 2, MinLinesInLastParagraph = 2, RestMarginTop = rc.Left, }; // Open an arbitrary PDF, load it into a temp document and use the map to find some texts: using (var fs = new FileStream(Path.Combine("Resources", "PDFs", "TimeSheet.pdf"), FileMode.Open, FileAccess.Read)) { var doc1 = new GcPdfDocument(); doc1.Load(fs); var tmap = doc1.Pages[0].GetTextMap(); // We retrieve the text at a specific (known to us) geometric location on the page: float tx0 = 2.1f, ty0 = 3.37f, tx1 = 3.1f, ty1 = 3.5f; HitTestInfo htiFrom = tmap.HitTest(tx0 * 72, ty0 * 72); HitTestInfo htiTo = tmap.HitTest(ty0 * 72, ty1 * 72); tmap.GetFragment(htiFrom.Pos, htiTo.Pos, out TextMapFragment range1, out string text1); tl.AppendLine($"Looked for text inside rectangle x={tx0:F2}\", y={ty0:F2}\", width={tx1-tx0:F2}\", height={ty1-ty0:F2}\", found:", tf); tl.AppendLine(text1, tfFound); tl.AppendLine(); // Get all text fragments and their locations on the page: tl.AppendLine("List of all texts found on the page", tf); tmap.GetFragment(out TextMapFragment range, out string text); foreach (TextLineFragment tlf in range) { var coords = tmap.GetCoords(tlf); tl.Append($"Text at ({coords.B.X / 72:F2}\",{coords.B.Y / 72:F2}\"):\t", tf); tl.AppendLine(tmap.GetText(tlf), tfFound); } // Print the results: tl.PerformLayout(true); while (true) { // 'rest' will accept the text that did not fit: var splitResult = tl.Split(to, out TextLayout rest); doc.Pages.Last.Graphics.DrawTextLayout(tl, PointF.Empty); if (splitResult != SplitResult.Split) { break; } tl = rest; doc.NewPage(); } // Append the original document for reference: doc.MergeWithDocument(doc1, new MergeDocumentOptions()); } // Done: doc.Save(stream); return(doc.Pages.Count); }
private RectangleF DrawTable(float[] widths, string[] captions, string[] samples, int rowCount) { System.Diagnostics.Debug.Assert(captions.Length == widths.Length && samples.Length == widths.Length); var ipSave = _ip; Pen p = new Pen(Color.Black, 0.5f); var g = CurrGraphics; TextLayout tl = g.CreateTextLayout(); tl.ParagraphAlignment = ParagraphAlignment.Center; tl.TextAlignment = TextAlignment.Center; tl.DefaultFormat.Font = TsNormal.Font; tl.DefaultFormat.FontSize = TsNormal.FontSize; tl.DefaultFormat.GlyphAdvanceFactor = TsNormal.GlyphAdvanceFactor; tl.DefaultFormat.ForeColor = Color.White; tl.WrapMode = WrapMode.NoWrap; tl.MaxHeight = TableCaptionHeight; float totW = 0; for (int i = 0; i < widths.Length; ++i) { if (i == widths.Length - 1) { widths[i] = CurrPage.Size.Width - MarginLeft - MarginRight - totW - 1; totW += 1; } totW += widths[i]; } g.FillRectangle(new RectangleF(MarginLeft, _ip.Y, totW, TableCaptionHeight), Color.Black); var pt = new PointF(MarginLeft, _ip.Y); for (int i = 0; i < widths.Length; ++i) { tl.MaxWidth = widths[i]; tl.Append(captions[i]); tl.PerformLayout(true); g.DrawTextLayout(tl, pt); pt.X = pt.X + widths[i]; tl.Inlines.Clear(); } tl.DefaultFormat.ForeColor = Color.Teal; tl.MaxHeight = TableSampleHeight; pt = new PointF(MarginLeft, _ip.Y + TableCaptionHeight); for (int i = 0; i < widths.Length; ++i) { tl.MaxWidth = widths[i]; tl.Append(samples[i]); tl.PerformLayout(true); g.DrawTextLayout(tl, pt); pt.X = pt.X + widths[i]; tl.Inlines.Clear(); } SetY(_ip.Y + TableCaptionHeight + TableSampleHeight, 0.5f); for (int row = 0; row < rowCount; ++row) { _ip.X = MarginLeft + 1; for (int i = 0; i < widths.Length; ++i) { var cr = DrawTextbox(widths[i] - 1, true); _ip.X = cr.Right + 1; } g.DrawLine(new PointF(MarginLeft, _ip.Y - 0.5f), new PointF(MarginLeft + totW, _ip.Y - 0.5f), p); SetY(null, Textbox.Height + 1); } var totH = TableCaptionHeight + TableSampleHeight + (Textbox.Height + 1) * rowCount; _ip.X = MarginLeft + 0.5f; for (int i = 0; i < widths.Length - 1; ++i) { _ip.X += widths[i]; g.DrawLine(new PointF(_ip.X, ipSave.Y), new PointF(_ip.X, ipSave.Y + totH), p); } var rect = new RectangleF(MarginLeft, ipSave.Y, totW, totH); g.DrawRectangle(rect, p); return(rect); }
// Adds a word index to the end of the passed document: private void AddWordIndex(GcPdfDocument doc, IEnumerable <string> words) { var tStart = DateTime.Now; // Words and page indices where they occur, sorted on words: SortedDictionary <string, List <int> > index = new SortedDictionary <string, List <int> >(); // Here the main loop building the index is on key words. // An alternative would be to loop over the pages. // Depending on the relative sizes of the keyword dictionary vs // the number of pages in the document, one or the other might be better, // but this is beyond the scope of this sample. foreach (string word in words) { bool wholeWord = word.IndexOf(' ') == -1; var ft = doc.FindText(new FindTextParams(word, wholeWord, false), OutputRange.All); var pgs = ft.Select(fp_ => fp_.PageIndex).Distinct(); // A very simplistic way of also finding plurals: if (wholeWord && !word.EndsWith('s')) { var ftpl = doc.FindText(new FindTextParams(word + "s", wholeWord, false), OutputRange.All); pgs = pgs.Concat(ftpl.Select(fp_ => fp_.PageIndex).Distinct()).Distinct(); } if (pgs.Any()) { var sorted = pgs.ToList(); sorted.Sort(); index.Add(word, sorted); } } // Prepare to render the index. The whole index is built // in a single TextLayout instance, set up to render it // in two columns per page. // The main rendering loop uses the TextLayout.SplitAndBalance method // using the approach demonstrated in BalancedColumns sample. // The complication here is that we need to associate a link to the // relevant page with each page number rendered, see linkIndices below. // Set up the TextLayout: const float margin = 72; var pageWidth = doc.PageSize.Width; var pageHeight = doc.PageSize.Height; var cW = pageWidth - margin * 2; // Caption (index letter) format: var tfCap = new TextFormat() { FontName = _fontFamily, FontBold = true, FontSize = 16, LineGap = 24, }; // Index word and pages format: var tfRun = new TextFormat() { FontName = _fontFamily, FontSize = 10, }; // Page headers/footers: var tfHdr = new TextFormat() { FontName = _fontFamily, FontItalic = true, FontSize = 10, }; // FirstLineIndent = -18 sets up hanging indent: var tl = new TextLayout(72) { FontCollection = _fc, FirstLineIndent = -18, MaxWidth = pageWidth, MaxHeight = pageHeight, MarginLeft = margin, MarginRight = margin, MarginBottom = margin, MarginTop = margin, ColumnWidth = cW * 0.46f, TextAlignment = TextAlignment.Leading, ParagraphSpacing = 4, LineGapBeforeFirstLine = false, }; // The list of text runs created for page numbers: List <Tuple <TextRun, int> > pgnumRuns = new List <Tuple <TextRun, int> >(); // This loop builds the index on the TextLayout, saving the text runs // created for each page number rendered. Note that at this point // (prior to the PerformLayout(true) call) the text runs do not contain any info // about their code points and render locations, so we can only save the text runs here. // Later they will be used to add links to referenced pages in the PDF: char litera = ' '; foreach (KeyValuePair <string, List <int> > kvp in index) { var word = kvp.Key; var pageIndices = kvp.Value; if (Char.ToUpper(word[0]) != litera) { litera = Char.ToUpper(word[0]); tl.Append($"{litera}\u2029", tfCap); } tl.Append(word, tfRun); tl.Append(" ", tfRun); for (int i = 0; i < pageIndices.Count; ++i) { var from = pageIndices[i]; var tr = tl.Append((from + 1).ToString(), tfRun); pgnumRuns.Add(Tuple.Create(tr, from)); // We merge sequential pages into "..-M": int k = i; for (int j = i + 1; j < pageIndices.Count && pageIndices[j] == pageIndices[j - 1] + 1; ++j) { k = j; } if (k > i + 1) { tl.Append("-", tfRun); var to = pageIndices[k]; tr = tl.Append((to + 1).ToString(), tfRun); pgnumRuns.Add(Tuple.Create(tr, to)); // Fast forward: i = k; } if (i < pageIndices.Count - 1) { tl.Append(", ", tfRun); } else { tl.AppendLine(tfRun); } } } // This calculates the glyphs and lays out the whole index. // The tl.SplitAndBalance() call in the loop below does not require redoing the layout: tl.PerformLayout(true); // // Now we are ready to split and render the text layout, and also add links to page numbers. // // Split areas and options - see BalancedColumns for details: var psas = new PageSplitArea[] { new PageSplitArea(tl) { MarginLeft = tl.MarginLeft + (cW * 0.54f) }, }; TextSplitOptions tso = new TextSplitOptions(tl) { KeepParagraphLinesTogether = true, }; // First original code point index in the current column: int cpiStart = 0; // Max+1 original code point index in the current column: int cpiEnd = 0; // Current index in pgnumRuns: int pgnumRunsIdx = 0; // Split and render the index in 2 columns: for (var page = doc.Pages.Add(); ; page = doc.Pages.Add()) { var g = page.Graphics; // Add a simple page header: g.DrawString($"Index generated by GcPdf on {tStart}", tfHdr, new RectangleF(margin, 0, pageWidth - margin * 2, margin), TextAlignment.Center, ParagraphAlignment.Center, false); // 'rest' will accept the text that did not fit on this page: var splitResult = tl.SplitAndBalance(psas, tso, out TextLayout rest); // Render text: g.DrawTextLayout(tl, PointF.Empty); g.DrawTextLayout(psas[0].TextLayout, PointF.Empty); // Add links from page numbers to pages: linkIndices(tl, page); linkIndices(psas[0].TextLayout, page); // Are we done yet? if (splitResult != SplitResult.Split) { break; } tl = rest; } // Done: return; // Method to add links to actual pages over page numbers in the current column: void linkIndices(TextLayout tl_, Page page_) { cpiEnd += tl_.CodePointCount; for (; pgnumRunsIdx < pgnumRuns.Count; ++pgnumRunsIdx) { var run = pgnumRuns[pgnumRunsIdx]; var textRun = run.Item1; int cpi = textRun.CodePointIndex; if (cpi >= cpiEnd) { break; } cpi -= cpiStart; var rects = tl_.GetTextRects(cpi, textRun.CodePointCount); System.Diagnostics.Debug.Assert(rects.Count > 0); page_.Annotations.Add(new LinkAnnotation(rects[0].ToRectangleF(), new DestinationFit(run.Item2))); } cpiStart += tl_.CodePointCount; } }
public void CreatePDF(Stream stream) { var doc = new GcPdfDocument(); // Text layout for main text (default GcPdf resolution is 72dpi): var tl = new TextLayout(72); tl.DefaultFormat.Font = StandardFonts.Times; tl.DefaultFormat.FontSize = 12; tl.FirstLineIndent = 72 / 2; tl.MaxWidth = doc.PageSize.Width; tl.MaxHeight = doc.PageSize.Height; tl.MarginAll = tl.Resolution; // Text layout for chapter headers: var tlCaption = new TextLayout(72); tlCaption.DefaultFormat.Font = StandardFonts.TimesBold; tlCaption.DefaultFormat.FontSize = tl.DefaultFormat.FontSize + 4; tlCaption.DefaultFormat.Underline = true; tlCaption.MaxWidth = tl.MaxWidth; tlCaption.MarginAll = tlCaption.Resolution; // Split options to control splitting of text between pages: TextSplitOptions to = new TextSplitOptions(tl) { RestMarginTop = tl.Resolution, MinLinesInFirstParagraph = 2, MinLinesInLastParagraph = 2 }; // Generate a number of "chapters", provide outline entry for each: const int NChapters = 20; for (int i = 0; i < NChapters; ++i) { // Chapter title - print as chapter header and add as outline node: string chapter = $"Chapter {i + 1}"; // All it takes to add page lables is to add a PageLabelingRange // associated with the index of the first page in the range, // and the range prefix and numbering style: doc.PageLabelingRanges.Add(doc.Pages.Count, new PageLabelingRange($"{chapter}, p. ", NumberingStyle.DecimalArabic, 1)); doc.Pages.Add(); tlCaption.Clear(); tlCaption.Append(chapter); tlCaption.PerformLayout(true); // Add outline node for the chapter: doc.Outlines.Add(new OutlineNode(chapter, new DestinationFitH(doc.Pages.Count - 1, tlCaption.MarginTop))); // Print the caption: doc.Pages.Last.Graphics.DrawTextLayout(tlCaption, PointF.Empty); // Chapter text: tl.Clear(); tl.FirstLineIsStartOfParagraph = true; tl.LastLineIsEndOfParagraph = true; tl.Append(Common.Util.LoremIpsum(7)); // Account for chapter header in the main text layout: tl.MarginTop = tlCaption.ContentRectangle.Bottom + 12; tl.PerformLayout(true); // Print the chapter: while (true) { // 'rest' will accept the text that did not fit: var splitResult = tl.Split(to, out TextLayout rest); doc.Pages.Last.Graphics.DrawTextLayout(tl, PointF.Empty); if (splitResult != SplitResult.Split) { break; } tl = rest; var p = doc.Pages.Add(); } } // Done: doc.Save(stream); }
// The main sample driver. public int CreatePDF(Stream stream) { GcPdfDocument doc = new GcPdfDocument(); // This will hold the llst of images so we can dispose them after saving the document: List <IDisposable> disposables = new List <IDisposable>(); // Page footer: var ftrImg = Image.FromFile(Path.Combine("Resources", "ImagesBis", "logo-GC-devsol.png")); disposables.Add(ftrImg); var fx = ftrImg.HorizontalResolution / 72f; var fy = ftrImg.VerticalResolution / 72f; var ftrRc = new RectangleF( doc.PageSize.Width / 2 - ftrImg.Width / fx / 2, doc.PageSize.Height - 40, ftrImg.Width / fx, ftrImg.Height / fy); // Color for the title: var colorBlue = Color.FromArgb(0x3B, 0x5C, 0xAA); // Color for the highlights: var colorRed = Color.Red; // The text layout used to render text: TextLayout tl = new TextLayout(72) { MaxWidth = doc.PageSize.Width, MaxHeight = doc.PageSize.Height, MarginLeft = 72, MarginRight = 72, MarginTop = 72, MarginBottom = 72, }; tl.DefaultFormat.Font = Font.FromFile(Path.Combine("Resources", "Fonts", "segoeui.ttf")); tl.DefaultFormat.FontSize = 11; var page = doc.NewPage(); addFtr(); var g = page.Graphics; // Caption: tl.TextAlignment = TextAlignment.Center; tl.Append("Introduction\n", new TextFormat() { FontSize = 16, ForeColor = colorBlue }); tl.Append("The Importance of Wetlands", new TextFormat() { FontSize = 13, ForeColor = colorBlue }); tl.PerformLayout(true); g.DrawTextLayout(tl, PointF.Empty); // Move below the caption for the first para: tl.MarginTop = tl.ContentHeight + 72 * 2; tl.Clear(); tl.TextAlignment = TextAlignment.Leading; tl.ParagraphSpacing = 12; // For the first para we want a bigger initial letter, but no first line indent, // so we render it separately from the rest of the text: tl.Append(_paras[0].Substring(0, 1), new TextFormat(tl.DefaultFormat) { FontSize = 22 }); addPara(_paras[0].Substring(1)); tl.PerformLayout(true); g.DrawTextLayout(tl, PointF.Empty); // Account for the first para, and set up the text layout // for the rest of the text (a TextLayout allows to render multiple paragraphs, // but they all must have the same paragraph format): tl.MarginTop = tl.ContentRectangle.Bottom; tl.Clear(); tl.FirstLineIndent = 36; // Add remaining paragraphs: foreach (var para in _paras.Skip(1)) { // Paragraphs starting with '::' indicate images to be rendered across the page width: if (para.StartsWith("::")) { var img = Image.FromFile(Path.Combine("Resources", "ImagesBis", para.Substring(2))); disposables.Add(img); var w = tl.MaxWidth.Value - tl.MarginLeft - tl.MarginRight; var h = (float)img.Height / (float)img.Width * w; tl.AppendInlineObject(img, w, h); tl.AppendLine(); } else { addPara(para); } } // Layout the paragraphs: tl.PerformLayout(true); // Text split options allow to implement widow and orphan control: var tso = new TextSplitOptions(tl) { RestMarginTop = 72, MinLinesInFirstParagraph = 2, MinLinesInLastParagraph = 2, }; // Image alignment used to render the pictures: var ia = new ImageAlign(ImageAlignHorz.Left, ImageAlignVert.Top, true, true, true, false, false) { BestFit = true }; // In a loop, split and render the text: while (true) { var splitResult = tl.Split(tso, out TextLayout rest); g = doc.Pages.Last.Graphics; doc.Pages.Last.Graphics.DrawTextLayout(tl, PointF.Empty); // Render all images that occurred on this page: foreach (var io in tl.InlineObjects) { doc.Pages.Last.Graphics.DrawImage((Image)io.Object, io.ObjectRect.ToRectangleF(), null, ia); } // Break unless there is more to render: if (splitResult != SplitResult.Split) { break; } // Assign the remaining text to the 'main' TextLayout, add a new page and continue: tl = rest; doc.Pages.Add(); addFtr(); } // Save the PDF: doc.Save(stream); // Dispose images (can be done only after saving the document): disposables.ForEach(d_ => d_.Dispose()); // Done: return(doc.Pages.Count); void addPara(string para) { // We implement a primitive markup to highlight some fragments in red: var txt = para.Split(new string[] { "<red>", "</red>" }, StringSplitOptions.None); for (int i = 0; i < txt.Length; ++i) { if (i % 2 == 0) { tl.Append(txt[i]); } else { tl.Append(txt[i], new TextFormat(tl.DefaultFormat) { ForeColor = colorRed }); } } tl.AppendLine(); } void addFtr() { doc.Pages.Last.Graphics.DrawImage(ftrImg, ftrRc, null, ImageAlign.StretchImage); } }
public void CreatePDF(Stream stream) { var doc = new GcPdfDocument(); var date = new DateTime(1961, 4, 12, 6, 7, 0, DateTimeKind.Utc); // Mark the document as PDF/A-3u conformant: doc.ConformanceLevel = PdfAConformanceLevel.PdfA3u; var fnt = Font.FromFile(Path.Combine("Resources", "Fonts", "arial.ttf")); var gap = 36; // PDF/A-3a requires all content to be tagged so create and populate StructElement when rendering: StructElement sePart = new StructElement("Part"); doc.StructTreeRoot.Children.Add(sePart); TextLayout tl = null; // Add 3 pages with sample content tagged according to PDF/A rules: for (int pageNo = 1; pageNo <= 3; ++pageNo) { var page = doc.Pages.Add(); var g = page.Graphics; float y = 72; if (doc.Pages.Count == 1) { // Create paragraph element: var seParagraph = new StructElement("P") { DefaultPage = page }; // Add it to Part element: sePart.Children.Add(seParagraph); tl = g.CreateTextLayout(); tl.MarginAll = 72; tl.MaxWidth = page.Size.Width; tl.DefaultFormat.Font = fnt; tl.DefaultFormat.FontBold = true; tl.DefaultFormat.FontSize = 20; tl.Append("PDF/A-3A Document"); // PerformLayout is done automatically in a new TextLayout or after a Clear(): //tl.PerformLayout(true); // Draw TextLayout within tagged content: g.BeginMarkedContent(new TagMcid("P", 0)); g.DrawTextLayout(tl, PointF.Empty); g.EndMarkedContent(); y = tl.ContentRectangle.Bottom + gap; seParagraph.ContentItems.Add(new McidContentItemLink(0)); } // Add some sample paragraphs tagged according to PDF/A rules: for (int i = 1; i <= 3; ++i) { // Create paragraph element: var seParagraph = new StructElement("P") { DefaultPage = page }; // Add it to Part element: sePart.Children.Add(seParagraph); var sb = new StringBuilder(); sb.Append(string.Format("Paragraph {0} on page {1}: ", i, pageNo)); sb.Append(Common.Util.LoremIpsum(1, 2, 4, 5, 10)); var para = sb.ToString(); tl.Clear(); tl.DefaultFormat.FontSize = 14; tl.DefaultFormat.FontBold = false; tl.MarginTop = y; tl.Append(para); // Draw TextLayout within tagged content: g.BeginMarkedContent(new TagMcid("P", i)); g.DrawTextLayout(tl, PointF.Empty); g.EndMarkedContent(); y += tl.ContentHeight + gap; // Add content item to paragraph StructElement: seParagraph.ContentItems.Add(new McidContentItemLink(i)); // PDF/A-3 allows to embed files into document, but they should be associated with some document element // add embedded file associated with seParagraph: var ef1 = EmbeddedFileStream.FromBytes(doc, Encoding.UTF8.GetBytes(para)); // ModificationDate and MimeType should be specified in case of PDF/A: ef1.ModificationDate = date; ef1.MimeType = "text/plain"; var fn = string.Format("Page{0}_Paragraph{1}.txt", pageNo, i); var fs1 = FileSpecification.FromEmbeddedStream(fn, ef1); // Relationship should be specified in case of PDF/A: fs1.Relationship = AFRelationship.Unspecified; doc.EmbeddedFiles.Add(fn, fs1); seParagraph.AssociatedFiles.Add(fs1); } } // PDF/A-3 allows transparency drawing in PDF file, add some: var gpage = doc.Pages[0].Graphics; gpage.FillRectangle(new RectangleF(20, 20, 200, 200), Color.FromArgb(40, Color.Red)); // PDF/A-3 allows to use FormXObjects, add one with transparency: var r = new RectangleF(0, 0, 144, 72); var fxo = new FormXObject(doc, r); var gfxo = fxo.Graphics; gfxo.FillRectangle(r, Color.FromArgb(40, Color.Violet)); TextFormat tf = new TextFormat() { Font = fnt, FontSize = 16, ForeColor = Color.FromArgb(100, Color.Black), }; gfxo.DrawString("FormXObject", tf, r, TextAlignment.Center, ParagraphAlignment.Center); gfxo.DrawRectangle(r, Color.Blue, 3); gpage.DrawForm(fxo, new RectangleF(300, 250, r.Width, r.Height), null, ImageAlign.ScaleImage); // PDF/A-3 allows to use embedded files, but each embedded file must be associated with a document's element: EmbeddedFileStream ef = EmbeddedFileStream.FromFile(doc, Path.Combine("Resources", "WordDocs", "ProcurementLetter.docx")); // ModificationDate and MimeType should be specified for EmbeddedFile in PDF/A: ef.ModificationDate = date; ef.MimeType = "application/msword"; var fs = FileSpecification.FromEmbeddedFile(ef); fs.Relationship = AFRelationship.Unspecified; doc.EmbeddedFiles.Add("ProcurementLetter.docx", fs); // Associate embedded file with the document: doc.AssociatedFiles.Add(fs); // Add an attachment associated with an annotation: var sa = new StampAnnotation() { UserName = "******", Font = fnt, Rect = new RectangleF(300, 36, 220, 72), }; sa.Flags |= AnnotationFlags.Print; // Use a FormXObject to represent the stamp annotation: var stampFxo = new FormXObject(doc, new RectangleF(PointF.Empty, sa.Rect.Size)); var gstampFxo = stampFxo.Graphics; gstampFxo.FillRectangle(stampFxo.Bounds, Color.FromArgb(40, Color.Green)); gstampFxo.DrawString("Stamp Annotation\nassociated with minerva.jpg", tf, stampFxo.Bounds, TextAlignment.Center, ParagraphAlignment.Center); gstampFxo.DrawRectangle(stampFxo.Bounds, Color.Green, 3); // sa.AppearanceStreams.Normal.Default = stampFxo; doc.Pages[0].Annotations.Add(sa); ef = EmbeddedFileStream.FromFile(doc, Path.Combine("Resources", "Images", "minerva.jpg")); ef.ModificationDate = date; ef.MimeType = "image/jpeg"; fs = FileSpecification.FromEmbeddedFile(ef); fs.Relationship = AFRelationship.Unspecified; doc.EmbeddedFiles.Add("minerva.jpg", fs); sa.AssociatedFiles.Add(fs); // Mark the document as conforming to Tagged PDF conventions (required for PDF/A): doc.MarkInfo.Marked = true; // Metadata.CreatorTool and DocumentInfo.Creator should be the same for a PDF/A document: doc.Metadata.CreatorTool = doc.DocumentInfo.Creator; // A title should be specified for PDF/A document: doc.Metadata.Title = "GcPdf Document"; doc.ViewerPreferences.DisplayDocTitle = true; // Done: doc.Save(stream); }
private RectangleF DrawExchangesTable() { // This table has two special extra titles spanning two tolumns. // To achieve this, we: // - force the column titles in those 4 columns to print as '2nd paragraph', // thus leaving an empty line for the span title; // - print the span titles here as a special case. float[] widths = new float[] { 50, 25, 25, 25, 25, 60, 150, 50, 40, 25, 35, 0 }; string[] captions = new string[] { "Item", "Style", "\r\n1st", "\r\n2nd", "Size", "Sleeve Length\r\n& Inseam", "Item Name", "\r\nCharacters", "\r\nStyle", "Qty.", "Price", "Total" }; string[] samples = new string[] { "LH123456", "Plain", "Tan", "Olive", "8", "28", "Example Item Only", "Amanda", "Block", "1", "49.95", "49.95" }; var cr = DrawTable(widths, captions, samples, 4); // print 2 spanning titles: var g = CurrGraphics; TextLayout tl = g.CreateTextLayout(); tl.ParagraphAlignment = ParagraphAlignment.Near; tl.TextAlignment = TextAlignment.Center; tl.DefaultFormat.Font = TsNormal.Font; tl.DefaultFormat.FontSize = TsNormal.FontSize; tl.DefaultFormat.GlyphAdvanceFactor = TsNormal.GlyphAdvanceFactor; tl.DefaultFormat.ForeColor = Color.White; tl.WrapMode = WrapMode.NoWrap; // Color Choice var width = widths[2] + widths[3]; tl.MaxWidth = width; tl.Append("Color Choice"); tl.PerformLayout(true); var pt = new PointF(cr.Left + widths[0] + widths[1], cr.Top); g.DrawTextLayout(tl, pt); Pen pen = new Pen(Color.White, 0.5f); var pt1 = new PointF(pt.X + 0.5f, pt.Y + TableCaptionHeight / 2); var pt2 = new PointF(pt1.X + width, pt1.Y); g.DrawLine(pt1, pt2, pen); pt1 = new PointF(pt.X + widths[2] + 0.5f, pt.Y + TableCaptionHeight / 2); pt2 = new PointF(pt1.X, pt.Y + TableCaptionHeight); g.DrawLine(pt1, pt2, pen); pt1 = new PointF(pt.X + 0.5f, pt.Y); pt2 = new PointF(pt1.X, pt.Y + TableCaptionHeight); g.DrawLine(pt1, pt2, pen); pt1 = new PointF(pt.X + width + 0.5f, pt.Y); pt2 = new PointF(pt1.X, pt.Y + TableCaptionHeight); g.DrawLine(pt1, pt2, pen); // Monogramming width = widths[7] + widths[8]; tl.Inlines.Clear(); tl.MaxWidth = width; tl.Append("Monogramming"); tl.PerformLayout(true); pt = new PointF(cr.Left + widths[0] + widths[1] + widths[2] + widths[3] + widths[4] + widths[5] + widths[6], cr.Top); g.DrawTextLayout(tl, pt); pt1 = new PointF(pt.X + 0.5f, pt.Y + TableCaptionHeight / 2); pt2 = new PointF(pt1.X + width, pt1.Y); g.DrawLine(pt1, pt2, pen); pt1 = new PointF(pt.X + widths[7] + 0.5f, pt.Y + TableCaptionHeight / 2); pt2 = new PointF(pt1.X, pt.Y + TableCaptionHeight); g.DrawLine(pt1, pt2, pen); pt1 = new PointF(pt.X + 0.5f, pt.Y); pt2 = new PointF(pt1.X, pt.Y + TableCaptionHeight); g.DrawLine(pt1, pt2, pen); pt1 = new PointF(pt.X + width + 0.5f, pt.Y); pt2 = new PointF(pt1.X, pt.Y + TableCaptionHeight); g.DrawLine(pt1, pt2, pen); return(cr); }
void Page1(GcPdfDocument doc) { var page = doc.Pages.Add(); var g = page.Graphics; var tl = new TextLayout(g.Resolution) { FontCollection = _fc }; var gclogo = GetImage(Path.Combine("Resources", "ImagesBis", "gc-logo-100px.png")); var gclogoRc = new RectangleF(36, 0, 72 * 1.8f, 72); g.DrawImage(gclogo, gclogoRc, null, new ImageAlign(ImageAlignHorz.Left, ImageAlignVert.Center, true, true, true, false, false), out RectangleF[] rcs); g.DrawLine(rcs[0].Right + 10, rcs[0].Top, rcs[0].Right + 10, rcs[0].Bottom, _darkGray, 1); tl.Clear(); tl.ParagraphAlignment = ParagraphAlignment.Center; tl.MaxHeight = gclogoRc.Height; tl.Append("Developer Solutions", new TextFormat() { FontName = "open sans", FontSize = 16, ForeColor = _darkGray }); tl.PerformLayout(true); g.DrawTextLayout(tl, new PointF(gclogoRc.Right + 20, gclogoRc.Y)); var back = GetImage(Path.Combine("Resources", "ImagesBis", "GCDocs-datasheet-sm.png")); var backRcClip = new RectangleF(0, 72, page.Size.Width, page.Size.Width - 72 * 1.75f); var backRc = new RectangleF(-72, -72 * 4, page.Size.Width + 72 * 4, page.Size.Height + 72 * 4); g.DrawImage(back, backRc, backRcClip, ImageAlign.StretchImage); g.FillRectangle(new RectangleF(0, backRcClip.Bottom, page.Size.Width, page.Size.Height - backRcClip.Bottom), _lightGray); g.DrawLine(backRcClip.X, backRcClip.Bottom, backRcClip.Right, backRcClip.Bottom, Color.White, 1, null); g.DrawLine(backRcClip.X, backRcClip.Bottom + 1, backRcClip.Right, backRcClip.Bottom + 1, _darkGray, 1, null); var blueRc = new RectangleF(0, backRcClip.Y, page.Size.Width, 72 * 4); g.FillRectangle(blueRc, Color.FromArgb(220, _blue)); blueRc.Inflate(0, -36); g.FillRectangle(new RectangleF(blueRc.Location, new SizeF(10, blueRc.Height)), Color.White); blueRc.Inflate(-36, 0); tl.Clear(); tl.ParagraphAlignment = ParagraphAlignment.Near; tl.MaxWidth = blueRc.Width; tl.MaxHeight = blueRc.Height; tl.Append("NEW PRODUCT LINE", new TextFormat() { FontName = "open sans semibold", FontSize = 20, ForeColor = Color.White }); tl.PerformLayout(true); g.DrawTextLayout(tl, blueRc.Location); var midRc = new RectangleF(blueRc.X, blueRc.Y + tl.ContentHeight, blueRc.Width, blueRc.Height - tl.ContentHeight); tl.Clear(); tl.ParagraphAlignment = ParagraphAlignment.Far; tl.Append( "Take total control of your digital documents with this NEW collection of ultra-fast, low-footprint document APIs for .NET Standard 2.0. These intuitive, extensible APIs " + "allow you to create, load, modify, and save Excel spreadsheets and PDF files in any .NET Standard 2.0 application", new TextFormat() { FontName = "open sans light", FontSize = 14, ForeColor = Color.White }); tl.PerformLayout(true); g.DrawTextLayout(tl, blueRc.Location); midRc.Height -= tl.ContentHeight; midRc.Inflate(0, -20); var hex = GetImage(Path.Combine("Resources", "ImagesBis", "gcd-hex-logo-white.png")); var hexRc = new RectangleF(midRc.Location, new SizeF(midRc.Height, midRc.Height)); g.DrawImage(hex, hexRc, null, ImageAlign.StretchImage); tl.Clear(); tl.ParagraphAlignment = ParagraphAlignment.Center; tl.MaxHeight = midRc.Height; tl.Append("GrapeCity Documents", new TextFormat() { FontName = "open sans semibold", FontSize = 26, ForeColor = Color.White }); tl.PerformLayout(true); g.DrawTextLayout(tl, new PointF(midRc.X + midRc.Height + 10, midRc.Y)); var pointRc = new RectangleF(0, backRcClip.Bottom, page.Size.Width / 2, (page.Size.Height - backRcClip.Bottom) / 2 - 12); tl.ParagraphAlignment = ParagraphAlignment.Near; tl.MaxWidth = pointRc.Width; tl.MaxHeight = pointRc.Height; tl.MarginLeft = 80; tl.MarginTop = 25; tl.MarginBottom = 0; addPoint(GetImage(Path.Combine("Resources", "ImagesBis", "ico-hex-.NET.png")), "Expand the reach of modern apps", "With full support for .NET Standard 2.0, you can target multiple platforms, devices, and cloud with one code base."); pointRc.Offset(0, pointRc.Height); addPoint(GetImage(Path.Combine("Resources", "ImagesBis", "ico-hex-code.png")), "Comprehensive, highly programmable", "Do more with your Excel spreadsheets and PDFs: these APIs support Windows, Mac, Linux, and a wide variety of features for your documents."); pointRc.Offset(pointRc.Width, -pointRc.Height); tl.MarginRight = 30; addPoint(GetImage(Path.Combine("Resources", "ImagesBis", "ico-hex-speed.png")), "High-speed, small footprint", "The API architecture is designed to generate large, optimized documents, fast—while remaining lightweight and extensible."); pointRc.Offset(0, pointRc.Height); addPoint(GetImage(Path.Combine("Resources", "ImagesBis", "ico-hex-nodependences.png")), "No dependencies", "Generate and edit digital documents with no Acrobat or Excel dependencies."); g.FillRectangle(new RectangleF(0, page.Size.Height - 16, page.Size.Width, 16), _darkGray); drawCircle(new PointF(page.Size.Width - 160, backRcClip.Bottom - 105)); void addPoint(IImage img, string caption, string text) { var imgRc = new RectangleF(pointRc.X + 20, pointRc.Y + tl.MarginTop, 48, 48); g.DrawImage(img, imgRc, null, new ImageAlign() { AlignHorz = ImageAlignHorz.Center, AlignVert = ImageAlignVert.Center, BestFit = true }); tl.Clear(); tl.AppendLine(caption, new TextFormat() { FontName = "open sans semibold", FontSize = 11 }); tl.Append(text, new TextFormat() { FontName = "open sans light", FontSize = 11 }); tl.PerformLayout(true); if (!tl.ContentHeightFitsInBounds) { throw new Exception("Unexpected: text overflow."); } g.DrawTextLayout(tl, pointRc.Location); } void drawCircle(PointF p) { float D = 128; float angle = (float)(16 * Math.PI) / 180f; g.Transform = Matrix3x2.CreateTranslation(-D / 2, -D / 2) * Matrix3x2.CreateRotation(angle) * Matrix3x2.CreateTranslation(p.X + D / 2, p.Y + D / 2); var r = new RectangleF(PointF.Empty, new SizeF(D, D)); for (int i = 0; i < 3; ++i) { g.FillEllipse(r, Color.FromArgb(30 + i * 10, _darkGray)); r.Inflate(-1, -1); } g.FillEllipse(r, _darkGray); r.Inflate(-1, -1); g.FillEllipse(r, Color.White); r.Inflate(-6, -6); g.FillEllipse(r, _darkGray); tl.Clear(); tl.MaxHeight = tl.MaxWidth = D; tl.MarginLeft = tl.MarginRight = tl.MarginTop = tl.MarginBottom = 0; tl.TextAlignment = TextAlignment.Center; tl.ParagraphAlignment = ParagraphAlignment.Center; tl.ParagraphSpacing = -4; var tf = new TextFormat() { FontName = "open sans light", FontSize = 18, ForeColor = Color.White }; tl.Append("DEPLOY\nTO", tf); tl.Append(" AZURE\n", new TextFormat(tf) { FontName = "open sans semibold" }); tl.Append(" "); tl.PerformLayout(true); g.DrawTextLayout(tl, PointF.Empty); g.Transform = Matrix3x2.Identity; } }
public void CreatePDF(Stream stream) { var doc = new GcPdfDocument(); var font = StandardFonts.Times; var fontSize = 12; // 1/2" margins all around (72 dpi is the default resolution used by GcPdf): var margin = 72 / 2; var pageWidth = doc.PageSize.Width; var pageHeight = doc.PageSize.Height; var cW = pageWidth - margin * 2; // Text format for the chapter titles: var tlCaption = new TextLayout(72); tlCaption.DefaultFormat.Font = font; tlCaption.DefaultFormat.FontSize = fontSize + 4; tlCaption.DefaultFormat.Underline = true; tlCaption.MaxWidth = pageWidth; tlCaption.MaxHeight = pageHeight; tlCaption.MarginLeft = tlCaption.MarginTop = tlCaption.MarginRight = tlCaption.MarginBottom = margin; tlCaption.TextAlignment = TextAlignment.Center; // Height of chapter caption (use a const for simplicity): const float captionH = 24; // Text layout for main document body (default GcPdf resolution is 72dpi): var tl = new TextLayout(72); tl.DefaultFormat.Font = font; tl.DefaultFormat.FontSize = fontSize; tl.FirstLineIndent = 72 / 2; tl.MaxWidth = pageWidth; tl.MaxHeight = pageHeight; tl.MarginLeft = tl.MarginRight = tl.MarginBottom = margin; tl.MarginTop = margin + captionH; tl.ColumnWidth = cW * 0.3f; tl.TextAlignment = TextAlignment.Justified; tl.AlignmentDelayToSplit = true; // Array of PageSplitArea's which control additional columns (1st column is controlled by // the 'main' TextLayout, for each additional one a PageSplitArea must be provided - // it will create and return a TextLayout that can then be used to render the column): var psas = new PageSplitArea[] { new PageSplitArea(tl) { MarginLeft = tl.MarginLeft + (cW * 0.35f) }, new PageSplitArea(tl) { ColumnWidth = -cW * 0.3f } }; // Split options to control splitting text between pages: TextSplitOptions tso = new TextSplitOptions(tl) { RestMarginTop = margin, MinLinesInFirstParagraph = 2, MinLinesInLastParagraph = 2 }; // Generate a number of "chapters", provide outline entry for each: const int NChapters = 20; doc.Pages.Add(); for (int i = 0; i < NChapters; ++i) { // Print chapter header across all columns: string chapter = $"Chapter {i + 1}"; tlCaption.Clear(); tlCaption.Append(chapter); tlCaption.PerformLayout(true); doc.Pages.Last.Graphics.DrawTextLayout(tlCaption, PointF.Empty); // Add outline node for the chapter: doc.Outlines.Add(new OutlineNode(chapter, new DestinationFitV(doc.Pages.Count - 1, null))); // // Clear last chapter's text and add new chapter: tl.FirstLineIsStartOfParagraph = true; tl.LastLineIsEndOfParagraph = true; tl.Clear(); tl.Append(Common.Util.LoremIpsum(5, 7, 9, 15, 25)); tl.PerformLayout(true); // Variable to hold last chapter end's bottom coord: float contentBottom = 0f; // Print the chapter: var tls = new TextLayoutSplitter(tl); while (true) { var tlCol0 = tls.SplitAndBalance(psas, tso); var g = doc.Pages.Last.Graphics; g.DrawTextLayout(tlCol0, PointF.Empty); g.DrawTextLayout(psas[0].TextLayout, PointF.Empty); g.DrawTextLayout(psas[1].TextLayout, PointF.Empty); if (tls.SplitResult != SplitResult.Split) { // End of chapter, find out how much height left on page for next chapter: contentBottom = tl.ContentY + tl.ContentHeight; contentBottom = Math.Max(contentBottom, psas[0].TextLayout.ContentRectangle.Bottom); contentBottom = Math.Max(contentBottom, psas[1].TextLayout.ContentRectangle.Bottom); // Done printing chapter: break; } // Continue printing chapter on new page: psas[0].MarginTop = psas[1].MarginTop = margin; doc.Pages.Add(); } // Next chapter - find out if we have enough space left on current page to start new chapter: if (contentBottom + captionH < pageHeight * 0.8f) { // Start new chapter on current page: contentBottom += pageHeight * 0.05f; tlCaption.MarginTop = contentBottom; tl.MarginTop = psas[0].MarginTop = psas[1].MarginTop = contentBottom + captionH; } else if (i < NChapters - 1) { // Start new chapter on new page: tlCaption.MarginTop = margin; tl.MarginTop = psas[0].MarginTop = psas[1].MarginTop = margin + captionH; doc.Pages.Add(); } } // Done: doc.Save(stream); }
public void CreatePDF(Stream stream) { // Create a FontCollection instance: FontCollection fc = new FontCollection(); // Populate it with fonts from the specified directory: fc.RegisterDirectory(Path.Combine("Resources", "Fonts")); // Generate a sample document using the font collection to provide fonts: var doc = new GcPdfDocument(); var page = doc.Pages.Add(); var g = page.Graphics; // For TextLayout/TextFormat to be able to use a font collection, it must be // associated with it like so: var tl = new TextLayout(g.Resolution) { FontCollection = fc }; // Render some strings using the different fonts from our collection: var tf = new TextFormat() { FontName = "times new roman", FontSize = 16 }; tl.Append("Using FontCollection to manage fonts and render text\n\n", tf); tf.FontSize = 12; tl.Append("Text rendered using Times New Roman regular font. \n", tf); // Setting a font style (bold or italic) will tell the font collection // to search for a suitable font (if it is not found, emulation will be used): tf.FontItalic = true; tl.Append("Text rendered using Times New Roman italic font. \n", tf); // Text format is applied to a text run when the text is appended, // so we can re-use the same format, modifying its properties // to render differently formatted texts: tf.FontBold = true; tl.Append("Text rendered using Times New Roman bold italic font. \n", tf); tf.FontItalic = false; tl.Append("Text rendered using Times New Roman bold font. \n", tf); tf.FontName = "segoe ui"; tl.Append("Text rendered using Segoe UI bold font. \n", tf); tf.FontBold = false; tl.Append("Text rendered using Segoe UI regular font. \n", tf); // Apply page settings to the page layout and render the page: tl.MaxWidth = page.Size.Width; tl.MaxHeight = page.Size.Height; tl.MarginAll = 72; tl.PerformLayout(true); g.DrawTextLayout(tl, PointF.Empty); // If using GcGraphics.DrawString/MeasureString, this will allow the TextLayout // created internally by GcGraphics to find the specified fonts in the font collection: g.FontCollection = fc; // Use GcGraphics.DrawString to show that the font collection is also used // by the graphics once the FontCollection has been set on it: g.DrawString("Text rendered using Segoe UI bold, drawn by GcGraphics.DrawString() method.", new TextFormat() { FontName = "segoe ui", FontBold = true, FontSize = 10 }, new PointF(72, tl.ContentRectangle.Bottom + 12)); // Done: doc.Save(stream); }