CJK
CJK

Reputation: 33

PDFBox: Draws images in different locations and sizes depending on input PDF

I've added images to a document using code as supplied by Nick Russler in answer to another question here https://stackoverflow.com/a/20618152/4652269

/**
 * Draw an image to the specified coordinates onto a single page. <br>
 * Also scaled the image with the specified factor.
 * 
 * @author Nick Russler
 * @param document PDF document the image should be written to.
 * @param pdfpage Page number of the page in which the image should be written to.
 * @param x X coordinate on the page where the left bottom corner of the image should be located. Regard that 0 is the left bottom of the pdf page.
 * @param y Y coordinate on the page where the left bottom corner of the image should be located.
 * @param scale Factor used to resize the image.
 * @param imageFilePath Filepath of the image that is written to the PDF.
 * @throws IOException
 */
public static void addImageToPage(PDDocument document, int pdfpage, int x, int y, float scale, String imageFilePath) throws IOException {   
    // Convert the image to TYPE_4BYTE_ABGR so PDFBox won't throw exceptions (e.g. for transparent png's).
    BufferedImage tmp_image = ImageIO.read(new File(imageFilePath));
    BufferedImage image = new BufferedImage(tmp_image.getWidth(), tmp_image.getHeight(), BufferedImage.TYPE_4BYTE_ABGR);        
    image.createGraphics().drawRenderedImage(tmp_image, null);

    PDXObjectImage ximage = new PDPixelMap(document, image);

    PDPage page = (PDPage)document.getDocumentCatalog().getAllPages().get(pdfpage);

    PDPageContentStream contentStream = new PDPageContentStream(document, page, true, true);
    contentStream.drawXObject(ximage, x, y, ximage.getWidth()*scale, ximage.getHeight()*scale);
    contentStream.close();
}

Basically the image is added to PDF page via an XObjectImage, however I am finding the same code gets different results based on the PDF being used. My guess is there seems to be some scale or transform in play but I cant work out where to find or correct this.

The page reports (from MediaBox PDRectangle) that it is (approximately) 600x800 (page units). but when I place my 500px image it displays differently based on the PDF in use. In one PDF it comes out at the width of the page (this a generated PDF - ie text and objects etc). In another PDF the image is about about half to a third the width (this PDF a scanned A4 TIF image on a PDF page - the image is about 1700x2300px - which lines up with the ratio of shrinking that is occurring to my image), and finally another TIF image on a PDF page, my added image also gets rotated through 90 degrees.

It appears obvious to me that I need to add or modify a transform - that the page has a default - or is remembering the last transform used, all I want is 1:1 ratio and 0 degrees rotation, but I don't know how to do this?

I've read about Matrix and AffineTransformations - but it's not making a lot of sense to me.

Is there a way to set the document or the drawXObject to be a very 1:1 scale with 0 degrees rotation?

Upvotes: 3

Views: 3007

Answers (1)

mkl
mkl

Reputation: 96064

My guess is there seems to be some scale or transform in play but I cant work out where to find or correct this.

Yes, your code

PDPageContentStream contentStream = new PDPageContentStream(document, page, true, true);

adds a new content stream at the end of the list of content streams of the page as is. This implies that it starts with the graphics state the formerly last stream ended with.

Some tools create content streams which end in the same state as they start in but this is not a requirement imposed by the PDF specification.

To make sure that your additions start with the default graphics state, you have to envelop the existing content in a pair of operators q...Q which save and restore the graphics state.

Fortunately PDFBox already does this for you if you use a different PDPageContentStream constructor, the one with three boolean parameters, and use true as value for the additional parameter:

PDPageContentStream contentStream = new PDPageContentStream(document, page, true, true, true);

Upvotes: 2

Related Questions