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 int CreatePDF(Stream stream) { // Setup: GcPdfDocument doc = new GcPdfDocument(); TextLayout tl = new TextLayout(72) { MaxWidth = doc.PageSize.Width, MaxHeight = doc.PageSize.Height, MarginAll = 72, }; tl.DefaultFormat.FontSize = 7; var tfH = new TextFormat() { Font = StandardFonts.TimesBold, FontSize = 12 }; var tfP = new TextFormat() { Font = StandardFonts.Times, FontSize = 11 }; // Loop through all system fonts, // list Unicode ranges provided by each font: foreach (Font font in FontCollection.SystemFonts) { tl.AppendLine($"{font.FontFileName} [{font.FullFontName}] [{font.FontFamilyName}]", tfH); var shot = font.CreateFontTables(TableTag.OS2); tl.AppendLine(shot.GetUnicodeRanges(), tfP); tl.AppendLine(); } // Split and render TextLayout as shown in the PaginatedText sample: TextSplitOptions to = new TextSplitOptions(tl) { MinLinesInFirstParagraph = 2, MinLinesInLastParagraph = 2 }; tl.PerformLayout(true); while (true) { 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 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); }
public static void Run() { string filePath = Constants.SAMPLE_TXT; string filePathOut = Path.Combine(Constants.GetOutputDirectoryPath(), "text_{0}.{1}"); TextSplitOptions splitOptions = new TextSplitOptions(filePathOut, TextSplitMode.Interval, new int[] { 3, 6 }); using (Merger merger = new Merger(filePath)) { merger.Split(splitOptions); } Console.WriteLine("Source document was splitted successfully."); Console.WriteLine($"Check output {filePathOut}."); }
// 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); }
// 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 int CreatePDF(Stream stream) { var sourcePDF = "CompleteJavaScriptBook.pdf"; GcPdfDocument doc = new GcPdfDocument(); var page = doc.NewPage(); var rc = Common.Util.AddNote( "This sample loads an arbitrary PDF into a temporary GcPdfDocument, " + "and lists all fonts found in that document, with some of their properties. " + "It also tries to create a Font object from each of those PDF fonts, " + "and reports whether this operation succeeded.", page); // Text layout to render the text: var tab = 24; var tl = page.Graphics.CreateTextLayout(); tl.DefaultFormat.Font = StandardFonts.Times; tl.DefaultFormat.FontSize = 12; tl.MaxWidth = doc.PageSize.Width; tl.MaxHeight = doc.PageSize.Height; tl.MarginAll = rc.Left; tl.MarginTop = rc.Bottom + 36; tl.TabStops = new List <TabStop>() { new TabStop(tab) }; tl.FirstLineIndent = -tab; tl.MarginRight = 144; // Text split options for widow/orphan control: TextSplitOptions to = new TextSplitOptions(tl) { KeepParagraphLinesTogether = true, MinLinesInFirstParagraph = 2, MinLinesInLastParagraph = 2, RestMarginTop = rc.Left, }; // Open an arbitrary PDF, load it into a temp document and get all fonts: using (var fs = new FileStream(Path.Combine("Resources", "PDFs", sourcePDF), FileMode.Open, FileAccess.Read)) { var doc1 = new GcPdfDocument(); doc1.Load(fs); var fonts = doc1.GetFonts(); tl.AppendLine($"Total of {fonts.Count} fonts found in {sourcePDF}:"); tl.AppendLine(); int i = 0; foreach (var font in fonts) { var nativeFont = font.CreateNativeFont(); tl.Append($"{i}:\tBaseFont: {font.BaseFont}; IsEmbedded: {font.IsEmbedded}."); tl.AppendParagraphBreak(); if (nativeFont != null) { tl.AppendLine($"\tCreateNativeFont succeeded, family: {nativeFont.FontFamilyName}; bold: {nativeFont.FontBold}; italic: {nativeFont.FontItalic}."); } else { tl.AppendLine("\tCreateNativeFont failed"); } tl.AppendLine(); ++i; } 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(); } } // Done: doc.Save(stream); return(doc.Pages.Count); }
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); }
// 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 int CreatePDF(Stream stream) { var doc = new GcPdfDocument(); var g = doc.NewPage().Graphics; // // We want to draw 3 images in certain arbitrary locations on the first page, // and then print a text that would take 2-3 pages, and have it flow around // the images on the first page. // // Get the images and their rectangles. Note that we specify a square // area for all images - but they will be aligned within that area // preserving their original aspect ratios, so we will later retrieve // the actual rectangles where the images were drawn: using (var imgPuffins = Image.FromFile("Resources/Images/puffins.jpg")) using (var imgReds = Image.FromFile("Resources/Images/reds.jpg")) using (var imgLavender = Image.FromFile("Resources/Images/lavender.jpg")) { var rectPuffins = new RectangleF(100, 70, 180, 180); var rectReds = new RectangleF(300, 280, 180, 180); var rectLavender = new RectangleF(190, 510, 180, 180); // Set up ImageAlign that would fit and center an image within a specified area, // preserving the image's original aspect ratio: ImageAlign ia = new ImageAlign(ImageAlignHorz.Center, ImageAlignVert.Center, true, true, true, false, false); // Draw each image, providing an array of rectangles as an output parameter for each DrawImage call, // so that we get the actual rectangle taken by the image (an array is needed to handle tiled images): g.DrawImage(imgPuffins, rectPuffins, null, ia, out RectangleF[] rectsPuffins); g.DrawImage(imgReds, rectReds, null, ia, out RectangleF[] rectsReds); g.DrawImage(imgLavender, rectLavender, null, ia, out RectangleF[] rectsLavender); // Create and set up a TextLayout object to print the text: var tl = g.CreateTextLayout(); tl.DefaultFormat.Font = StandardFonts.Times; tl.DefaultFormat.FontSize = 9; tl.TextAlignment = TextAlignment.Justified; tl.ParagraphSpacing = 72 / 8; tl.MaxWidth = doc.PageSize.Width; tl.MaxHeight = doc.PageSize.Height; // 1/2" margins all around tl.MarginAll = 72 / 2; // ObjectRect is the type used to specify the areas to flow around to TextLayout. // We set up a local function to create an ObjecRect based on an image rectangle, // adding some padding so that the result looks nicer: Func <RectangleF, ObjectRect> makeObjectRect = rect_ => new ObjectRect(rect_.X - 6, rect_.Y - 2, rect_.Width + 12, rect_.Height + 4); // Specify the array of ObjectRects on the TextLayout: tl.ObjectRects = new List <ObjectRect>() { makeObjectRect(rectsPuffins[0]), makeObjectRect(rectsReds[0]), makeObjectRect(rectsLavender[0]), }; // Add several paragraphs of text: tl.Append(Common.Util.LoremIpsum(7, 5, 6, 28, 32)); // Calculate glyphs and lay out the text: tl.PerformLayout(true); // Split options to control splitting of text between pages. // We can either use the default ctor and set up values like MaxWidth etc, // or create a TextSplitOptions based on the TextLayout, and clear RestObjectRects: TextSplitOptions to = new TextSplitOptions(tl) { RestObjectRects = null, MinLinesInFirstParagraph = 2, 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.Last.Graphics.DrawTextLayout(tl, PointF.Empty); if (splitResult != SplitResult.Split) { break; } tl = rest; // We only draw images on the first page: tl.ObjectRects = null; doc.Pages.Add(); } // Done: doc.Save(stream); return(doc.Pages.Count); } }
public int CreatePDF(Stream stream) { const string pdfName = "ExternalCMapTest.pdf"; // This line may not be needed if the GcPdfDocument class ctor finds // the GrapeCity.Documents.Pdf.Resources.dll at startup // (this depends on the way the app is deployed): GcPdfDocument.CMapProvider = CMapProvider.Instance; GcPdfDocument doc = new GcPdfDocument(); var page = doc.NewPage(); var rc = Common.Util.AddNote("This sample loads a PDF into a temporary GcPdfDocument, " + "retrieves all text from each page of the loaded document using the Page.GetText() method, " + "adds all those texts to a TextLayout and renders it into the current document. " + "CMaps used by the PDF in this sample are provided by the optional " + "https://www.nuget.org/packages/GrapeCity.Documents.Pdf.Resources/ package. " + "Without a reference to that package most of the text in this particular PDF will not be found " + "as it uses the less common CMaps that are not built into GcPdf itself." + "\n\n" + "To use GrapeCity.Documents.Pdf.Resources in a project, add a reference to it, " + "and either make sure that GrapeCity.Documents.Pdf.Resources.dll is present in the runtime directory, " + "or add the line:" + "\n\tGcPdfDocument.CMapProvider = CMapProvider.Instance;" + "\nto the project's initialization code.", page); Font arialbd = Font.FromFile(Path.Combine("Resources", "Fonts", "arialbd.ttf")); Font segoe = Font.FromFile(Path.Combine("Resources", "Fonts", "segoeui.ttf")); Font arialuni = Font.FromFile(Path.Combine("Resources", "Fonts", "arialuni.ttf")); segoe.AddLinkedFont(arialuni); // Text format for captions: var tf = new TextFormat() { Font = arialbd, FontSize = 14, ForeColor = Color.Blue }; // Text layout to render the text: var tl = new TextLayout(72); tl.DefaultFormat.Font = segoe; tl.DefaultFormat.FontSize = 12; tl.MaxWidth = doc.PageSize.Width; tl.MaxHeight = doc.PageSize.Height; tl.MarginAll = rc.Left; tl.MarginTop = rc.Bottom + 36; // Text split options for widow/orphan control: TextSplitOptions to = new TextSplitOptions(tl) { MinLinesInFirstParagraph = 2, MinLinesInLastParagraph = 2, RestMarginTop = rc.Left, }; // Open an arbitrary PDF, load it into a temp document and get all page texts: using (var fs = new FileStream(Path.Combine("Resources", "PDFs", pdfName), FileMode.Open, FileAccess.Read)) { var doc1 = new GcPdfDocument(); doc1.Load(fs); // Get the texts of the loaded document's pages: var texts = new List <string>(); doc1.Pages.ToList().ForEach(p_ => texts.Add(p_.GetText())); // Add texts and captions to the text layout: for (int i = 0; i < texts.Count; ++i) { tl.AppendLine($"Text from page {i + 1} of {pdfName}:", tf); tl.AppendLine(texts[i]); } 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(); } } // Done: doc.Save(stream); return(doc.Pages.Count); }
public void CreatePDF(Stream stream) { var doc = new GcPdfDocument(); // Create a Part element, it will contain P (paragraph) elements: StructElement sePart = new StructElement("Part"); doc.StructTreeRoot.Children.Add(sePart); // Create and set up a TextLayout to render paragraphs: 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; // // Append the text (20 paragraphs so they would not fit on a single page) // (note that TextLayout interprets "\r\n" as paragraph delimiter): // // Get the text (20 paragraphs): var text = Common.Util.LoremIpsum(20); // In order to tag the individual paragraphs, we need to split the text into paragraphs, // and use each paragraph format's Tag property (which is not related to PDF tags, // it is just an arbitrary data that can be associated with a TextFormat) to add the // paragraph's index to the paragraph: var pars = text.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < pars.Length; ++i) { var tf = new TextFormat(tl.DefaultFormat) { Tag = i }; tl.AppendLine(pars[i], tf); } // Layout the text: tl.PerformLayout(true); // Use split options to provide widow/orphan control: TextSplitOptions to = new TextSplitOptions(tl) { MinLinesInFirstParagraph = 2, MinLinesInLastParagraph = 2, }; // TextLayoutHandler implements ITextLayoutHandler, which // allows to tag the text as it is rendered: TextLayoutHandler tlh = new TextLayoutHandler() { ParentElement = sePart }; // 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); var page = doc.Pages.Add(); var g = page.Graphics; // Tell the TextLayoutHandler which page we're on: tlh.Page = page; // ..and associate it with the graphics: g.TextLayoutHandler = tlh; // Draw the text that fits on the current page, and advance to next page unless we're done: g.DrawTextLayout(tl, PointF.Empty); if (splitResult != SplitResult.Split) { break; } tl = rest; } // Mark document as tagged: doc.MarkInfo.Marked = true; // Done: doc.Save(stream); }
public int CreatePDF(Stream stream) { GcPdfDocument doc = new GcPdfDocument(); var page = doc.NewPage(); var rc = Common.Util.AddNote( "This sample loads an arbitrary PDF into a temporary GcPdfDocument, " + "then retrieves text from each page of the loaded document using the Page.GetText() method, " + "adds all those texts to a TextLayout and renders it into the current document. " + "An alternative to Page.GetText() is the method GcPdfDocument.GetText() " + "which retrieves the text from the whole document at once.", page); // Text format for captions: var tf = new TextFormat() { Font = Font.FromFile(Path.Combine("Resources", "Fonts", "yumin.ttf")), FontSize = 14, ForeColor = Color.Blue }; // Text layout to render the text: var tl = new TextLayout(72); tl.DefaultFormat.Font = StandardFonts.Times; tl.DefaultFormat.FontSize = 12; tl.MaxWidth = doc.PageSize.Width; tl.MaxHeight = doc.PageSize.Height; tl.MarginAll = rc.Left; tl.MarginTop = rc.Bottom + 36; // Text split options for widow/orphan control: TextSplitOptions to = new TextSplitOptions(tl) { MinLinesInFirstParagraph = 2, MinLinesInLastParagraph = 2, RestMarginTop = rc.Left, }; // Open an arbitrary PDF, load it into a temp document and get all page texts: using (var fs = new FileStream(Path.Combine("Resources", "PDFs", "Wetlands.pdf"), FileMode.Open, FileAccess.Read)) { var doc1 = new GcPdfDocument(); doc1.Load(fs); // Get the texts of the loaded document's pages: var texts = new List <string>(); doc1.Pages.ToList().ForEach(p_ => texts.Add(p_.GetText())); // Add texts and captions to the text layout: for (int i = 0; i < texts.Count; ++i) { tl.AppendLine(string.Format("Text from page {0} of the loaded document:", i + 1), tf); tl.AppendLine(texts[i]); } 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(); } } // Done: doc.Save(stream); return(doc.Pages.Count); }
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); } }
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); }
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 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 paraIdx = 0; paraIdx < N; ++paraIdx) { tl.AppendLine(Common.Util.LoremIpsum(1)); } // Split and render TextLayout as shown in the PaginatedText sample: TextSplitOptions tso = new TextSplitOptions(tl) { MinLinesInFirstParagraph = 2, MinLinesInLastParagraph = 2, }; tl.PerformLayout(true); // The loop splitting and rendering the layout: var tls = new TextLayoutSplitter(tl); for (var tlPage = tls.Split(tso); tlPage != null; tlPage = tls.Split(tso)) { doc.NewPage().Graphics.DrawTextLayout(tlPage, 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() { 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} 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); }