CaiJingLong / flutter_photo

Pick image/video from album by flutter. Support ios and android. UI by flutter, no native.
Apache License 2.0
301 stars 132 forks source link

HEIC: java.io.FileNotFoundException: Failed to create thumbnail. How to handle it? #130

Open rignaneseleo opened 4 years ago

rignaneseleo commented 4 years ago

Nowadays the HEIC and HEIF contents are not supported from your ImageItem widget that will give an error like this:

E/PhotoManagerPlugin(27461): get thumb error
E/PhotoManagerPlugin(27461): java.io.FileNotFoundException: Failed to create thumbnail
E/PhotoManagerPlugin(27461):    at android.database.DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(DatabaseUtils.java:149)
E/PhotoManagerPlugin(27461):    at android.content.ContentProviderProxy.openTypedAssetFile(ContentProviderNative.java:719)
E/PhotoManagerPlugin(27461):    at android.content.ContentResolver.openTypedAssetFileDescriptor(ContentResolver.java:1705)
E/PhotoManagerPlugin(27461):    at android.content.ContentResolver.openTypedAssetFile(ContentResolver.java:1610)
E/PhotoManagerPlugin(27461):    at android.content.ContentResolver.lambda$loadThumbnail$0(ContentResolver.java:3636)
E/PhotoManagerPlugin(27461):    at android.content.-$$Lambda$ContentResolver$7ILY1SWNxC2xhk-fQUG6tAXW9Ik.call(Unknown Source:10)
E/PhotoManagerPlugin(27461):    at android.graphics.ImageDecoder$CallableSource.createImageDecoder(ImageDecoder.java:550)
E/PhotoManagerPlugin(27461):    at android.graphics.ImageDecoder.decodeBitmapImpl(ImageDecoder.java:1847)
E/PhotoManagerPlugin(27461):    at android.graphics.ImageDecoder.decodeBitmap(ImageDecoder.java:1840)
E/PhotoManagerPlugin(27461):    at android.content.ContentResolver.loadThumbnail(ContentResolver.java:3635)
E/PhotoManagerPlugin(27461):    at android.content.ContentResolver.loadThumbnail(ContentResolver.java:3619)
E/PhotoManagerPlugin(27461):    at top.kikt.imagescanner.core.utils.AndroidQDBUtils.getThumb(AndroidQDBUtils.kt:300)
E/PhotoManagerPlugin(27461):    at top.kikt.imagescanner.core.PhotoManager.getThumb(PhotoManager.kt:85)
E/PhotoManagerPlugin(27461):    at top.kikt.imagescanner.core.PhotoManagerPlugin.onHandlePermissionResult(PhotoManagerPlugin.kt:198)
E/PhotoManagerPlugin(27461):    at top.kikt.imagescanner.core.PhotoManagerPlugin.access$onHandlePermissionResult(PhotoManagerPlugin.kt:23)
E/PhotoManagerPlugin(27461):    at top.kikt.imagescanner.core.PhotoManagerPlugin$onMethodCall$$inlined$apply$lambda$1.onGranted(PhotoManagerPlugin.kt:134)
E/PhotoManagerPlugin(27461):    at top.kikt.imagescanner.old.permission.PermissionsUtils.getPermissionsWithTips(PermissionsUtils.java:128)
E/PhotoManagerPlugin(27461):    at top.kikt.imagescanner.old.permission.PermissionsUtils.getPermissions(PermissionsUtils.java:102)
E/PhotoManagerPlugin(27461):    at top.kikt.imagescanner.core.PhotoManagerPlugin.onMethodCall(PhotoManagerPlugin.kt:145)
E/PhotoManagerPlugin(27461):    at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:230)
E/PhotoManagerPlugin(27461):    at io.flutter.embedding.engine.dart.DartMessenger.handleMessageFromDart(DartMessenger.java:85)
E/PhotoManagerPlugin(27461):    at io.flutter.embedding.engine.FlutterJNI.handlePlatformMessage(FlutterJNI.java:650)
E/PhotoManagerPlugin(27461):    at android.os.MessageQueue.nativePollOnce(Native Method)
E/PhotoManagerPlugin(27461):    at android.os.MessageQueue.next(MessageQueue.java:336)
E/PhotoManagerPlugin(27461):    at android.os.Looper.loop(Looper.java:174)
E/PhotoManagerPlugin(27461):    at android.app.ActivityThread.main(ActivityThread.java:7697)
E/PhotoManagerPlugin(27461):    at java.lang.reflect.Method.invoke(Native Method)
E/PhotoManagerPlugin(27461):    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:516)
E/PhotoManagerPlugin(27461):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)

I'm wondering if you can let us handle the onError situation so we can manually convert the picture in JPG and display it.

Thanks

rignaneseleo commented 4 years ago

I solved using this workaround widget:

import 'dart:typed_data';
import 'dart:ui';
import 'package:photo/photo.dart';
import 'package:photo_manager/photo_manager.dart';
import 'package:flutter/material.dart';
import 'package:photo/src/delegate/badge_delegate.dart';
import 'package:photo/src/delegate/loading_delegate.dart';
import 'package:photo/src/engine/lru_cache.dart';

class MyImageItem extends StatefulWidget {
  final AssetEntity entity;

  final Color themeColor;

  final int size;

  final LoadingDelegate loadingDelegate;

  final BadgeDelegate badgeDelegate;

  const MyImageItem({
    Key key,
    this.entity,
    this.themeColor,
    this.size = 64,
    this.loadingDelegate,
    this.badgeDelegate,
  }) : super(key: key);

  @override
  _MyImageItemState createState() => _MyImageItemState();
}

class _MyImageItemState extends State<MyImageItem> {
  bool _isInit = false;
  Uint8List data;

  @override
  void initState() {
    _load();
    super.initState();
  }

  _load() async {
    setState(() {
      _isInit = false;
    });

    try {
      data = await widget.entity.thumbDataWithSize(widget.size, widget.size);
    } catch (e) {
      print("ERROR!!!!!!!!!!");
      data= //LOAD HERE A REPLACER
    }

    setState(() {
      _isInit = true;
    });
  }

  @override
  Widget build(BuildContext context) {
    if (!_isInit)
      return Center(
        child: widget.loadingDelegate.buildPreviewLoading(
          context,
          widget.entity,
          widget.themeColor,
        ),
      );

    var thumb = ImageLruCache.getData(widget.entity, widget.size);
    if (thumb != null) {
      return _buildImageItem(context, thumb);
    }

    ImageLruCache.setData(widget.entity, widget.size, data);
    return _buildImageItem(context, data);
  }

  Widget _buildImageItem(BuildContext context, Uint8List data) {
    var image = Image.memory(
      data,
      width: double.infinity,
      height: double.infinity,
      fit: BoxFit.cover,
    );
    var badge;
    final badgeBuilder = widget.badgeDelegate
        ?.buildBadge(context, widget.entity.type, widget.entity.videoDuration);
    if (badgeBuilder == null) {
      badge = Container();
    } else {
      badge = badgeBuilder;
    }

    return Stack(
      children: <Widget>[
        image,
        IgnorePointer(
          child: badge,
        ),
      ],
    );
  }
}