Skip to content

Commit bd1ac04

Browse files
committed
Improve float arithmetic isIdentityMatrix method
DEVSIX-4620
1 parent 4cb1c09 commit bd1ac04

File tree

4 files changed

+90
-15
lines changed

4 files changed

+90
-15
lines changed

kernel/src/main/java/com/itextpdf/kernel/pdf/canvas/PdfCanvas.java

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,8 @@ public class PdfCanvas implements Serializable {
173173
private static final PdfSpecialCs.Pattern pattern = new PdfSpecialCs.Pattern();
174174
private static final long serialVersionUID = -4706222391732334562L;
175175

176+
private static final float IDENTITY_MATRIX_EPS = 1e-4f;
177+
176178
/**
177179
* a LIFO stack of graphics state saved states.
178180
*/
@@ -1995,6 +1997,8 @@ public PdfXObject addImage(ImageData image, Rectangle rect, boolean asInline) {
19951997
* @param asInline true if to add image as in-line
19961998
* @return the created imageXObject or null in case of in-line image (asInline = true)
19971999
* @see #concatMatrix(double, double, double, double, double, double)
2000+
* @see PdfXObject#calculateProportionallyFitRectangleWithWidth(PdfXObject, float, float, float)
2001+
* @see PdfXObject#calculateProportionallyFitRectangleWithHeight(PdfXObject, float, float, float)
19982002
*/
19992003
public PdfXObject addImageFittedIntoRectangle(ImageData image, Rectangle rect, boolean asInline) {
20002004
return addImageWithTransformationMatrix(image, rect.getWidth(), 0, 0, rect.getHeight(),
@@ -2124,7 +2128,7 @@ public PdfXObject addImage(ImageData image, float x, float y, float height, bool
21242128
*/
21252129
public PdfCanvas addXObjectWithTransformationMatrix(PdfXObject xObject, float a, float b, float c, float d, float e, float f) {
21262130
if (xObject instanceof PdfFormXObject) {
2127-
return addFormWithTransformationMatrix((PdfFormXObject) xObject, a, b, c, d, e, f);
2131+
return addFormWithTransformationMatrix((PdfFormXObject) xObject, a, b, c, d, e, f, true);
21282132
} else if (xObject instanceof PdfImageXObject) {
21292133
return addImageWithTransformationMatrix(xObject, a, b, c, d, e, f);
21302134
} else {
@@ -2200,6 +2204,8 @@ public PdfCanvas addXObject(PdfXObject xObject, float x, float y) {
22002204
* @param xObject the xObject to add
22012205
* @param rect the rectangle in which the xObject will be fitted
22022206
* @return the current canvas
2207+
* @see PdfXObject#calculateProportionallyFitRectangleWithWidth(PdfXObject, float, float, float)
2208+
* @see PdfXObject#calculateProportionallyFitRectangleWithHeight(PdfXObject, float, float, float)
22032209
*/
22042210
public PdfCanvas addXObjectFittedIntoRectangle(PdfXObject xObject, Rectangle rect) {
22052211
if (xObject instanceof PdfFormXObject) {
@@ -2308,7 +2314,7 @@ public PdfCanvas addXObject(PdfXObject xObject, float x, float y, float height,
23082314
*/
23092315
public PdfCanvas addXObject(PdfXObject xObject) {
23102316
if (xObject instanceof PdfFormXObject) {
2311-
return addFormWithTransformationMatrix((PdfFormXObject) xObject, 1, 0, 0, 1, 0, 0);
2317+
return addFormWithTransformationMatrix((PdfFormXObject) xObject, 1, 0, 0, 1, 0, 0, false);
23122318
} else if (xObject instanceof PdfImageXObject) {
23132319
return addImageAt((PdfImageXObject) xObject, 0, 0);
23142320
} else {
@@ -2506,17 +2512,21 @@ protected void addInlineImage(PdfImageXObject imageXObject, float a, float b, fl
25062512
* Adds {@link PdfFormXObject} to canvas.
25072513
*
25082514
* @param form the formXObject to add
2509-
* @param a an element of the transformation matrix
2510-
* @param b an element of the transformation matrix
2511-
* @param c an element of the transformation matrix
2512-
* @param d an element of the transformation matrix
2513-
* @param e an element of the transformation matrix
2514-
* @param f an element of the transformation matrix
2515+
* @param a an element of the transformation matrix
2516+
* @param b an element of the transformation matrix
2517+
* @param c an element of the transformation matrix
2518+
* @param d an element of the transformation matrix
2519+
* @param e an element of the transformation matrix
2520+
* @param f an element of the transformation matrix
2521+
* @param writeIdentityMatrix true if the matrix is written in any case, otherwise if the
2522+
* {@link #isIdentityMatrix(float, float, float, float, float, float)} method indicates
2523+
* that the matrix is identity, the matrix will not be written
25152524
* @return current canvas
25162525
*/
2517-
private PdfCanvas addFormWithTransformationMatrix(PdfFormXObject form, float a, float b, float c, float d, float e, float f) {
2526+
private PdfCanvas addFormWithTransformationMatrix(PdfFormXObject form, float a, float b, float c,
2527+
float d, float e, float f, boolean writeIdentityMatrix) {
25182528
saveState();
2519-
if (!PdfCanvas.isIdentityMatrix(a, b, c, d, e, f)) {
2529+
if (writeIdentityMatrix || !PdfCanvas.isIdentityMatrix(a, b, c, d, e, f)) {
25202530
concatMatrix(a, b, c, d, e, f);
25212531
}
25222532
PdfName name = resources.addForm(form);
@@ -2537,7 +2547,7 @@ private PdfCanvas addFormWithTransformationMatrix(PdfFormXObject form, float a,
25372547
* @param f an element of the transformation matrix
25382548
* @return current canvas
25392549
* @deprecated will be removed in 7.2, use
2540-
* {@link #addFormWithTransformationMatrix(PdfFormXObject, float, float, float, float, float, float)} instead
2550+
* {@link #addFormWithTransformationMatrix(PdfFormXObject, float, float, float, float, float, float, boolean)} instead
25412551
*/
25422552
@Deprecated
25432553
private PdfCanvas addForm(PdfFormXObject form, float a, float b, float c, float d, float e, float f) {
@@ -2566,7 +2576,7 @@ private PdfCanvas addFormAt(PdfFormXObject form, float x, float y) {
25662576
y + bBoxMax.get(Vector.I2) - bBoxMin.get(Vector.I2), 1);
25672577

25682578
float[] result = PdfCanvas.calculateTransformationMatrix(rectMin, rectMax, bBoxMin, bBoxMax);
2569-
return addFormWithTransformationMatrix(form, result[0], result[1], result[2], result[3], result[4], result[5]);
2579+
return addFormWithTransformationMatrix(form, result[0], result[1], result[2], result[3], result[4], result[5], false);
25702580
}
25712581

25722582
/**
@@ -2640,7 +2650,7 @@ private PdfCanvas addFormFittedIntoRectangle(PdfFormXObject form, Rectangle rect
26402650
Vector rectMax = new Vector(rect.getRight(), rect.getTop(), 1);
26412651

26422652
float[] result = PdfCanvas.calculateTransformationMatrix(rectMin, rectMax, bBoxMin, bBoxMax);
2643-
return addFormWithTransformationMatrix(form, result[0], result[1], result[2], result[3], result[4], result[5]);
2653+
return addFormWithTransformationMatrix(form, result[0], result[1], result[2], result[3], result[4], result[5], false);
26442654
}
26452655

26462656
/**
@@ -2805,7 +2815,7 @@ private static float[] calculateTransformationMatrix(Vector expectedMin, Vector
28052815
}
28062816

28072817
private static boolean isIdentityMatrix(float a, float b, float c, float d, float e, float f) {
2808-
return Float.compare(a, 1) == 0 && Float.compare(b, 0) == 0 && Float.compare(c, 0) == 0 &&
2809-
Float.compare(d, 1) == 0 && Float.compare(e, 0) == 0 && Float.compare(f, 0) == 0;
2818+
return Math.abs(1 - a) < IDENTITY_MATRIX_EPS && Math.abs(b) < IDENTITY_MATRIX_EPS && Math.abs(c) < IDENTITY_MATRIX_EPS &&
2819+
Math.abs(1 - d) < IDENTITY_MATRIX_EPS && Math.abs(e) < IDENTITY_MATRIX_EPS && Math.abs(f) < IDENTITY_MATRIX_EPS;
28102820
}
28112821
}

kernel/src/test/java/com/itextpdf/kernel/pdf/canvas/PdfCanvasXObjectTest.java

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -583,4 +583,69 @@ protected CustomPdfXObject(PdfStream pdfObject) {
583583
super(pdfObject);
584584
}
585585
}
586+
587+
// Adds PdfFormXObject with matrix close to the identity matrix tests block
588+
589+
590+
@Test
591+
public void addFormXObjectWithUserIdentityMatrixTest() throws IOException, InterruptedException {
592+
final String fileName = "addFormXObjectWithUserIdentityMatrixTest.pdf";
593+
final String destPdf = DESTINATION_FOLDER + fileName;
594+
final String cmpPdf = SOURCE_FOLDER + "cmp_" + fileName;
595+
FileOutputStream fos = new FileOutputStream(destPdf);
596+
PdfWriter writer = new PdfWriter(fos);
597+
PdfDocument document = new PdfDocument(writer);
598+
599+
PdfFormXObject formXObject = new PdfFormXObject(new Rectangle(0, 0, 20, 20));
600+
new PdfCanvas(formXObject, document).circle(10, 10, 10).fill();
601+
602+
PdfPage page = document.addNewPage();
603+
PdfCanvas canvas = new PdfCanvas(page);
604+
// It should be written because it is user matrix
605+
canvas.addXObjectWithTransformationMatrix(formXObject, 1.00011f, 0, 0, 1, 0, 0);
606+
canvas.release();
607+
page.flush();
608+
609+
page = document.addNewPage();
610+
canvas = new PdfCanvas(page);
611+
// It should be written because it is user matrix
612+
canvas.addXObjectWithTransformationMatrix(formXObject, 1.00009f, 0, 0, 1, 0, 0);
613+
canvas.release();
614+
page.flush();
615+
616+
document.close();
617+
618+
Assert.assertNull(new CompareTool().compareByContent(destPdf, cmpPdf, DESTINATION_FOLDER, "diff_"));
619+
}
620+
621+
@Test
622+
public void addFormXObjectWithIdentityMatrixTest() throws IOException, InterruptedException {
623+
final String fileName = "addFormXObjectWithIdentityMatrixTest.pdf";
624+
final String destPdf = DESTINATION_FOLDER + fileName;
625+
final String cmpPdf = SOURCE_FOLDER + "cmp_" + fileName;
626+
FileOutputStream fos = new FileOutputStream(destPdf);
627+
PdfWriter writer = new PdfWriter(fos);
628+
PdfDocument document = new PdfDocument(writer);
629+
630+
PdfFormXObject formXObject = new PdfFormXObject(new Rectangle(0, 0, 20, 20));
631+
new PdfCanvas(formXObject, document).circle(10, 10, 10).fill();
632+
633+
PdfPage page = document.addNewPage();
634+
PdfCanvas canvas = new PdfCanvas(page);
635+
// It should be written because it is larger then PdfCanvas#IDENTITY_MATRIX_EPS
636+
canvas.addXObjectAt(formXObject, 0.00011f, 0);
637+
canvas.release();
638+
page.flush();
639+
640+
page = document.addNewPage();
641+
canvas = new PdfCanvas(page);
642+
// It shouldn't be written because it is less then PdfCanvas#IDENTITY_MATRIX_EPS
643+
canvas.addXObjectAt(formXObject, 0.00009f, 0);
644+
canvas.release();
645+
page.flush();
646+
647+
document.close();
648+
649+
Assert.assertNull(new CompareTool().compareByContent(destPdf, cmpPdf, DESTINATION_FOLDER, "diff_"));
650+
}
586651
}

0 commit comments

Comments
 (0)