Search code examples
dictionaryannotationsitextareameasure

Create measure dictionary for area annotation in iText


The supposed value for this would is 15.2 sq cm. however, when annotation is moved, it becomes 0.04 sq cm.

I got this data from my application where area is computed as 9658.6572265625 and its calibration value is 0.00157889 which results in 15.2 value.

when the corresponding coordinates in pdf space are provided (see code below), the area computed is 5433.001953125.

so i compute the calibration value in pdf space like this.

ratio = area / pdfArea pdfCalibrationValue = 0.00157889 * ratio;

the result is 0.002806911838696635. which if computed

5433.001953125 x 0.002806911838696635 = 15.2

so i am wondering why the result becomes 0.04.

Thoughts?

public class Test {

    public static void main(String[] args) throws Exception {
        PdfReader reader = new PdfReader("src.pdf");
        PdfStamper stamper = new PdfStamper(reader, new FileOutputStream("result.pdf"));

        Rectangle location = new Rectangle(426.582f, 514.291f, 559.0f, 613.818f);
        float[] floats = new float[] { 
            427.582f, 582.873f,
            493.036f, 515.291f,
            558.0f, 554.237f,
            527.4f, 612.818f,
            464.727f, 564.709f,
            427.582f, 582.873f
        };

        PdfArray pdfVertices= new PdfArray(floats);
        float calib = 0.002806911838696635f;

        PdfAnnotation stamp = PdfAnnotation.createPolygonPolyline(stamper.getWriter(), 
            location, "15.2 sq cm", true, new PdfArray(pdfVertices));
        stamp.setColor(BaseColor.RED);
        stamp.setBorderStyle(new PdfBorderDictionary(1, PdfBorderDictionary.STYLE_SOLID));
        stamp.put(PdfName.SUBTYPE, PdfName.POLYGON);
        stamp.put(new PdfName("IT"), new PdfName("PolygonDimension"));
        stamp.put(PdfName.MEASURE, createMeasureDictionary(calib));

        stamper.addAnnotation(stamp, 1);
        stamper.close();
        reader.close();
    }

    private static PdfDictionary createMeasureDictionary(float pdfCalibrationValue) {
        String unit = "cm";

        PdfDictionary measureDictionary = new PdfDictionary();
        measureDictionary.put(PdfName.TYPE, PdfName.MEASURE);
        measureDictionary.put(PdfName.R, new PdfString("1 " + unit + " = 1 " + unit));

        PdfDictionary xDictionary = new PdfDictionary();
        xDictionary.put(PdfName.TYPE, PdfName.NUMBERFORMAT);
        xDictionary.put(PdfName.U, new PdfString(unit));
        xDictionary.put(PdfName.C, new PdfNumber(pdfCalibrationValue));
        PdfArray xarr = new PdfArray();
        xarr.add(xDictionary);
        measureDictionary.put(PdfName.X, xarr);

        PdfDictionary dDictionary = new PdfDictionary();
        dDictionary.put(PdfName.TYPE, PdfName.NUMBERFORMAT);
        dDictionary.put(PdfName.U, new PdfString(unit));
        dDictionary.put(PdfName.C, new PdfNumber(1));
        PdfArray darr = new PdfArray();
        darr.add(dDictionary);
        measureDictionary.put(PdfName.D, darr);

        PdfDictionary aDictionary = new PdfDictionary();
        aDictionary.put(PdfName.TYPE, PdfName.NUMBERFORMAT);
        aDictionary.put(PdfName.U, new PdfString("sq " + unit));
        aDictionary.put(PdfName.C, new PdfNumber(1));
        PdfArray aarr = new PdfArray();
        aarr.add(aDictionary);
        measureDictionary.put(PdfName.A, aarr);

        return measureDictionary;
    }        

}

Solution

  • You have calculated a factor to translate the areas:

    the result is 0.002806911838696635. which if computed

    5433.001953125 x 0.002806911838696635 = 15.2

    But then you use this factor meant for areas unchanged as conversion factor in the X number format array.

    The X number format array is the number format array for measurement of change along the x axis and, if Y is not present, along the y axis as well.

    Thus, as you don't have a Y entry, your factor for areas must be the conversion factor in X squared!

    In other words, use the square root of your area conversion factor as X conversion factor, i.e. replace

    float calib = 0.002806911838696635f;
    

    by

    float calib = (float)Math.sqrt(0.002806911838696635);
    

    The result now is much better:

    screenshot

    But it is not exactly your 15.2 cm². Thus, I checked your numbers, and indeed, your value of 5433.001953125 for the polygone area is slightly off, it should be around 5388.9613.

    Using this more correct value I replaced the line above again, this time by:

    float calib = (float)Math.sqrt(15.2/5388.96);
    

    and the result:

    screenshot