improved mimetype resolution

This commit is contained in:
Thibault Deckers 2020-10-03 23:45:36 +09:00
parent 8ca648b94a
commit 5c0e9063f4
3 changed files with 98 additions and 17 deletions

View file

@ -303,36 +303,44 @@ public class MetadataHandler implements MethodChannel.MethodCallHandler {
private void getCatalogMetadata(MethodCall call, MethodChannel.Result result) {
String mimeType = call.argument("mimeType");
String uri = call.argument("uri");
String extension = call.argument("extension");
Map<String, Object> metadataMap = new HashMap<>(getCatalogMetadataByImageMetadataReader(uri, mimeType));
Map<String, Object> metadataMap = new HashMap<>(getCatalogMetadataByImageMetadataReader(uri, mimeType, extension));
if (isVideo(mimeType)) {
metadataMap.putAll(getVideoCatalogMetadataByMediaMetadataRetriever(uri));
}
if (metadataMap.isEmpty()) {
result.error("getCatalogMetadata-failure", "failed to get catalog metadata for uri=" + uri, null);
result.error("getCatalogMetadata-failure", "failed to get catalog metadata for uri=" + uri + ", extension=" + extension, null);
} else {
result.success(metadataMap);
}
}
private Map<String, Object> getCatalogMetadataByImageMetadataReader(String uri, String mimeType) {
private Map<String, Object> getCatalogMetadataByImageMetadataReader(String uri, String mimeType, String extension) {
Map<String, Object> metadataMap = new HashMap<>();
// as of metadata-extractor 2.14.0, MP2T files are not supported
if (MimeTypes.MP2T.equals(mimeType)) return metadataMap;
// as of metadata-extractor v2.14.0, MP2T/WBMP files are not supported
if (MimeTypes.MP2T.equals(mimeType) || MimeTypes.WBMP.equals(mimeType)) return metadataMap;
try (InputStream is = StorageUtils.openInputStream(context, Uri.parse(uri))) {
Metadata metadata = ImageMetadataReader.readMetadata(is);
// File type
for (FileTypeDirectory dir : metadata.getDirectoriesOfType(FileTypeDirectory.class)) {
// the reported `mimeType` (e.g. from Media Store) is sometimes incorrect
// file extension is unreliable
// `metadata-extractor` sometimes detect the the wrong mime type (e.g. `pef` file as `tiff`)
// the content resolver / media store sometimes report the wrong mime type (e.g. `png` file as `jpeg`)
// `context.getContentResolver().getType()` sometimes return incorrect value
// `MediaMetadataRetriever.setDataSource()` sometimes fail with `status = 0x80000000`
if (dir.containsTag(FileTypeDirectory.TAG_DETECTED_FILE_MIME_TYPE)) {
metadataMap.put(KEY_MIME_TYPE, dir.getString(FileTypeDirectory.TAG_DETECTED_FILE_MIME_TYPE));
String detectedMimeType = dir.getString(FileTypeDirectory.TAG_DETECTED_FILE_MIME_TYPE);
if (detectedMimeType != null && !detectedMimeType.equals(mimeType)) {
// file extension is unreliable, but we use it as a tie breaker
String extensionMimeType = MimeTypes.getMimeTypeForExtension(extension.toLowerCase());
if (detectedMimeType.equals(extensionMimeType)) {
metadataMap.put(KEY_MIME_TYPE, detectedMimeType);
}
}
}
}
@ -385,7 +393,7 @@ public class MetadataHandler implements MethodChannel.MethodCallHandler {
}
}
} catch (Exception | NoClassDefFoundError e) {
Log.w(LOG_TAG, "failed to get catalog metadata by ImageMetadataReader for uri=" + uri, e);
Log.w(LOG_TAG, "failed to get catalog metadata by ImageMetadataReader for uri=" + uri + ", mimeType=" + mimeType, e);
}
return metadataMap;
}

View file

@ -1,27 +1,99 @@
package deckers.thibault.aves.utils
import java.util.*
object MimeTypes {
const val IMAGE = "image"
// generic raster
const val BMP = "image/bmp"
const val GIF = "image/gif"
const val HEIC = "image/heic"
const val HEIF = "image/heif"
const val ICO = "image/x-icon"
const val JPEG = "image/jpeg"
const val PCX = "image/x-pcx"
const val PNG = "image/png"
const val PSD = "image/x-photoshop" // aka "image/vnd.adobe.photoshop"
const val TIFF = "image/tiff"
const val WBMP = "image/vnd.wap.wbmp"
const val WEBP = "image/webp"
const val HEIC = "image/heic"
const val HEIF = "image/heif"
const val PSD = "image/x-photoshop" // .psd
// raw raster
const val ARW = "image/x-sony-arw"
const val CR2 = "image/x-canon-cr2"
const val CRW = "image/x-canon-crw"
const val DCR = "image/x-kodak-dcr"
const val DNG = "image/x-adobe-dng"
const val ERF = "image/x-epson-erf"
const val K25 = "image/x-kodak-k25"
const val KDC = "image/x-kodak-kdc"
const val MRW = "image/x-minolta-mrw"
const val NEF = "image/x-nikon-nef"
const val NRW = "image/x-nikon-nrw"
const val ORF = "image/x-olympus-orf"
const val PEF = "image/x-pentax-pef"
const val RAF = "image/x-fuji-raf"
const val RAW = "image/x-panasonic-raw"
const val RW2 = "image/x-panasonic-rw2"
const val SR2 = "image/x-sony-sr2"
const val SRF = "image/x-sony-srf"
const val SRW = "image/x-samsung-srw"
const val X3F = "image/x-sigma-x3f"
const val DNG = "image/x-adobe-dng" // .dng
const val SVG = "image/svg+xml" // .svg
// vector
const val SVG = "image/svg+xml"
const val VIDEO = "video"
const val AVI = "video/avi"
const val MP2T = "video/mp2t" // .m2ts
const val MOV = "video/quicktime"
const val MP2T = "video/mp2t"
const val MP4 = "video/mp4"
}
@JvmStatic
fun getMimeTypeForExtension(extension: String?): String? = when (extension?.toLowerCase(Locale.ROOT)) {
// generic raster
".bmp" -> BMP
".gif" -> GIF
".heic" -> HEIC
".heif" -> HEIF
".ico" -> ICO
".jpg", ".jpeg", ".jpe" -> JPEG
".pcx" -> PCX
".png" -> PNG
".psd" -> PSD
".tiff", ".tif" -> TIFF
".wbmp" -> WBMP
".webp" -> WEBP
// raw raster
".arw" -> ARW
".cr2" -> CR2
".crw" -> CRW
".dcr" -> DCR
".dng" -> DNG
".erf" -> ERF
".k25" -> K25
".kdc" -> KDC
".mrw" -> MRW
".nef" -> NEF
".nrw" -> NRW
".orf" -> ORF
".pef" -> PEF
".raf" -> RAF
".raw" -> RAW
".rw2" -> RW2
".sr2" -> SR2
".srf" -> SRF
".srw" -> SRW
".x3f" -> X3F
// vector
".svg" -> SVG
// video
".avi" -> AVI
".m2ts" -> MP2T
".mov", ".qt" -> MOV
".mp4", ".m4a", ".m4p", ".m4b", ".m4r", ".m4v" -> MP4
else -> null
}
}

View file

@ -42,6 +42,7 @@ class MetadataService {
final result = await platform.invokeMethod('getCatalogMetadata', <String, dynamic>{
'mimeType': entry.mimeType,
'uri': entry.uri,
'extension': entry.extension,
}) as Map;
result['contentId'] = entry.contentId;
return CatalogMetadata.fromMap(result);