How to Tell Browsers to Honor The Jpeg Exif Orientation

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 :)

Images being displayed in wrong orientation

I'm guessing the OP is having problems due to EXIF data. If the original images contain EXIF data indicating that they should be rotated, special measures must be taken to get that data interpreted by a web browser when displaying a page. It is discussed here:

Is there a way to tell browsers to honor the jpeg exif orientation?

If the the solutions provided for exif orientation are not acceptable, the OP will have to preprocess the images to rotate them to proper orientation and save them that way on the serverside. Then the correctly rotated images can be delivered on web page.

Photos show up in landscape orientation on a webpage, vertically elsewhere. Why?

Your image has embedded exif orientation data which is presumably being ignored when rendering the page. See this answer for a bit more detail.

Basically, the camera you took the image with stored it in landscape, but stored some metadata with it saying that the image needs to be rotated 270°. The browser is apparently ignoring this tag when rendering it in the webpage, but not when you access the image directly.

Image Upload Not Retrieving Orientation exif data

Solution

I realised that every time it got to the point where it tried to read the exif data using exif_read_data() the data was already gone.

I resulted to retrieving the exif data within the JavaScript instead using a library called exif.js. Further explanation found here.

What's wrong with the image?

Below is Thilo's answer:

There is a EXIF attribute "Orientation" in the file, set to "3 (rotated 180 degrees)".

Same problem in a .NET image processor: Problem reading JPEG Metadata (Orientation)

Browser support for EXIF orientation is complicated:https://code.google.com/p/chromium/issues/detail?id=56845

And I also found a post about the EXIF "Orientation": Exif Orientation Tag

Thanks Thilo!

Am I serving my images incorrect, they are all shown rotated 90 degrees

Orientation was setted in Exif. Picture wasn't rotated phisicaly.
Image-viewer can to work with it but the browser in tag doesn't rotate it.

Your can rotate pictures on server by imagemagick --auto-orient http://imagemagick.org/Usage/photos/#orient

You can also rotate it "on fly". Just get Exif info by exif_read_data() and rotate it if it has 3(180degree), 6(90CW), or 8(-90CCW) in 'Orientation'

// dump the picture and stop the script
$source = imagecreatefromjpeg($filename);
$exif = exif_read_data($filename);
if (isset($exif['Orientation'])) {
switch($exif['Orientation']) {
case 3: // 180 degree
$rotate=imagerotate($source,180,0);
break;
case 6: // 90 CW
$rotate=imagerotate($source,-90,0);
break;
case 8: // 90 CCW
$rotate=imagerotate($source,90,0);
break;
default:
$rotate=imagerotate($source,0,0);
break;
}
imagejpeg($rotate);
imagedestroy($source);
imagedestroy($rotate);
} else {
imagejpeg($source);
imagedestroy($source);
}

But of course better to prepare all pictures once.

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



Related Topics



Leave a reply



Submit