improved mimetype resolution
This commit is contained in:
parent
8ca648b94a
commit
5c0e9063f4
3 changed files with 98 additions and 17 deletions
|
@ -303,36 +303,44 @@ public class MetadataHandler implements MethodChannel.MethodCallHandler {
|
||||||
private void getCatalogMetadata(MethodCall call, MethodChannel.Result result) {
|
private void getCatalogMetadata(MethodCall call, MethodChannel.Result result) {
|
||||||
String mimeType = call.argument("mimeType");
|
String mimeType = call.argument("mimeType");
|
||||||
String uri = call.argument("uri");
|
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)) {
|
if (isVideo(mimeType)) {
|
||||||
metadataMap.putAll(getVideoCatalogMetadataByMediaMetadataRetriever(uri));
|
metadataMap.putAll(getVideoCatalogMetadataByMediaMetadataRetriever(uri));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (metadataMap.isEmpty()) {
|
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 {
|
} else {
|
||||||
result.success(metadataMap);
|
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<>();
|
Map<String, Object> metadataMap = new HashMap<>();
|
||||||
|
|
||||||
// as of metadata-extractor 2.14.0, MP2T files are not supported
|
// as of metadata-extractor v2.14.0, MP2T/WBMP files are not supported
|
||||||
if (MimeTypes.MP2T.equals(mimeType)) return metadataMap;
|
if (MimeTypes.MP2T.equals(mimeType) || MimeTypes.WBMP.equals(mimeType)) return metadataMap;
|
||||||
|
|
||||||
try (InputStream is = StorageUtils.openInputStream(context, Uri.parse(uri))) {
|
try (InputStream is = StorageUtils.openInputStream(context, Uri.parse(uri))) {
|
||||||
Metadata metadata = ImageMetadataReader.readMetadata(is);
|
Metadata metadata = ImageMetadataReader.readMetadata(is);
|
||||||
|
|
||||||
// File type
|
// File type
|
||||||
for (FileTypeDirectory dir : metadata.getDirectoriesOfType(FileTypeDirectory.class)) {
|
for (FileTypeDirectory dir : metadata.getDirectoriesOfType(FileTypeDirectory.class)) {
|
||||||
// the reported `mimeType` (e.g. from Media Store) is sometimes incorrect
|
// `metadata-extractor` sometimes detect the the wrong mime type (e.g. `pef` file as `tiff`)
|
||||||
// file extension is unreliable
|
// the content resolver / media store sometimes report the wrong mime type (e.g. `png` file as `jpeg`)
|
||||||
// `context.getContentResolver().getType()` sometimes return incorrect value
|
// `context.getContentResolver().getType()` sometimes return incorrect value
|
||||||
// `MediaMetadataRetriever.setDataSource()` sometimes fail with `status = 0x80000000`
|
// `MediaMetadataRetriever.setDataSource()` sometimes fail with `status = 0x80000000`
|
||||||
if (dir.containsTag(FileTypeDirectory.TAG_DETECTED_FILE_MIME_TYPE)) {
|
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) {
|
} 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;
|
return metadataMap;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,27 +1,99 @@
|
||||||
package deckers.thibault.aves.utils
|
package deckers.thibault.aves.utils
|
||||||
|
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
object MimeTypes {
|
object MimeTypes {
|
||||||
const val IMAGE = "image"
|
const val IMAGE = "image"
|
||||||
|
|
||||||
|
// generic raster
|
||||||
const val BMP = "image/bmp"
|
const val BMP = "image/bmp"
|
||||||
const val GIF = "image/gif"
|
const val GIF = "image/gif"
|
||||||
|
const val HEIC = "image/heic"
|
||||||
|
const val HEIF = "image/heif"
|
||||||
const val ICO = "image/x-icon"
|
const val ICO = "image/x-icon"
|
||||||
const val JPEG = "image/jpeg"
|
const val JPEG = "image/jpeg"
|
||||||
|
const val PCX = "image/x-pcx"
|
||||||
const val PNG = "image/png"
|
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 WBMP = "image/vnd.wap.wbmp"
|
||||||
const val WEBP = "image/webp"
|
const val WEBP = "image/webp"
|
||||||
|
|
||||||
const val HEIC = "image/heic"
|
// raw raster
|
||||||
const val HEIF = "image/heif"
|
const val ARW = "image/x-sony-arw"
|
||||||
const val PSD = "image/x-photoshop" // .psd
|
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
|
// vector
|
||||||
|
const val SVG = "image/svg+xml"
|
||||||
const val SVG = "image/svg+xml" // .svg
|
|
||||||
|
|
||||||
const val VIDEO = "video"
|
const val VIDEO = "video"
|
||||||
|
|
||||||
const val AVI = "video/avi"
|
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"
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -42,6 +42,7 @@ class MetadataService {
|
||||||
final result = await platform.invokeMethod('getCatalogMetadata', <String, dynamic>{
|
final result = await platform.invokeMethod('getCatalogMetadata', <String, dynamic>{
|
||||||
'mimeType': entry.mimeType,
|
'mimeType': entry.mimeType,
|
||||||
'uri': entry.uri,
|
'uri': entry.uri,
|
||||||
|
'extension': entry.extension,
|
||||||
}) as Map;
|
}) as Map;
|
||||||
result['contentId'] = entry.contentId;
|
result['contentId'] = entry.contentId;
|
||||||
return CatalogMetadata.fromMap(result);
|
return CatalogMetadata.fromMap(result);
|
||||||
|
|
Loading…
Reference in a new issue