Problem Reading Jpeg Metadata (Orientation)

Problem reading JPEG Metadata (Orientation)

It appears that you forgotten that the orientation id values you looked up are in hex. Where you use 112, you should have used 0x112.

This article explains how Windows ballsed-up orientation handing, and this one seems pretty relevant to what you are doing.

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

Accessing JPEG EXIF rotation data in JavaScript on the client side

If you only want the orientation tag and nothing else and don't like to include another huge javascript library I wrote a little code that extracts the orientation tag as fast as possible (It uses DataView and readAsArrayBuffer which are available in IE10+, but you can write your own data reader for older browsers):

function getOrientation(file, callback) {

var reader = new FileReader();

reader.onload = function(e) {

var view = new DataView(e.target.result);

if (view.getUint16(0, false) != 0xFFD8)

{

return callback(-2);

}

var length = view.byteLength, offset = 2;

while (offset < length)

{

if (view.getUint16(offset+2, false) <= 8) return callback(-1);

var marker = view.getUint16(offset, false);

offset += 2;

if (marker == 0xFFE1)

{

if (view.getUint32(offset += 2, false) != 0x45786966)

{

return callback(-1);

}

var little = view.getUint16(offset += 6, false) == 0x4949;

offset += view.getUint32(offset + 4, little);

var tags = view.getUint16(offset, little);

offset += 2;

for (var i = 0; i < tags; i++)

{

if (view.getUint16(offset + (i * 12), little) == 0x0112)

{

return callback(view.getUint16(offset + (i * 12) + 8, little));

}

}

}

else if ((marker & 0xFF00) != 0xFF00)

{

break;

}

else

{

offset += view.getUint16(offset, false);

}

}

return callback(-1);

};

reader.readAsArrayBuffer(file);

}

// usage:

var input = document.getElementById('input');

input.onchange = function(e) {

getOrientation(input.files[0], function(orientation) {

alert('orientation: ' + orientation);

});

}
<input id='input' type='file' />

Does ImageIO.read() take EXIF orientation metadata into account?

The short answer is, unfortunately, no; ImageIO.read(..) (by default) does not take the Exif Orientation tag into account. Your PNG will be not be rotated accordingly.


However, all ImageIO.read(..) does internally, is to look up an appropriate ImageReader plug-in for the input, and delegate reading to it. And while the JRE-bundled plug-in does not take Exif into account, it is possible to add support for it, in a third-party ImageReader. Unfortunately, I don't know of any that do, but I am considering adding Exif orientation support to the TwelveMonkeys ImageIO JPEGImageReader in the future.

In the mean time, you have to apply the rotation yourself, by reading the metadata and rotating. The value of the orientation tag can be acquired either using the ImageIO JPEG metadata or some third-party library. I think both the mentioned metadata-extractor or TwelveMonkeys ImageIO can be used for this purpose. JAI ImageIO (using the TIFF metadata) can probably also do this.

If using the ImageIO JPEG metadata, be aware:

Note that an application wishing to interpret Exif metadata given a metadata tree structure in the javax_imageio_jpeg_image_1.0 format must check for an unknown marker segment with a tag indicating an APP1 marker and containing data identifying it as an Exif marker segment.

reading android jpeg EXIF metadata from picture callback

The bad news:

Android Api sadly won't allow you to read exif data from a Stream, only from a File.

ExifInterface don't have a constructor with an InputStream.
So you must parse jpeg content by yourself.

The good news:

API exists in pure Java for this. You can use this one: https://drewnoakes.com/code/exif/

It's Open Source, published under Apache Licence 2 and available as a Maven package.

There is a constructor with an InputStream:
public ExifReader(java.io.InputStream is)

You can build an InputStream backed by your byte[] using a ByteArrayInputStream like this:

InputStream is = new ByteArrayInputStream(decodedBytes);

PHP read_exif_data and Adjust Orientation

The documentation for imagerotate refers to a different type for the first parameter than you use:

An image resource, returned by one of the image creation functions,
such as imagecreatetruecolor().

Here is a small example for using this function:

function resample($jpgFile, $thumbFile, $width, $orientation) {
// Get new dimensions
list($width_orig, $height_orig) = getimagesize($jpgFile);
$height = (int) (($width / $width_orig) * $height_orig);
// Resample
$image_p = imagecreatetruecolor($width, $height);
$image = imagecreatefromjpeg($jpgFile);
imagecopyresampled($image_p, $image, 0, 0, 0, 0, $width, $height, $width_orig, $height_orig);
// Fix Orientation
switch($orientation) {
case 3:
$image_p = imagerotate($image_p, 180, 0);
break;
case 6:
$image_p = imagerotate($image_p, 90, 0);
break;
case 8:
$image_p = imagerotate($image_p, -90, 0);
break;
}
// Output
imagejpeg($image_p, $thumbFile, 90);
}


Related Topics



Leave a reply



Submit