diff --git a/engines/misc/pom.xml b/engines/misc/pom.xml
index d3ce1f47..a5cdf926 100644
--- a/engines/misc/pom.xml
+++ b/engines/misc/pom.xml
@@ -52,6 +52,13 @@
${dependency.pdfbox.version}
+
+
+ org.apache.commons
+ commons-imaging
+ ${dependency.imaging.version}
+
+
org.apache.poi
diff --git a/engines/misc/src/main/java/org/alfresco/transform/misc/transformers/ImageToPdfTransformer.java b/engines/misc/src/main/java/org/alfresco/transform/misc/transformers/ImageToPdfTransformer.java
index d6167cfb..64515757 100644
--- a/engines/misc/src/main/java/org/alfresco/transform/misc/transformers/ImageToPdfTransformer.java
+++ b/engines/misc/src/main/java/org/alfresco/transform/misc/transformers/ImageToPdfTransformer.java
@@ -2,7 +2,7 @@
* #%L
* Alfresco Transform Core
* %%
- * Copyright (C) 2005 - 2022 Alfresco Software Limited
+ * Copyright (C) 2005 - 2024 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* -
@@ -30,6 +30,8 @@ import static org.alfresco.transform.common.RequestParamMap.END_PAGE;
import static org.alfresco.transform.common.RequestParamMap.PDF_FORMAT;
import static org.alfresco.transform.common.RequestParamMap.PDF_ORIENTATION;
import static org.alfresco.transform.common.RequestParamMap.START_PAGE;
+import static org.apache.commons.imaging.formats.tiff.constants.TiffTagConstants.TIFF_TAG_XRESOLUTION;
+import static org.apache.commons.imaging.formats.tiff.constants.TiffTagConstants.TIFF_TAG_YRESOLUTION;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
@@ -45,6 +47,12 @@ import java.util.stream.Stream;
import org.alfresco.transform.base.TransformManager;
import org.alfresco.transform.base.util.CustomTransformerFileAdaptor;
+import org.apache.commons.imaging.Imaging;
+import org.apache.commons.imaging.ImagingException;
+import org.apache.commons.imaging.common.ImageMetadata;
+import org.apache.commons.imaging.formats.tiff.TiffField;
+import org.apache.commons.imaging.formats.tiff.TiffImageMetadata;
+import org.apache.commons.imaging.formats.tiff.taginfos.TagInfo;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
@@ -75,8 +83,9 @@ public class ImageToPdfTransformer implements CustomTransformerFileAdaptor
private static final String START_PAGE_GREATER_THAN_END_PAGE_ERROR_MESSAGE = "Start page number cannot be greater than end page.";
private static final String INVALID_OPTION_ERROR_MESSAGE = "Parameter '%s' is invalid: \"%s\" - it must be an integer.";
private static final String INVALID_IMAGE_ERROR_MESSAGE = "Image file (%s) format (%s) not supported by ImageIO.";
- private static final String DEFAULT_PDF_FORMAT_STRING = "DEFAULT";
+ private static final String DEFAULT_PDF_FORMAT_STRING = "DEFAULT"; // pdf format to use when no pdf format specified
private static final String DEFAULT_PDF_ORIENTATION_STRING = "DEFAULT";
+ private static final float PDFBOX_POINTS_PER_INCH = 72.0F;
@Override
public String getTransformerName()
@@ -99,6 +108,7 @@ public class ImageToPdfTransformer implements CustomTransformerFileAdaptor
final String pdfOrientation = parseOptionIfPresent(transformOptions, PDF_ORIENTATION, String.class).orElse(DEFAULT_PDF_ORIENTATION_STRING);
verifyOptions(startPage, endPage);
+ final Map resolution = determineImageResolution(imageFile);
final ImageReader imageReader = findImageReader(imageInputStream, imageFile.getName(), sourceMimetype);
for (int i = 0; i < imageReader.getNumImages(true); i++)
{
@@ -111,7 +121,7 @@ public class ImageToPdfTransformer implements CustomTransformerFileAdaptor
break;
}
- scaleAndDrawImage(pdfDocument, imageReader.read(i), pdfFormat, pdfOrientation);
+ scaleAndDrawImage(pdfDocument, imageReader.read(i), pdfFormat, pdfOrientation, resolution);
}
pdfDocument.save(pdfFile);
@@ -131,11 +141,22 @@ public class ImageToPdfTransformer implements CustomTransformerFileAdaptor
return imageReader;
}
- private void scaleAndDrawImage(final PDDocument pdfDocument, final BufferedImage bufferedImage, final String pdfFormat, final String pdfOrientation)
+ private void scaleAndDrawImage(final PDDocument pdfDocument, final BufferedImage bufferedImage, final String pdfFormat, final String pdfOrientation, final Map resolution)
throws IOException
{
final PDImageXObject image = LosslessFactory.createFromImage(pdfDocument, bufferedImage);
- final PDPage pdfPage = new PDPage(resolvePdfFormat(pdfFormat, pdfOrientation, image.getWidth(), image.getHeight()));
+
+ int imageWidth = image.getWidth();
+ int imageHeight = image.getHeight();
+ // if the image has a resolution which differs from pdfbox then adjust size in pixels according to pdfbox ppi
+ if (resolution.get("X") > 0 && resolution.get("X") != PDFBOX_POINTS_PER_INCH &&
+ resolution.get("Y") > 0 && resolution.get("Y") != PDFBOX_POINTS_PER_INCH)
+ {
+ imageWidth = (int)(((float)imageWidth / resolution.get("X")) * PDFBOX_POINTS_PER_INCH);
+ imageHeight = (int)(((float)imageHeight / resolution.get("Y")) * PDFBOX_POINTS_PER_INCH);
+ }
+
+ final PDPage pdfPage = new PDPage(resolvePdfFormat(pdfFormat, pdfOrientation, imageWidth, imageHeight));
pdfDocument.addPage(pdfPage);
try (PDPageContentStream pdfPageContent = new PDPageContentStream(pdfDocument, pdfPage))
{
@@ -257,4 +278,44 @@ public class ImageToPdfTransformer implements CustomTransformerFileAdaptor
throw new IllegalArgumentException(START_PAGE_GREATER_THAN_END_PAGE_ERROR_MESSAGE);
}
}
+
+ private static Map determineImageResolution(File imageFile)
+ {
+ int xResolution = 0;
+ int yResolution = 0;
+
+ try
+ {
+ final ImageMetadata metadata = Imaging.getMetadata(imageFile);
+ if (metadata instanceof TiffImageMetadata)
+ {
+ final TiffImageMetadata tiffImageMetadata = (TiffImageMetadata) metadata;
+ xResolution = findMetadataField(tiffImageMetadata, TIFF_TAG_XRESOLUTION);
+ yResolution = findMetadataField(tiffImageMetadata, TIFF_TAG_YRESOLUTION);
+ }
+ }
+ catch (IOException e)
+ {
+ // treat as though no resolution exists
+ }
+ return Map.of("X", xResolution, "Y", yResolution);
+ }
+
+ static private int findMetadataField(TiffImageMetadata tiffImageMetadata, TagInfo tagInfo)
+ {
+ int value = 0;
+ try
+ {
+ TiffField field = tiffImageMetadata.findField(tagInfo);
+ if (field != null)
+ {
+ value = field.getIntValue();
+ }
+ }
+ catch (ImagingException e)
+ {
+ // treat as though field not found
+ }
+ return value;
+ }
}
diff --git a/engines/misc/src/test/java/org/alfresco/transform/misc/transformers/ImageToPdfTransformerTest.java b/engines/misc/src/test/java/org/alfresco/transform/misc/transformers/ImageToPdfTransformerTest.java
index 64c81ed3..269ec388 100644
--- a/engines/misc/src/test/java/org/alfresco/transform/misc/transformers/ImageToPdfTransformerTest.java
+++ b/engines/misc/src/test/java/org/alfresco/transform/misc/transformers/ImageToPdfTransformerTest.java
@@ -2,7 +2,7 @@
* #%L
* Alfresco Transform Core
* %%
- * Copyright (C) 2005 - 2022 Alfresco Software Limited
+ * Copyright (C) 2005 - 2024 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* -
@@ -290,6 +290,41 @@ class ImageToPdfTransformerTest
}
}
+ static Stream imageFilesOfVariousSizeAndResolution()
+ {
+ return Stream.of(
+ Arguments.of(ImageFile.of("MNT-24205.tiff", MIMETYPE_IMAGE_TIFF), 612.0f, 792.0f),
+ Arguments.of(ImageFile.of("459x594-50.tif", MIMETYPE_IMAGE_TIFF), 660.0f, 855.0f),
+ Arguments.of(ImageFile.of("459x594-72.tif", MIMETYPE_IMAGE_TIFF), 459.0f, 594.0f),
+ Arguments.of(ImageFile.of("459x594-300.tif", MIMETYPE_IMAGE_TIFF), 110.0f, 142.0f),
+ Arguments.of(ImageFile.of("612x792-50.tif", MIMETYPE_IMAGE_TIFF), 881.0f, 1140.0f),
+ Arguments.of(ImageFile.of("612x792-72.tif", MIMETYPE_IMAGE_TIFF), 612.0f, 792.0f),
+ Arguments.of(ImageFile.of("612x792-300.tif", MIMETYPE_IMAGE_TIFF), 146.0f, 190.0f),
+ Arguments.of(ImageFile.of("765x990-50.tif", MIMETYPE_IMAGE_TIFF), 1101.0f, 1425.0f),
+ Arguments.of(ImageFile.of("765x990-72.tif", MIMETYPE_IMAGE_TIFF), 765.0f, 990.0f),
+ Arguments.of(ImageFile.of("765x990-300.tif", MIMETYPE_IMAGE_TIFF), 183.0f, 237.0f)
+ );
+ }
+
+ @ParameterizedTest
+ @MethodSource("imageFilesOfVariousSizeAndResolution")
+ void testTransformTiffToPDF_withVariousImageSizes(ImageFile imageFile, float expectedWidth, float expectedHeight) throws Exception
+ {
+ TransformOptions transformOptions = TransformOptions.of("DEFAULT");
+
+ File source = loadFile(imageFile.fileName);
+
+ // when
+ transformer.transform(imageFile.mimetype, MIMETYPE_PDF, transformOptions.toMap(), source, targetFile, transformManager);
+
+ try (PDDocument actualPdfDocument = PDDocument.load(targetFile))
+ {
+ assertNotNull(actualPdfDocument);
+ assertEquals(expectedWidth, actualPdfDocument.getPage(0).getMediaBox().getWidth(),"Pdf width");
+ assertEquals(expectedHeight,actualPdfDocument.getPage(0).getMediaBox().getHeight(),"Pdf height");
+ }
+ }
+
//----------------------------------------------- Helper methods and classes -----------------------------------------------
private static BiFunction unchangedRectangle()
diff --git a/engines/misc/src/test/resources/459x594-300.tif b/engines/misc/src/test/resources/459x594-300.tif
new file mode 100644
index 00000000..c3b64b88
Binary files /dev/null and b/engines/misc/src/test/resources/459x594-300.tif differ
diff --git a/engines/misc/src/test/resources/459x594-50.tif b/engines/misc/src/test/resources/459x594-50.tif
new file mode 100644
index 00000000..29d6d02b
Binary files /dev/null and b/engines/misc/src/test/resources/459x594-50.tif differ
diff --git a/engines/misc/src/test/resources/459x594-72.tif b/engines/misc/src/test/resources/459x594-72.tif
new file mode 100644
index 00000000..7bc05a79
Binary files /dev/null and b/engines/misc/src/test/resources/459x594-72.tif differ
diff --git a/engines/misc/src/test/resources/612x792-300.tif b/engines/misc/src/test/resources/612x792-300.tif
new file mode 100644
index 00000000..18fa08d9
Binary files /dev/null and b/engines/misc/src/test/resources/612x792-300.tif differ
diff --git a/engines/misc/src/test/resources/612x792-50.tif b/engines/misc/src/test/resources/612x792-50.tif
new file mode 100644
index 00000000..cd77e5ae
Binary files /dev/null and b/engines/misc/src/test/resources/612x792-50.tif differ
diff --git a/engines/misc/src/test/resources/612x792-72.tif b/engines/misc/src/test/resources/612x792-72.tif
new file mode 100644
index 00000000..51aea01b
Binary files /dev/null and b/engines/misc/src/test/resources/612x792-72.tif differ
diff --git a/engines/misc/src/test/resources/765x990-300.tif b/engines/misc/src/test/resources/765x990-300.tif
new file mode 100644
index 00000000..e449cafd
Binary files /dev/null and b/engines/misc/src/test/resources/765x990-300.tif differ
diff --git a/engines/misc/src/test/resources/765x990-50.tif b/engines/misc/src/test/resources/765x990-50.tif
new file mode 100644
index 00000000..3f094ae5
Binary files /dev/null and b/engines/misc/src/test/resources/765x990-50.tif differ
diff --git a/engines/misc/src/test/resources/765x990-72.tif b/engines/misc/src/test/resources/765x990-72.tif
new file mode 100644
index 00000000..a3c85025
Binary files /dev/null and b/engines/misc/src/test/resources/765x990-72.tif differ
diff --git a/engines/misc/src/test/resources/MNT-24205.tiff b/engines/misc/src/test/resources/MNT-24205.tiff
new file mode 100644
index 00000000..df419d3d
Binary files /dev/null and b/engines/misc/src/test/resources/MNT-24205.tiff differ
diff --git a/pom.xml b/pom.xml
index a9a4017d..eba30cca 100644
--- a/pom.xml
+++ b/pom.xml
@@ -27,6 +27,7 @@
2.16.1
2.9.2
5.2.5
+ 1.0.0-alpha5
2.2
1.78.1
@@ -160,6 +161,12 @@
pdfbox-tools
${dependency.pdfbox.version}
+
+
+ org.apache.commons
+ commons-imaging
+ ${dependency.imaging.version}
+
com.fasterxml.jackson