improved thumbnail loading error reporting

This commit is contained in:
Thibault Deckers 2021-08-16 11:32:53 +09:00
parent cb102cbc6b
commit d7e14cd84b
7 changed files with 31 additions and 25 deletions

View file

@ -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)
}
}

View file

@ -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)
}

View file

@ -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) {

View file

@ -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
}

View file

@ -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);

View file

@ -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');

View file

@ -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,8 +262,10 @@ class PlatformImageFileService implements ImageFileService {
});
if (result != null) return result as Uint8List;
} on PlatformException catch (e, stack) {
if (!MimeTypes.knownMediaTypes.contains(mimeType)) {
await reportService.recordError(e, stack);
}
}
return Uint8List(0);
},
priority: priority ?? (extent == 0 ? ServiceCallPriority.getFastThumbnail : ServiceCallPriority.getSizedThumbnail),