improved thumbnail loading error reporting
This commit is contained in:
parent
cb102cbc6b
commit
d7e14cd84b
7 changed files with 31 additions and 25 deletions
|
@ -81,7 +81,7 @@ class ThumbnailFetcher internal constructor(
|
|||
if (errorDetails?.isNotEmpty() == true) {
|
||||
errorDetails = errorDetails.split("\n".toRegex(), 2).first()
|
||||
}
|
||||
result.error("getThumbnail-null", "failed to get thumbnail for uri=$uri", errorDetails)
|
||||
result.error("getThumbnail-null", "failed to get thumbnail for mimeType=$mimeType uri=$uri", errorDetails)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -95,22 +95,22 @@ class ImageByteStreamHandler(private val activity: Activity, private val argumen
|
|||
}
|
||||
|
||||
if (isVideo(mimeType)) {
|
||||
streamVideoByGlide(uri)
|
||||
streamVideoByGlide(uri, mimeType)
|
||||
} else if (!isSupportedByFlutter(mimeType, rotationDegrees, isFlipped)) {
|
||||
// decode exotic format on platform side, then encode it in portable format for Flutter
|
||||
streamImageByGlide(uri, pageId, mimeType, rotationDegrees, isFlipped)
|
||||
} else {
|
||||
// to be decoded by Flutter
|
||||
streamImageAsIs(uri)
|
||||
streamImageAsIs(uri, mimeType)
|
||||
}
|
||||
endOfStream()
|
||||
}
|
||||
|
||||
private fun streamImageAsIs(uri: Uri) {
|
||||
private fun streamImageAsIs(uri: Uri, mimeType: String) {
|
||||
try {
|
||||
StorageUtils.openInputStream(activity, uri)?.use { input -> streamBytes(input) }
|
||||
} catch (e: IOException) {
|
||||
error("streamImage-image-read-exception", "failed to get image from uri=$uri", e.message)
|
||||
error("streamImage-image-read-exception", "failed to get image for mimeType=$mimeType uri=$uri", e.message)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -137,16 +137,16 @@ class ImageByteStreamHandler(private val activity: Activity, private val argumen
|
|||
if (bitmap != null) {
|
||||
success(bitmap.getBytes(MimeTypes.canHaveAlpha(mimeType), recycle = false))
|
||||
} else {
|
||||
error("streamImage-image-decode-null", "failed to get image from uri=$uri", null)
|
||||
error("streamImage-image-decode-null", "failed to get image for mimeType=$mimeType uri=$uri", null)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
error("streamImage-image-decode-exception", "failed to get image from uri=$uri model=$model", toErrorDetails(e))
|
||||
error("streamImage-image-decode-exception", "failed to get image for mimeType=$mimeType uri=$uri model=$model", toErrorDetails(e))
|
||||
} finally {
|
||||
Glide.with(activity).clear(target)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun streamVideoByGlide(uri: Uri) {
|
||||
private suspend fun streamVideoByGlide(uri: Uri, mimeType: String) {
|
||||
val target = Glide.with(activity)
|
||||
.asBitmap()
|
||||
.apply(glideOptions)
|
||||
|
@ -158,10 +158,10 @@ class ImageByteStreamHandler(private val activity: Activity, private val argumen
|
|||
if (bitmap != null) {
|
||||
success(bitmap.getBytes(canHaveAlpha = false, recycle = false))
|
||||
} else {
|
||||
error("streamImage-video-null", "failed to get image from uri=$uri", null)
|
||||
error("streamImage-video-null", "failed to get image for mimeType=$mimeType uri=$uri", null)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
error("streamImage-video-exception", "failed to get image from uri=$uri", e.message)
|
||||
error("streamImage-video-exception", "failed to get image for mimeType=$mimeType uri=$uri", e.message)
|
||||
} finally {
|
||||
Glide.with(activity).clear(target)
|
||||
}
|
||||
|
|
|
@ -161,7 +161,7 @@ abstract class ImageProvider {
|
|||
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")
|
||||
bitmap ?: throw Exception("failed to get image for mimeType=$sourceMimeType uri=$sourceUri page=$pageId")
|
||||
|
||||
destinationDocFile.openOutputStream().use { output ->
|
||||
if (exportMimeType == MimeTypes.BMP) {
|
||||
|
|
|
@ -37,6 +37,7 @@ object MimeTypes {
|
|||
|
||||
private const val VIDEO = "video"
|
||||
|
||||
private const val MKV = "video/x-matroska"
|
||||
private const val MP2T = "video/mp2t"
|
||||
private const val MP2TS = "video/mp2ts"
|
||||
const val MP4 = "video/mp4"
|
||||
|
@ -72,7 +73,7 @@ object MimeTypes {
|
|||
|
||||
// as of `metadata-extractor` v2.14.0
|
||||
fun isSupportedByMetadataExtractor(mimeType: String) = when (mimeType) {
|
||||
DJVU, WBMP, MP2T, MP2TS, OGV, WEBM -> false
|
||||
DJVU, WBMP, MKV, MP2T, MP2TS, OGV, WEBM -> false
|
||||
else -> true
|
||||
}
|
||||
|
||||
|
|
|
@ -43,15 +43,6 @@ class AvesEntry {
|
|||
|
||||
final AChangeNotifier imageChangeNotifier = AChangeNotifier(), metadataChangeNotifier = AChangeNotifier(), addressChangeNotifier = AChangeNotifier();
|
||||
|
||||
// TODO TLAD make it dynamic if it depends on OS/lib versions
|
||||
static const List<String> undecodable = [
|
||||
MimeTypes.art,
|
||||
MimeTypes.crw,
|
||||
MimeTypes.djvu,
|
||||
MimeTypes.psdVnd,
|
||||
MimeTypes.psdX,
|
||||
];
|
||||
|
||||
AvesEntry({
|
||||
required this.uri,
|
||||
required String? path,
|
||||
|
@ -74,7 +65,7 @@ class AvesEntry {
|
|||
this.durationMillis = durationMillis;
|
||||
}
|
||||
|
||||
bool get canDecode => !undecodable.contains(mimeType);
|
||||
bool get canDecode => !MimeTypes.undecodableImages.contains(mimeType);
|
||||
|
||||
bool get canHaveAlpha => MimeTypes.alphaImages.contains(mimeType);
|
||||
|
||||
|
|
|
@ -41,18 +41,29 @@ class MimeTypes {
|
|||
static const anyVideo = 'video/*';
|
||||
|
||||
static const avi = 'video/avi';
|
||||
static const mkv = 'video/x-matroska';
|
||||
static const mov = 'video/quicktime';
|
||||
static const mp2t = 'video/mp2t'; // .m2ts
|
||||
static const mp4 = 'video/mp4';
|
||||
static const ogg = 'video/ogg';
|
||||
|
||||
static const json = 'application/json';
|
||||
|
||||
// groups
|
||||
|
||||
// formats that support transparency
|
||||
static const List<String> alphaImages = [bmp, gif, ico, png, svg, tiff, webp];
|
||||
static const Set<String> alphaImages = {bmp, gif, ico, png, svg, tiff, webp};
|
||||
|
||||
static const List<String> rawImages = [arw, cr2, crw, dcr, dng, erf, k25, kdc, mrw, nef, nrw, orf, pef, raf, raw, rw2, sr2, srf, srw, x3f];
|
||||
static const Set<String> rawImages = {arw, cr2, crw, dcr, dng, erf, k25, kdc, mrw, nef, nrw, orf, pef, raf, raw, rw2, sr2, srf, srw, x3f};
|
||||
|
||||
// TODO TLAD make it dynamic if it depends on OS/lib versions
|
||||
static const Set<String> undecodableImages = {art, crw, djvu, psdVnd, psdX};
|
||||
|
||||
static const Set<String> _knownOpaqueImages = {heic, heif, jpeg};
|
||||
|
||||
static const Set<String> _knownVideos = {avi, mkv, mov, mp2t, mp4, ogg};
|
||||
|
||||
static final Set<String> knownMediaTypes = {..._knownOpaqueImages, ...alphaImages, ...rawImages, ...undecodableImages, ..._knownVideos};
|
||||
|
||||
static bool isImage(String mimeType) => mimeType.startsWith('image');
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import 'dart:typed_data';
|
|||
import 'dart:ui';
|
||||
|
||||
import 'package:aves/model/entry.dart';
|
||||
import 'package:aves/ref/mime_types.dart';
|
||||
import 'package:aves/services/image_op_events.dart';
|
||||
import 'package:aves/services/output_buffer.dart';
|
||||
import 'package:aves/services/service_policy.dart';
|
||||
|
@ -261,7 +262,9 @@ class PlatformImageFileService implements ImageFileService {
|
|||
});
|
||||
if (result != null) return result as Uint8List;
|
||||
} on PlatformException catch (e, stack) {
|
||||
await reportService.recordError(e, stack);
|
||||
if (!MimeTypes.knownMediaTypes.contains(mimeType)) {
|
||||
await reportService.recordError(e, stack);
|
||||
}
|
||||
}
|
||||
return Uint8List(0);
|
||||
},
|
||||
|
|
Loading…
Reference in a new issue