reading android jpeg EXIF metadata from picture callback
To read metadata/EXIF from image byte[]
(useful for Camera.takePicture()
) using version 2.9.1 of the metadata extraction library in Java by Drew Noakes:
try{ // Extract metadata. Metadata metadata = ImageMetadataReader.readMetadata(new BufferedInputStream(new ByteArrayInputStream(imageData)), imageData.length); // Log each directory. for(Directory directory : metadata.getDirectories()) { Log.d("LOG", "Directory: " + directory.getName()); // Log all errors. for(String error : directory.getErrors()) { Log.d("LOG", "> error: " + error); } // Log all tags. for(Tag tag : directory.getTags()) { Log.d("LOG", "> tag: " + tag.getTagName() + " = " + tag.getDescription()); } }}catch(Exception e){ // TODO: handle exception}
To read the EXIF orientation of the image (not the orientation of the thumbnail):
try{ // Get the EXIF orientation. final ExifIFD0Directory exifIFD0Directory = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class); if(exifIFD0Directory.containsTag(ExifIFD0Directory.TAG_ORIENTATION)) { final int exifOrientation = exifIFD0Directory.getInt(ExifIFD0Directory.TAG_ORIENTATION); /* Work on exifOrientation */ } else { /* Not found */ }}catch(Exception e){ // TODO: handle exception}
The orientation is from 1 to 8. See here, here, here or here.
To transform a bitmap based on its EXIF orientation:
try{ final Matrix bitmapMatrix = new Matrix(); switch(exifOrientation) { case 1: break; // top left case 2: bitmapMatrix.postScale(-1, 1); break; // top right case 3: bitmapMatrix.postRotate(180); break; // bottom right case 4: bitmapMatrix.postRotate(180); bitmapMatrix.postScale(-1, 1); break; // bottom left case 5: bitmapMatrix.postRotate(90); bitmapMatrix.postScale(-1, 1); break; // left top case 6: bitmapMatrix.postRotate(90); break; // right top case 7: bitmapMatrix.postRotate(270); bitmapMatrix.postScale(-1, 1); break; // right bottom case 8: bitmapMatrix.postRotate(270); break; // left bottom default: break; // Unknown } // Create new bitmap. final Bitmap transformedBitmap = Bitmap.createBitmap(imageBitmap, 0, 0, imageBitmap.getWidth(), imageBitmap.getHeight(), bitmapMatrix, false);}catch(Exception e){ // TODO: handle exception}
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);
AndroidX ExifInterface supports reading EXIF information from an inputstream:
implementation "androidx.exifinterface:exifinterface:1.1.0"
You can then just pass the inputstream into the constructor like that:
val exif = ExifInterface(inputStream)val orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)