Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

reading android jpeg EXIF metadata from picture callback

Background: I am writing a camera app for a messenger program. I cannot save the captured image to persistent disk at any time. The camera must support all orientations. My implementation is that of the familiar Surfaceview examples. I use the Display class to detect orientation and rotate the camera accordingly. In the takePicture jpeg callback, I construct a bitmap from the byte[] in order to get around some aspect ratio issues I was having: Camera API: Cross device issues

Problem Description: On some devices, the constructed Bitmap taken at ROTATION_270 (device rotated 90 degrees clockwise) comes in upside down. So far, it seems to be Samsung. I can only assume that maybe the camera is soldered on the other way or something to that affect but that's neither here nor there. While I can check if a Bitmap is sideways I can't logically check if it is upside down by dimensions so I need access to the EXIF data.

Android provides a parser for this http://developer.android.com/reference/android/media/ExifInterface.html but unfortunately it has a single constructor which accepts a file... which I don't have and don't want. Intuitively I could write a constructor for a byte array but that seems really painful given their calls into native code http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/2.2.1_r1/android/media/ExifInterface.java

My question then has two parts:

  1. Does anyone know if the byte[] array contains full EXIF jpeg header data as is or is the path through the BitmapFactory.decode(...) / BitmapFactory.compress(...) adding that somehow?

  2. If this EXIF data exits in the byte array how can I parse out the orientation information in a dependable manner?

Edit 10/18/12

pcans' answer below involves part 2 of my question. As I pointed to in the comments below his answer, if you want to use that parser you'll have to incorporate the source into your project. The changes mentioned in that linked SO post have already been made and reposted here: https://github.com/strangecargo/metadata-extractor

NOTE newer versions of metadata-extractor work directly on Android without modification, and are available via Maven.

However, as to part 1, I'm getting 0 tags back from the parser when I run it with the byte array I get from takePicture. I'm becoming concerned that the byte array doesn't have the data I need. I will continue to look into this but welcome any further insight.

like image 810
Andrew G Avatar asked Oct 17 '12 22:10

Andrew G


People also ask

How do I view EXIF data on a JPEG?

Just right-click on the photo in question and select “Properties”. Click on the “Details” tab and scroll down—you'll see all kinds of information about the camera used, and the settings the photo was taken with.

How do I see the metadata of an image on my phone?

Follow these steps to view EXIF data on your Android smartphone. Open Google Photos on the phone - install it if needed. Open any photo and tap the i icon. This will show you all the EXIF data you need.

What is ExifInterface in Android?

android.media.ExifInterface. This is a class for reading and writing Exif tags in various image file formats. Supported for reading: JPEG, PNG, WebP, HEIF, DNG, CR2, NEF, NRW, ARW, RW2, ORF, PEF, SRW, RAF, AVIF. Supported for writing: JPEG, PNG, WebP, DNG.


1 Answers

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 } 
like image 103
Pang Avatar answered Sep 18 '22 23:09

Pang