From b59b323d34c81ca36b889203b04e81f8b6f591a3 Mon Sep 17 00:00:00 2001 From: Thibault Deckers Date: Mon, 25 Jan 2021 18:21:18 +0900 Subject: [PATCH] multipage: heic track tiling --- .../aves/channel/calls/ImageFileHandler.kt | 24 ++++---- .../calls/{ => fetchers}/RegionFetcher.kt | 57 ++++++++++++++++++- .../calls/{ => fetchers}/ThumbnailFetcher.kt | 2 +- .../calls/{ => fetchers}/TiffRegionFetcher.kt | 4 +- lib/model/entry.dart | 3 +- 5 files changed, 73 insertions(+), 17 deletions(-) rename android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/{ => fetchers}/RegionFetcher.kt (58%) rename android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/{ => fetchers}/ThumbnailFetcher.kt (99%) rename android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/{ => fetchers}/TiffRegionFetcher.kt (95%) diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/ImageFileHandler.kt b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/ImageFileHandler.kt index 43a8ff81d..f37b4f2ce 100644 --- a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/ImageFileHandler.kt +++ b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/ImageFileHandler.kt @@ -5,6 +5,9 @@ import android.graphics.Rect import android.net.Uri import android.util.Size import com.bumptech.glide.Glide +import deckers.thibault.aves.channel.calls.fetchers.RegionFetcher +import deckers.thibault.aves.channel.calls.fetchers.ThumbnailFetcher +import deckers.thibault.aves.channel.calls.fetchers.TiffRegionFetcher import deckers.thibault.aves.model.ExifOrientationOp import deckers.thibault.aves.model.provider.FieldMap import deckers.thibault.aves.model.provider.ImageProvider.ImageOpCallback @@ -102,19 +105,20 @@ class ImageFileHandler(private val activity: Activity) : MethodCallHandler { val regionRect = Rect(x, y, x + width, y + height) when (mimeType) { MimeTypes.TIFF -> TiffRegionFetcher(activity).fetch( - uri, - sampleSize, - regionRect, + uri = uri, page = pageId ?: 0, - result, + sampleSize = sampleSize, + regionRect = regionRect, + result = result, ) else -> regionFetcher.fetch( - uri, - mimeType, - sampleSize, - regionRect, - Size(imageWidth, imageHeight), - result, + uri = uri, + mimeType = mimeType, + pageId = pageId, + sampleSize = sampleSize, + regionRect = regionRect, + imageSize = Size(imageWidth, imageHeight), + result = result, ) } } diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/RegionFetcher.kt b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/fetchers/RegionFetcher.kt similarity index 58% rename from android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/RegionFetcher.kt rename to android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/fetchers/RegionFetcher.kt index 7b9689a7e..e432fac28 100644 --- a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/RegionFetcher.kt +++ b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/fetchers/RegionFetcher.kt @@ -1,15 +1,22 @@ -package deckers.thibault.aves.channel.calls +package deckers.thibault.aves.channel.calls.fetchers import android.content.Context +import android.graphics.Bitmap import android.graphics.BitmapFactory import android.graphics.BitmapRegionDecoder import android.graphics.Rect import android.net.Uri import android.util.Size +import com.bumptech.glide.Glide +import com.bumptech.glide.load.DecodeFormat +import com.bumptech.glide.load.engine.DiskCacheStrategy +import com.bumptech.glide.request.RequestOptions +import deckers.thibault.aves.decoder.MultiTrackImage import deckers.thibault.aves.utils.BitmapUtils.getBytes import deckers.thibault.aves.utils.MimeTypes import deckers.thibault.aves.utils.StorageUtils import io.flutter.plugin.common.MethodChannel +import java.io.File import kotlin.math.roundToInt class RegionFetcher internal constructor( @@ -17,21 +24,42 @@ class RegionFetcher internal constructor( ) { private var lastDecoderRef: LastDecoderRef? = null + private val pageTempUris = HashMap, Uri>() + + private val multiTrackGlideOptions = RequestOptions() + .format(DecodeFormat.PREFER_ARGB_8888) + .diskCacheStrategy(DiskCacheStrategy.NONE) + .skipMemoryCache(true) + fun fetch( uri: Uri, mimeType: String, + pageId: Int?, sampleSize: Int, regionRect: Rect, imageSize: Size, result: MethodChannel.Result, ) { + if (MimeTypes.isHeifLike(mimeType) && pageId != null) { + val id = Pair(uri, pageId) + fetch( + uri = pageTempUris.getOrPut(id) { createJpegForPage(uri, pageId) }, + mimeType = MimeTypes.JPEG, + pageId = null, + sampleSize = sampleSize, + regionRect = regionRect, + imageSize = imageSize, + result = result, + ) + return + } + val options = BitmapFactory.Options().apply { inSampleSize = sampleSize } var currentDecoderRef = lastDecoderRef if (currentDecoderRef != null && currentDecoderRef.uri != uri) { - currentDecoderRef.decoder.recycle() currentDecoderRef = null } @@ -74,6 +102,31 @@ class RegionFetcher internal constructor( result.error("getRegion-read-exception", "failed to initialize region decoder for uri=$uri regionRect=$regionRect", e.message) } } + + private fun createJpegForPage(sourceUri: Uri, pageId: Int): Uri { + val target = Glide.with(context) + .asBitmap() + .apply(multiTrackGlideOptions) + .load(MultiTrackImage(context, sourceUri, pageId)) + .submit() + try { + val bitmap = target.get() +// if (MimeTypes.needRotationAfterGlide(sourceMimeType)) { +// bitmap = BitmapUtils.applyExifOrientation(context, bitmap, sourceEntry.rotationDegrees, sourceEntry.isFlipped) +// } + bitmap ?: throw Exception("failed to get image from uri=$sourceUri page=$pageId") + + val tempFile = File.createTempFile("aves", null, context.cacheDir).apply { + deleteOnExit() + outputStream().use { outputStream -> + bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream) + } + } + return Uri.fromFile(tempFile) + } finally { + Glide.with(context).clear(target) + } + } } private data class LastDecoderRef( diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/ThumbnailFetcher.kt b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/fetchers/ThumbnailFetcher.kt similarity index 99% rename from android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/ThumbnailFetcher.kt rename to android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/fetchers/ThumbnailFetcher.kt index 5d9f83388..e631af9eb 100644 --- a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/ThumbnailFetcher.kt +++ b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/fetchers/ThumbnailFetcher.kt @@ -1,4 +1,4 @@ -package deckers.thibault.aves.channel.calls +package deckers.thibault.aves.channel.calls.fetchers import android.content.ContentUris import android.content.Context diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/TiffRegionFetcher.kt b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/fetchers/TiffRegionFetcher.kt similarity index 95% rename from android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/TiffRegionFetcher.kt rename to android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/fetchers/TiffRegionFetcher.kt index 2d17f62d6..502553422 100644 --- a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/TiffRegionFetcher.kt +++ b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/fetchers/TiffRegionFetcher.kt @@ -1,4 +1,4 @@ -package deckers.thibault.aves.channel.calls +package deckers.thibault.aves.channel.calls.fetchers import android.content.Context import android.graphics.Rect @@ -13,9 +13,9 @@ class TiffRegionFetcher internal constructor( ) { fun fetch( uri: Uri, + page: Int, sampleSize: Int, regionRect: Rect, - page: Int = 0, result: MethodChannel.Result, ) { try { diff --git a/lib/model/entry.dart b/lib/model/entry.dart index ab7101131..d2244db43 100644 --- a/lib/model/entry.dart +++ b/lib/model/entry.dart @@ -227,8 +227,7 @@ class AvesEntry { MimeTypes.rw2, MimeTypes.srw, ].contains(mimeType) && - !isAnimated && - pageId == null; + !isAnimated; bool get supportTiling => _supportedByBitmapRegionDecoder || mimeType == MimeTypes.tiff;