fixed rotate with incorrect reported mime type

This commit is contained in:
Thibault Deckers 2020-03-18 10:43:46 +09:00
parent ec51b1878a
commit b9dd6becaf
3 changed files with 51 additions and 17 deletions

View file

@ -125,13 +125,14 @@ public class MetadataHandler implements MethodChannel.MethodCallHandler {
private void getAllVideoMetadataFallback(MethodCall call, MethodChannel.Result result) { private void getAllVideoMetadataFallback(MethodCall call, MethodChannel.Result result) {
String path = call.argument("path"); String path = call.argument("path");
String uri = call.argument("uri"); String uri = call.argument("uri");
try {
Map<String, Map<String, String>> metadataMap = new HashMap<>(); Map<String, Map<String, String>> metadataMap = new HashMap<>();
Map<String, String> dirMap = new HashMap<>(); Map<String, String> dirMap = new HashMap<>();
// unnamed fallback directory // unnamed fallback directory
metadataMap.put("", dirMap); metadataMap.put("", dirMap);
MediaMetadataRetriever retriever = new MediaMetadataRetriever(); MediaMetadataRetriever retriever = new MediaMetadataRetriever();
try {
if (path != null) { if (path != null) {
retriever.setDataSource(path); retriever.setDataSource(path);
} else { } else {
@ -152,11 +153,11 @@ public class MetadataHandler implements MethodChannel.MethodCallHandler {
dirMap.put(kv.getValue(), value); dirMap.put(kv.getValue(), value);
} }
} }
retriever.release();
result.success(metadataMap); result.success(metadataMap);
} catch (Exception e) { } catch (Exception e) {
result.error("getAllVideoMetadataFallback-exception", "failed to get metadata for uri=" + uri + ", path=" + path, e.getMessage()); result.error("getAllVideoMetadataFallback-exception", "failed to get metadata for uri=" + uri + ", path=" + path, e.getMessage());
} finally {
retriever.release();
} }
} }
@ -208,8 +209,8 @@ public class MetadataHandler implements MethodChannel.MethodCallHandler {
} }
if (isVideo(call.argument("mimeType"))) { if (isVideo(call.argument("mimeType"))) {
try {
MediaMetadataRetriever retriever = new MediaMetadataRetriever(); MediaMetadataRetriever retriever = new MediaMetadataRetriever();
try {
if (path != null) { if (path != null) {
retriever.setDataSource(path); retriever.setDataSource(path);
} else { } else {
@ -218,7 +219,6 @@ public class MetadataHandler implements MethodChannel.MethodCallHandler {
String dateString = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DATE); String dateString = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DATE);
String rotationString = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION); String rotationString = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION);
String locationString = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_LOCATION); String locationString = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_LOCATION);
retriever.release();
if (dateString != null) { if (dateString != null) {
long dateMillis = MetadataHelper.parseVideoMetadataDate(dateString); long dateMillis = MetadataHelper.parseVideoMetadataDate(dateString);
@ -251,6 +251,8 @@ public class MetadataHandler implements MethodChannel.MethodCallHandler {
} }
} catch (Exception e) { } catch (Exception e) {
result.error("getCatalogMetadata-exception", "failed to get video metadata for uri=" + uri + ", path=" + path, e.getMessage()); result.error("getCatalogMetadata-exception", "failed to get video metadata for uri=" + uri + ", path=" + path, e.getMessage());
} finally {
retriever.release();
} }
} }
result.success(metadataMap); result.success(metadataMap);

View file

@ -3,6 +3,7 @@ package deckers.thibault.aves.model.provider;
import android.app.Activity; import android.app.Activity;
import android.content.ContentResolver; import android.content.ContentResolver;
import android.content.ContentValues; import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor; import android.database.Cursor;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.BitmapFactory; import android.graphics.BitmapFactory;
@ -15,11 +16,17 @@ import android.os.ParcelFileDescriptor;
import android.provider.MediaStore; import android.provider.MediaStore;
import android.util.Log; import android.util.Log;
import com.drew.imaging.ImageMetadataReader;
import com.drew.imaging.ImageProcessingException;
import com.drew.metadata.Metadata;
import com.drew.metadata.file.FileTypeDirectory;
import java.io.File; import java.io.File;
import java.io.FileDescriptor; import java.io.FileDescriptor;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -109,20 +116,43 @@ public abstract class ImageProvider {
}); });
} }
// file extension is unreliable
// `context.getContentResolver().getType()` sometimes return incorrect value
// `MediaMetadataRetriever.setDataSource()` sometimes fail with `status = 0x80000000`
// so we check with `metadata-extractor`
private String getMimeType(final Context context, final Uri uri) {
try (InputStream is = context.getContentResolver().openInputStream(uri)) {
Metadata metadata = ImageMetadataReader.readMetadata(is);
FileTypeDirectory fileTypeDir = metadata.getFirstDirectoryOfType(FileTypeDirectory.class);
if (fileTypeDir != null) {
if (fileTypeDir.containsTag(FileTypeDirectory.TAG_DETECTED_FILE_MIME_TYPE)) {
return fileTypeDir.getString(FileTypeDirectory.TAG_DETECTED_FILE_MIME_TYPE);
}
}
} catch (IOException | ImageProcessingException e) {
Log.w(LOG_TAG, "failed to get mime type from metadata for uri=" + uri, e);
}
return null;
}
public void rotate(final Activity activity, final String path, final Uri uri, final String mimeType, final boolean clockwise, final ImageOpCallback callback) { public void rotate(final Activity activity, final String path, final Uri uri, final String mimeType, final boolean clockwise, final ImageOpCallback callback) {
switch (mimeType) { // the reported `mimeType` (e.g. from Media Store) is sometimes incorrect
// so we retrieve it again from the file metadata
String metadataMimeType = getMimeType(activity, uri);
switch (metadataMimeType != null ? metadataMimeType : mimeType) {
case Constants.MIME_JPEG: case Constants.MIME_JPEG:
rotateJpeg(activity, path, uri, mimeType, clockwise, callback); rotateJpeg(activity, path, uri, clockwise, callback);
break; break;
case Constants.MIME_PNG: case Constants.MIME_PNG:
rotatePng(activity, path, uri, mimeType, clockwise, callback); rotatePng(activity, path, uri, clockwise, callback);
break; break;
default: default:
callback.onFailure(); callback.onFailure();
} }
} }
private void rotateJpeg(final Activity activity, final String path, final Uri uri, final String mimeType, boolean clockwise, final ImageOpCallback callback) { private void rotateJpeg(final Activity activity, final String path, final Uri uri, boolean clockwise, final ImageOpCallback callback) {
final String mimeType = Constants.MIME_JPEG;
String editablePath = path; String editablePath = path;
boolean onSdCard = Env.isOnSdCard(activity, path); boolean onSdCard = Env.isOnSdCard(activity, path);
if (onSdCard) { if (onSdCard) {
@ -197,7 +227,8 @@ public abstract class ImageProvider {
} }
} }
private void rotatePng(final Activity activity, final String path, final Uri uri, final String mimeType, boolean clockwise, final ImageOpCallback callback) { private void rotatePng(final Activity activity, final String path, final Uri uri, boolean clockwise, final ImageOpCallback callback) {
final String mimeType = Constants.MIME_PNG;
if (path == null) { if (path == null) {
callback.onFailure(); callback.onFailure();
return; return;

View file

@ -34,8 +34,8 @@ class UnknownContentImageProvider extends ImageProvider {
// check first metadata with MediaMetadataRetriever // check first metadata with MediaMetadataRetriever
try {
MediaMetadataRetriever retriever = new MediaMetadataRetriever(); MediaMetadataRetriever retriever = new MediaMetadataRetriever();
try {
retriever.setDataSource(activity, uri); retriever.setDataSource(activity, uri);
title = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE); title = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE);
@ -71,9 +71,10 @@ class UnknownContentImageProvider extends ImageProvider {
if (durationMillisString != null) { if (durationMillisString != null) {
durationMillis = Long.parseLong(durationMillisString); durationMillis = Long.parseLong(durationMillisString);
} }
retriever.release();
} catch (Exception e) { } catch (Exception e) {
// ignore // ignore
} finally {
retriever.release();
} }
// fallback to metadata-extractor for known types // fallback to metadata-extractor for known types