3-Heights™ PDF Toolbox – Create, combine and edit PDF in C# .NET Core and Java

The 3-Heights™ PDF Toolbox API is a fast, high-quality, PDF/A-compliant component to programmatically create PDF documents from scratch, add any content, such as text and images to existing PDFs and assemble (merge and split) PDF documents.

Combine PDF

Assemble PDF documents from various sources. Merge and split PDF pages.

Edit PDF

Change PDF documents. Add additional information, such as a stamp, image or text or remove text from a PDF.

Create PDF

Create new pages with any content. Make a new PDF or merge them with your existing PDFs.

Save time thanks to cloud-based PDF services

As the user base kept growing, more and more new functionalities were requested, such as compressing PDF files and converting office documents to PDF.

Smallpdf is a big hit when it comes to compression

Attaching a large file to an email can prevent it from being sent or received due to technical limitations. In order to solve this problem, the founders of Smallpdf searched for a way to reduce the size of these files. 

PDF Toolbox - Advanced PDF manipulation - edit and composite your PDF documents

PDF Toolbox - features

Document assembly

  • Copy pages from existing PDFs
  • Copy annotations, form fields, links, logical structure, destinations, outlines, layers
  • Flatten annotations, form fields, signatures
  • Optimize resources
  • Crop and rotate pages
  • Free composition of content: Overlays, Underlays, Stamps, Transformations
  • Encryption: User password, Owner password, Permissions
  • Copy and modify document metadata
  • Copy and modify page metadata
  • Add embedded files and associated files
  • Get and set OpenAction destination

Generation

  • Document Level
    • Create pages
      • Create form fields
      • General text fields and comb text fields
      • Check boxes
      • Radio buttons
      • List boxes
      • Combo boxes
    • Create new outline items and insert them at any position in the tree
    • Destinations: Named and direct destinations in the same document
  • Page Content Level
    • Create new PDF content from scratch
    • Apply content to existing pages
  • Colors
    • Device colors: RGB, CMYK and Grayscale
    • ICC color profiles
    • Transparency: Alpha and Blend mode
  • Paths
    • Single and Multi-segment lines
    • Rectangle, Circle, Bezier curves, Ellipse, Arc, Pie
    • Filling, stroking, clipping and combinations thereof
    • Line width, cap, join, dash array, dash phase and miter limit
    • Inside rule: Nonzero winding rule, Even/odd rule
  • Text
    • Font size, Character spacing, Word spacing
    • Horizontal scaling, leading, rise
    • Enables simple text layouting
    • Standard PDF fonts, installed fonts
    • Font metrics: Italic angle, Ascent, Descent, Cap height, Character width
    • Unicode characters
    • Text stroke: Line width, Line join and Dashes
    • Fill and stroke text, invisible text
    • Use text as clipping path
  • Images
    • Bi-level: CCITT G3, G3 2D and G4, Flate, LZW, Packbits, uncompressed
    • 4 bit and 8 bit grayscale: Flate, LZW, Packbits, JPEG and JPEG-6 (8 bit only), uncompressed
    • RGB: Flate, JPEG and JPEG-6, LZW, Packbits, uncompressed
  • Transformations
    • Translation
    • Scaling
    • Skewing (Horizontal, Vertical)
    • Rotation

Modification

  • Page Content
    • Selective copying of content elements (without markup)
    • Geometric transformation of content elements
  • Form Fields
    • Deletion of fields and modification of field values for
      • General text fields and comb text fields
      • Check boxes
      • Radio buttons
      • List boxes
      • Combo boxes

Extraction

  • Document and Page
    • Document information entries: Title, Author, Subject, Keywords, Creator, Producer, Creation date, Modification date
    • Document XMP metadata
    • Embedded files
    • Page bounding boxes: Media box, Crop box, Bleed box, Trim box, Art box
    • Page XMP metadata
    • Outline item tree: Tree structure, item title, expanded/collapsed
    • Destinations: Named and direct destinations in the same document
  • Content
    • Page’s and group’s content elements including
      • Bounding box
      • Affine transformation
    • As either of the following:
      • Group element
      • Image element
        • Width and height in pixel
        • Bits per component
        • Color space
    • Image mask element
      • Width and height in pixel
      • Paint for filling the mask
    • Path element
      • Alignment box
      • Fill parameters including paint and fill rule
      • Stroke parameters including line paint and line style
    • Shading element
    • Text element
      • Text fragments
        • Bounding box
        • Affine transformation
        • Unicode string
        • Fill parameters including paint and fill rule
        • Stroke parameters including line paint and line style
  • Annotations
    • Annotations: location
    • Signature fields: Name, Location, Reason, Contact info, Date, Visibility
  • AcroForm Form Fields
    • Form field identifiers, export names and user names, including form field hierarchy
    • Form field export and display content of:
      • Push buttons
      • Check boxes
      • Radio buttons
      • General text fields and comb text fields
      • List boxes
      • Combo boxes

Conformance

  • ISO 32000-1 (PDF 1.7)
  • ISO 32000-2 (PDF 2.0)
  • ISO 19005-1 (PDF/A-1)
  • ISO 19005-2 (PDF/A-2)
  • ISO 19005-3 (PDF/A-3)

Supported formats

Supported PDF Formats

  • PDF 1.0 to 1.7
  • PDF 2.0
  • PDF/A-1, PDF/A-2, PDF/A-3

Supported image formats

  • BMP
  • DIB
  • JPEG
  • JPEG2000
  • JBIG2
  • PNG
  • GIF
  • TIFF

Supported Font Formats

  • Type1
  • TrueType
  • OpenType
  • OpenType (CFF)
Magnifying lens for our PDF manuals and PDF sample code

MANUAL

API

Areas of use - edit and composite PDF documents

PDF generation

Programmatic creation of any PDF/A-conform document, whereby its content can stem from any source such as a database or webpage form.

Personalization

PDF documents are used for distributing e-books as well as for creating invoices, contracts and terms and conditions, for instance in insurance application forms. These documents share a common requirement: they need to be supplemented with data specific to the recipient.

Automated reporting

Large quantities of information are stored in databases and DMS systems. PDF Toolbox is designed to receive this information and convert it into distributable standardized PDF documents. It therefore enables the distribution of documents across infrastructures where different technologies and operating systems are in use.

Other areas of use

  • Mass production of invoices, reports, etc.
  • PDF creation "on-the-fly" in web server applications
  • "Save as PDF/A" function in application programs
  • Import images and text in PDF/A documents

Add stamp to PDF

Add a semi-transparent stamp text onto each page of a PDF document. Optionally specify the color and the opacity of the stamp.

C# sample:
// Open input document
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))

// Create output document
using (Stream outStream = new FileStream(outPath, FileMode.Create, FileAccess.ReadWrite))
using (Document outDoc = Document.Create(outStream, Conformance.Unknown, null))
{
    Font font = outDoc.CreateSystemFont("Arial", "Italic", true);

    // Set output intent
    ColorSpace inIntent = inDoc.OutputIntent;
    if (inIntent != null)
    {
        ColorSpace outputIntent = outDoc.CopyColorSpace(inIntent);
        outDoc.OutputIntent = outputIntent;
    }

    // Copy metadata
    Metadata metadata = outDoc.CopyMetadata(inDoc.Metadata);
    outDoc.Metadata = metadata;

    // Get the device color space
    ColorSpace colorspace = outDoc.CreateDeviceColorSpace(DeviceColorSpaceType.RGB);
    // Create paint object with the choosen RGB color
    paint = outDoc.CreateAlphaPaint(colorspace, alpha, 1.0, 0.0, 0.0);

    // Define copy options
    CopyOption copyOptions = CopyOption.CopyLinks | CopyOption.CopyAnnotations |
        CopyOption.CopyFormFields | CopyOption.CopyOutlines | CopyOption.CopyLogicalStructure;

    // Copy all pages from input document
    foreach (Page inPage in inDoc.Pages)
    {
        // Copy page from input to output
        Page outPage = outDoc.CopyPage(inPage, copyOptions);

        // Add text to page
        AddStamp(outDoc, outPage, stampString, font, 50);

        // Add page to document
        outDoc.Pages.Add(outPage);
    }
}
private static void AddStamp(Document outputDoc, Page outPage, string stampString, 
    Font font, double fontSize)
{
    // Create content generator and text object
    using (ContentGenerator gen = new ContentGenerator(outPage.Content, false))
    {
        Text text = outputDoc.CreateText();

        // Create text generator
        using (TextGenerator textgenerator = new TextGenerator(text, font, fontSize, null))
        {
            // Calculate point and angle of rotation
            Point rotationCenter = new Point
            {
                X = outPage.Size.Width / 2.0,
                Y = outPage.Size.Height / 2.0
            };
            double rotationAngle = Math.Atan2(outPage.Size.Height,
                outPage.Size.Width) / Math.PI * 180.0;

            // Rotate textinput around the calculated position
            Transformation trans = new Transformation();
            trans.RotateAround(rotationAngle, rotationCenter);
            gen.Transform(trans);

            // Calculate position
            Point position = new Point
            {
                X = (outPage.Size.Width - textgenerator.GetWidth(stampString)) / 2.0,
                Y = (outPage.Size.Height - font.Ascent * fontSize) / 2.0
            };

            // Move to position
            textgenerator.MoveTo(position);
            // Set text rendering 
            textgenerator.SetRendering(paint, null, false);
            // Add given stamp string
            textgenerator.ShowLine(stampString);
        }
        // Paint the positioned text
        gen.PaintText(text);
    }
}
Java sample:
try (// Open input document
    FileStream inStream = new FileStream(inPath, "r");
    Document inDoc = Document.open(inStream, null);
    FileStream outStream = new FileStream(outPath, "rw")) {
    outStream.setLength(0);
    try (// Create output document
        Document outDoc = Document.create(outStream, Conformance.UNKNOWN, null)) {
        // Create embedded font in output document
        Font font = outDoc.createSystemFont("Arial", "Italic", true);

        // Set output intent
        if (inDoc.getOutputIntent() != null)
            outDoc.setOutputIntent(outDoc.copyColorSpace(inDoc.getOutputIntent()));

        // Copy metadata
        Metadata metadata = outDoc.copyMetadata(inDoc.getMetadata());
        outDoc.setMetadata(metadata);

        // Set copy options
        EnumSet<CopyOption> copyOptions = EnumSet.of(CopyOption.COPY_LINKS, CopyOption.COPY_ANNOTATIONS,
                CopyOption.COPY_FORM_FIELDS, CopyOption.COPY_OUTLINES, CopyOption.COPY_LOGIGAL_STRUCTURE);

        // Get the device color space
        ColorSpace colorSpace = outDoc.createDeviceColorSpace(DeviceColorSpaceType.RGB);

        // Choose the RGB color value
        double[] color = { 1.0, 0.0, 0.0 };

        // Create paint object
        paint = outDoc.createAlphaPaint(colorSpace, alpha, color);

        // Loop throw all pages of input
        for (Page inPage : inDoc.getPages()) {
            // Copy page from input to output
            Page outPage = outDoc.copyPage(inPage, copyOptions);

            // Add text to page
            addStamp(outDoc, outPage, stampString, font, 50);

            // Add page to document
            outDoc.getPages().add(outPage);
        }
    }
}
private static void addStamp(Document outputDoc, Page outPage, String stampString, Font font, double fontSize)
        throws ErrorCodeException {
    try (// Create content generator
        ContentGenerator generator = new ContentGenerator(outPage.getContent(), false)) {
        // Create text object
        Text text = outputDoc.createText();
        try (// Create text generator
            TextGenerator textgenerator = new TextGenerator(text, font, fontSize, null)) {
            // Calculate point and angle of rotation
            Point rotationCenter = new Point(outPage.getSize().width / 2.0, outPage.getSize().height / 2.0);

            // Calculate rotation angle
            double rotationAngle = Math.atan2(outPage.getSize().height, outPage.getSize().width) / Math.PI * 180.0;

            // Rotate text input around the calculated position
            Transformation trans = new Transformation();
            trans.rotateAround(rotationAngle, rotationCenter);
            generator.transform(trans);

            // Calculate position
            Point position = new Point((outPage.getSize().width - textgenerator.getWidth(stampString)) / 2.0,
                    (outPage.getSize().height - font.getAscent() * fontSize) / 2.0);

            // Move to position
            textgenerator.moveTo(position);

            // Set text rendering
            textgenerator.setRendering(paint, null, false);

            // Add given stamp string
            textgenerator.showLine(stampString);
        }

        // Paint the positioned text
        generator.paintText(text);
    }
}
C sample:
// Open input document
pInStream = _tfopen(szInPath, _T("rb"));
GOTO_CLEANUP_IF_NULL(pInStream, _T("Failed to open input file \"%s\".\n"), szInPath);
PdfCreateFILEStreamDescriptor(&inDescriptor, pInStream, FALSE);
pInDoc = PdfDocumentOpen(&inDescriptor, _T(""));
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInDoc, _T("Input file \"%s\" cannot be opened. %s (ErrorCode: 0x%08x).\n"), szInPath, szErrorBuff, PdfGetLastError());

// Create output document
pOutStream = _tfopen(szOutPath, _T("wb+"));
GOTO_CLEANUP_IF_NULL(pOutStream, _T("Failed to open output file %s.\n"), szOutPath);
PdfCreateFILEStreamDescriptor(&outDescriptor, pOutStream, 0);
pOutDoc = PdfDocumentCreate(&outDescriptor, PdfDocumentGetConformance(pInDoc), NULL);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutDoc, _T("Output file %s cannot be closed. %s (ErrorCode: 0x%08x).\n"), szOutPath, szErrorBuff, PdfGetLastError());

// Create embedded font in output document
pFont = PdfDocumentCreateSystemFont(pOutDoc, _T("Arial"), _T("Italic"), TRUE);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pFont, _T("Embedded font cannot be created. %s (ErrorCode: 0x%08x).\n"), szErrorBuff, PdfGetLastError());

// Set output intent
if (PdfDocumentGetOutputIntent(pInDoc) != NULL)
    PdfDocumentSetOutputIntent(pOutDoc, PdfDocumentCopyColorSpace(pOutDoc, PdfDocumentGetOutputIntent(pInDoc)));

// Copy metadata
pMetadata = PdfDocumentCopyMetadata(pOutDoc, PdfDocumentGetMetadata(pInDoc));
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pMetadata, _T("Failed to copy metadata from input file. %s (ErrorCode: 0x%08x).\n"), szErrorBuff, PdfGetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PdfDocumentSetMetadata(pOutDoc, pMetadata), _T("Failed to set metadata. %s (ErrorCode: 0x%08x).\n"), szErrorBuff, PdfGetLastError());

// Set copy options
TPdfCopyOption pCopyOptions = ePdfCopyLinks | ePdfCopyAnnotations | ePdfCopyFormFields | ePdfCopyOutlines | ePdfCopyLogicalStructure;

// Get the device color space
TPdfColorSpace* pColorSpace = PdfDocumentCreateDeviceColorSpace(pOutDoc, ePdfColorSpaceRGB);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pColorSpace, _T("Failed to get the device color space. %s (ErrorCode: 0x%08x).\n"), szErrorBuff, PdfGetLastError());

// Chose the RGB color values
double color[] = { 1.0, 0.0, 0.0 };
size_t nColor = sizeof(color) / sizeof(double);

// Create paint object
pPaint = PdfDocumentCreateAlphaPaint(pOutDoc, pColorSpace, dAlpha, color, nColor);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pPaint, _T("Failed to create a transparent paint. %s (ErrorCode: 0x%08x).\n"), szErrorBuff, PdfGetLastError());

pInPageList = PdfDocumentGetPages(pInDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPageList, _T("Failed to get the pages of the input document. %s (ErrorCode: 0x%08x).\n"), szErrorBuff, PdfGetLastError());
pOutPageList = PdfDocumentGetPages(pOutDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPageList, _T("Failed to get the pages of the output document. %s (ErrorCode: 0x%08x).\n"), szErrorBuff, PdfGetLastError());

// Loop through all pages of input
for (int i = 0; i < PdfPageListGetCount(pInPageList); i++)
{
    // Get a list of pages
    pInPage = PdfPageListGet(pInPageList, i);

    // Copy page from input to output
    pOutPage = PdfDocumentCopyPage(pOutDoc, pInPage, pCopyOptions);
    GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPage, _T("Failed to copy pages from input to output. %s (ErrorCode: 0x%08x).\n"), szErrorBuff, PdfGetLastError());

    // Add stamp to page
    if (addStamp(pOutDoc, pOutPage, szStampString, pFont, 50) == 1)
    {
        goto cleanup;
    }

    // Add page to output document
    GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PdfPageListAppend(pOutPageList, pOutPage), _T("Failed to add page to output document. %s (ErrorCode: 0x%08x).\n"), szErrorBuff, PdfGetLastError());

    if (pOutPage != NULL)
    {
        PdfClose(pOutPage);
        pOutPage = NULL;
    }

    if (pInPage != NULL)
    {
        PdfClose(pInPage);
        pInPage = NULL;
    }
}
int addStamp(TPdfDocument* pOutDoc, TPdfPage* pOutPage, TCHAR* szStampString, TPdfFont* pFont, double dFontSize)
{
    TPdfContentGenerator* pGenerator = NULL;
    TPdfText* pText = NULL;
    TPdfTextGenerator* pTextGenerator = NULL;
    TPdfTransformation* pTrans = NULL;

    TPdfContent* pContent = PdfPageGetContent(pOutPage);

    // Create content generator
    pGenerator = PdfNewContentGenerator(pContent, FALSE);
    GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pGenerator, _T("Failed to create a content generator. %s (ErrorCode: 0x%08x).\n"), szErrorBuff, PdfGetLastError());

    // Create text object
    pText = PdfDocumentCreateText(pOutDoc);
    GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pText, _T("Failed to create a text object. %s (ErrorCode: 0x%08x).\n"), szErrorBuff, PdfGetLastError());

    // Create a text generator 
    pTextGenerator = PdfNewTextGenerator(pText, pFont, dFontSize, NULL);
    GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pTextGenerator, _T("Failed to create a text generator. %s (ErrorCode: 0x%08x).\n"), szErrorBuff, PdfGetLastError());

    // Get output page size
    TPdfSize size;
    GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PdfPageGetSize(pOutPage, &size), _T("Failed to read page size. %s (ErrorCode: 0x%08x).\n"), szErrorBuff, PdfGetLastError());

    // Calculate point and angle of rotation
    TPdfPoint rotationCenter;
    rotationCenter.dX = size.dWidth / 2.0;
    rotationCenter.dY = size.dHeight / 2.0;
    double dRotationAngle = atan2(size.dHeight, size.dWidth) / M_PI * 180.0;

    // Rotate textinput around the calculated position
    pTrans = PdfNewTransformationIdentity();
    GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PdfTransformationRotateAround(pTrans, dRotationAngle, &rotationCenter), _T("Failed to rotate textinput around the calculated position. %s (ErrorCode: 0x%08x).\n"), szErrorBuff, PdfGetLastError());
    GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PdfContentGeneratorTransform(pGenerator, pTrans), _T("Failed to modify the current transformation. %s (ErrorCode: 0x%08x).\n"), szErrorBuff, PdfGetLastError());

    // Calculate position
    TPdfPoint position;
    double dTextWidth = PdfTextGeneratorGetWidth(pTextGenerator, szStampString);
    GOTO_CLEANUP_IF_ZERO_PRINT_ERROR(dTextWidth, _T("%s (ErrorCode: 0x%08x).\n"), szErrorBuff, PdfGetLastError());
    double dFontAscent = PdfFontGetAscent(pFont);
    GOTO_CLEANUP_IF_ZERO_PRINT_ERROR(dFontAscent, _T("%s (ErrorCode: 0x%08x).\n"), szErrorBuff, PdfGetLastError());
    position.dX = (size.dWidth - dTextWidth) / 2.0;
    position.dY = (size.dHeight - dFontAscent * dFontSize) / 2.0;

    // Move to position
    GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PdfTextGeneratorMoveTo(pTextGenerator, &position), _T("Failed to move to position. %s (ErrorCode: 0x%08x).\n"), szErrorBuff, PdfGetLastError());
    // Set text rendering
    GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PdfTextGeneratorSetRendering(pTextGenerator, pPaint, NULL, FALSE), _T("Failed to set rendering. %s (ErrorCode: 0x%08x).\n"), szErrorBuff, PdfGetLastError());
    // Add given stamp string
    GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PdfTextGeneratorShowLine(pTextGenerator, szStampString), _T("Failed to add stamp. %s (ErrorCode: 0x%08x).\n"), szErrorBuff, PdfGetLastError());

    // Close text generator
    if (pTextGenerator != NULL)
    {
        PdfClose(pTextGenerator);
        pTextGenerator = NULL;
    }

    // Paint the positioned text
    GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PdfContentGeneratorPaintText(pGenerator, pText), _T("Failed to paint the positioned text. %s (ErrorCode: 0x%08x).\n"), szErrorBuff, PdfGetLastError());

cleanup:
    if (pTrans != NULL)
        PdfClose(pTrans);
    if (pTextGenerator != NULL)
        PdfClose(pTextGenerator);
    if (pText != NULL)
        PdfClose(pText);
    if (pContent != NULL)
        PdfClose(pContent);
    if (pGenerator != NULL)
        PdfClose(pGenerator);

    return iReturnValue;
}
PDF Expert blog - the caveats of assembling PDF/A documents

The caveats of assembling PDF/A documents

Assembling PDF documents from various sources is a crucial part of an output management system. And, as the document needs to be archived in most cases, it should conform to the PDF/A standard. Is there a way to assemble a document and accomplish PDF/A conformance in one step?


PDF Expert Blog - embedded fonts and PDF mass printing application

The problem with embedded fonts in PDF mass printing applications

PDF is more and more finding its way into mass printing applications. However, PDF spool files often ask too much from a print engine resulting in aborts or, even worse, incomplete prints which may not be noticed. What is special about PDF mass printing...