Fix bug wrong orientation caused by EXIF
This commit is contained in:
@@ -2,6 +2,7 @@ package marketing.heyday.hartmann.fotodocumentation.core.utils;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
@@ -17,13 +18,19 @@ import javax.imageio.stream.ImageOutputStream;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
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.ExifIFD0Directory;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* <p>Copyright: Copyright (c) 2024</p>
|
||||
* <p>Company: heyday Marketing GmbH</p>
|
||||
* @author <a href="mailto:p.verboom@heyday.marketing">Patrick Verboom</a>
|
||||
* @version 1.0
|
||||
*
|
||||
*
|
||||
* created: 2 Feb 2026
|
||||
*/
|
||||
|
||||
@@ -44,10 +51,10 @@ public class ImageUtil {
|
||||
public byte[] getImage(String base64, int size) {
|
||||
byte[] original = Base64.getDecoder().decode(base64);
|
||||
return switch (size) {
|
||||
case 1 -> original;
|
||||
case 1 -> applyExifOrientation(original);
|
||||
case 2 -> normal(original);
|
||||
case 3 -> thumbnail(original);
|
||||
default -> original;
|
||||
default -> applyExifOrientation(original);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -61,16 +68,27 @@ public class ImageUtil {
|
||||
|
||||
private byte[] resize(byte[] original, int maxWidth, float quality) {
|
||||
try {
|
||||
int orientation = getExifOrientation(original);
|
||||
BufferedImage image = ImageIO.read(new ByteArrayInputStream(original));
|
||||
if (image == null) {
|
||||
LOG.error("Failed to read image from byte array");
|
||||
return original;
|
||||
}
|
||||
|
||||
// For rotated images (orientation 5, 6, 7, 8), width and height are swapped
|
||||
int effectiveWidth = (orientation >= 5 && orientation <= 8) ? image.getHeight() : image.getWidth();
|
||||
|
||||
// If no resize needed and no orientation fix needed, return original
|
||||
if (effectiveWidth <= maxWidth && orientation == 1) {
|
||||
return original;
|
||||
}
|
||||
|
||||
image = applyOrientation(image, orientation);
|
||||
|
||||
int originalWidth = image.getWidth();
|
||||
|
||||
if (originalWidth <= maxWidth) {
|
||||
return original;
|
||||
return writeJpeg(image, quality);
|
||||
}
|
||||
|
||||
double scale = (double) maxWidth / originalWidth;
|
||||
@@ -92,6 +110,104 @@ public class ImageUtil {
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] applyExifOrientation(byte[] original) {
|
||||
try {
|
||||
int orientation = getExifOrientation(original);
|
||||
if (orientation == 1) {
|
||||
return original;
|
||||
}
|
||||
|
||||
BufferedImage image = ImageIO.read(new ByteArrayInputStream(original));
|
||||
if (image == null) {
|
||||
return original;
|
||||
}
|
||||
|
||||
BufferedImage rotated = applyOrientation(image, orientation);
|
||||
return writeJpeg(rotated, 1.0F);
|
||||
} catch (IOException e) {
|
||||
LOG.error("Failed to apply EXIF orientation", e);
|
||||
return original;
|
||||
}
|
||||
}
|
||||
|
||||
private int getExifOrientation(byte[] imageBytes) {
|
||||
try {
|
||||
Metadata metadata = ImageMetadataReader.readMetadata(new ByteArrayInputStream(imageBytes));
|
||||
ExifIFD0Directory directory = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);
|
||||
if (directory != null && directory.containsTag(ExifIFD0Directory.TAG_ORIENTATION)) {
|
||||
return directory.getInt(ExifIFD0Directory.TAG_ORIENTATION);
|
||||
}
|
||||
} catch (ImageProcessingException | IOException | MetadataException e) {
|
||||
LOG.debug("Could not read EXIF orientation: " + e.getMessage());
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
private BufferedImage applyOrientation(BufferedImage image, int orientation) {
|
||||
int width = image.getWidth();
|
||||
int height = image.getHeight();
|
||||
|
||||
AffineTransform transform = new AffineTransform();
|
||||
int newWidth = width;
|
||||
int newHeight = height;
|
||||
|
||||
switch (orientation) {
|
||||
case 1 -> {
|
||||
return image;
|
||||
}
|
||||
case 2 -> {
|
||||
transform.scale(-1.0, 1.0);
|
||||
transform.translate(-width, 0);
|
||||
}
|
||||
case 3 -> {
|
||||
transform.translate(width, height);
|
||||
transform.rotate(Math.PI);
|
||||
}
|
||||
case 4 -> {
|
||||
transform.scale(1.0, -1.0);
|
||||
transform.translate(0, -height);
|
||||
}
|
||||
case 5 -> {
|
||||
newWidth = height;
|
||||
newHeight = width;
|
||||
transform.rotate(-Math.PI / 2);
|
||||
transform.scale(-1.0, 1.0);
|
||||
}
|
||||
case 6 -> {
|
||||
newWidth = height;
|
||||
newHeight = width;
|
||||
transform.translate(height, 0);
|
||||
transform.rotate(Math.PI / 2);
|
||||
}
|
||||
case 7 -> {
|
||||
newWidth = height;
|
||||
newHeight = width;
|
||||
transform.scale(-1.0, 1.0);
|
||||
transform.translate(-height, 0);
|
||||
transform.translate(0, width);
|
||||
transform.rotate(3 * Math.PI / 2);
|
||||
}
|
||||
case 8 -> {
|
||||
newWidth = height;
|
||||
newHeight = width;
|
||||
transform.translate(0, width);
|
||||
transform.rotate(-Math.PI / 2);
|
||||
}
|
||||
default -> {
|
||||
return image;
|
||||
}
|
||||
}
|
||||
|
||||
BufferedImage rotated = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);
|
||||
Graphics2D g2d = rotated.createGraphics();
|
||||
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
||||
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
|
||||
g2d.drawImage(image, transform, null);
|
||||
g2d.dispose();
|
||||
|
||||
return rotated;
|
||||
}
|
||||
|
||||
private byte[] writeJpeg(BufferedImage image, float quality) throws IOException {
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
ImageWriter writer = ImageIO.getImageWritersByFormatName("jpg").next();
|
||||
|
||||
Reference in New Issue
Block a user