Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android image resizing and preserving EXIF data (orientation, rotation, etc.)

People also ask

What is EXIF rotation?

Auto-rotation The EXIF orientation value is used by Photoshop and other photo editing software to automatically rotate photos, saving you a manual task.

Do Android photos have EXIF data?

How to view Exif data on Android. Checking the Exif data of a photo on an Android phone or tablet is pretty easy. You don't need access to any special apps. The gallery app of your phone or Google Photos can show the most important bits from the Exif data of your photos.

How do you preserve EXIF data?

EXIF data is only preserved when syncing the photo back to your computer directly. Emailing the photo will not save EXIF data. Additionally, please ensure that the Location Services is turned on for Snapseed in the iOS Settings.

How do I get rid of EXIF orientation?

To fix the EXIF orientation, open the image in an image editing program. Rotate the image to the correct orientation, then save the file and reupload your image. As an alternative, you can simply remove all EXIF data from images in Windows and macOS.


As far as I can tell, there is no mechanism to persist the metadata automatically or even snapshot whatever is there and transfer in bulk.

Rather, it seems you must explicitly check for specific properties and copy them yourself to the new image file using the ExifInterface.

http://developer.android.com/reference/android/media/ExifInterface.html

So something like:

ExifInterface oldExif = new ExifInterface(oldImagePath);
String exifOrientation = oldExif.getAttribute(ExifInterface.TAG_ORIENTATION);

if (exifOrientation != null) {
   ExifInterface newExif = new ExifInterface(imagePath);
   newExif.setAttribute(ExifInterface.TAG_ORIENTATION, exifOrientation);
   newExif.saveAttributes();
}

For the lazy ones, here's a reusable function:

public static void copyExif(String oldPath, String newPath) throws IOException
{
    ExifInterface oldExif = new ExifInterface(oldPath);

    String[] attributes = new String[]
    {
            ExifInterface.TAG_APERTURE,
            ExifInterface.TAG_DATETIME,
            ExifInterface.TAG_DATETIME_DIGITIZED,
            ExifInterface.TAG_EXPOSURE_TIME,
            ExifInterface.TAG_FLASH,
            ExifInterface.TAG_FOCAL_LENGTH,
            ExifInterface.TAG_GPS_ALTITUDE,
            ExifInterface.TAG_GPS_ALTITUDE_REF,
            ExifInterface.TAG_GPS_DATESTAMP,
            ExifInterface.TAG_GPS_LATITUDE,
            ExifInterface.TAG_GPS_LATITUDE_REF,
            ExifInterface.TAG_GPS_LONGITUDE,
            ExifInterface.TAG_GPS_LONGITUDE_REF,
            ExifInterface.TAG_GPS_PROCESSING_METHOD,
            ExifInterface.TAG_GPS_TIMESTAMP,
            ExifInterface.TAG_IMAGE_LENGTH,
            ExifInterface.TAG_IMAGE_WIDTH,
            ExifInterface.TAG_ISO,
            ExifInterface.TAG_MAKE,
            ExifInterface.TAG_MODEL,
            ExifInterface.TAG_ORIENTATION,
            ExifInterface.TAG_SUBSEC_TIME,
            ExifInterface.TAG_SUBSEC_TIME_DIG,
            ExifInterface.TAG_SUBSEC_TIME_ORIG,
            ExifInterface.TAG_WHITE_BALANCE
    };

    ExifInterface newExif = new ExifInterface(newPath);
    for (int i = 0; i < attributes.length; i++)
    {
        String value = oldExif.getAttribute(attributes[i]);
        if (value != null)
            newExif.setAttribute(attributes[i], value);
    }
    newExif.saveAttributes();
}

As others have indicated, you must copy the Exif data from the original image to the final resized image. The Sanselan Android library is typically best for this. Depending on Android OS version, the ExifInterface sometimes corrupts the Exifdata.

In addition, the ExifInterface also handles a limited number of Exif tags -- namely only the tags that it "knows" about. Sanselan on the other hand will keep all Exiftags and marker notes.

Here is a blog post that shows how to use Sanselan for copying image data:

Copying Exif metadata using Sanselan

BTW, on Android I also tend to rotate the images and remove the Orientation Exiftag. For example, on a Nexus S with Android 4.03, the camera was setting an orientation tag in the Exifmetadata, but the webview was ignoring that information and displaying the image incorrectly. Sadly, rotating the actual image data and removing the Exiforientation tag is the only way to get every program to display images correctly.


It's already 2019 and there is still no better answer than those proposed by @prom85, Mike Repass and Theo.

In 2016, Android team introduced ExifInterface Support Library what can be the best option if you want to have consisent behaviour between Android versions. I ended up creating a subset of tags ExifInterface#EXIF_TAGS (source code) and I just iterate over this subset to extract metadata from input file and set it in an output. If you ever get a requirement to copy over all tags I recommend you to not do it! Value of some of the tags will need to be updated accordingly anyway (e.g. TAG_IMAGE_LENGTH and TAG_IMAGE_WIDTH). Personally, I kept asking questions why we need to keep all metedata data in the first place (it differs what you get between devices and camera you use anyway) and we realised that gps location and date/time data is as well need to keep.


Why not just modify the ExifInterface source and add your own implementation to support reading/writing in bulk so you don't have to specify tag by tag. Here is a snippet of what I would do.

Add new method to expose the internal attributes:

public HashMap<String, ExifAttribute>[] getAllAttributes() {
    return mAttributes;
}

Add new method to set all the attributes:

public void setAttributes(HashMap<String, ExifAttribute>[] attributes) {
    for (int i = 0 ; i < EXIF_TAGS.length; ++i) {
        mAttributes[i] = attributes[i];
    }
}

Then use it like this to preserve Exif and save to another File

// Grab all the original exif attributes from an image file and save to memory or wherever
let attributes = ExifInterface2(sourceImagePath).attributes

// Later on you can just copy those attributes to another image
ExifInterface2(destImagePath)
    .setAttributes(attributes)
    .saveAttributes();