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.net.Uri
|
||||
import android.util.Log
|
||||
import androidx.exifinterface.media.ExifInterface
|
||||
import deckers.thibault.aves.utils.LogUtils
|
||||
import deckers.thibault.aves.utils.MimeTypes
|
||||
import deckers.thibault.aves.utils.StorageUtils
|
||||
import java.io.File
|
||||
|
@ -13,6 +15,8 @@ import java.util.*
|
|||
import java.util.regex.Pattern
|
||||
|
||||
object Metadata {
|
||||
private val LOG_TAG = LogUtils.createTag<Metadata>()
|
||||
|
||||
// Pattern to extract latitude & longitude from a video location tag (cf ISO 6709)
|
||||
// Examples:
|
||||
// "+37.5090+127.0243/" (Samsung)
|
||||
|
@ -96,10 +100,10 @@ object Metadata {
|
|||
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.
|
||||
// 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
|
||||
// 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 fun getSafeUri(context: Context, uri: Uri, mimeType: String, sizeBytes: Long?): Uri {
|
||||
if (mimeType != MimeTypes.TIFF) return uri
|
||||
|
||||
if (sizeBytes != null && sizeBytes < tiffSizeBytesMax) return uri
|
||||
|
||||
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)
|
||||
return when (mimeType) {
|
||||
// formats known to yield OOM for large files
|
||||
MimeTypes.PSD_VND,
|
||||
MimeTypes.PSD_X,
|
||||
MimeTypes.TIFF -> {
|
||||
if (sizeBytes != null && sizeBytes < fileSizeBytesMax) {
|
||||
// small enough to be safe as it is
|
||||
uri
|
||||
} else {
|
||||
// make a preview from the beginning of the file,
|
||||
// hoping the metadata is accessible in the copied chunk
|
||||
Log.d(LOG_TAG, "use a preview for uri=$uri mimeType=$mimeType size=$sizeBytes")
|
||||
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? {
|
||||
|
|
|
@ -14,6 +14,8 @@ object MimeTypes {
|
|||
private const val ICO = "image/x-icon"
|
||||
const val JPEG = "image/jpeg"
|
||||
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"
|
||||
private const val WBMP = "image/vnd.wap.wbmp"
|
||||
const val WEBP = "image/webp"
|
||||
|
|
Loading…
Reference in a new issue