decodeFrame method

  1. @override
Image? decodeFrame(
  1. int frame
)
override

Decode the frame (assuming startDecode has already been called).

Implementation

@override
Image? decodeFrame(int frame) {
  if (_info == null) {
    return null;
  }

  Uint8List imageData;

  int? width = _info!.width;
  int? height = _info!.height;

  if (!_info!.isAnimated || frame == 0) {
    var dataBlocks = <Uint8List>[];
    var totalSize = 0;
    for (var i = 0, len = _info!.idat.length; i < len; ++i) {
      _input.offset = _info!.idat[i];
      final chunkSize = _input.readUint32();
      final chunkType = _input.readString(4);
      final data = _input.readBytes(chunkSize).toUint8List();
      totalSize += data.length;
      dataBlocks.add(data);
      final crc = _input.readUint32();
      final computedCrc = _crc(chunkType, data);
      if (crc != computedCrc) {
        throw ImageException('Invalid $chunkType checksum');
      }
    }
    imageData = Uint8List(totalSize);
    var offset = 0;
    for (var data in dataBlocks) {
      imageData.setAll(offset, data);
      offset += data.length;
    }
  } else {
    if (frame < 0 || frame >= _info!.frames.length) {
      throw ImageException('Invalid Frame Number: $frame');
    }

    final f = _info!.frames[frame] as InternalPngFrame;
    width = f.width;
    height = f.height;
    var totalSize = 0;
    var dataBlocks = <Uint8List>[];
    for (var i = 0; i < f.fdat.length; ++i) {
      _input.offset = f.fdat[i];
      final chunkSize = _input.readUint32();
      _input.readString(4); // fDat chunk header
      _input.skip(4); // sequence number
      final data = _input.readBytes(chunkSize - 4).toUint8List();
      totalSize += data.length;
      dataBlocks.add(data);
    }
    imageData = Uint8List(totalSize);
    var offset = 0;
    for (var data in dataBlocks) {
      imageData.setAll(offset, data);
      offset += data.length;
    }

    //_frame = frame;
    //_numFrames = _info.numFrames;
  }

  Channels channels;
  if (_info!.colorType == GRAYSCALE_ALPHA ||
      _info!.colorType == RGBA ||
      _info!.transparency != null) {
    channels = Channels.rgba;
  } else {
    channels = Channels.rgb;
  }

  final image = Image(width!, height!, channels: channels);

  List<int> uncompressed;
  try {
    uncompressed = const ZLibDecoder().decodeBytes(imageData);
  } catch (error) {
    print(error);
    return null;
  }

  // input is the decompressed data.
  final input = InputBuffer(uncompressed, bigEndian: true);
  _resetBits();

  // Set up a LUT to transform colors for gamma correction.
  if (_info!.colorLut == null) {
    _info!.colorLut = List<int>.generate(256, (i) {
      final c = i;
      /*if (info.gamma != null) {
        c = (Math.pow((c / 255.0), info.gamma) * 255.0).toInt();
      }*/
      return c;
    }, growable: false);

    // Apply the LUT to the palette, if necessary.
    if (_info!.palette != null && _info!.gamma != null) {
      for (var i = 0; i < _info!.palette!.length; ++i) {
        _info!.palette![i] = _info!.colorLut![_info!.palette![i]!];
      }
    }
  }

  final origW = _info!.width;
  final origH = _info!.height;
  _info!.width = width;
  _info!.height = height;

  final w = width;
  final h = height;
  _progressY = 0;
  if (_info!.interlaceMethod != 0) {
    _processPass(input, image, 0, 0, 8, 8, (w + 7) >> 3, (h + 7) >> 3);
    _processPass(input, image, 4, 0, 8, 8, (w + 3) >> 3, (h + 7) >> 3);
    _processPass(input, image, 0, 4, 4, 8, (w + 3) >> 2, (h + 3) >> 3);
    _processPass(input, image, 2, 0, 4, 4, (w + 1) >> 2, (h + 3) >> 2);
    _processPass(input, image, 0, 2, 2, 4, (w + 1) >> 1, (h + 1) >> 2);
    _processPass(input, image, 1, 0, 2, 2, w >> 1, (h + 1) >> 1);
    _processPass(input, image, 0, 1, 1, 2, w, h >> 1);
  } else {
    _process(input, image);
  }

  _info!.width = origW;
  _info!.height = origH;

  if (_info!.iCCPData != null) {
    image.iccProfile = ICCProfileData(
        _info!.iCCPName, ICCPCompression.deflate, _info!.iCCPData!);
  }

  if (_info!.textData.isNotEmpty) {
    image.addTextData(_info!.textData);
  }

  return image;
}