package com.almalence.plugins.export.ExifDriver;
import java.util.Arrays;
import android.content.Context;
import com.almalence.plugins.export.ExifDriver.Values.ExifValue;
import com.almalence.plugins.export.ExifDriver.Values.UndefinedValueAccessException;
import com.almalence.plugins.export.ExifDriver.Values.ValueByteArray;
import com.almalence.plugins.export.ExifDriver.Values.ValueNumber;
import com.almalence.plugins.export.ExifDriver.Values.ValueRationals;
public class ExifManager
{
ExifDriver driver;
Context context;
public ExifManager(ExifDriver _driver, Context _context)
{
driver = _driver;
context = _context;
}
/*
* Here go the user-space set/get methods
*/
/**
* Get photographer/editor copyright pair string. In case, that only editor
* is specified, photographer copyright will contain space character, so it
* is recommended to trim it, or use specialized getPhotographerCopyright()
* method
*
* @return Array of Strings. Item 0 is photographer copyright, 1 holds the
* editor copyright
*/
public String[] getCopyright()
{
byte[][] result = new byte[2][];
result[0] = new byte[] { 0 };
result[1] = new byte[] { 0 };
ExifValue exifValue = driver.getIfd0().get(ExifDriver.TAG_COPYRIGHT);
if (exifValue != null && exifValue.getDataType() == ExifDriver.FORMAT_UNDEFINED)
{
byte[] values;
try
{
values = exifValue.getBytes();
} catch (UndefinedValueAccessException e)
{
e.printStackTrace();
return new String[] { "Error" };
}
int copyrightIndex = 0;
result[0] = new byte[values.length];
Arrays.fill(result[0], (byte) 0);
result[1] = new byte[values.length];
Arrays.fill(result[1], (byte) 0);
int index = 0;
for (int i = 0; i < values.length && copyrightIndex < 2; i++)
{
if (values[i] != 0)
{
result[copyrightIndex][index] = values[i];
index++;
} else
{
copyrightIndex++;
index = 0;
}
}
}
return new String[] { new String(result[0]).trim(), new String(result[1]).trim() };
}
/**
* Photographer copyright in one single string
*
* @return Photographer copyright
*/
public String getPhotographerCopyright()
{
return getCopyright()[0];
}
/**
* Editor copyright in one single string
*
* @return Editor copyright
*/
public String getEditorCopyright()
{
return getCopyright()[1];
}
/**
* Get marker note - the marker specific (possibly binary) data. User should
* know, what the tag holds.
*
* @return Marker note byte[] or null if Marker note could not be found
*/
public byte[] getMarkerNote()
{
ExifValue exifValue = driver.getIfdExif().get(ExifDriver.TAG_MARKER_NOTE);
if (exifValue != null && exifValue.getDataType() == ExifDriver.FORMAT_UNDEFINED)
{
try
{
return exifValue.getBytes();
} catch (UndefinedValueAccessException e)
{
e.printStackTrace();
return new byte[0];
}
} else
{
return null;
}
}
/**
* Get artist, which is actually an author of the image
*
* @return Name of artist or null if the tag could not be found
*/
public String getArtist()
{
ExifValue exifValue = driver.getIfd0().get(ExifDriver.TAG_ARTIST);
if (exifValue != null && exifValue.getDataType() == ExifDriver.FORMAT_ASCII_STRINGS)
{
try
{
return new String(exifValue.getBytes());
} catch (UndefinedValueAccessException e)
{
e.printStackTrace();
return "Error";
}
} else
{
return null;
}
}
/**
*
* @return
*/
public String getImageDescription()
{
ExifValue exifValue = driver.getIfd0().get(ExifDriver.TAG_IMAGE_DESCRIPTION);
if (exifValue != null && exifValue.getDataType() == ExifDriver.FORMAT_ASCII_STRINGS)
{
try
{
return new String(exifValue.getBytes());
} catch (UndefinedValueAccessException e)
{
e.printStackTrace();
return "Error";
}
} else
{
return null;
}
}
/**
* Get user comment it differs from image description - it can hold wide
* characters
*
* @return
*/
public String getUserComment()
{
ExifValue exifValue = driver.getIfdExif().get(ExifDriver.TAG_USER_COMMENT);
if (exifValue != null && exifValue.getDataType() == ExifDriver.FORMAT_UNDEFINED)
{
try
{
return new String(exifValue.getBytes());
} catch (UndefinedValueAccessException e)
{
e.printStackTrace();
return "Error";
}
} else
{
return null;
}
}
/**
* Set the Marker note. the value can be whatever byte array
*
* @param _value
* byte array - binary or text information
*/
public void setMarkerNote(byte[] _value)
{
ValueByteArray baValue = new ValueByteArray(ExifDriver.FORMAT_UNDEFINED);
baValue.setBytes(_value);
driver.getIfdExif().put(ExifDriver.TAG_MARKER_NOTE, baValue);
}
/**
* Artist - or author - should be an ASCII string, but sometimes even
* unicode works fine
*
* @param _artist
* Name of the arist
*/
public void setArtist(String _artist)
{
ValueByteArray baValue = new ValueByteArray(ExifDriver.FORMAT_ASCII_STRINGS);
baValue.setBytes(_artist.getBytes());
driver.getIfd0().put(ExifDriver.TAG_ARTIST, baValue);
}
/**
* Copyright for the photographer and editor in common it is used internally
* by specialized methods for setting photographer and editor copyright
* separately
*
* @param _author
* Photographer copyright can be null
* @param _editor
* Editor copyright can be null
*/
public void setCopyright(String _author, String _editor)
{
boolean editorPresented = false;
String author = _author;
if (author == null)
{
author = "";
}
author = author.trim();
if (author.equals(""))
{
author = " ";
}
String editor = _editor;
if (editor == null)
{
editor = "";
}
editor = editor.trim();
editorPresented = !(editor.equals(""));
byte[] authorBytes = author.getBytes();
byte[] editorBytes = _editor.getBytes();
int size = authorBytes.length + 1;
if (editorPresented)
{
size += editorBytes.length + 1;
}
byte[] value = new byte[size];
System.arraycopy(authorBytes, 0, value, 0, authorBytes.length);
value[authorBytes.length] = 0;
if (editorPresented)
{
System.arraycopy(editorBytes, 0, value, authorBytes.length + 1, editorBytes.length);
value[value.length - 1] = 0;
}
ValueByteArray baValue = new ValueByteArray(ExifDriver.FORMAT_ASCII_STRINGS);
baValue.setBytes(value);
driver.getIfd0().put(ExifDriver.TAG_COPYRIGHT, baValue);
}
/**
* Copyright for the photographer (editor) ASCII string
*
* @param _copyright
* Copyright string
*/
public void setPhotographerCopyright(String _copyright)
{
setCopyright(_copyright, getEditorCopyright());
}
/**
* Copyright for the editor ASCII string
*
* @param _copyright
* Copyright string
*/
public void setEditorCopyright(String _copyright)
{
setCopyright(getPhotographerCopyright(), _copyright);
}
/**
* Some nice ASCII image description, like "Picnic in the summer A.D. 2012"
*
* @param _desc
* Description of the image
*/
public void setImageDescription(String _desc)
{
ValueByteArray baValue = new ValueByteArray(ExifDriver.FORMAT_ASCII_STRINGS);
baValue.setBytes(_desc.getBytes());
driver.getIfd0().put(ExifDriver.TAG_IMAGE_DESCRIPTION, baValue);
}
/**
* User comment - alternative to image description. Difference is, that this
* tag is expected to hold wide characters, so UTF-8 string is possible to
* store here
*
* @param _comment
*/
public void setUserComment(String _comment)
{
ValueByteArray baValue = new ValueByteArray(ExifDriver.FORMAT_UNDEFINED);
baValue.setBytes(_comment.getBytes());
driver.getIfdExif().put(ExifDriver.TAG_USER_COMMENT, baValue);
}
private int[][] toDdMmSs(double _value)
{
double value = Math.abs(_value);
int[][] ddmmss = new int[3][2];
ddmmss[0][0] = (int) Math.floor(value);
ddmmss[0][1] = 1;
value -= Math.floor(value);
value *= 60;
ddmmss[1][0] = (int) Math.floor(value);
ddmmss[1][1] = 1;
value -= Math.floor(value);
value *= 60000;
ddmmss[2][0] = (int) Math.floor(value);
ddmmss[2][1] = 1000;
return ddmmss;
}
private void setGpsVersion()
{
ValueNumber version = new ValueNumber(ExifDriver.FORMAT_UNSIGNED_BYTE);
version.setIntegers(new int[] { 2, 2, 0, 0 });
driver.getIfdExif().put(ExifDriver.TAG_GPS_VERSION_ID, version);
}
public void setGPSLocation(double _lat, double _lon, double _alt)
{
setGpsVersion();
// Latitude
ValueByteArray latRef = new ValueByteArray(ExifDriver.FORMAT_ASCII_STRINGS);
ValueRationals lat = new ValueRationals(ExifDriver.FORMAT_UNSIGNED_RATIONAL);
lat.setRationals(toDdMmSs(_lat));
if (_lat > 0)
{
latRef.setBytes(new byte[] { 'N' });
} else
{
latRef.setBytes(new byte[] { 'S' });
}
driver.getIfdGps().put(ExifDriver.TAG_GPS_LATITUDE, lat);
driver.getIfdGps().put(ExifDriver.TAG_GPS_LATITUDE_REF, latRef);
// Longitude
ValueByteArray lonRef = new ValueByteArray(ExifDriver.FORMAT_ASCII_STRINGS);
ValueRationals lon = new ValueRationals(ExifDriver.FORMAT_UNSIGNED_RATIONAL);
lon.setRationals(toDdMmSs(_lon));
if (_lon > 0)
{
lonRef.setBytes(new byte[] { 'E' });
} else
{
lonRef.setBytes(new byte[] { 'W' });
}
driver.getIfdGps().put(ExifDriver.TAG_GPS_LONGITUDE, lon);
driver.getIfdGps().put(ExifDriver.TAG_GPS_LONGITUDE_REF, lonRef);
// Altitude
ValueNumber altRef = new ValueNumber(ExifDriver.FORMAT_UNSIGNED_BYTE);
ValueRationals alt = new ValueRationals(ExifDriver.FORMAT_UNSIGNED_RATIONAL);
int[][] altValue = new int[1][];
altValue[0] = new int[] { (int) Math.abs(_alt), 1 };
alt.setRationals(altValue);
if (_alt >= 0)
{
altRef.setIntegers(new int[] { 0 });
} else
{
altRef.setIntegers(new int[] { 1 });
}
driver.getIfdGps().put(ExifDriver.TAG_GPS_ALTITUDE, alt);
driver.getIfdGps().put(ExifDriver.TAG_GPS_ALTITUDE_REF, altRef);
}
// Convert string like "123/456" or "1.23" to Rational (2 integers).
public static int[][] stringToRational(String string)
{
int[][] res = null;
String[] splited = string.split("/");
if (splited.length == 2)
{
res = new int[1][2];
res[0][0] = Integer.parseInt(splited[0]);
res[0][1] = Integer.parseInt(splited[1]);
return res;
}
splited = string.split("\\.");
if (splited.length == 2)
{
res = new int[1][2];
res[0][0] = Integer.parseInt(splited[0] + splited[1]);
res[0][1] = 10;
for (int i = 0; i < splited[1].length() - 1; i++)
{
res[0][1] *= 10;
}
return res;
}
return res;
}
}