summaryrefslogtreecommitdiff
path: root/pdf-over-commons
diff options
context:
space:
mode:
authorJakob Heher <jakob.heher@iaik.tugraz.at>2022-08-03 13:00:26 +0200
committerJakob Heher <jakob.heher@iaik.tugraz.at>2022-08-03 13:00:26 +0200
commitf9def921178f2c1995b28900e80e2a338257729b (patch)
tree46a9143f7454c6f11451175123c0600bb4d54ca8 /pdf-over-commons
parenta25b8b2fa18e7789968dbeb802df2dfade577205 (diff)
downloadpdf-over-f9def921178f2c1995b28900e80e2a338257729b.tar.gz
pdf-over-f9def921178f2c1995b28900e80e2a338257729b.tar.bz2
pdf-over-f9def921178f2c1995b28900e80e2a338257729b.zip
refactor out EXIF rotation nonsense into its self-contained class
Diffstat (limited to 'pdf-over-commons')
-rw-r--r--pdf-over-commons/pom.xml4
-rw-r--r--pdf-over-commons/src/main/java/at/asit/pdfover/Util.java147
2 files changed, 151 insertions, 0 deletions
diff --git a/pdf-over-commons/pom.xml b/pdf-over-commons/pom.xml
index c198773f..385c3136 100644
--- a/pdf-over-commons/pom.xml
+++ b/pdf-over-commons/pom.xml
@@ -22,6 +22,10 @@
<version>4.23</version>
<scope>compile</scope>
</dependency>
+ <dependency>
+ <groupId>com.drewnoakes</groupId>
+ <artifactId>metadata-extractor</artifactId>
+ </dependency>
</dependencies>
<build>
diff --git a/pdf-over-commons/src/main/java/at/asit/pdfover/Util.java b/pdf-over-commons/src/main/java/at/asit/pdfover/Util.java
new file mode 100644
index 00000000..ff33fb5e
--- /dev/null
+++ b/pdf-over-commons/src/main/java/at/asit/pdfover/Util.java
@@ -0,0 +1,147 @@
+package at.asit.pdfover;
+
+import java.awt.Graphics2D;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+import java.util.Iterator;
+
+import javax.imageio.ImageIO;
+import javax.imageio.ImageReadParam;
+import javax.imageio.ImageReader;
+import javax.imageio.stream.ImageInputStream;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.drew.imaging.ImageMetadataReader;
+import com.drew.imaging.ImageProcessingException;
+import com.drew.metadata.Metadata;
+import com.drew.metadata.MetadataException;
+import com.drew.metadata.exif.ExifDirectoryBase;
+import com.drew.metadata.exif.ExifIFD0Directory;
+
+class EXIFRotation {
+ private static final Logger log = LoggerFactory.getLogger(EXIFRotation.class);
+ /**
+ * rotate by this times Math.PI / 2
+ */
+ final int rotationInQuarters;
+ /**
+ * whether you should mirror (left-right) the image AFTER rotation
+ */
+ final boolean shouldMirrorLR;
+
+ private EXIFRotation(int rotateQuarters, boolean mirrorLR) {
+ this.rotationInQuarters = rotateQuarters;
+ this.shouldMirrorLR = mirrorLR;
+ }
+
+ public static final EXIFRotation NONE = new EXIFRotation(0, false);
+
+ private static final EXIFRotation[] rotationForIndex = {
+ /* invalid (0) */ NONE,
+ /* 1 */ NONE,
+ /* 2 */ new EXIFRotation(0, true),
+ /* 3 */ new EXIFRotation(2, false),
+ /* 4 */ new EXIFRotation(2, true),
+ /* 5 */ new EXIFRotation(1, true),
+ /* 6 */ new EXIFRotation(1, false),
+ /* 7 */ new EXIFRotation(3, true),
+ /* 8 */ new EXIFRotation(3, false)
+ };
+
+ static EXIFRotation For(File file) throws IOException
+ {
+ try
+ {
+ Metadata metadata = ImageMetadataReader.readMetadata(file);
+ if (metadata == null)
+ return NONE;
+ ExifIFD0Directory metaDir = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);
+ if (metaDir == null)
+ return NONE;
+ int orientation = metaDir.getInt(ExifDirectoryBase.TAG_ORIENTATION);
+ if (rotationForIndex.length <= orientation)
+ {
+ log.warn("Invalid orientation {} in EXIF metadata for {}", orientation, file.getName());
+ return NONE;
+ }
+ return rotationForIndex[orientation];
+ } catch (ImageProcessingException | MetadataException e) {
+ log.error("Failed to read EXIF metadata for {}", file.getName(), e);
+ return NONE;
+ }
+ }
+}
+
+public final class Util {
+
+ /**
+ * ImageIO.read, except it honors EXIF rotation metadata
+ * (which the default, for some reason, does not)
+ */
+ public static final BufferedImage readImageWithEXIFRotation(File input) throws IOException
+ {
+ if (input == null)
+ throw new IllegalArgumentException("input == null");
+ if (!input.canRead())
+ throw new IllegalArgumentException("cannot read input");
+
+ ImageInputStream stream = ImageIO.createImageInputStream(input);
+ if (stream == null)
+ throw new RuntimeException("Failed to create ImageInputStream for some reason?");
+
+ Iterator<ImageReader> iter = ImageIO.getImageReaders(stream);
+ if (!iter.hasNext())
+ {
+ stream.close();
+ return null;
+ }
+
+ ImageReader reader = iter.next();
+ boolean isJPEG = reader.getFormatName().equals("JPEG");
+ ImageReadParam param = reader.getDefaultReadParam();
+ reader.setInput(stream, true, false);
+ BufferedImage image;
+ try {
+ image = reader.read(0, param);
+ } finally {
+ reader.dispose();
+ stream.close();
+ }
+
+ if (!isJPEG)
+ return image;
+
+ EXIFRotation rotation = EXIFRotation.For(input);
+ if (rotation.rotationInQuarters > 0)
+ {
+ boolean isSideways = ((rotation.rotationInQuarters % 2) == 1);
+ int sourceWidth = image.getWidth();
+ int sourceHeight = image.getHeight();
+ int targetWidth = isSideways ? sourceHeight : sourceWidth;
+ int targetHeight = isSideways ? sourceWidth : sourceHeight;
+
+ BufferedImage result = new BufferedImage(targetWidth, targetHeight, image.getType());
+ Graphics2D g = result.createGraphics();
+ g.translate((targetWidth - sourceWidth)/2, (targetHeight - sourceHeight)/2);
+ g.rotate(rotation.rotationInQuarters * Math.PI / 2, sourceWidth/2, sourceHeight/2);
+ g.drawRenderedImage(image, null);
+ g.dispose();
+ image = result;
+ }
+
+ if (rotation.shouldMirrorLR)
+ {
+ int width = image.getWidth();
+ int height = image.getHeight();
+ BufferedImage result = new BufferedImage(width, height, image.getType());
+ Graphics2D g = result.createGraphics();
+ g.drawImage(image, width, 0, -width, height, null);
+ g.dispose();
+ image = result;
+ }
+ return image;
+ }
+}