fixed crash when opening large PSD
This commit is contained in:
parent
fba090ae1f
commit
492d9964ad
2 changed files with 36 additions and 17 deletions
|
@ -2,7 +2,9 @@ package deckers.thibault.aves.metadata
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
import android.util.Log
|
||||||
import androidx.exifinterface.media.ExifInterface
|
import androidx.exifinterface.media.ExifInterface
|
||||||
|
import deckers.thibault.aves.utils.LogUtils
|
||||||
import deckers.thibault.aves.utils.MimeTypes
|
import deckers.thibault.aves.utils.MimeTypes
|
||||||
import deckers.thibault.aves.utils.StorageUtils
|
import deckers.thibault.aves.utils.StorageUtils
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
@ -13,6 +15,8 @@ import java.util.*
|
||||||
import java.util.regex.Pattern
|
import java.util.regex.Pattern
|
||||||
|
|
||||||
object Metadata {
|
object Metadata {
|
||||||
|
private val LOG_TAG = LogUtils.createTag<Metadata>()
|
||||||
|
|
||||||
// Pattern to extract latitude & longitude from a video location tag (cf ISO 6709)
|
// Pattern to extract latitude & longitude from a video location tag (cf ISO 6709)
|
||||||
// Examples:
|
// Examples:
|
||||||
// "+37.5090+127.0243/" (Samsung)
|
// "+37.5090+127.0243/" (Samsung)
|
||||||
|
@ -96,10 +100,10 @@ object Metadata {
|
||||||
return dateMillis
|
return dateMillis
|
||||||
}
|
}
|
||||||
|
|
||||||
// opening large TIFF files yields an OOM (both with `metadata-extractor` v2.15.0 and `ExifInterface` v1.3.1),
|
// opening large PSD/TIFF 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.
|
// 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.
|
// It is not clear whether it is because of the file itself or its metadata.
|
||||||
private const val tiffSizeBytesMax = 100 * (1 shl 20) // MB
|
private const val fileSizeBytesMax = 100 * (1 shl 20) // MB
|
||||||
|
|
||||||
// we try and read metadata from large files by copying an arbitrary amount from its beginning
|
// we try and read metadata from large files by copying an arbitrary amount from its beginning
|
||||||
// to a temporary file, and reusing that preview file for all metadata reading purposes
|
// to a temporary file, and reusing that preview file for all metadata reading purposes
|
||||||
|
@ -108,25 +112,38 @@ object Metadata {
|
||||||
private val previewFiles = HashMap<Uri, File>()
|
private val previewFiles = HashMap<Uri, File>()
|
||||||
|
|
||||||
private fun getSafeUri(context: Context, uri: Uri, mimeType: String, sizeBytes: Long?): Uri {
|
private fun getSafeUri(context: Context, uri: Uri, mimeType: String, sizeBytes: Long?): Uri {
|
||||||
if (mimeType != MimeTypes.TIFF) return uri
|
return when (mimeType) {
|
||||||
|
// formats known to yield OOM for large files
|
||||||
if (sizeBytes != null && sizeBytes < tiffSizeBytesMax) return uri
|
MimeTypes.PSD_VND,
|
||||||
|
MimeTypes.PSD_X,
|
||||||
var previewFile = previewFiles[uri]
|
MimeTypes.TIFF -> {
|
||||||
if (previewFile == null) {
|
if (sizeBytes != null && sizeBytes < fileSizeBytesMax) {
|
||||||
previewFile = File.createTempFile("aves", null, context.cacheDir).apply {
|
// small enough to be safe as it is
|
||||||
deleteOnExit()
|
uri
|
||||||
outputStream().use { outputStream ->
|
} else {
|
||||||
StorageUtils.openInputStream(context, uri)?.use { inputStream ->
|
// make a preview from the beginning of the file,
|
||||||
val b = ByteArray(previewSize)
|
// hoping the metadata is accessible in the copied chunk
|
||||||
inputStream.read(b, 0, previewSize)
|
Log.d(LOG_TAG, "use a preview for uri=$uri mimeType=$mimeType size=$sizeBytes")
|
||||||
outputStream.write(b)
|
var previewFile = previewFiles[uri]
|
||||||
|
if (previewFile == null) {
|
||||||
|
previewFile = File.createTempFile("aves", null, context.cacheDir).apply {
|
||||||
|
deleteOnExit()
|
||||||
|
outputStream().use { outputStream ->
|
||||||
|
StorageUtils.openInputStream(context, uri)?.use { inputStream ->
|
||||||
|
val b = ByteArray(previewSize)
|
||||||
|
inputStream.read(b, 0, previewSize)
|
||||||
|
outputStream.write(b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
previewFiles[uri] = previewFile
|
||||||
}
|
}
|
||||||
|
Uri.fromFile(previewFile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
previewFiles[uri] = previewFile
|
// *probably* safe
|
||||||
|
else -> uri
|
||||||
}
|
}
|
||||||
return Uri.fromFile(previewFile)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun openSafeInputStream(context: Context, uri: Uri, mimeType: String, sizeBytes: Long?): InputStream? {
|
fun openSafeInputStream(context: Context, uri: Uri, mimeType: String, sizeBytes: Long?): InputStream? {
|
||||||
|
|
|
@ -14,6 +14,8 @@ object MimeTypes {
|
||||||
private const val ICO = "image/x-icon"
|
private const val ICO = "image/x-icon"
|
||||||
const val JPEG = "image/jpeg"
|
const val JPEG = "image/jpeg"
|
||||||
const val PNG = "image/png"
|
const val PNG = "image/png"
|
||||||
|
const val PSD_VND = "image/vnd.adobe.photoshop"
|
||||||
|
const val PSD_X = "image/x-photoshop"
|
||||||
const val TIFF = "image/tiff"
|
const val TIFF = "image/tiff"
|
||||||
private const val WBMP = "image/vnd.wap.wbmp"
|
private const val WBMP = "image/vnd.wap.wbmp"
|
||||||
const val WEBP = "image/webp"
|
const val WEBP = "image/webp"
|
||||||
|
|
Loading…
Reference in a new issue