fix missing width/height for jpeg & mp4

This commit is contained in:
Thibault Deckers 2020-03-18 12:35:48 +09:00
parent 298817d888
commit ce878614cf
3 changed files with 79 additions and 38 deletions

View file

@ -107,7 +107,7 @@ public abstract class ImageProvider {
cursor.close(); cursor.close();
} }
} catch (Exception e) { } catch (Exception e) {
Log.w(LOG_TAG, "failed to update MediaStore after renaming entry at path=" + oldPath, e); Log.w(LOG_TAG, "failed to update Media Store after renaming entry at path=" + oldPath, e);
callback.onFailure(); callback.onFailure();
return; return;
} }
@ -222,7 +222,7 @@ public abstract class ImageProvider {
callback.onSuccess(newFields); callback.onSuccess(newFields);
}); });
} else { } else {
Log.w(LOG_TAG, "failed to update fields in MediaStore for uri=" + uri); Log.w(LOG_TAG, "failed to update fields in Media Store for uri=" + uri);
callback.onSuccess(newFields); callback.onSuccess(newFields);
} }
} }
@ -307,7 +307,7 @@ public abstract class ImageProvider {
callback.onSuccess(newFields); callback.onSuccess(newFields);
}); });
} else { } else {
Log.w(LOG_TAG, "failed to update fields in MediaStore for uri=" + uri); Log.w(LOG_TAG, "failed to update fields in Media Store for uri=" + uri);
callback.onSuccess(newFields); callback.onSuccess(newFields);
} }
} }

View file

@ -13,7 +13,7 @@ public class ImageProviderFactory {
switch (scheme) { switch (scheme) {
case ContentResolver.SCHEME_CONTENT: // content:// case ContentResolver.SCHEME_CONTENT: // content://
// a URI's authority is [userinfo@]host[:port] // a URI's authority is [userinfo@]host[:port]
// but we only want the host when comparing to MediaStore's "authority" // but we only want the host when comparing to Media Store's "authority"
String host = uri.getHost(); String host = uri.getHost();
if (host != null) { if (host != null) {
switch (host) { switch (host) {

View file

@ -9,6 +9,16 @@ import android.os.Build;
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.MetadataException;
import com.drew.metadata.exif.ExifIFD0Directory;
import com.drew.metadata.jpeg.JpegDirectory;
import com.drew.metadata.mp4.media.Mp4VideoDirectory;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.stream.Stream; import java.util.stream.Stream;
@ -20,6 +30,8 @@ import deckers.thibault.aves.utils.StorageUtils;
import deckers.thibault.aves.utils.Utils; import deckers.thibault.aves.utils.Utils;
import io.flutter.plugin.common.EventChannel; import io.flutter.plugin.common.EventChannel;
import static deckers.thibault.aves.utils.MetadataHelper.getOrientationDegreesForExifCode;
public class MediaStoreImageProvider extends ImageProvider { public class MediaStoreImageProvider extends ImageProvider {
private static final String LOG_TAG = Utils.createLogTag(MediaStoreImageProvider.class); private static final String LOG_TAG = Utils.createLogTag(MediaStoreImageProvider.class);
@ -113,41 +125,70 @@ public class MediaStoreImageProvider extends ImageProvider {
Uri itemUri = ContentUris.withAppendedId(contentUri, contentId); Uri itemUri = ContentUris.withAppendedId(contentUri, contentId);
String path = cursor.getString(pathColumn); String path = cursor.getString(pathColumn);
int width = cursor.getInt(widthColumn); int width = cursor.getInt(widthColumn);
// TODO TLAD sanitize mimeType int height = cursor.getInt(heightColumn);
// problem: some images were added as image/jpeg, but they're actually image/png int orientationDegrees = orientationColumn != -1 ? cursor.getInt(orientationColumn) : 0;
// possible solution: if (width <= 0 || height <= 0) {
// 1) check that MediaStore mimeType matches expected mimeType from file path extension // some images are incorrectly registered in the Media Store,
// 2) extract actual mimeType with metadata-extractor // they are valid but miss some attributes, such as width, height, orientation
// 3) update MediaStore try (InputStream is = activity.getContentResolver().openInputStream(itemUri)) {
if (width > 0) { Metadata metadata = ImageMetadataReader.readMetadata(is);
newEntryHandler.handleEntry(
new HashMap<String, Object>() {{ // JPEG
put("uri", itemUri.toString());
put("path", path); JpegDirectory jpegDir = metadata.getFirstDirectoryOfType(JpegDirectory.class);
put("contentId", contentId); if (jpegDir != null) {
put("mimeType", cursor.getString(mimeTypeColumn)); if (jpegDir.containsTag(JpegDirectory.TAG_IMAGE_WIDTH)) {
put("width", width); width = jpegDir.getInt(JpegDirectory.TAG_IMAGE_WIDTH);
put("height", cursor.getInt(heightColumn)); }
put("orientationDegrees", orientationColumn != -1 ? cursor.getInt(orientationColumn) : 0); if (jpegDir.containsTag(JpegDirectory.TAG_IMAGE_HEIGHT)) {
put("sizeBytes", cursor.getLong(sizeColumn)); height = jpegDir.getInt(JpegDirectory.TAG_IMAGE_HEIGHT);
put("title", cursor.getString(titleColumn)); }
put("dateModifiedSecs", cursor.getLong(dateModifiedColumn)); }
put("sourceDateTakenMillis", cursor.getLong(dateTakenColumn));
put("bucketDisplayName", cursor.getString(bucketDisplayNameColumn)); // EXIF
put("durationMillis", durationColumn != -1 ? cursor.getLong(durationColumn) : 0);
}}); ExifIFD0Directory exifDir = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);
entryCount++; if (exifDir != null) {
} else { if (exifDir.containsTag(ExifIFD0Directory.TAG_ORIENTATION)) {
orientationDegrees = getOrientationDegreesForExifCode(exifDir.getInt(ExifIFD0Directory.TAG_ORIENTATION));
}
}
// MP4
Mp4VideoDirectory mp4VideoDir = metadata.getFirstDirectoryOfType(Mp4VideoDirectory.class);
if (mp4VideoDir != null) {
if (mp4VideoDir.containsTag(Mp4VideoDirectory.TAG_WIDTH)) {
width = mp4VideoDir.getInt(Mp4VideoDirectory.TAG_WIDTH);
}
if (mp4VideoDir.containsTag(Mp4VideoDirectory.TAG_HEIGHT)) {
height = mp4VideoDir.getInt(Mp4VideoDirectory.TAG_HEIGHT);
}
}
} catch (IOException | ImageProcessingException | MetadataException e) {
// this is probably not a real image, like "/storage/emulated/0", so we skip it
}
}
if (width <= 0 || height <= 0) {
Log.w(LOG_TAG, "failed to get size for uri=" + itemUri + ", path=" + path); Log.w(LOG_TAG, "failed to get size for uri=" + itemUri + ", path=" + path);
// // some images are incorrectly registered in the MediaStore, } else {
// // they are valid but miss some attributes, such as width, height, orientation Map<String, Object> entryMap = new HashMap<String, Object>() {{
// try { put("uri", itemUri.toString());
// imageEntry.fixMissingWidthHeightOrientation(activity); put("path", path);
// entrySink.success(imageEntry); put("contentId", contentId);
// } catch (IOException e) { put("mimeType", cursor.getString(mimeTypeColumn));
// // this is probably not a real image, like "/storage/emulated/0", so we skip it put("sizeBytes", cursor.getLong(sizeColumn));
// Log.w(LOG_TAG, "failed to compute dimensions of imageEntry=" + imageEntry); put("title", cursor.getString(titleColumn));
// } put("dateModifiedSecs", cursor.getLong(dateModifiedColumn));
put("sourceDateTakenMillis", cursor.getLong(dateTakenColumn));
put("bucketDisplayName", cursor.getString(bucketDisplayNameColumn));
put("durationMillis", durationColumn != -1 ? cursor.getLong(durationColumn) : 0);
}};
entryMap.put("width", width);
entryMap.put("height", height);
entryMap.put("orientationDegrees", orientationDegrees);
newEntryHandler.handleEntry(entryMap);
entryCount++;
} }
} }
cursor.close(); cursor.close();