decode method

  1. @override
Future<DecodeResult> decode(
  1. RequestContext ctx,
  2. FetchResult fetch
)

Implementation

@override
Future<DecodeResult> decode(RequestContext ctx, FetchResult fetch) async {
  final bytes = await fetch.dataSource.bytes();
  ctx.cancelToken.throwIfCancelled();

  final target = await ctx.request.size?.resolve();
  final Map<Object?, Object?>? payload;
  try {
    payload = await _channel.invokeMapMethod<Object?, Object?>('decode', {
      'bytes': bytes,
      'targetWidth': target?.width,
      'targetHeight': target?.height,
    });
  } on PlatformException catch (e) {
    throw ImageLoadException(
      'AVIF decode failed: ${e.message}',
      cause: e,
      source: ctx.request.source,
    );
  } on MissingPluginException catch (e) {
    throw ImageLoadException(
      'AVIF plugin not available on this platform',
      cause: e,
      source: ctx.request.source,
    );
  }
  if (payload == null) {
    throw ImageLoadException('AVIF decode returned nothing',
        source: ctx.request.source);
  }

  final png = payload['png'] as Uint8List?;
  if (png == null) {
    throw ImageLoadException('AVIF decode returned no image',
        source: ctx.request.source);
  }
  final frameCount = (payload['frameCount'] as int?) ?? 1;

  // instantiateImageCodecFromBuffer takes ownership of the buffer and
  // disposes it once the codec is built — we must not dispose it ourselves.
  final buffer = await ui.ImmutableBuffer.fromUint8List(png);
  final codec = await ui.instantiateImageCodecFromBuffer(buffer);
  try {
    final frame = await codec.getNextFrame();
    return DecodeResult(
      image: frame.image,
      from: fetch.dataSource.from,
      mimeType: 'image/avif',
      frameCount: frameCount,
    );
  } finally {
    codec.dispose();
  }
}