//--------------------------------------------------------------------------------------- // Copyright (c) 2001-2025 by Apryse Software Inc. All Rights Reserved. // Consult legal.txt regarding legal and license information. //--------------------------------------------------------------------------------------- #include #include #include #include #include #include #include #include #include #include #include "../../LicenseKey/CPP/LicenseKey.h" using namespace std; using namespace pdftron; using namespace SDF; using namespace PDF; using namespace Filters; int main(int argc, char *argv[]) { int ret = 0; PDFNet::Initialize(LicenseKey); // Relative path to the folder containing test files. string input_path = "../../TestFiles/"; string output_path = "../../TestFiles/Output/"; try { PDFDoc doc; ElementBuilder eb; // ElementBuilder is used to build new Element objects ElementWriter writer; // ElementWriter is used to write Elements to the page Element element; GState gstate; // Start a new page ------------------------------------ Page page = doc.PageCreate(Rect(0, 0, 612, 794)); writer.Begin(page); // begin writing to the page // Create an Image that can be reused in the document or on the same page. Image img = Image::Create(doc, (input_path + "peppers.jpg").c_str()); element = eb.CreateImage(img, Common::Matrix2D(img.GetImageWidth()/2, -145, 20, img.GetImageHeight()/2, 200, 150)); writer.WritePlacedElement(element); gstate = element.GetGState(); // use the same image (just change its matrix) gstate.SetTransform(200, 0, 0, 300, 50, 450); writer.WritePlacedElement(element); // use the same image again (just change its matrix). writer.WritePlacedElement(eb.CreateImage(img, 300, 600, 200, -150)); writer.End(); // save changes to the current page doc.PagePushBack(page); // Start a new page ------------------------------------ // Construct and draw a path object using different styles page = doc.PageCreate(Rect(0, 0, 612, 794)); writer.Begin(page); // begin writing to this page eb.Reset(); // Reset the GState to default eb.PathBegin(); // start constructing the path eb.MoveTo(306, 396); eb.CurveTo(681, 771, 399.75, 864.75, 306, 771); eb.CurveTo(212.25, 864.75, -69, 771, 306, 396); eb.ClosePath(); element = eb.PathEnd(); // the path is now finished element.SetPathFill(true); // the path should be filled // Set the path color space and color gstate = element.GetGState(); gstate.SetFillColorSpace(ColorSpace::CreateDeviceCMYK()); gstate.SetFillColor(ColorPt(1, 0, 0, 0)); // cyan gstate.SetTransform(0.5, 0, 0, 0.5, -20, 300); writer.WritePlacedElement(element); // Draw the same path using a different stroke color element.SetPathStroke(true); // this path is should be filled and stroked gstate.SetFillColor(ColorPt(0, 0, 1, 0)); // yellow gstate.SetStrokeColorSpace(ColorSpace::CreateDeviceRGB()); gstate.SetStrokeColor(ColorPt(1, 0, 0)); // red gstate.SetTransform(0.5, 0, 0, 0.5, 280, 300); gstate.SetLineWidth(20); writer.WritePlacedElement(element); // Draw the same path with with a given dash pattern element.SetPathFill(false); // this path is should be only stroked gstate.SetStrokeColor(ColorPt(0, 0, 1)); // blue gstate.SetTransform(0.5, 0, 0, 0.5, 280, 0); vector dash_pattern; dash_pattern.push_back(30); gstate.SetDashPattern(dash_pattern, 0); writer.WritePlacedElement(element); // Use the path as a clipping path writer.WriteElement(eb.CreateGroupBegin()); // Save the graphics state // Start constructing the new path (the old path was lost when we created // a new Element using CreateGroupBegin()). eb.PathBegin(); eb.MoveTo(306, 396); eb.CurveTo(681, 771, 399.75, 864.75, 306, 771); eb.CurveTo(212.25, 864.75, -69, 771, 306, 396); eb.ClosePath(); element = eb.PathEnd(); // path is now constructed element.SetPathClip(true); // this path is a clipping path element.SetPathStroke(true); // this path should be filled and stroked gstate = element.GetGState(); gstate.SetTransform(0.5, 0, 0, 0.5, -20, 0); writer.WriteElement(element); writer.WriteElement(eb.CreateImage(img, 100, 300, 400, 600)); writer.WriteElement(eb.CreateGroupEnd()); // Restore the graphics state writer.End(); // save changes to the current page doc.PagePushBack(page); // Start a new page ------------------------------------ page = doc.PageCreate(Rect(0, 0, 612, 794)); writer.Begin(page); // begin writing to this page eb.Reset(); // Reset the GState to default // Begin writing a block of text element = eb.CreateTextBegin(Font::Create(doc, Font::e_times_roman), 12); writer.WriteElement(element); element = eb.CreateTextRun("Hello World!"); element.SetTextMatrix(10, 0, 0, 10, 0, 600); element.GetGState().SetLeading(15); // Set the spacing between lines writer.WriteElement(element); writer.WriteElement(eb.CreateTextNewLine()); // New line element = eb.CreateTextRun("Hello World!"); gstate = element.GetGState(); gstate.SetTextRenderMode(GState::e_stroke_text); gstate.SetCharSpacing(-1.25); gstate.SetWordSpacing(-1.25); writer.WriteElement(element); writer.WriteElement(eb.CreateTextNewLine()); // New line element = eb.CreateTextRun("Hello World!"); gstate = element.GetGState(); gstate.SetCharSpacing(0); gstate.SetWordSpacing(0); gstate.SetLineWidth(3); gstate.SetTextRenderMode(GState::e_fill_stroke_text); gstate.SetStrokeColorSpace(ColorSpace::CreateDeviceRGB()); gstate.SetStrokeColor(ColorPt(1, 0, 0)); // red gstate.SetFillColorSpace(ColorSpace::CreateDeviceCMYK()); gstate.SetFillColor(ColorPt(1, 0, 0, 0)); // cyan writer.WriteElement(element); writer.WriteElement(eb.CreateTextNewLine()); // New line // Set text as a clipping path to the image. element = eb.CreateTextRun("Hello World!"); gstate = element.GetGState(); gstate.SetTextRenderMode(GState::e_clip_text); writer.WriteElement(element); // Finish the block of text writer.WriteElement(eb.CreateTextEnd()); // Draw an image that will be clipped by the above text writer.WriteElement(eb.CreateImage(img, 10, 100, 1300, 720)); writer.End(); // save changes to the current page doc.PagePushBack(page); // Start a new page ------------------------------------ // // The example illustrates how to embed the external font in a PDF document. // The example also shows how ElementReader can be used to copy and modify // Elements between pages. ElementReader reader; // Start reading Elements from the last page. We will copy all Elements to // a new page but will modify the font associated with text. reader.Begin(doc.GetPage(doc.GetPageCount())); page = doc.PageCreate(Rect(0, 0, 1300, 794)); writer.Begin(page); // begin writing to this page eb.Reset(); // Reset the GState to default // Embed an external font in the document. Font font = Font::CreateTrueTypeFont(doc, (input_path + "font.ttf").c_str()); while ((element = reader.Next())==true) // Read page contents { if (element.GetType() == Element::e_text) { element.GetGState().SetFont(font, 12); } writer.WriteElement(element); } reader.End(); writer.End(); // save changes to the current page doc.PagePushBack(page); // Start a new page ------------------------------------ // // The example illustrates how to embed the external font in a PDF document. // The example also shows how ElementReader can be used to copy and modify // Elements between pages. // Start reading Elements from the last page. We will copy all Elements to // a new page but will modify the font associated with text. reader.Begin(doc.GetPage(doc.GetPageCount())); page = doc.PageCreate(Rect(0, 0, 1300, 794)); writer.Begin(page); // begin writing to this page eb.Reset(); // Reset the GState to default // Embed an external font in the document. Font font2 = Font::CreateType1Font(doc, (input_path + "Misc-Fixed.pfa").c_str()); while ((element = reader.Next())) // Read page contents { if (element.GetType() == Element::e_text) { element.GetGState().SetFont(font2, 12); } writer.WriteElement(element); } reader.End(); writer.End(); // save changes to the current page doc.PagePushBack(page); // Start a new page ------------------------------------ page = doc.PageCreate(); writer.Begin(page); // begin writing to this page eb.Reset(); // Reset the GState to default // Begin writing a block of text element = eb.CreateTextBegin(Font::Create(doc, Font::e_times_roman), 12); element.SetTextMatrix(1.5, 0, 0, 1.5, 50, 600); element.GetGState().SetLeading(15); // Set the spacing between lines writer.WriteElement(element); const char* para = "A PDF text object consists of operators that can show " "text strings, move the text position, and set text state and certain " "other parameters. In addition, there are three parameters that are " "defined only within a text object and do not persist from one text " "object to the next: Tm, the text matrix, Tlm, the text line matrix, " "Trm, the text rendering matrix, actually just an intermediate result " "that combines the effects of text state parameters, the text matrix " "(Tm), and the current transformation matrix"; const char* para_end = para + strlen(para); const char* text_run = para; const char* text_run_end; double para_width = 300; // paragraph width is 300 units double cur_width = 0; while (text_run < para_end) { text_run_end = strchr(text_run, ' '); if (!text_run_end) text_run_end = para_end; element = eb.CreateTextRun(text_run, UInt32(text_run_end-text_run+1)); if (cur_width + element.GetTextLength() < para_width) { writer.WriteElement(element); cur_width += element.GetTextLength(); } else { writer.WriteElement(eb.CreateTextNewLine()); // New line element = eb.CreateTextRun(text_run, UInt32(text_run_end-text_run+1)); cur_width = element.GetTextLength(); writer.WriteElement(element); } text_run = text_run_end+1; } // ----------------------------------------------------------------------- // The following code snippet illustrates how to adjust spacing between // characters (text runs). element = eb.CreateTextNewLine(); writer.WriteElement(element); // Skip 2 lines writer.WriteElement(element); writer.WriteElement(eb.CreateTextRun("An example of space adjustments between inter-characters:")); writer.WriteElement(eb.CreateTextNewLine()); // Write string "AWAY" without space adjustments between characters. element = eb.CreateTextRun("AWAY"); writer.WriteElement(element); writer.WriteElement(eb.CreateTextNewLine()); // Write string "AWAY" with space adjustments between characters. element = eb.CreateTextRun("A"); writer.WriteElement(element); element = eb.CreateTextRun("W"); element.SetPosAdjustment(140); writer.WriteElement(element); element = eb.CreateTextRun("A"); element.SetPosAdjustment(140); writer.WriteElement(element); element = eb.CreateTextRun("Y again"); element.SetPosAdjustment(115); writer.WriteElement(element); // Draw the same strings using direct content output... writer.Flush(); // flush pending Element writing operations. // You can also write page content directly to the content stream using // ElementWriter.WriteString(...) and ElementWriter.WriteBuffer(...) methods. // Note that if you are planning to use these functions you need to be familiar // with PDF page content operators (see Appendix A in PDF Reference Manual). // Because it is easy to make mistakes during direct output we recommend that // you use ElementBuilder and Element interface instead. writer.WriteString("T* T* "); // Skip 2 lines writer.WriteString("(Direct output to PDF page content stream:) Tj T* "); writer.WriteString("(AWAY) Tj T* "); writer.WriteString("[(A)140(W)140(A)115(Y again)] TJ "); // Finish the block of text writer.WriteElement(eb.CreateTextEnd()); writer.End(); // save changes to the current page doc.PagePushBack(page); // Start a new page ------------------------------------ // Image Masks // // In the opaque imaging model, images mark all areas they occupy on the page as // if with opaque paint. All portions of the image, whether black, white, gray, // or color, completely obscure any marks that may previously have existed in the // same place on the page. // In the graphic arts industry and page layout applications, however, it is common // to crop or 'mask out' the background of an image and then place the masked image // on a different background, allowing the existing background to show through the // masked areas. This sample illustrates how to use image masks. page = doc.PageCreate(); writer.Begin(page); // begin writing to the page // Create the Image Mask MappedFile imgf(input_path + "imagemask.dat"); FilterReader mask_read(imgf); ColorSpace device_gray = ColorSpace::CreateDeviceGray(); Image mask = Image::Create(doc, mask_read, 64, 64, 1, device_gray, Image::e_ascii_hex); mask.GetSDFObj().PutBool("ImageMask", true); element = eb.CreateRect(0, 0, 612, 794); element.SetPathStroke(false); element.SetPathFill(true); element.GetGState().SetFillColorSpace(device_gray); element.GetGState().SetFillColor(ColorPt(0.8)); writer.WritePlacedElement(element); element = eb.CreateImage(mask, Common::Matrix2D(200, 0, 0, -200, 40, 680)); element.GetGState().SetFillColor(ColorPt(0.1)); writer.WritePlacedElement(element); element.GetGState().SetFillColorSpace(ColorSpace::CreateDeviceRGB()); element.GetGState().SetFillColor(ColorPt(1, 0, 0)); element = eb.CreateImage(mask, Common::Matrix2D(200, 0, 0, -200, 320, 680)); writer.WritePlacedElement(element); element.GetGState().SetFillColor(ColorPt(0, 1, 0)); element = eb.CreateImage(mask, Common::Matrix2D(200, 0, 0, -200, 40, 380)); writer.WritePlacedElement(element); { // This sample illustrates Explicit Masking. Image img = Image::Create(doc, (input_path + "peppers.jpg").c_str()); // mask is the explicit mask for the primary (base) image img.SetMask(mask); element = eb.CreateImage(img, Common::Matrix2D(200, 0, 0, -200, 320, 380)); writer.WritePlacedElement(element); } writer.End(); // save changes to the current page doc.PagePushBack(page); // Transparency sample ---------------------------------- // Start a new page ------------------------------------- page = doc.PageCreate(); writer.Begin(page); // begin writing to this page eb.Reset(); // Reset the GState to default // Write some transparent text at the bottom of the page. element = eb.CreateTextBegin(Font::Create(doc, Font::e_times_roman), 100); // Set the text knockout attribute. Text knockout must be set outside of // the text group. gstate = element.GetGState(); gstate.SetTextKnockout(false); gstate.SetBlendMode(GState::e_bl_difference); writer.WriteElement(element); element = eb.CreateTextRun("Transparency"); element.SetTextMatrix(1, 0, 0, 1, 30, 30); gstate = element.GetGState(); gstate.SetFillColorSpace(ColorSpace::CreateDeviceCMYK()); gstate.SetFillColor(ColorPt(1, 0, 0, 0)); gstate.SetFillOpacity(0.5); writer.WriteElement(element); // Write the same text on top the old; shifted by 3 points element.SetTextMatrix(1, 0, 0, 1, 33, 33); gstate.SetFillColor(ColorPt(0, 1, 0, 0)); gstate.SetFillOpacity(0.5); writer.WriteElement(element); writer.WriteElement(eb.CreateTextEnd()); // Draw three overlapping transparent circles. eb.PathBegin(); // start constructing the path eb.MoveTo(459.223, 505.646); eb.CurveTo(459.223, 415.841, 389.85, 343.04, 304.273, 343.04); eb.CurveTo(218.697, 343.04, 149.324, 415.841, 149.324, 505.646); eb.CurveTo(149.324, 595.45, 218.697, 668.25, 304.273, 668.25); eb.CurveTo(389.85, 668.25, 459.223, 595.45, 459.223, 505.646); element = eb.PathEnd(); element.SetPathFill(true); gstate = element.GetGState(); gstate.SetFillColorSpace(ColorSpace::CreateDeviceRGB()); gstate.SetFillColor(ColorPt(0, 0, 1)); // Blue Circle gstate.SetBlendMode(GState::e_bl_normal); gstate.SetFillOpacity(0.5); writer.WriteElement(element); // Translate relative to the Blue Circle gstate.SetTransform(1, 0, 0, 1, 113, -185); gstate.SetFillColor(ColorPt(0, 1, 0)); // Green Circle gstate.SetFillOpacity(0.5); writer.WriteElement(element); // Translate relative to the Green Circle gstate.SetTransform(1, 0, 0, 1, -220, 0); gstate.SetFillColor(ColorPt(1, 0, 0)); // Red Circle gstate.SetFillOpacity(0.5); writer.WriteElement(element); writer.End(); // save changes to the current page doc.PagePushBack(page); // End page ------------------------------------ doc.Save((output_path + "element_builder.pdf").c_str(), SDFDoc::e_remove_unused, NULL); // doc.Save((output_path + "element_builder.pdf").c_str(), Doc::e_linearized, NULL); cout << "Done. Result saved in element_builder.pdf..." << endl; } catch(Common::Exception& e) { cout << e << endl; ret = 1; } catch(...) { cout << "Unknown Exception" << endl; ret = 1; } PDFNet::Terminate(); return ret; }