AAS.N
AAS.N

Reputation: 313

iTextSharp 7: Proper Way to Resize Stamps?

I recently got exposure to iText in general -- Having seen both version 5 and 7, I remain confused as to how stamps are implemented. I followed one of the example codes using iTextSharp 7 in order to add annotation:

 PdfReader reader = new PdfReader(source);
        PdfWriter writer = new PdfWriter(dest);
        PdfDocument pdfDoc = new PdfDocument(reader, writer);

        Rectangle crop = pdfDoc.GetPage(1).GetCropBox();
        Debug.WriteLine("CropBox Rectangle Dim "+crop);


        ImageData img = ImageDataFactory.Create(imgsrc);

        float iWidth = img.GetWidth();
        float iHeight = img.GetHeight();

        //Ignore the below statement
        if (crop.GetWidth() > crop.GetHeight())
        {
            w = crop.GetWidth();
            h = crop.GetHeight();
        }
        else
        {
            w = crop.GetHeight();
            h = crop.GetWidth();
        }


        Debug.WriteLine("Width = "+w+" and Height = "+h);


        Rectangle location = new Rectangle(crop.GetLeft(),crop.GetBottom(),iWidth,iHeight);

        //Creates a Stamp Bounding Box on "Location"
        PdfStampAnnotation stamp = new PdfStampAnnotation(location).SetStampName(new PdfName("Logo"));

        PdfFormXObject xObj = new PdfFormXObject(new Rectangle(iWidth, iHeight));
        PdfCanvas canvas = new PdfCanvas(xObj, pdfDoc);

        canvas.AddImage(img, 0, 0, false);
        stamp.SetNormalAppearance(xObj.GetPdfObject());



        stamp.SetFlags(PdfAnnotation.PRINT);

        pdfDoc.GetFirstPage().AddAnnotation(stamp);
        pdfDoc.Close();

So first and foremost, I notice I am using an ImageData object to input my image. However, I can't find any method to "scale" the image down -- something similar to the Image.scaleAbsolute. The output PDF ends up stamping correctly, but completely oversized. I think I understand what the FormXObject represents, but what is the Canvas for? What does it correspond to in the PDF. Any clarification could go a long way to aiding in future implementation.

Thanks

Upvotes: 2

Views: 1189

Answers (1)

mkl
mkl

Reputation: 96064

Scaling down

I can't find any method to "scale" the image down

As already explained in a comment, there are overloads of the AddImage method which do allow scaling the image, in particular:

/// <summary>Creates Image XObject from image and adds it to the specified position with specified width preserving aspect ratio.
///     </summary>
/// <param name="asInline">true if to add image as in-line.</param>
/// <returns>created XObject or null in case of in-line image (asInline = true).</returns>
public virtual PdfXObject AddImage(ImageData image, float x, float y, float width, bool asInline)

/// <summary>Creates Image XObject from image and adds it to canvas.</summary>
/// <param name="asInline">true if to add image as in-line.</param>
/// <returns>created XObject or null in case of in-line image (asInline = true).</returns>
public virtual PdfXObject AddImage(ImageData image, iText.Kernel.Geom.Rectangle rect, bool asInline)

/// <summary>Creates Image XObject from image and adds it to canvas.</summary>
/// <param name="image">
/// the
/// <c>PdfImageXObject</c>
/// object
/// </param>
/// <param name="a">an element of the transformation matrix</param>
/// <param name="b">an element of the transformation matrix</param>
/// <param name="c">an element of the transformation matrix</param>
/// <param name="d">an element of the transformation matrix</param>
/// <param name="e">an element of the transformation matrix</param>
/// <param name="f">an element of the transformation matrix</param>
/// <param name="asInline">true if to add image as in-line.</param>
/// <returns>created Image XObject or null in case of in-line image (asInline = true).</returns>
public virtual PdfXObject AddImage(ImageData image, float a, float b, float c, float d, float e, float f, 
    bool asInline)

The first of these overloads already helped the OP.

Backgrounds

I think I understand what the FormXObject represents, but what is the Canvas for? What does it correspond to in the PDF.

[...]

What is the difference between the "Location" rectangle and the PdfFormXObject rectangle

The location rectangle

As the PDF specification ISO 32000-1 (part 2 will be published this year) says

An annotation associates an object such as a note, sound, or movie with a location on a page of a PDF document

(section 12.5.1 Annotations - General)

One of the first things to fix for an annotation, therefore, is this location which is a rectangle,

The annotation rectangle, defining the location of the annotation on the page in default user space units.

(section 12.5.2 Annotation Dictionaries)

The coordinate system to use here coincides with the one defined for the page as MediaBox from which the CropBox is the displayed section.

In case of the OP's code this annotation rectangle is chosen here:

Rectangle location = new Rectangle(crop.GetLeft(),crop.GetBottom(),iWidth,iHeight);
PdfStampAnnotation stamp = new PdfStampAnnotation(location)...

I.e. the annotation rectangle location is located in the lower left of the visible page area and has width and height iWidth,iHeight.

The PdfFormXObject rectangle

But how does the annotation look like? Actually annotations can have different looks, e.g. depending on whether the cursor hovers over them or not. So, each annotation object may have one or more appearances defined in its appearance dictionary as individual appearance streams:

Appearance streams enable the annotation to be presented visually in different ways to reflect its interactions with the user. Each appearance stream is a form XObject: a self-contained content stream that shall be rendered inside the annotation rectangle.

(section 12.5.5 Appearance Streams)

So here the form XObject become part of the story: They are self contained and can also be referenced from other content streams, not only from an annotation.

They actually are so independent from the annotation that they have their own coordinate systems (given by its bounding box BBox) and are merely fitted into the annotation rectangle upon display, potentially after an affine transformation (given by its matrix Matrix):

Algorithm: Appearance streams

a) The appearance’s bounding box (specified by its BBox entry) shall be transformed, using Matrix, to produce a quadrilateral with arbitrary orientation. The transformed appearance box is the smallest upright rectangle that encompasses this quadrilateral.

b) A matrix A shall be computed that scales and translates the transformed appearance box to align with the edges of the annotation’s rectangle (specified by the Rect entry). A maps the lower-left corner (the corner with the smallest x and y coordinates) and the upper-right corner (the corner with the greatest x and y coordinates) of the transformed appearance box to the corresponding corners of the annotation’s rectangle.

c) Matrix shall be concatenated with A to form a matrix AA that maps from the appearance’s coordinate system to the annotation’s rectangle in default user space:

AA = Matrix * A

(section 12.5.5 Appearance Streams)

In case of the OP's code this bounding box is chosen here:

PdfFormXObject xObj = new PdfFormXObject(new Rectangle(iWidth, iHeight));

The matrix is not explicitly given and, therefore, defaults to the identity matrix.

I.e. the appearance's bounding box (the PdfFormXObject rectangle) has width and height iWidth, iHeight just like the annotation rectangle but its lower left is the origin (0, 0) of its coordinate system.

By the algorithm above it will smoothly be fit into the annotation rectangle without any distortions.

One might wonder why there are so many independent coordinate systems making such transformations necessary. The reason is simple: This allows the form XObjects to be easily re-used, and it makes the drawing instructions in it as simple as can be by choice of coordinate system.

The Canvas

PdfCanvas merely is a helper class providing a unified way in iText for creating content instructions for any content stream, here for the appearance XObject content stream.

Upvotes: 2

Related Questions