pdf links

PDF Rendering
Convert PDF to Image (.NET)
Convert PDF to image on Android (Xamarin)
Convert PDF to image on iOS (Xamarin)
Convert PDF to image in Windows Store apps (.NET)
Convert PDF to image in Windows Phone apps (.NET)
PDF to image in Universal Windows Store apps (.NET)
Free PDF Viewer control for Windows Forms (.NET)
How to integrate PDF Viewer control in WPF app (.NET)
Creating WPF PDF Viewer supporting bookmarks (.NET)
Cross-platform PDF Viewer using GTK# (MONO)
Silverlight PDF viewer control (Silverlight 5)
Multithreaded PDF rendering (.NET)
Convert pdf to image in Silverlight app (C# sample)
How to set fallback fonts for PDF rendering (C#)
Avoiding the out-of-memory exception on rendering (C#)
PDF viewer single page application (WebAPI, AngularJS)
PDF viewer control for Windows 10 universal applications
Use custom ICC profile for CMYK to RGB conversion
PDF layers - separate images, text, annotations, graphics

PDF Forms Creation PDF Security
Conversion to PDF/A
Other topics
PDF Document Manipulation PDF Content Generation
Fixed and Flow layout document API (.NET)
Creation of grids and tables in PDF (C# sample)
How to create interactive documents using Actions (C# sample)
Text flow effects in PDF (C# sample)
How to generate ordered and bulleted lists in PDF (C# sample)
Convert HTML to PDF using flow layout API (C# sample)
How to use custom fonts for PDF generation (.NET)
Create document with differently sized pages (C#)
Create PDF documents using MONO (C#/MONO/Windows/OSX)
How to use background images for content elements (C#/PDF Kit/FlowLayout)
Add transparent images to PDF document (C#)
Draw round rect borders in PDF documents(C#)
ICC color profiles and and ICC based colors in PDF (C#)
How to use bidirectional and right to left text in PDF (C#)
Create PDF documents from XML templates (C# sample)
How to resize PDF pages and use custom stamps (C#)
Add header and footer to PDF page (.NET sample)
How to use clipping mask for drawing on PDF page
Fill graphics path with gradient brushes in PDF (Shadings)
Apitron PDF Kit and Rasterizer engine settings
Add layers to PDF page (optional content, C# sample)
How to create free text annotation with custom appearance
PDF Content Extraction PDF Navigation
PDF to TIFF conversion
Contact us if you have a PDF related question and we'll cover it in our blog.

2017-04-30

Open source Apitron PDF Kit extensions library

Introduction



Apitron PDF Kit is an outstanding library for all kinds of tasks related to PDF, it offers well-designed and balanced API that follows the specification as much as possible at the same time making your life easier by automating many routine operations. 

We decided to take it one step further and introduced Apitron PDF Kit open source extensions library which would automate most frequent pdf manipulation activities, and started with adding digital signatures and watermarks. 

The project pursues two main goals:

1. Make PDF processing more intuitive and straightforward
2. Show how the base Apitron PDF Kit API works using real-life examples

The source code for the library can be found in our github repo by the following link. We will probably wrap it as a nuget package later, but for now you can just checkout the code and compile it yourself.


Code samples



Signing is very simple and consist of a one line call of the method Sign, you provide the certicate, password, signature image and its boundaries and a few optional params if needed.


using (Stream inputStream = File.Open("../../data/letter_unsigned.pdf", FileMode.Open))
{
     using (FixedDocument doc = new FixedDocument(inputStream))
     {
         doc.Sign("../../data/johndoe.pfx", "password",
                    "../../data/signatureImage.png",
         new Boundary(100, 140, 190, 180), outputFileName);
     }
}



And the result:

Pic. 1 Signed PDF Document
Pic. 1 Signed PDF Document

 
Same applies to stamping a document with a transparent watermark, just add a one-line call and voilĂ :

using (Stream inputStream = File.Open("../../data/letter_unsigned.pdf", FileMode.Open))
{
     using (FixedDocument doc = new FixedDocument(inputStream))
     {
         doc.Watermark("../../data/watermarkTransparent.png", outputFileName);
     }
}



The result is below:

Pic. 2 Stamped PDF document
Pic. 2 Stamped PDF document
 

Summary



If you need to incorporate the basic PDF processing functionality into your applications, then the open-source Apitron PDF Kit extensions library we’ve published a few weeks ago could be the right choice. It saves time keeping things simple, and you can always fallback to the main API if you need something going beyond its capabilities. 

Please let us know what you think about it or suggest new functions to implement. If you want your code to be added to the library just send us a patch for review.

2017-03-31

Signing pdf documents with smartcards using cryptoapi or PKCS#11 cryptographic token interface

Signing with smartcards might be challenging as they usually restrict private key export and only allow signing via own custom api, integrate with existing cryptoserviceproviders (windows cryptoapi) or provide an implementation of PKCS#11 cryptographic token interface.

If you need to implement an advanced signing workflow using smart cards, we can help you on the way as our products are fully compatible and provide extensible interfaces for these purposes. Should you have any questions, just let us know and we'll be happy to help you.

2017-02-28

How to programmatically delete, edit or replace content in PDF documents

Introduction


Replacing, editing or deleting content from PDF documents programmatically is not a trivial task and requires expert knowledge of the format and internal structures to be implemented from scratch. Luckily, we made it much easier for you by introducing native support for these operations. You can examine document’s content page by page and change the things you need without any significant efforts. In this article we’ll demonstrate how to implement text and image replacement or editing, removing contents from the desired area or region, resources replacement, graphics paths alteration, and getting content elements’ boundaries.



Replacing text and images


Let’s assume you’re developing a web-based solution for a real estate agency and you need to process advertisements stored as PDF documents. One of them could look as below:


Pic. 1 Sample advertisement stored as PDF

Pic. 1 Sample advertisement stored as PDF

But the complete listing should only be accessible to the logged in customers, while you still want the ad to be viewable by other users but with some restrictions that include price and the photo of the object. One of solutions is to generate it dynamically. Here is the code: 

static void Main(string[] args)
{
       ReplaceTextAndImages("../../../data/advertisement.pdf", "$","Price: contact us",
              "../../../data/replacement.png");
}

private static void ReplaceTextAndImages(string inputFilePath, string oldText, 
      string newText, string replacementImagePath)
{
    using (Stream inputStream = File.Open(inputFilePath, FileMode.Open, FileAccess.Read))
    {
        using (FixedDocument doc = new FixedDocument(inputStream))
        {
            // add the replacement image to document's resources
            doc.ResourceManager.RegisterResource(new Image("replacement_image",
                  replacementImagePath, true));

            // enumerate content elements found on document's first page
            foreach (IContentElement element in doc.Pages[0].Elements)
            {
                // handle the text element case
                if (element.ElementType == ElementType.Text)
                {
                    TextContentElement textElement = element as TextContentElement;
                    if (textElement != null)
                    {
                        // go thought all the text segments and replace 
                        // the segment that contains the sample text
                        foreach (TextSegment textSegment in textElement.Segments)
                        {
                            if (textSegment.Text.Contains(oldText))
                            {
                                TextObject newTextObject = 
                                new TextObject(textSegment.FontName,textSegment.FontSize);
                                newTextObject.AppendText(newText);
                                textSegment.ReplaceText(0, textSegment.Text.Length, newTextObject);
                            }
                        }
                    }
                } // handle image case
                else if (element.ElementType == ElementType.Image)
                {
                    ImageContentElement imageElement = element as ImageContentElement;

                    if (imageElement != null)
                    {
                        // just replace the image with new one using
                        // registered resource, removing old one
                        imageElement.Replace("replacement_image", true);
                    }
                }
            }

            // save modified file
            using (Stream outputStream = File.Create(outputFileName))
            {
                doc.Save(outputStream);
            }
        }
    }

    Process.Start(outputFileName);
} 


And the resulting file produced by this code is shown below:


Pic. 2 Edited PDF document

Pic. 2 Edited PDF document




Content deletion


Let’s say you have a document shown below and would like to remove all content that intersects with an arbitrary rectangular region.


Pic. 3 Sample document for content removal

Pic. 3 Sample document for content removal

Here is the code that does the job, it also highlights the elements that were removed using their calculated boundaries:

static void Main(string[] args)
{
    RemoveContentInRect("../../../data/apitron_pdf_kit_in_action_excerpt.pdf",
          new Boundary(70, 200, 330, 450));
}

private static void RemoveContentInRect(string inputFilePath, Boundary redactionRect)
{
    using (Stream inputStream = File.Open(inputFilePath, FileMode.Open, FileAccess.Read))
    {
        using (FixedDocument doc = new FixedDocument(inputStream))
        {
            doc.ResourceManager.RegisterResource(
               new GraphicsState("myGraphicsState") {CurrentNonStrokingAlpha = 0.3});

            // enumerate content elements found on document's first page
            Page firstPage = doc.Pages[0];

            firstPage.Content.SaveGraphicsState();
            firstPage.Content.SetDeviceStrokingColor(new []{1.0,0,0});

            foreach (IContentElement element in firstPage.Elements)
            {
                // remove elements falling into the deletion region
                // even if they just overlap
                if (element.ElementType == ElementType.Text)
                {
                    TextContentElement textElement = (TextContentElement) element;

                    foreach (TextSegment segment in textElement.Segments)
                    {
                        if (RectsOverlap(redactionRect, segment.Boundary))
                        {
                            firstPage.Content.StrokePath(Path.CreateRect(segment.Boundary));
                            segment.Remove();
                        }
                    }
                }
                else if (!RectsOverlap(redactionRect, element.Boundary))
                {
                    firstPage.Content.StrokePath(Path.CreateRect(element.Boundary));
                    element.Remove();
                }
            }
                
            // highlight deletetion region
            firstPage.Content.SetGraphicsState("myGraphicsState");
            firstPage.Content.SetDeviceStrokingColor(new []{0.0});
            firstPage.Content.SetDeviceNonStrokingColor(new []{0.0});
            firstPage.Content.FillAndStrokePath(Path.CreateRect(redactionRect));
            firstPage.Content.RestoreGraphicsState();

            // save modified file
            using (Stream outputStream = File.Create(outputFileName))
            {
                doc.Save(outputStream);
            }
        }
    }
}

public static bool RectsOverlap(Boundary a, Boundary b)
{
    return (a.Left < b.Right && a.Right> b.Left && a.Bottom<b.Top && a.Top>b.Bottom);
}


Resulting document is demonstrated below:


Pic. 4 Document with partially removed content

Pic. 4 Document with partially removed content



Changing existing drawings or graphics paths


If you have a drawing you would like to alter there is an API for that as well. You can also prepend or append PDF content to it, scale, translate or delete. Here is our sample file:


Pic. 5 PDF document with vector drawing

Pic. 5 PDF document with vector drawing


And our code that changes it a bit by altering non stroking colors for all found paths:


static void Main(string[] args)
{
    ReplacePaths("../../../data/graphics.pdf");
}

private static void ReplacePaths(string inputFilePath)
{
    using (Stream inputStream = File.Open(inputFilePath, FileMode.Open, FileAccess.Read))
    {
        using (FixedDocument doc = new FixedDocument(inputStream))
        {
            double colorComponent = 0;
            double colorDelta = 0.1;

            // enumerate content elements found on document's first page
            foreach (IContentElement element in doc.Pages[0].Elements)
            {
                // change the fill color of each found drawing
                if (element.ElementType == ElementType.Drawing)
                {
                    DrawingContentElement drawingElement = (DrawingContentElement) element;
                    drawingElement.SetNonStrokingColor(
                          new double[] { Math.Min(colorComponent,1),0, 0});
                    colorComponent += colorDelta;
                }
            }

            // save modified file
            using (Stream outputStream = File.Create(outputFileName))
            {
                doc.Save(outputStream);
            }
        }
    }

    Process.Start(outputFileName);
}

You can set stroking or non-stroking colors, examine drawing rule or operation type used, even examine the path or add some content by using AddContent method if you need.

The resulting document produced by the code is shown below:

Pic. 6 Edited graphics paths

Pic. 6 Edited graphics paths


Replacing resources in PDF documents


You probably know that PDF documents can contains various resources like fonts, tiling patterns, images, FormXObjects, colorprofiles etc. Whenever you need to replace a resource you can use a special API created for that.

Every FixedDocument (our name for PDF document) has its own resource manager accessible by the property of the same name. So in order to change the resource you can use the following code (relevant part is highlighted):

static void Main(string[] args)
{
    using (Stream inputStream = File.Open("../../../data/patternFill.pdf",
         FileMode.Open, FileAccess.Read))
    {
        using (FixedDocument doc = new FixedDocument(inputStream))
        {
            // create a new tiling pattern
            TilingPattern pattern = new TilingPattern("myNewPattern", 
      new Boundary(0, 0, 20, 20), 25, 25);
            pattern.Content.SetDeviceNonStrokingColor(new double[] { 0.1, 0.5, 0.7 });
            pattern.Content.FillAndStrokePath(Path.CreateCircle(10, 10,9));

            // register new pattern as a resource
            doc.ResourceManager.RegisterResource(pattern);

            // replace the old pattern with new one
            doc.ResourceManager.RegisterReplacement("myPattern","myNewPattern");

            //save modified file
            using (Stream outputStream = File.Create(outputFileName))
            {
                doc.Save(outputStream);
            }
        }
    }

    Process.Start(outputFileName);
}

In this example we replaced the old tiling pattern resource with the new one. Using this technique you can change the appearance of the PDF documents just by changing resources used by drawing operations.


Summary


In this article we demonstrated a few possible scenarios for content editing, removal and replacement in PDF. The topic is quite extensive, so probably we didn’t cover your particular case or maybe you have a specific question. If you need any help with the API or a professional advice just drop us an email, and we’ll be happy to assist you. All samples used in this article can be found in our github repo as well.

2017-01-31

Long-term validation of signatures in PDF documents or LTV enabled signatures

Introduction 

 

Long-term validation of signatures in PDF documents is a mechanism to check that the signature and all related certificates are still valid at the time of checking (opening the doc) without making any requests to the signing authorities. That is all required information including OCSP responses, CRLs and timestamp should be present into the document.

Checking long term validation state


So, how can you check if the file you're viewing has LTV enabled signatures? See the image below that demonstrates that:

LTV-enabled signature  
Pic.1 LTV-enabled signature

Basically PDF reader makes the check for you and displays the "Signature is LTV enabled" message. It also says that the signature is timestamped and it's very important because it proves that the file was signed at specific time and the clock couldn't be manipulated to produce the signature. Another way to check if the signature is LTV enabled is by examining whether the certificates' revocation info is embedded into the document. To do this, open signature properties window and check certs from the certificate chain one by one, you should see the similar picture:

Checking certificate revocation info status
Pic.2 Checking certificate revocation info status

Additionally, you can take a look at advanced signature properties to find the timestamping authority details, hash algorithm used and producer info.

Advanced signature properties
Pic.3 Advanced signature properties

Conclusion

 

While LTV can be tricky to implement sometimes, we have invaluable experience in that area and our products are ready to process LTV enabled documents as well.  So if you need any help with implementing digital signatures workflow, just let us know and we'll be happy to come up with a solution for you.

2016-12-31

Process and manipulate PDF content using Apitron PDF library

Dear Customers,

we wish you a happy new year and will continue to provide the best PDF tools and support on the market. Thanks for choosing our products and your invaluable feedback. Should you have any questions or need assistance we'll be always happy to help you.

With warm wishes,
The Apitron Team.

2016-11-30

Convert PDF to tiff using custom bitonal image conversion

Introduction

 

Sometimes default PDF to TIFF conversion doesn't provide the desired results, especially if it comes to black and white tiffs, containing so-called bitonal images. We've recently added a new mechanism into our Apitron PDF Rasterizer product which allows you to use custom bitonal image conversion implementation if you need it. See the sample below to see how it works.

The code

 

Provided code sample is a demo of custom bitonal conversion implementation and shows one of the possible ways to convert an RGB image to its black and white analog.

The idea is to scale the resulting image by the factory of 8 and put variably sized pixels consisting of black dots depending on the luminosity of  the source pixel. Thus one source pixel would correspond to a square formed by 64 black and white 1-bit pixels.

static void Main(string[] args)
{
    using (Stream inputStream = File.OpenRead("../../data/document.pdf"), 
        outputStream = File.Create("out.tiff"))
    {
        using (Document doc = new Document(inputStream))
        {
            doc.SaveToTiff(outputStream, new TiffRenderingSettings()
            {
                // set our conversion delegate
                ConvertToBitonal = MyConvertToBitonal
            });
        }
    }

    Process.Start("out.tiff");
}

private static byte[] MyConvertToBitonal(int width, int height, byte[] imageData, 
    out int resultingWidth, out int resultingHeight)
{
    // we will scale the resulting image,
    // each source pixel will correspond to 64 black and white pixels
    int scaleFactor = 8;
    resultingWidth = width * scaleFactor;
    resultingHeight = height * scaleFactor;

    // create resulting data buffer
    byte[] resultingImage = new byte[width * resultingHeight];
           
    double luminance;

    // black pixel goes first, lighter pixels follow
    byte[] pixel0 = new byte[] {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
    byte[] pixel1 = new byte[] {0x18, 0x3c, 0x7e, 0xFF, 0xFF, 0x7e, 0x3c, 0x18 };
    byte[] pixel2 = new byte[] {0, 0x18, 0x3c, 0x7e, 0x7e, 0x3c, 0x18, 0 };
    byte[] pixel3 = new byte[] {0, 0, 0x18, 0x3c, 0x3c, 0x18, 0, 0 };
    byte[] pixel4 = new byte[] {0, 0, 0, 0x18, 0x18, 0, 0, 0 };

           
    // iterate over the source pixels and modify bitonal image
    // according to own algorithm
    for (int y = 0, offsetY=0, stride=width*4; y < height; ++y, offsetY+=stride)
    {  
        // base offset for final pixel(s)
        int resultingPixelOffsetBase = y*width*scaleFactor;

        for (int x = 0, offsetX=0; x < width; ++x, offsetX+=4)
        {
            // read pixel data
            byte b = imageData[offsetY+offsetX];
            byte g = imageData[offsetY+offsetX+1];
            byte r = imageData[offsetY+offsetX+2];

            // calculate the luminance
            luminance = (0.2126*r + 0.7152*g + 0.0722*b);

            // based on the luminance we'll select which pixel to use
            // from the darkest one to the lightest
            if (luminance < 50)
            {
                SetPixel(resultingImage, resultingPixelOffsetBase+x, pixel0, width);
            }
            else if (luminance<100)
            {
                SetPixel(resultingImage, resultingPixelOffsetBase+x, pixel1, width);
            }
            else if(luminance <150)
            {
                SetPixel(resultingImage, resultingPixelOffsetBase+x, pixel2, width);
            }
            else if (luminance<200)
            {
                SetPixel(resultingImage, resultingPixelOffsetBase+x, pixel3, width);
            }
            else if (luminance < 250)
            {
                SetPixel(resultingImage, resultingPixelOffsetBase+x, pixel4, width);
            }
        }
    }

    return resultingImage;
}

/// Copies pixel data describing resulting pixel shape to the
/// resulting image
private static void SetPixel(byte[] resultingImage, int resultingPixelOffset, byte[] pixelData, 
int strideInBytes)
{
    for (int i = 0; i < pixelData.Length; ++i)
    {
        resultingImage[resultingPixelOffset + strideInBytes*i] = pixelData[i];
    }
}


The source file looks as follows:


Pic.1 Source PDF document
Pic. 1 Source PDF document

And the converted document is on the image below:

Converted bitonal tiff
Pic. 2 Converted bitonal tiff

If you zoom in you'll see that the image consists of variable black dots that create the smooth gradient fill:

 

Pic.3 Bitonal image
Pic.3 Bitonal image

 

 

The complete code sample can be found in our github repo.

 

 Conclusion 

 

The Apitron PDF Rasterizer is a powerful and extensible cross platform library that can be used to handle all PDF rendering tasks with incredible ease and quality. If you have any questions just send us an email and we'll be happy to help you.

2016-10-20

Convert PDF to TIFF using custom rendering settings

Introduction


The task to convert from PDF to TIFF format can sometimes be tricky and quite challenging if you don’t have the right tool for that. Our Apitron PDF Rasterizer for .NET component has been offering this feature for years and now we’ve tweaked it a bit to fit into more demanding workflows. From now on, you’ll be able to control the conversion of the individual page by changing its DPI, rotation, crop and other parameters.

The complete code sample can be downloaded from our github repo.

 

The code


We’ll start with the following PDF document having one rotated page:

Pic. 1 Source PDF file before conversion to TIFF

Pic. 1 Source PDF file before conversion to TIFF


Using the custom page conversion handling code in the handler of BeforeRenderPage event, we’ll correct the rotation for the second page, set the crop and remove the 3d page.

internal class Program
{
    const int DPI = 144;

    private static void Main(string[] args)
    {
        // open and load the file
        using (FileStream fs = new FileStream(@"..\..\map.pdf", FileMode.Open),
             fsOut = File.Create("out.tiff"))
        {
            // this objects represents a PDF document
            using (Document document = new Document(fs))
            {
                // save to tiff using CCIT4 compression, black and white tiff.
                // set the DPI to 144.0 for this sample, so twice more than default PDF dpi setting.
               TiffRenderingSettings tiffRenderingSettings = 
                    new TiffRenderingSettings(TiffCompressionMethod.LZW, DPI, DPI);

                tiffRenderingSettings.RenderMode = RenderMode.HighQuality;
                tiffRenderingSettings.ScaleMode = ScaleMode.PreserveAspectRatio;
                tiffRenderingSettings.Compression = TiffCompressionMethod.LZW;

                // subscribe to before rendering event and adjust rendering settings 
                // for each page as you want 
                tiffRenderingSettings.BeforeRenderPage += TiffRenderingSettings_BeforeRenderPage;

                document.SaveToTiff(fsOut, tiffRenderingSettings);
            }

            System.Diagnostics.Process.Start("out.tiff");
        }
    }
         
    private static void TiffRenderingSettings_BeforeRenderPage(BeforeRenderPageEventArgs args)
    {
        // skip all pages expect first two
        if (args.PageIndex > 1)
        {
            args.IsPageSkipped = true;
            return;
        }

        // force the portrait mode for all pages if needed
        if (args.DesiredHeight < args.DesiredWidth)
        {
            args.RenderingSettings.RotationAngle = RotationAngle.Rotate270;
        }

        // crop from the all sides by cutting out existing margins
        double margin = 40;
        args.CropBox = new Rectangle(margin, margin, args.DesiredWidth - margin, 
              args.DesiredHeight - margin);
    }
}

The complete code sample can be found in our github repo and the resulting image is shown below:

Pic. 2 Cropped first page of the resulting TIFF file (gray area outlines its original dimensions)

Pic. 2 Cropped first page of the resulting TIFF file
(gray area outlines its original dimensions)

Produced tiff file will have only two cropped pages left as we ignored everything starting from the second one, and additionally the second page will be rotated for a better viewing.

Summary


The Apitron PDF Rasterizer for .NET component is a reliable and highly effective solution for those who need the ultimate quality and control over the PDF to image conversion. It can also be used for creation of cross-platform solutions targeting many platforms at once being available (including plain vanilla .NET) for Xamarin, Mono and Windows store based applications.