Quantcast
Channel: PDF tips & tricks
Viewing all articles
Browse latest Browse all 125

How to resize PDF pages and stamp PDF documents

$
0
0

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
{
    classProgram
    {
        staticvoid 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>
staticclassPageStamper
{
    privateconstint stampHeight = 36;
    private  constint sectionMargin = 40;

    publicstaticvoid 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 = newFixedDocument(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>
    privatestaticvoid ResizePage(Page page)
    {
        Boundary mediaBox = ResizeBoundary(page.Boundary.MediaBox, page.Rotate);
        page.Resize(newPageBoundary(mediaBox));
    }

    privatestaticSection CreateStampSection(Page page, string branchNo, string incomingNo,
        string documentStatus, int pageNumber)
    {
        // create section content element and set its size
        Section stampSection = newSection();
        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 = newGrid(Length.Auto,Length.Auto,Length.Auto,Length.Auto,Length.Auto);
        grid.Font = newFont(StandardFonts.HelveticaBold, 12);
        grid.Color = RgbColors.Red;
        grid.InnerBorderColor = RgbColors.Red;
        grid.InnerBorder = newBorder(1);
        grid.Width = Length.FromPercentage(100);

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

        // add data row
        grid.Add(newGridRow( newTextBlock(pageNumber.ToString()),
            newTextBlock(branchNo),
            newTextBlock(incomingNo),
            newTextBlock(documentStatus),
            newTextBlock(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>
    privatestaticvoid ApplyTransformations(Page page, Section section)
    {
        switch (page.Rotate)
        {
            casePageRotate.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;
            }  
            casePageRotate.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;
            }
            casePageRotate.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;
            }
            casePageRotate.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>
    privatestaticBoundary ResizeBoundary(Boundary boundary, PageRotate rotation,
        double heightDelta = stampHeight)
    {
        if (boundary == null)
        {
            returnnull;
        }
        switch (rotation)
        {
            casePageRotate.Rotate90:
                returnnewBoundary(boundary.Left, boundary.Bottom, boundary.Right + 
                    heightDelta,
                    boundary.Top);
            casePageRotate.Rotate180:
                returnnewBoundary(boundary.Left, boundary.Bottom, boundary.Right,
                    boundary.Top + heightDelta);
            casePageRotate.Rotate270:
                returnnewBoundary(boundary.Left - heightDelta, boundary.Bottom,
                    boundary.Right + heightDelta, boundary.Top);
            casePageRotate.Rotate0:
            default:
                returnnewBoundary(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 .NETcan 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.

Viewing all articles
Browse latest Browse all 125

Trending Articles