#1037 use truncated preview when opening large DNG with metadata extractor
This commit is contained in:
parent
981727cb1d
commit
1346e8867b
4 changed files with 17 additions and 13 deletions
|
@ -296,7 +296,7 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler {
|
|||
byGeoTiff[false]?.map { exifTagMapper(it) }?.let { dirMap.putAll(it) }
|
||||
}
|
||||
|
||||
mimeType == MimeTypes.DNG -> {
|
||||
mimeType == MimeTypes.DNG || mimeType == MimeTypes.DNG_ADOBE -> {
|
||||
// split DNG tags in their own directory
|
||||
val dngDirMap = metadataMap[DIR_DNG] ?: HashMap()
|
||||
metadataMap[DIR_DNG] = dngDirMap
|
||||
|
|
|
@ -120,7 +120,7 @@ object Metadata {
|
|||
return date.time + parseSubSecond(subSecond)
|
||||
}
|
||||
|
||||
// Opening large PSD/TIFF files yields an OOM (both with `metadata-extractor` v2.15.0 and `ExifInterface` v1.3.1),
|
||||
// Opening some large files yields an OOM (both with `metadata-extractor` v2.15.0 and `ExifInterface` v1.3.1),
|
||||
// so we define an arbitrary threshold to avoid a crash on launch.
|
||||
// It is not clear whether it is because of the file itself or its metadata.
|
||||
private const val FILE_SIZE_MAX = 100 * (1 shl 20) // MB
|
||||
|
@ -136,6 +136,8 @@ object Metadata {
|
|||
private fun getSafeUri(context: Context, uri: Uri, mimeType: String, sizeBytes: Long?): Uri {
|
||||
return when (mimeType) {
|
||||
// formats known to yield OOM for large files
|
||||
MimeTypes.DNG,
|
||||
MimeTypes.DNG_ADOBE,
|
||||
MimeTypes.HEIC,
|
||||
MimeTypes.HEIF,
|
||||
MimeTypes.MP4,
|
||||
|
|
|
@ -60,19 +60,20 @@ object Helper {
|
|||
// e.g. "exif [...] 134 [...] 4578696600004949[...]"
|
||||
private val PNG_RAW_PROFILE_PATTERN = Regex("^\\n(.*?)\\n\\s*(\\d+)\\n(.*)", RegexOption.DOT_MATCHES_ALL)
|
||||
|
||||
// providing the stream length is risky, as it may crash if it is incorrect
|
||||
private const val SAFE_READ_STREAM_LENGTH = -1L
|
||||
|
||||
fun readMimeType(input: InputStream): String? {
|
||||
val bufferedInputStream = if (input is BufferedInputStream) input else BufferedInputStream(input)
|
||||
return FileTypeDetector.detectFileType(bufferedInputStream).mimeType
|
||||
}
|
||||
|
||||
@Throws(IOException::class, ImageProcessingException::class)
|
||||
fun safeRead(input: InputStream, sizeBytes: Long?): com.drew.metadata.Metadata {
|
||||
fun safeRead(input: InputStream, @Suppress("unused_parameter") sizeBytes: Long?): com.drew.metadata.Metadata {
|
||||
val inputStream = if (input is BufferedInputStream) input else BufferedInputStream(input)
|
||||
val fileType = FileTypeDetector.detectFileType(inputStream)
|
||||
val streamLength = sizeBytes ?: SAFE_READ_STREAM_LENGTH
|
||||
|
||||
// Providing the stream length is risky, as it may crash if it is incorrect.
|
||||
// Not providing the stream length is also risky, as it may lead to OOM
|
||||
// when `RandomAccessStreamReader` reads the entire stream to validate offsets.
|
||||
val undefinedStreamLength = -1L
|
||||
|
||||
val metadata = when (fileType) {
|
||||
FileType.Jpeg -> safeReadJpeg(inputStream)
|
||||
|
@ -84,9 +85,9 @@ object Helper {
|
|||
FileType.Cr2,
|
||||
FileType.Nef,
|
||||
FileType.Orf,
|
||||
FileType.Rw2 -> safeReadTiff(inputStream, streamLength)
|
||||
FileType.Rw2 -> safeReadTiff(inputStream, undefinedStreamLength)
|
||||
|
||||
else -> ImageMetadataReader.readMetadata(inputStream, streamLength, fileType)
|
||||
else -> ImageMetadataReader.readMetadata(inputStream, undefinedStreamLength, fileType)
|
||||
}
|
||||
|
||||
metadata.addDirectory(FileTypeDirectory(fileType))
|
||||
|
|
|
@ -28,7 +28,8 @@ object MimeTypes {
|
|||
private const val CR2 = "image/x-canon-cr2"
|
||||
private const val CRW = "image/x-canon-crw"
|
||||
private const val DCR = "image/x-kodak-dcr"
|
||||
const val DNG = "image/x-adobe-dng"
|
||||
const val DNG = "image/dng"
|
||||
const val DNG_ADOBE = "image/x-adobe-dng"
|
||||
private const val ERF = "image/x-epson-erf"
|
||||
private const val K25 = "image/x-kodak-k25"
|
||||
private const val KDC = "image/x-kodak-kdc"
|
||||
|
@ -71,7 +72,7 @@ object MimeTypes {
|
|||
|
||||
fun isRaw(mimeType: String): Boolean {
|
||||
return when (mimeType) {
|
||||
ARW, CR2, CRW, DCR, DNG, ERF, K25, KDC, MRW, NEF, NRW, ORF, PEF, RAF, RAW, RW2, SR2, SRF, SRW, X3F -> true
|
||||
ARW, CR2, CRW, DCR, DNG, DNG_ADOBE, ERF, K25, KDC, MRW, NEF, NRW, ORF, PEF, RAF, RAW, RW2, SR2, SRF, SRW, X3F -> true
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
@ -142,7 +143,7 @@ object MimeTypes {
|
|||
return if (pageId != null && MultiPageImage.isSupported(mimeType)) {
|
||||
true
|
||||
} else when (mimeType) {
|
||||
DNG, HEIC, HEIF, PNG, WEBP -> true
|
||||
DNG, DNG_ADOBE, HEIC, HEIF, PNG, WEBP -> true
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
@ -151,7 +152,7 @@ object MimeTypes {
|
|||
// according to EXIF orientation when decoding images of known formats
|
||||
// but we need to rotate the decoded bitmap for the other formats
|
||||
fun needRotationAfterContentResolverThumbnail(mimeType: String) = when (mimeType) {
|
||||
DNG, PNG -> true
|
||||
DNG, DNG_ADOBE, PNG -> true
|
||||
else -> false
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue