package it.sephiroth.android.example.exifsample;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.location.Address;
import android.location.Geocoder;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.os.SystemClock;
import android.text.Html;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import org.apache.commons.lang3.StringUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
import java.util.UUID;
import it.sephiroth.android.example.exifsample.utils.IOUtils;
import it.sephiroth.android.library.exif2.BuildConfig;
import it.sephiroth.android.library.exif2.ExifInterface;
import it.sephiroth.android.library.exif2.ExifTag;
import it.sephiroth.android.library.exif2.ExifUtil;
import it.sephiroth.android.library.exif2.IfdId;
import it.sephiroth.android.library.exif2.Rational;
public class MainActivity extends Activity implements OnClickListener {
static final String LOG_TAG = "MainActivity";
static final int REQUEST_FILE = 1;
Button button1, button2;
ImageView image;
TextView exifText;
ExifInterface mExif;
Uri mUri;
@Override
protected void onCreate( Bundle savedInstanceState ) {
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_main );
button1 = (Button) findViewById( R.id.button1 );
button2 = (Button) findViewById( R.id.button2 );
image = (ImageView) findViewById( R.id.image1 );
exifText = (TextView) findViewById( R.id.exif );
button1.setOnClickListener( this );
button2.setOnClickListener( this );
Log.i( LOG_TAG, "ExifInterfaceExtended.Version: " + BuildConfig.VERSION_NAME + " - " + BuildConfig.VERSION_CODE );
processAsset( "image.jpg" );
}
private void loadImage() {
Intent intent = new Intent( Intent.ACTION_GET_CONTENT );
intent.setType( "image/*" );
Intent chooser = Intent.createChooser( intent, "Choose picture" );
startActivityForResult( chooser, REQUEST_FILE );
}
public void saveImage() throws IOException {
if( null != mExif ) {
Log.i( LOG_TAG, "saving: " + mExif );
File dst_file = new File( Environment.getExternalStoragePublicDirectory( Environment.DIRECTORY_DOWNLOADS ), "exif.jpg" );
if( null != mUri ) {
ExifInterface exif = new ExifInterface();
exif.setTags( mExif.getAllTags() );
exif.setCompressedThumbnail( mExif.getThumbnail() );
// exif.deleteTag( ExifInterface.TAG_COLOR_SPACE );
// exif.deleteTag( ExifInterface.TAG_ORIENTATION );
// exif.deleteTag(ExifInterface.TAG_INTEROP_VERSION);
String uuid = UUID.randomUUID().toString();
if( uuid.length() > 32 ) {
uuid = uuid.substring( 0, 32 );
} else if( uuid.length() < 32 ) {
uuid = StringUtils.leftPad( uuid, 32 );
}
Log.d(LOG_TAG, "uuid: " + uuid + ", size: " + uuid.length());
// exif.setTag( exif.buildTag( ExifInterface.TAG_IMAGE_UNIQUE_ID, uuid ) );
// exif.setTag( exif.buildTag( ExifInterface.TAG_ARTIST, "Alessandro Crugnola" ) );
// exif.addDateTimeStampTag( ExifInterface.TAG_DATE_TIME, new Date().getTime(), TimeZone.getDefault() );
InputStream is = openInputStream( mUri );
OutputStream os = new FileOutputStream( dst_file );
org.apache.commons.io.IOUtils.copy( is, os );
is.close();
os.close();
long t1 = SystemClock.uptimeMillis();
// exif.writeExif( tmp_file.getAbsolutePath(), dst_file.getAbsolutePath() );
// exif.writeExif( openInputStream( mUri ), dst_file.getAbsolutePath() );
exif.writeExif( dst_file.getAbsolutePath() );
long t2 = SystemClock.uptimeMillis();
Log.d( LOG_TAG, "saveImage time: " + (t2-t1) + "ms" );
}
}
}
private void dumpToFile( ExifInterface exif ) {
if( null == exif ) return;
try {
File file = new File( Environment.getExternalStoragePublicDirectory( Environment.DIRECTORY_DOWNLOADS ), "exif.txt" );
Log.d( LOG_TAG, "writing to " + file.getAbsolutePath() );
FileOutputStream stream = new FileOutputStream( file );
List<ExifTag> tags = exif.getAllTags();
if( null == tags ) return;
for( ExifTag key : tags ) {
String line = key.toString() + "\n";
stream.write( line.getBytes() );
}
stream.flush();
stream.close();
} catch( IOException e ) {
e.printStackTrace();
}
}
private void processUri( Uri uri ) {
mUri = uri;
try {
processInputStream( openInputStream( uri ) );
} catch( FileNotFoundException e ) {
e.printStackTrace();
}
}
private InputStream openInputStream( Uri uri ) throws FileNotFoundException {
String filename = IOUtils.getRealFilePath( this, uri );
if( null == filename ) {
return getContentResolver().openInputStream( uri );
}
else {
return new FileInputStream( filename );
}
}
int mTagsCount = 0;
private String createStringFromIfFound( ExifInterface exif, int key, String label, final List<ExifTag> all_tags ) {
String exifString = "";
ExifTag tag = exif.getTag( key );
if( null != tag ) {
all_tags.remove( tag );
int ifid = tag.getIfd();
String ifdid_str = "";
switch( ifid ) {
case IfdId.TYPE_IFD_0:
ifdid_str = "ifd0";
break;
case IfdId.TYPE_IFD_1:
ifdid_str = "ifd1";
break;
case IfdId.TYPE_IFD_EXIF:
ifdid_str = "exif";
break;
case IfdId.TYPE_IFD_GPS:
ifdid_str = "gps";
break;
case IfdId.TYPE_IFD_INTEROPERABILITY:
ifdid_str = "interop";
break;
}
mTagsCount++;
exifString += "<b>" + label + "(" + ifdid_str + "): </b>";
if( key == ExifInterface.TAG_DATE_TIME || key == ExifInterface.TAG_DATE_TIME_DIGITIZED || key == ExifInterface.TAG_DATE_TIME_ORIGINAL ) {
Date date = ExifInterface.getDateTime( tag.getValueAsString(), TimeZone.getDefault() );
if( null != date ) {
exifString += java.text.DateFormat.getDateTimeInstance().format( date );
}
else {
Log.e( LOG_TAG, "failed to format the date" );
}
} else {
exifString += tag.forceGetValueAsString();
}
exifString += "<br>";
}
else {
// Log.w( LOG_TAG, "'" + label + "' not found" );
}
return exifString;
}
private void processAsset( String assetname ) {
InputStream stream;
try {
stream = getAssets().open( assetname );
} catch( IOException e ) {
e.printStackTrace();
return;
}
processInputStream( stream );
}
private void processInputStream( InputStream stream ) {
mExif = new ExifInterface();
List<ExifTag> all_tags = null;
if( null != stream ) {
long t1 = System.currentTimeMillis();
try {
mExif.readExif( stream, ExifInterface.Options.OPTION_ALL );
} catch( IOException e ) {
e.printStackTrace();
mExif = null;
}
long t2 = System.currentTimeMillis();
Log.d( LOG_TAG, "parser time: " + ( t2 - t1 ) + "ms" );
if(null != mExif) {
all_tags = mExif.getAllTags();
Log.d(LOG_TAG, "total tags: " + (all_tags != null ? all_tags.size() : 0));
}
}
image.setImageBitmap( null );
exifText.setText( "" );
if( null != mExif ) {
mTagsCount = 0;
StringBuilder string = new StringBuilder();
NumberFormat numberFormatter = DecimalFormat.getNumberInstance();
// dumpToFile( mExif );
exifText.setText( "<h2>JPEG Info<h2><br/>" );
new LoadThumbnailTask().execute( mExif );
if( mExif.getQualityGuess() > 0 ) {
string.append( "<b>JPEG quality:</b> " + mExif.getQualityGuess() + "<br>" );
}
int[] imagesize = mExif.getImageSize();
if( imagesize[0] > 0 && imagesize[1] > 0 ) {
string.append( "<b>Image Size: </b>" + imagesize[0] + "x" + imagesize[1] + "<br>" );
}
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_IMAGE_WIDTH, "TAG_IMAGE_WIDTH", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_IMAGE_LENGTH, "TAG_IMAGE_LENGTH", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_BITS_PER_SAMPLE, "TAG_BITS_PER_SAMPLE", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_COMPRESSION, "TAG_COMPRESSION", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_PHOTOMETRIC_INTERPRETATION, "TAG_PHOTOMETRIC_INTERPRETATION", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_IMAGE_DESCRIPTION, "TAG_IMAGE_DESCRIPTION", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_MAKE, "TAG_MAKE", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_MODEL, "TAG_MODEL", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_STRIP_OFFSETS, "TAG_STRIP_OFFSETS", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_ORIENTATION, "TAG_ORIENTATION", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_SAMPLES_PER_PIXEL, "TAG_SAMPLES_PER_PIXEL", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_ROWS_PER_STRIP, "TAG_ROWS_PER_STRIP", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_STRIP_BYTE_COUNTS, "TAG_STRIP_BYTE_COUNTS", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_X_RESOLUTION, "TAG_X_RESOLUTION", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_Y_RESOLUTION, "TAG_Y_RESOLUTION", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_PLANAR_CONFIGURATION, "TAG_PLANAR_CONFIGURATION", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_RESOLUTION_UNIT, "TAG_RESOLUTION_UNIT", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_TRANSFER_FUNCTION, "TAG_TRANSFER_FUNCTION", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_SOFTWARE, "TAG_SOFTWARE", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_DATE_TIME, "TAG_DATE_TIME", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_ARTIST, "TAG_ARTIST", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_WHITE_POINT, "TAG_WHITE_POINT", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_PRIMARY_CHROMATICITIES, "TAG_PRIMARY_CHROMATICITIES", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_Y_CB_CR_COEFFICIENTS, "TAG_Y_CB_CR_COEFFICIENTS", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_Y_CB_CR_SUB_SAMPLING, "TAG_Y_CB_CR_SUB_SAMPLING", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_Y_CB_CR_POSITIONING, "TAG_Y_CB_CR_POSITIONING", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_REFERENCE_BLACK_WHITE, "TAG_REFERENCE_BLACK_WHITE", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_COPYRIGHT, "TAG_COPYRIGHT", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_EXIF_IFD, "TAG_EXIF_IFD", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_GPS_IFD, "TAG_GPS_IFD", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT, "TAG_JPEG_INTERCHANGE_FORMAT", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH, "TAG_JPEG_INTERCHANGE_FORMAT_LENGTH", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_EXPOSURE_TIME, "TAG_EXPOSURE_TIME", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_F_NUMBER, "TAG_F_NUMBER", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_EXPOSURE_PROGRAM, "TAG_EXPOSURE_PROGRAM", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_SPECTRAL_SENSITIVITY, "TAG_SPECTRAL_SENSITIVITY", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_ISO_SPEED_RATINGS, "TAG_ISO_SPEED_RATINGS", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_OECF, "TAG_OECF", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_EXIF_VERSION, "TAG_EXIF_VERSION", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_DATE_TIME_ORIGINAL, "TAG_DATE_TIME_ORIGINAL", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_DATE_TIME_DIGITIZED, "TAG_DATE_TIME_DIGITIZED", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_COMPONENTS_CONFIGURATION, "TAG_COMPONENTS_CONFIGURATION", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_COMPRESSED_BITS_PER_PIXEL, "TAG_COMPRESSED_BITS_PER_PIXEL", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_SHUTTER_SPEED_VALUE, "TAG_SHUTTER_SPEED_VALUE", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_APERTURE_VALUE, "TAG_APERTURE_VALUE", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_BRIGHTNESS_VALUE, "TAG_BRIGHTNESS_VALUE", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_EXPOSURE_BIAS_VALUE, "TAG_EXPOSURE_BIAS_VALUE", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_MAX_APERTURE_VALUE, "TAG_MAX_APERTURE_VALUE", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_SUBJECT_DISTANCE, "TAG_SUBJECT_DISTANCE", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_METERING_MODE, "TAG_METERING_MODE", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_LIGHT_SOURCE, "TAG_LIGHT_SOURCE", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_FLASH, "TAG_FLASH", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_FOCAL_LENGTH, "TAG_FOCAL_LENGTH", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_SUBJECT_AREA, "TAG_SUBJECT_AREA", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_MAKER_NOTE, "TAG_MAKER_NOTE", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_USER_COMMENT, "TAG_USER_COMMENT", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_SUB_SEC_TIME, "TAG_SUB_SEC_TIME", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_SUB_SEC_TIME_ORIGINAL, "TAG_SUB_SEC_TIME_ORIGINAL", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_SUB_SEC_TIME_DIGITIZED, "TAG_SUB_SEC_TIME_DIGITIZED", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_FLASHPIX_VERSION, "TAG_FLASHPIX_VERSION", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_COLOR_SPACE, "TAG_COLOR_SPACE", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_PIXEL_X_DIMENSION, "TAG_PIXEL_X_DIMENSION", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_PIXEL_Y_DIMENSION, "TAG_PIXEL_Y_DIMENSION", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_RELATED_SOUND_FILE, "TAG_RELATED_SOUND_FILE", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_INTEROPERABILITY_IFD, "TAG_INTEROPERABILITY_IFD", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_FLASH_ENERGY, "TAG_FLASH_ENERGY", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_SPATIAL_FREQUENCY_RESPONSE, "TAG_SPATIAL_FREQUENCY_RESPONSE", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_FOCAL_PLANE_X_RESOLUTION, "TAG_FOCAL_PLANE_X_RESOLUTION", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_FOCAL_PLANE_Y_RESOLUTION, "TAG_FOCAL_PLANE_Y_RESOLUTION", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_FOCAL_PLANE_RESOLUTION_UNIT, "TAG_FOCAL_PLANE_RESOLUTION_UNIT", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_SUBJECT_LOCATION, "TAG_SUBJECT_LOCATION", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_EXPOSURE_INDEX, "TAG_EXPOSURE_INDEX", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_SENSING_METHOD, "TAG_SENSING_METHOD", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_FILE_SOURCE, "TAG_FILE_SOURCE", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_SCENE_TYPE, "TAG_SCENE_TYPE", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_CFA_PATTERN, "TAG_CFA_PATTERN", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_CUSTOM_RENDERED, "TAG_CUSTOM_RENDERED", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_EXPOSURE_MODE, "TAG_EXPOSURE_MODE", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_WHITE_BALANCE, "TAG_WHITE_BALANCE", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_DIGITAL_ZOOM_RATIO, "TAG_DIGITAL_ZOOM_RATIO", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_FOCAL_LENGTH_IN_35_MM_FILE, "TAG_FOCAL_LENGTH_IN_35_MM_FILE", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_SCENE_CAPTURE_TYPE, "TAG_SCENE_CAPTURE_TYPE", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_GAIN_CONTROL, "TAG_GAIN_CONTROL", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_CONTRAST, "TAG_CONTRAST", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_SATURATION, "TAG_SATURATION", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_SHARPNESS, "TAG_SHARPNESS", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_DEVICE_SETTING_DESCRIPTION, "TAG_DEVICE_SETTING_DESCRIPTION", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_SUBJECT_DISTANCE_RANGE, "TAG_SUBJECT_DISTANCE_RANGE", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_IMAGE_UNIQUE_ID, "TAG_IMAGE_UNIQUE_ID", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_GPS_VERSION_ID, "TAG_GPS_VERSION_ID", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_GPS_LATITUDE_REF, "TAG_GPS_LATITUDE_REF", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_GPS_LATITUDE, "TAG_GPS_LATITUDE", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_GPS_LONGITUDE_REF, "TAG_GPS_LONGITUDE_REF", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_GPS_LONGITUDE, "TAG_GPS_LONGITUDE", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_GPS_ALTITUDE_REF, "TAG_GPS_ALTITUDE_REF", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_GPS_ALTITUDE, "TAG_GPS_ALTITUDE", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_GPS_TIME_STAMP, "TAG_GPS_TIME_STAMP", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_GPS_SATTELLITES, "TAG_GPS_SATTELLITES", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_GPS_STATUS, "TAG_GPS_STATUS", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_GPS_MEASURE_MODE, "TAG_GPS_MEASURE_MODE", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_GPS_DOP, "TAG_GPS_DOP", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_GPS_SPEED_REF, "TAG_GPS_SPEED_REF", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_GPS_SPEED, "TAG_GPS_SPEED", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_GPS_TRACK_REF, "TAG_GPS_TRACK_REF", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_GPS_TRACK, "TAG_GPS_TRACK", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_GPS_IMG_DIRECTION_REF, "TAG_GPS_IMG_DIRECTION_REF", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_GPS_IMG_DIRECTION, "TAG_GPS_IMG_DIRECTION", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_GPS_MAP_DATUM, "TAG_GPS_MAP_DATUM", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_GPS_DEST_LATITUDE_REF, "TAG_GPS_DEST_LATITUDE_REF", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_GPS_DEST_LATITUDE, "TAG_GPS_DEST_LATITUDE", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_GPS_DEST_LONGITUDE_REF, "TAG_GPS_DEST_LONGITUDE_REF", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_GPS_DEST_LONGITUDE, "TAG_GPS_DEST_LONGITUDE", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_GPS_DEST_BEARING_REF, "TAG_GPS_DEST_BEARING_REF", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_GPS_DEST_BEARING, "TAG_GPS_DEST_BEARING", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_GPS_DEST_DISTANCE_REF, "TAG_GPS_DEST_DISTANCE_REF", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_GPS_DEST_DISTANCE, "TAG_GPS_DEST_DISTANCE", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_GPS_PROCESSING_METHOD, "TAG_GPS_PROCESSING_METHOD", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_GPS_AREA_INFORMATION, "TAG_GPS_AREA_INFORMATION", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_GPS_DATE_STAMP, "TAG_GPS_DATE_STAMP", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_GPS_DIFFERENTIAL, "TAG_GPS_DIFFERENTIAL", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_INTEROPERABILITY_INDEX, "TAG_INTEROPERABILITY_INDEX", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_LENS_MAKE, "TAG_LENS_MAKE", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_LENS_MODEL, "TAG_LENS_MODEL", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_LENS_SPECS, "TAG_LENS_SPECS", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_SENSITIVITY_TYPE, "TAG_SENSITIVITY_TYPE", all_tags ) );
string.append( createStringFromIfFound( mExif, ExifInterface.TAG_INTEROP_VERSION, "TAG_INTEROP_VERSION", all_tags ) );
List<ExifTag> tags = mExif.getTagsForTagId( mExif.getTrueTagKey( ExifInterface.TAG_ORIENTATION ) );
Log.d( LOG_TAG, "tags: " + tags );
string.append( "<br>--------------<br>" );
string.append( "<b>Total tags parsed:</b> " + mTagsCount + "<br>" );
string.append( "<b>Remaining tags:</b> " + ( all_tags != null ? all_tags.size() : 0 ) + "<br>" );
string.append( "<b>Has Thumbnail:</b> " + mExif.hasThumbnail() + "<br>" );
ExifTag tag = mExif.getTag( ExifInterface.TAG_EXIF_VERSION );
if( null != tag ) {
string.append( "<b>Exif version: </b> " + tag.getValueAsString() + "<br>" );
}
String latitude = mExif.getLatitude();
String longitude = mExif.getLongitude();
if( null != latitude && null != longitude ) {
string.append( "<b>Latitude: </b> " + latitude + "<br>" );
string.append( "<b>Longitude: </b> " + longitude + "<br>" );
}
Integer val = mExif.getTagIntValue( ExifInterface.TAG_ORIENTATION );
int orientation = 0;
if( null != val ) {
orientation = ExifInterface.getRotationForOrientationValue( val.shortValue() );
}
string.append( "<b>Orientation: </b> " + orientation + "<br>" );
double aperture = mExif.getApertureSize();
if( aperture > 0 ) {
string.append( "<b>Aperture Size: </b> " + String.format( "%.2f", aperture ) + "<br>" );
}
ExifTag shutterSpeed = mExif.getTag( ExifInterface.TAG_SHUTTER_SPEED_VALUE );
if( null != shutterSpeed ) {
double speed = shutterSpeed.getValueAsRational( 0 ).toDouble();
Log.d( LOG_TAG, "speed: " + speed );
NumberFormat decimalFormatter = DecimalFormat.getNumberInstance();
decimalFormatter.setMaximumFractionDigits( 1 );
String speedString = "1/" + decimalFormatter.format( Math.pow( 2, speed ) ) + "s";
string.append( "<b>Shutter Speed: </b> " + speedString + "<br>" );
}
String lensModel = mExif.getLensModelDescription();
if( null != lensModel ) {
string.append( "<b>Lens Specifications: </b> " + lensModel + "<br>" );
}
short process = mExif.getJpegProcess();
string.append( "<b>JPEG Process: </b> " + process + "<br>" );
exifText.setText( Html.fromHtml( string.toString() ) );
if( null != all_tags ) {
Log.i( LOG_TAG, "---- remaining tags ---" );
for( ExifTag remaining_tag : all_tags ) {
Log.v( LOG_TAG, "tag: " + String.format( "0x%X", remaining_tag.getTagId() ) + ", value: " + remaining_tag );
}
}
double[] latlon = mExif.getLatLongAsDoubles();
if( null != latlon ) {
GetGeoLocationTask task = new GetGeoLocationTask();
task.execute( latlon[0], latlon[1] );
}
}
}
private String processSharpness( int value ) {
switch( value ) {
case 0:
return "Normal";
case 1:
return "Soft";
case 2:
return "Hard";
default:
return "Unknown";
}
}
private String processContrast( int value ) {
switch( value ) {
case 0:
return "Normal";
case 1:
return "Soft";
case 2:
return "Hard";
default:
return "Unknown";
}
}
private String processSaturation( int value ) {
switch( value ) {
case 0:
return "Normal";
case 1:
return "Low Saturation";
case 2:
return "High Saturation";
default:
return "Unknown";
}
}
private String processGainControl( int value ) {
switch( value ) {
case 0:
return "None";
case 1:
return "Low Gain Up";
case 2:
return "High Gain Up";
case 3:
return "Low Gain Down";
case 4:
return "High Gain Down";
default:
return "Unknown";
}
}
private String processSceneCaptureType( int value ) {
switch( value ) {
case 0:
return "Standard";
case 1:
return "Landscape";
case 2:
return "Portrait";
case 3:
return "Night scene";
default:
return "Unknown";
}
}
private String processSensingMethod( int value ) {
switch( value ) {
case 1:
return "Not defined";
case 2:
return "One-chip color area sensor";
case 3:
return "Two-chip color area sensor JEITA CP-3451 - 41";
case 4:
return "Three-chip color area sensor";
case 5:
return "Color sequential area sensor";
case 7:
return "Trilinear sensor";
case 8:
return "Color sequential linear sensor";
default:
return "Unknown";
}
}
private String processColorSpace( int value ) {
switch( value ) {
case 1:
return "sRGB";
case 0xFFFF:
return "Uncalibrated";
default:
return "Unknown";
}
}
private String processExposureMode( int mode ) {
switch( mode ) {
case 0:
return "Auto exposure";
case 1:
return "Manual exposure";
case 2:
return "Auto bracket";
default:
return "Unknown";
}
}
private String processExposureProgram( int program ) {
switch( program ) {
case 1:
return "Manual control";
case 2:
return "Program normal";
case 3:
return "Aperture priority";
case 4:
return "Shutter priority";
case 5:
return "Program creative (slow program)";
case 6:
return "Program action(high-speed program)";
case 7:
return "Portrait mode";
case 8:
return "Landscape mode";
default:
return "Unknown";
}
}
private String processMeteringMode( int mode ) {
switch( mode ) {
case 1:
return "Average";
case 2:
return "CenterWeightedAverage";
case 3:
return "Spot";
case 4:
return "MultiSpot";
case 5:
return "Pattern";
case 6:
return "Partial";
case 255:
return "Other";
default:
return "Unknown";
}
}
private String processLightSource( int value ) {
switch( value ) {
case 0:
return "Auto";
case 1:
return "Daylight";
case 2:
return "Fluorescent";
case 3:
return "Tungsten (incandescent light)";
case 4:
return "Flash";
case 9:
return "Fine weather";
case 10:
return "Cloudy weather";
case 11:
return "Shade";
case 12:
return "Daylight fluorescent (D 5700 - 7100K)";
case 13:
return "Day white fluorescent (N 4600 - 5400K)";
case 14:
return "Cool white fluorescent (W 3900 - 4500K)";
case 15:
return "White fluorescent (WW 3200 - 3700K)";
case 17:
return "Standard light A";
case 18:
return "Standard light B";
case 19:
return "Standard light C";
case 20:
return "D55";
case 21:
return "D65";
case 22:
return "D75";
case 23:
return "D50";
case 24:
return "ISO studio tungsten";
case 255:
return "Other light source";
default:
return "Unknown";
}
}
private String processWhiteBalance( int value ) {
switch( value ) {
case 0:
return "Auto";
case 1:
return "Manual";
default:
return "Unknown";
}
}
private String processSubjectDistanceRange( int value ) {
switch( value ) {
case 1:
return "Macro";
case 2:
return "Close View";
case 3:
return "Distant View";
default:
return "Unknown";
}
}
private String processFlash( int flash ) {
Log.i( LOG_TAG, "flash: " + flash + ", " + ( flash & 1 ) );
switch( flash ) {
case 0x0000:
return "Flash did not fire";
case 0x0001:
return "Flash fired";
case 0x0005:
return "Strobe return light not detected";
case 0x0007:
return "Strobe return light detected";
case 0x0009:
return "Flash fired, compulsory flash mode";
case 0x000D:
return "Flash fired, compulsory flash mode, return light not detected";
case 0x000F:
return "Flash fired, compulsory flash mode, return light detected";
case 0x0010:
return "Flash did not fire, compulsory flash mode";
case 0x0018:
return "Flash did not fire, auto mode";
case 0x0019:
return "Flash fired, auto mode";
case 0x001D:
return "Flash fired, auto mode, return light not detected";
case 0x001F:
return "Flash fired, auto mode, return light detected";
case 0x0020:
return "No flash function";
case 0x0041:
return "Flash fired, red-eye reduction mode";
case 0x0045:
return "Flash fired, red-eye reduction mode, return light not detected";
case 0x0047:
return "Flash fired, red-eye reduction mode, return light detected";
case 0x0049:
return "Flash fired, compulsory flash mode, red-eye reduction mode";
case 0x004D:
return "Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected";
case 0x004F:
return "Flash fired, compulsory flash mode, red-eye reduction mode, return light detected";
case 0x0059:
return "Flash fired, auto mode, red-eye reduction mode";
case 0x005D:
return "Flash fired, auto mode, return light not detected, red-eye reduction mode";
case 0x005F:
return "Flash fired, auto mode, return light detected, red-eye reduction mode";
default:
return "Reserved";
}
}
private String parseProcess( int process ) {
switch( process ) {
case 192:
return "Baseline";
case 193:
return "Extended sequential";
case 194:
return "Progressive";
case 195:
return "Lossless";
case 197:
return "Differential sequential";
case 198:
return "Differential progressive";
case 199:
return "Differential lossless";
case 201:
return "Extended sequential, arithmetic coding";
case 202:
return "Progressive, arithmetic coding";
case 203:
return "Lossless, arithmetic coding";
case 205:
return "Differential sequential, arithmetic coding";
case 206:
return "Differential progressive, arithmetic codng";
case 207:
return "Differential lossless, arithmetic coding";
}
return "Unknown";
}
@Override
protected void onActivityResult( int requestCode, int resultCode, Intent data ) {
Log.d( LOG_TAG, "data: " + data );
if( resultCode == RESULT_OK ) {
if( requestCode == REQUEST_FILE ) {
processUri( data.getData() );
}
}
}
@Override
public void onClick( View v ) {
final int id = v.getId();
if( id == button1.getId() ) {
loadImage();
}
else if( id == button2.getId() ) {
try {
saveImage();
} catch( Exception e ) {
e.printStackTrace();
Toast.makeText( this, e.getMessage(), Toast.LENGTH_SHORT ).show();
}
}
}
private class LoadThumbnailTask extends AsyncTask<ExifInterface, Void, Bitmap> {
@Override
protected Bitmap doInBackground( ExifInterface... params ) {
ExifInterface exif = params[0];
if( exif.hasThumbnail() ) {
return exif.getThumbnailBitmap();
}
return null;
}
@Override
protected void onPostExecute( Bitmap result ) {
super.onPostExecute( result );
image.setImageBitmap( result );
}
}
private class GetGeoLocationTask extends AsyncTask<Double, Void, Address> {
@Override
protected Address doInBackground( Double... params ) {
double lat = params[0];
double lon = params[1];
Log.d( LOG_TAG, "lat: " + lat + ", lon: " + lon );
List<Address> result = null;
try {
if( Geocoder.isPresent() ) {
Geocoder geo = new Geocoder( MainActivity.this );
result = geo.getFromLocation( lat, lon, 1 );
}
} catch( Exception e ) {
e.printStackTrace();
return null;
}
Log.d( LOG_TAG, "result: " + result );
if( null != result && result.size() > 0 ) {
return result.get( 0 );
}
return null;
}
@Override
protected void onPostExecute( Address result ) {
super.onPostExecute( result );
if( isCancelled() || isFinishing() ) return;
if( null != result ) {
StringBuilder finalString = new StringBuilder();
if( null != result.getThoroughfare() ) {
finalString.append( result.getThoroughfare() );
if( null != result.getSubThoroughfare() ) {
finalString.append( " " + result.getSubThoroughfare() );
}
finalString.append( "\n" );
}
if( null != result.getPostalCode() ) {
finalString.append( result.getPostalCode() );
if( null != result.getLocality() ) {
finalString.append( " - " + result.getLocality() + "\n" );
}
}
else {
if( null != result.getLocality() ) {
finalString.append( result.getLocality() + "\n" );
}
}
if( null != result.getCountryName() ) {
finalString.append( result.getCountryName() );
}
else if( null != result.getCountryCode() ) {
finalString.append( result.getCountryCode() );
}
if( finalString.length() > 0 ) {
finalString.append( "\n" );
exifText.append( "\nAddress:\n" );
exifText.append( finalString );
}
}
}
}
}