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.

2015-12-22

How to resize PDF pages and stamp PDF documents

Introduction


Many custom workflows which are in use in small and big companies implement incoming PDF documents processing and stamping for tracking, archiving, and later use. These docs can be of any origin: received by emails, scanned by the personnel from hard copies etc.

Manual processing takes significant amount of time, and in this article we’ll show how to speed up this process by creating an app for automatic PDF page resizing and stamping.

The app


Consider the following simple program:

namespace ResizeAndStampPDF
{
    class Program
    {
        static void Main(string[] args)
        {
            if (args != null && args.Length > 0)
            {
                string destinationPath =
      System.IO.Path.GetFileNameWithoutExtension(args[0]) + "_stamped.pdf";

                PageStamper.Stamp(args[0],destinationPath,"FF6173","949124","Approved");

                Process.Start(destinationPath);
            }
        }
    }
}

It uses the PageStamper.Stamp() method to perform the stamping task by passing doc’s attributes. This class uses Apitron PDF Kit .NET component and also demonstrates its Fixed and Flow layout APIs in action (see this blog post to read about the difference between them). See the next section for the details.

PDF Stamping implementation

                         
Class PageStamper listed below transforms the page by expanding it down and adding a stamp onto this area.

/// <summary>
/// Resizes PDF page and adds custom stamp at the bottom.
/// </summary>
static class PageStamper
{
    private const int stampHeight = 36;
    private  const int sectionMargin = 40;

    public static void Stamp(string sourcePath, string destinationPath, string branchNo,
        string incomingNo, string documentStatus)
    {
        // open file
        using (Stream stream = File.Open(sourcePath, FileMode.Open, FileAccess.ReadWrite))
        {
            // load pdf document from stream
            using (FixedDocument originalDoc = new FixedDocument(stream))
            {
                int pageNumber = 1;
                // process pages
                foreach (Page page in originalDoc.Pages)
                {
                    // append the required stamp
                    Section stampSection = CreateStampSection(page, branchNo, incomingNo,
                       documentStatus, pageNumber++);
                    // resize the page
                    ResizePage(page);
                    // save state to avoid any problems with possible graphics state change
                    page.Content.SaveGraphicsState();
                    // apply transformations to properly position the stamp
                    ApplyTransformations(page, stampSection);
                    // add section object to the page
                    page.Content.AppendContentElement(stampSection,
                        stampSection.Width.Value, stampSection.Height.Value);
                    // restore the original state
                    page.Content.RestoreGraphicsState();
                }   
                // save changes to PDF
                using (Stream outputStream = File.Create(destinationPath))
                {
                    originalDoc.Save(outputStream);
                }
            }
        }
    }

    /// <summary>
    /// Resizes PDF page, taking into account its rotation property.
    /// </summary>
    /// <param name="page"></param>
    private static void ResizePage(Page page)
    {
        Boundary mediaBox = ResizeBoundary(page.Boundary.MediaBox, page.Rotate);
        page.Resize(new PageBoundary(mediaBox));
    }

    private static Section CreateStampSection(Page page, string branchNo, string incomingNo,
        string documentStatus, int pageNumber)
    {
        // create section content element and set its size
        Section stampSection = new Section();
        stampSection.Height = stampHeight;

        if(page.Rotate == PageRotate.Rotate0 || page.Rotate == PageRotate.Rotate180)
        {
            stampSection.Width = page.Boundary.MediaBox.Width - sectionMargin;
        }
        else
        {
            stampSection.Width = page.Boundary.MediaBox.Height - sectionMargin;
        }           

        // create grid element
        Grid grid = new Grid(Length.Auto,Length.Auto,Length.Auto,Length.Auto,Length.Auto);
        grid.Font = new Font(StandardFonts.HelveticaBold, 12);
        grid.Color = RgbColors.Red;
        grid.InnerBorderColor = RgbColors.Red;
        grid.InnerBorder = new Border(1);
        grid.Width = Length.FromPercentage(100);

        // add header row
        grid.Add(new GridRow( new TextBlock("Page #"),
            new TextBlock("Branch #"),
            new TextBlock("Incoming Doc #"),
            new TextBlock("Document Status#"),
            new TextBlock("Date"))
            { Align = Align.Center });

        // add data row
        grid.Add(new GridRow( new TextBlock(pageNumber.ToString()),
            new TextBlock(branchNo),
            new TextBlock(incomingNo),
            new TextBlock(documentStatus),
            new TextBlock(DateTime.Now.ToString("dd/MM/yyyy")))
            { Align = Align.Center });

        stampSection.Add(grid);
        return stampSection;
    }

    /// <summary>
    /// Applies transformations to generated content considering initial page rotation.
    /// </summary>
    /// <param name="page">The page to transform.</param>
    /// <param name="section">Section used </param>
    private static void ApplyTransformations(Page page, Section section)
    {
        switch (page.Rotate)
        {
            case PageRotate.Rotate90:
            {
                page.Content.SetRotate(Math.PI/2.0f);
                // set current position on page
                page.Content.Translate((page.Boundary.MediaBox.Height 
                    -section.Width.Value)/2.0,
                    -page.Boundary.MediaBox.Right);
                break;
            }  
            case PageRotate.Rotate180:
            {
                page.Content.SetRotate(Math.PI);
                // set current position on page
                page.Content.Translate(
                    -page.Boundary.MediaBox.Width +
                    ((page.Boundary.MediaBox.Width - section.Width.Value)/2.0),
                    -page.Boundary.MediaBox.Height);
                break;
            }
            case PageRotate.Rotate270:
            {
                page.Content.SetRotate(-Math.PI/2.0f);
                // set current position on page
                page.Content.Translate(
                    -page.Boundary.MediaBox.Height +
                    (page.Boundary.MediaBox.Height - section.Width.Value)/2.0,
                    page.Boundary.MediaBox.Left);

                break;
            }
            case PageRotate.Rotate0:
            default:
            {
                // set current position on page
                page.Content.Translate((page.Boundary.MediaBox.Width 
                    - section.Width.Value)/2.0,
                    page.Boundary.MediaBox.Bottom);
                break;
            }
        }
    }

    /// <summary>
    /// Resizes passed boundary if it's not null, otherwise returns null.
    /// </summary>
    /// <param name="boundary">Boundary to resize.</param>
    /// <param name="rotation">Page rotation.</param>
    /// <param name="heightDelta">The height delta, defaut is 36.</param>
    /// <returns>New boundary the <paramref name="boundary"/> is not null, otherwise null.
    </returns>
    private static Boundary ResizeBoundary(Boundary boundary, PageRotate rotation,
        double heightDelta = stampHeight)
    {
        if (boundary == null)
        {
            return null;
        }
        switch (rotation)
        {
            case PageRotate.Rotate90:
                return new Boundary(boundary.Left, boundary.Bottom, boundary.Right + 
                    heightDelta,
                    boundary.Top);
            case PageRotate.Rotate180:
                return new Boundary(boundary.Left, boundary.Bottom, boundary.Right,
                    boundary.Top + heightDelta);
            case PageRotate.Rotate270:
                return new Boundary(boundary.Left - heightDelta, boundary.Bottom,
                    boundary.Right + heightDelta, boundary.Top);
            case PageRotate.Rotate0:
            default:
                return new Boundary(boundary.Left, boundary.Bottom - heightDelta,
                    boundary.Right,
                    boundary.Top);
        }
    }
}                     

      
The resulting document, transformed by the code above, looks as follows:

Pic. 1 Transformed PDF document with stamp

Pic. 1 Transformed PDF document with stamp

Conclusion


This sample shows how to combine fixed and flow layout API together and get the best form both. We open the document using Fixed layout API and add a Section content element from Flow layout API after resizing. It helps us to quickly generate the stamp grid, and avoid many manual drawing operations.

The actual resizing magic happens in Page.Resize() method which repositions the content according to its initial state. 

This project is a small demo of what Apitron PDF Kit for .NET can do with PDF and if you’d like to know more, then our free book is at your service. The complete code for this example can be found in our GitHub repo.

Downloadable version of this article can be found by the following link [PDF].

No comments:

Post a Comment