package org.horaapps.leafpic.data;
import android.content.Context;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.media.ExifInterface;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
import com.drew.imaging.ImageMetadataReader;
import com.drew.imaging.ImageProcessingException;
import com.drew.lang.GeoLocation;
import com.drew.lang.annotations.NotNull;
import com.drew.metadata.Directory;
import com.drew.metadata.Metadata;
import com.drew.metadata.Tag;
import org.horaapps.leafpic.R;
import org.horaapps.leafpic.data.base.MediaDetailsMap;
import org.horaapps.leafpic.util.MediaSignature;
import org.horaapps.leafpic.util.StringUtils;
import org.jetbrains.annotations.TestOnly;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* Created by dnld on 26/04/16.
*/
public class Media implements Parcelable, Serializable {
private String path = null;
private long dateModified = -1;
private String mimeType = null;
private int orientation = 0;
private String uri = null;
private long size = 0;
private boolean selected = false;
private MetadataItem metadata;
public Media() { }
public Media(String path, long dateModified) {
this.path = path;
this.dateModified = dateModified;
this.mimeType = StringUtils.getMimeType(path);
}
public Media(File file) {
this(file.getPath(), file.lastModified());
this.size = file.length();
this.mimeType = StringUtils.getMimeType(path);
}
public Media(String path) {
this(path, -1);
}
public Media(Context context, Uri mediaUri) {
this.uri = mediaUri.toString();
this.path = null;
this.mimeType = context.getContentResolver().getType(getUri());
}
public Media(@NotNull Cursor cur) {
this.path = cur.getString(0);
this.dateModified = cur.getLong(1);
this.mimeType = cur.getString(2);
this.size = cur.getLong(3);
this.orientation = cur.getInt(4);
}
private static int findOrientation(int exifOrientation){
switch (exifOrientation) {
case ExifInterface.ORIENTATION_ROTATE_90: return 90;
case ExifInterface.ORIENTATION_ROTATE_180: return 180;
case ExifInterface.ORIENTATION_ROTATE_270: return 270;
}
return 0;
}
public void setUri(String uriString) {
this.uri = uriString;
}
public void setPath(String path) {
this.path = path;
}
public String getMimeType() {
return mimeType;
}
public boolean isSelected() {
return selected;
}
void setSelected(boolean selected) {
this.selected = selected;
}
public boolean isGif() { return mimeType.endsWith("gif"); }
public boolean isImage() { return mimeType.startsWith("image"); }
public boolean isVideo() { return mimeType.startsWith("video"); }
public Uri getUri() {
return uri != null ? Uri.parse(uri) : Uri.fromFile(new File(path));
}
public String getName() {
return StringUtils.getPhotoNameByPath(path);
}
public long getSize() {
return size;
}
public String getPath() {
return path;
}
public Long getDateModified() {
return dateModified;
}
public Bitmap getBitmap(){
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
Bitmap bitmap = BitmapFactory.decodeFile(path,bmOptions);
bitmap = Bitmap.createScaledBitmap(bitmap,bitmap.getWidth(),bitmap.getHeight(),true);
return bitmap;
}
public MediaSignature getSignature() {
return new MediaSignature(this);
}
//<editor-fold desc="Exif & More">
public GeoLocation getGeoLocation() {
return metadata.getLocation();
}
public MediaDetailsMap<String, String> getAllDetails() {
MediaDetailsMap<String, String> data = new MediaDetailsMap<String, String>();
try {
Metadata metadata = ImageMetadataReader.readMetadata(new File(path));
for(Directory directory : metadata.getDirectories()) {
for(Tag tag : directory.getTags()) {
data.put(tag.getTagName(), directory.getObject(tag.getTagType())+"");
}
}
} catch (ImageProcessingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return data;
}
public MediaDetailsMap<String, String> getMainDetails(Context context){
metadata = new MetadataItem(new File(path));
MediaDetailsMap<String, String> details = new MediaDetailsMap<String, String>();
details.put(context.getString(R.string.path), path != null ? path : getUri().getEncodedPath());
details.put(context.getString(R.string.type), getMimeType());
String tmp;
if ((tmp = metadata.getResolution()) != null)
details.put(context.getString(R.string.resolution), tmp);
details.put(context.getString(R.string.size), StringUtils.humanReadableByteCount(size, true));
details.put(context.getString(R.string.date), SimpleDateFormat.getDateTimeInstance().format(new Date(getDateModified())));
details.put(context.getString(R.string.orientation), getOrientation()+"");
if (metadata.getDateOriginal() != null)
details.put(context.getString(R.string.date_taken), SimpleDateFormat.getDateTimeInstance().format(metadata.getDateOriginal()));
if ((tmp = metadata.getCameraInfo()) != null)
details.put(context.getString(R.string.camera), tmp);
if ((tmp = metadata.getExifInfo()) != null)
details.put(context.getString(R.string.exif), tmp);
GeoLocation location;
if ((location = metadata.getLocation()) != null)
details.put(context.getString(R.string.location), location.toDMSString());
return details;
}
public boolean setOrientation(final int orientation) {
this.orientation = orientation;
// TODO: 28/08/16 find a better way
new Thread(new Runnable() {
public void run() {
int exifOrientation = -1;
try {
ExifInterface exif = new ExifInterface(path);
switch (orientation) {
case 90: exifOrientation = ExifInterface.ORIENTATION_ROTATE_90; break;
case 180: exifOrientation = ExifInterface.ORIENTATION_ROTATE_180; break;
case 270: exifOrientation = ExifInterface.ORIENTATION_ROTATE_270; break;
case 0: exifOrientation = ExifInterface.ORIENTATION_NORMAL; break;
}
if (exifOrientation != -1) {
exif.setAttribute(ExifInterface.TAG_ORIENTATION, String.valueOf(exifOrientation));
exif.saveAttributes();
}
}
catch (IOException ignored) { }
}
}).start();
return true;
}
private long getDateTaken() {
// TODO: 16/08/16 improved
Date dateOriginal = metadata.getDateOriginal();
if (dateOriginal != null) return metadata.getDateOriginal().getTime();
return -1;
}
public boolean fixDate(){
long newDate = getDateTaken();
if (newDate != -1){
File f = new File(path);
if (f.setLastModified(newDate)) {
dateModified = newDate;
return true;
}
}
return false;
}
//</editor-fold>
public File getFile() {
if (path != null) return new File(path);
return null;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(this.path);
dest.writeLong(this.dateModified);
dest.writeString(this.mimeType);
dest.writeLong(this.size);
dest.writeByte(this.selected ? (byte) 1 : (byte) 0);
}
protected Media(Parcel in) {
this.path = in.readString();
this.dateModified = in.readLong();
this.mimeType = in.readString();
this.size = in.readLong();
this.selected = in.readByte() != 0;
}
public static final Creator<Media> CREATOR = new Creator<Media>() {
@Override
public Media createFromParcel(Parcel source) {
return new Media(source);
}
@Override
public Media[] newArray(int size) {
return new Media[size];
}
};
public int getOrientation() {
return orientation;
}
//<editor-fold desc="Thumbnail Tests">
@TestOnly public byte[] getThumbnail() {
ExifInterface exif;
try {
exif = new ExifInterface(path);
} catch (IOException e) {
return null;
}
if (exif.hasThumbnail())
return exif.getThumbnail();
return null;
// NOTE: ExifInterface is faster than metadata-extractor to getValue the thumbnail data
/*try {
Metadata metadata = ImageMetadataReader.readMetadata(new File(getMediaPath()));
ExifThumbnailDirectory thumbnailDirectory = metadata.getFirstDirectoryOfType(ExifThumbnailDirectory.class);
if (thumbnailDirectory.hasThumbnailData())
return thumbnailDirectory.getThumbnailData();
} catch (Exception e) { return null; }*/
}
@TestOnly public String getThumbnail(Context context) {
/*Cursor cursor = MediaStore.Images.Thumbnails.queryMiniThumbnail(
context.getContentResolver(), id,
MediaStore.Images.Thumbnails.MINI_KIND,
new String[]{ MediaStore.Images.Thumbnails.DATA } );
if(cursor.moveToFirst())
return cursor.getString(cursor.getColumnIndex(MediaStore.Images.Thumbnails.DATA));
return null;*/
return null;
}
//</editor-fold>
}