How to rotate JPEG images based on the orientation metadata?
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
JS Client-Side Exif Orientation: Rotate and Mirror JPEG Images
The github project JavaScript-Load-Image provides a complete solution to the EXIF orientation problem, correctly rotating/mirroring images for all 8 exif orientations. See the online demo of javascript exif orientation
The image is drawn onto an HTML5 canvas. Its correct rendering is implemented in js/load-image-orientation.js through canvas operations.
Hope this saves somebody else some time, and teaches the search engines about this open source gem :)
How to fix EXIF orientation data in JPG files
As you say, there is orientation data in Exif. It defines how the raw pixel data should be transformed before being displayed (rotation, but also potentially flipping on either axis).
For a JPEG image with Exif, the 'easy' way to rotate the image is just to update the Exif info. Of course this requires the viewer to honour that rotation information.
The more expensive way (and potentially lossy) is to physically rotate the image data. I suspect that this is what you need to do to satisfy your photo frame.
In .NET you can do this with System.Windows.Drawing
, for example. The Image.RotateFlip
method would be a good place to start.
To extract the orientation data from your image, may I humbly suggest using my MetadataExtractor library?
var orientation = ImageMetadataReader.ReadMetadata(myImagePath)
.OfType<ExifIfd0Directory>()
.FirstOrDefault()
?.GetObject(ExifIfd0Directory.TagOrientation);
That'll give you an int?
, the values of which are:
- Top, left side (Horizontal / normal)
- Top, right side (Mirror horizontal)
- Bottom, right side (Rotate 180)", "Bottom, left side (Mirror vertical)
- Left side, top (Mirror horizontal and rotate 270 CW)
- Right side, top (Rotate 90 CW)
- Right side, bottom (Mirror horizontal and rotate 90 CW)
- Left side, bottom (Rotate 270 CW)
An aside here, mostly because it's interesting: JPEG images are encoded as a grid of 16x16 pixel 'blocks'. If your image is not exactly a multiple of 16 pixels in both directions, then rotation can potentially shift the alignment of this grid which will result in decoding and re-encoding of the images, which will lose information. If the original JPEG has low compression then you probably won't be able to perceive this loss, so it may be academic to point it out, but it will still be there.
Different rotation of image on PC and through input type file
There are two main metadata tags for specifying image orientation:
Orientation: [TopLeft, BottomRight, RightTop, LeftBottom]
and
exif:Orientation: [1, 3, 6, 8]
I suspect your image was taken by a device, which uses exif:Orientation
meta tag. Ubuntu default image viewer supports exif:Orientation
and thus it displays the image correctly. Browsers, however, do not support this tag (for backward compatibility reasons) and they have to fall back to the default orientation which is rotated 90 deg to right in your case.
You could solve your issue by supplementing your images with the Orientation
meta tag. This could be done with most image viewing software by simply rotating your image and saving it in place (in Ubuntu you will see the image rotated properly, so simply rotate it in any direction and rotate it back and save).
Related Topics
Can an Interface Extend Multiple Interfaces in Java
Can't Rid of 'T' in Localdatetime
Difference Between Wait and Blocked Thread States
Native Query with Named Parameter Fails with "Not All Named Parameters Have Been Set"
Java- the Meaning of <T Extends Comparable<T>>
How to Pass Jvm Options from Bootrun
Check If a Value Exists in Arraylist
Java's Fork/Join VS Executorservice - When to Use Which
Could Not Serialize Object Cause of Hibernateproxy
How to Pass Parameter to Jsp:Include via C:Set? What Are the Scopes of the Variables in Jsp
Eclipse Reading Stdin (System.In) from a File
Cannot Assign Requested Address Using Serversocket.Socketbind
What Is the Point of Getters and Setters