void AvifDecompressor::_ensureEntireImageIsRead()

in cpp/spectrum/plugins/avif/AvifDecompressor.cpp [89:145]


void AvifDecompressor::_ensureEntireImageIsRead() {
  if (_entireImageHasBeenRead) {
    return;
  }
  _entireImageHasBeenRead = true;

  _parseContainer();

  SPECTRUM_ERROR_CSTR_IF_NOT(
      AVIF_RESULT_OK == avifDecoderNextImage(_decoder) && _decoder->image,
      codecs::error::DecompressorFailure,
      "failed avifDecoderNextImage");
  _sourceData.clear();

  const auto image = _decoder->image;

  avifRGBImage rgb;
  avifRGBImageSetDefaults(&rgb, image);
  rgb.depth = 8;
  rgb.format = AVIF_RGB_FORMAT_RGB;

  avifRGBImageAllocatePixels(&rgb);
  SCOPE_EXIT {
    avifRGBImageFreePixels(&rgb);
  };

  SPECTRUM_ERROR_CSTR_IF_NOT(
      AVIF_RESULT_OK == avifImageYUVToRGB(image, &rgb),
      codecs::error::DecompressorFailure,
      "failed avifImageYUVToRGB");

  _entireImage.reserve(image->height);
  for (auto row = 0; row < image->height; ++row) {
    auto scanline = std::make_unique<image::Scanline>(
        image::pixel::specifications::RGB, image->width);

    SPECTRUM_ERROR_FORMAT_IF_NOT(
        scanline->sizeBytes() == rgb.rowBytes,
        codecs::error::DecompressorFailure,
        "scanline size (%d) does not match decoded row bytes (%d)",
        scanline->sizeBytes(),
        rgb.rowBytes);

    std::memcpy(
        scanline->data(), rgb.pixels + row * rgb.rowBytes, rgb.rowBytes);
    _entireImage.push_back(std::move(scanline));
  }

  _imageSpecification = image::Specification{
      .size = image::Size{image->width, image->height},
      .format = image::formats::Avif,
      .pixelSpecification = image::pixel::specifications::RGB};

  // We are done with the decoder, free it now to save memory
  avifDecoderDestroy(_decoder);
  _decoder = nullptr;
}