FlavorFlav
FlavorFlav

Reputation: 19

Get correct (rotated) image dimensions in PDF with pdfbox

I want render a PDF as image and draw the borders of all included images on it. For this I need the correct dimensions for the images on a page.

this is working with the following code:

public class PrintImageLocations extends PDFStreamEngine
{
    @Override
    protected void processOperator( Operator operator, List<COSBase> operands) throws IOException
    {
        String operation = operator.getName();
        if( "Do".equals(operation) )
        {
            COSName objectName = (COSName) operands.get( 0 );
            PDXObject xobject = getResources().getXObject( objectName );
            if( xobject instanceof PDImageXObject)
            {
                PDImageXObject image = (PDImageXObject)xobject;
                int imageWidth = image.getWidth();
                int imageHeight = image.getHeight();

                System.out.println("Found image " + objectName.getName());

                Matrix ctmNew = getGraphicsState().getCurrentTransformationMatrix();
                float imageXScale = ctmNew.getScalingFactorX();
                float imageYScale = ctmNew.getScalingFactorY();
                // position in user space units. 1 unit = 1/72 inch at 72 dpi
                System.out.println("position in PDF = " + ctmNew.getTranslateX() + ", " + ctmNew.getTranslateY() + " in user space units");
                           }
            else if(xobject instanceof PDFormXObject)
            {
                PDFormXObject form = (PDFormXObject)xobject;
                showForm(form);
            }
        }
        else
        {
            super.processOperator( operator, operands);
        }
    }

}

Source: PrintImageLocations.java

Output Example: position in PDF = 535.68, 97.79052 in user space units

Unfortunatly I have a problem when the page is rotated. There are lot of pdfs which return 90 on "getCurrentPage().getRotation()". For 90 degree I have to switch getTranslateX and getTranslateY values to get the correct position, but this only works specially for 90 degree. Is there any cool Matrix trasnformation which I can use for rotating the position?

I think in this code, the author tried to solve this rotation problem, but 1st) I don't understand what the transformations are doing and 2nd) it doesn't work correctly because after rotation one value in in negative.

Upvotes: 1

Views: 942

Answers (2)

FlavorFlav
FlavorFlav

Reputation: 19

OK... I thought I can gt it work with some math... unfortunatly it didn't work (I think the problem was sitting before the computer)

protected void processOperator(Operator operator, List<COSBase> operands) throws IOException {
        String operation = operator.getName();

        if ("Do".equals(operation)) {
            COSName objectName = (COSName) operands.get(0);
            PDXObject xobject = getResources().getXObject(objectName);

            if (xobject instanceof PDImageXObject) {
                PDImageXObject image = (PDImageXObject) xobject;

                Matrix ctmNew = getGraphicsState().getCurrentTransformationMatrix();
                float imageXScale = ctmNew.getScalingFactorX();
                float imageYScale = ctmNew.getScalingFactorY();

                int rotationDegree = getCurrentPage().getRotation();

                float pageHeight = this.getCurrentPage().getBBox().getHeight();
                float pageWidth = this.getCurrentPage().getBBox().getWidth();
                float translateX;
                float translateY;

                if (rotationDegree == 0) {
                    translateX = ctmNew.getTranslateX();
                    translateY = pageHeight - ctmNew.getTranslateY() - imageYScale;
                } else if (rotationDegree == 90) {
                    translateX = ctmNew.getTranslateY();
                    translateY = ctmNew.getTranslateX() - imageYScale;
                } else if (rotationDegree == 270) {
                    translateX = pageHeight - ctmNew.getTranslateY();
                    translateY = pageWidth - ctmNew.getTranslateX() - imageYScale;
                } else if (rotationDegree == 180) {
                    translateX=pageWidth - ctmNew.getTranslateX() -imageXScale ;
                    translateY=pageHeight - ctmNew.getTranslateY() - imageYScale;
                    logger.log(Level.INFO, "image rotation 180 degree. not fully tested yet");
                }
                else {
                    throw new RuntimeException("");
                }

                PdfImage pdfImage = new PdfImage(objectName.getName(), translateX, translateY, imageXScale, imageYScale, image.getImage());
                pdfImages.add(pdfImage);

            } else if (xobject instanceof PDFormXObject) {
                PDFormXObject form = (PDFormXObject) xobject;
                showForm(form);
            }
        } else {
            super.processOperator(operator, operands);
        }
}

Upvotes: 0

Travis
Travis

Reputation: 2188

Rotation

You can perform a rotation in Euclidean space using the following rotation matrices.

Counter-clockwise:

R = ⎡ cosθ -sinθ ⎤
    ⎣ sinθ  cosθ ⎦

Clockwise:

R = ⎡  cosθ  sinθ ⎤
    ⎣ -sinθ  cosθ ⎦

Each matrix will rotate points in the 2-dimensional Cartesian plane through an angle θ about the origin. This technique assumes that each point is represented a column vector v. The new value of each point is calculated by R * v where * represents matrix multiplication.


"Negative" Values

This technique will produce negative values (relative to the initial values, anyway) for at least some points on at least one of the two dimensions. In order to correct this relative to the Cartesian origin, translate the rotated image "up" by min(y) - min(y') and "right" by min(x) - min(x'), where min(d) represents the minimum value along that dimension of any point.


Using a Library

So that you don't have to do all the boilerplate on this yourself, you should take a look at the AffineTransform class.

Upvotes: 0

Related Questions