I have some server code that is generating thumbnails when an image is uploaded. The issue is that when the image was taken and the camera/device was rotated, the thumbnails are rotated, even though the full size images themselves are displayed in the correct orientation in any image viewing software. This is only happening with jpgs.
Using Preview on OSX, I can see that jpgs have orientation metadata embedded within. When I use ImageTools (Grails Plugin) to generate a thumbnail, the EXIF metadata is not in the thumbnail, which is why the thumbnails appear rotated.
Via offline conversations, I have learned that while it is relatively easy to read EXIF metadata, there is no easy way to write it, which is why the data is lost when generating a jpg thumbnail.
So it seems I have two options:
Does anyone know of any other options?
Rotate a pictureMove the mouse pointer over the image. Two buttons with arrow will appear at the bottom. Select either Rotate the image 90 degrees to the left or Rotate the image 90 degrees to the right. If you want to keep the picture rotated in this way, click Save.
EXIF data is useful information about a JPEG image, hidden inside the file. When images are photographed, digital cameras use orientation sensors to store an EXIF orientation value for how the camera is held. There are 8 possible values (not just landscape and portrait!).
IrfanView. IrfanView is a great image viewer on Windows, which respects the image Exif info. To view the image Exif info, open an image and click Image -> Information . If the image contains Exif info, you can then click the EXIF info button at the bottom left of the popup window to check the image Exif info.
If you want to rotate your images, I would suggest to use the metadata extractor library http://code.google.com/p/metadata-extractor/. You can get the image information with the following code:
// Inner class containing image information public static class ImageInformation { public final int orientation; public final int width; public final int height; public ImageInformation(int orientation, int width, int height) { this.orientation = orientation; this.width = width; this.height = height; } public String toString() { return String.format("%dx%d,%d", this.width, this.height, this.orientation); } } public static ImageInformation readImageInformation(File imageFile) throws IOException, MetadataException, ImageProcessingException { Metadata metadata = ImageMetadataReader.readMetadata(imageFile); Directory directory = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class); JpegDirectory jpegDirectory = metadata.getFirstDirectoryOfType(JpegDirectory.class); int orientation = 1; try { orientation = directory.getInt(ExifIFD0Directory.TAG_ORIENTATION); } catch (MetadataException me) { logger.warn("Could not get orientation"); } int width = jpegDirectory.getImageWidth(); int height = jpegDirectory.getImageHeight(); return new ImageInformation(orientation, width, height); }
Then given the orientation you retrieve, you can rotate and/or flip the image to the right orientation. The Affine transform for the EXIF orientation is given by the following method:
// Look at http://chunter.tistory.com/143 for information public static AffineTransform getExifTransformation(ImageInformation info) { AffineTransform t = new AffineTransform(); switch (info.orientation) { case 1: break; case 2: // Flip X t.scale(-1.0, 1.0); t.translate(-info.width, 0); break; case 3: // PI rotation t.translate(info.width, info.height); t.rotate(Math.PI); break; case 4: // Flip Y t.scale(1.0, -1.0); t.translate(0, -info.height); break; case 5: // - PI/2 and Flip X t.rotate(-Math.PI / 2); t.scale(-1.0, 1.0); break; case 6: // -PI/2 and -width t.translate(info.height, 0); t.rotate(Math.PI / 2); break; case 7: // PI/2 and Flip t.scale(-1.0, 1.0); t.translate(-info.height, 0); t.translate(0, info.width); t.rotate( 3 * Math.PI / 2); break; case 8: // PI / 2 t.translate(0, info.width); t.rotate( 3 * Math.PI / 2); break; } return t; }
The rotation of the image would be done by the following method:
public static BufferedImage transformImage(BufferedImage image, AffineTransform transform) throws Exception { AffineTransformOp op = new AffineTransformOp(transform, AffineTransformOp.TYPE_BICUBIC); BufferedImage destinationImage = op.createCompatibleDestImage(image, (image.getType() == BufferedImage.TYPE_BYTE_GRAY) ? image.getColorModel() : null ); Graphics2D g = destinationImage.createGraphics(); g.setBackground(Color.WHITE); g.clearRect(0, 0, destinationImage.getWidth(), destinationImage.getHeight()); destinationImage = op.filter(image, destinationImage); return destinationImage; }
In a server environment, don't forget to run with -Djava.awt.headless=true
The Thumbnailator library honors EXIF orientation flags. To read an image at full size with correct orientation:
BufferedImage image = Thumbnails.of(inputStream).scale(1).asBufferedImage();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With