AOMediaCodec / libavif

libavif - Library for encoding and decoding .avif files
Other
1.53k stars 195 forks source link

[Support] Reading a crop region from a file #1147

Open rfezzani opened 1 year ago

rfezzani commented 1 year ago

Hello and thank you for this amazing library :slightly_smiling_face:

I am interested in reading only a crop region [i0, j0, h, w] from a large gird image. I though about using avifCropRect for that:

.
.
.
  const avifCropRect rect = {(uint32_t)j0, (uint32_t)i0,
                             (uint32_t)w, (uint32_t)h};

  avifRGBImage rgb;
  memset(&rgb, 0, sizeof(avifRGBImage));
  (&rgb)->width = (int)w;
  (&rgb)->height = (int)h;
  (&rgb)->depth = decoder->image->depth;
  (&rgb)->rowBytes = (&rgb)->width * avifRGBImagePixelSize(&rgb);
  (&rgb)->format = AVIF_RGB_FORMAT_RGB;
  (&rgb)->pixels = (uint8_t *)buf;

  avifImage* image_crop = avifImageCreate(h, w, decoder->image->depth, decoder->image->yuvFormat);
  avifImageSetViewRect(image_crop, decoder->image, &rect);

  if (avifImageYUVToRGB(image_crop, &rgb,
                        AVIF_YUV_TO_RGB_DEFAULT) != AVIF_RESULT_OK) {
    avifDecoderDestroy(decoder);
    avifImageDestroy(image_crop);
    return 1;
  }
.
.
.

But I get a segfault :confused:

Am I doing something wrong or is there any other way to achieve my goal? Thanks in advance for your help :wink:

y-guyon commented 1 year ago

I am interested in reading only a crop region [i0, j0, h, w] from a large gird image.

I am afraid there is currently no API in libavif to decode only some area of a grid image.

Code snippet to decode the entire image and get a view on a crop of it:

avifImage * image = avifImageCreateEmpty();
avifImage * croppedImage = avifImageCreateEmpty();
avifDecoder * decoder = avifDecoderCreate();
avifResult result = avifDecoderReadFile(decoder, image, "/path/to/image.avif");
avifDecoderDestroy(decoder);
if (result != AVIF_RESULT_OK) {
  // Handle error
} else {
  const avifCropRect rect = {(uint32_t)j0, (uint32_t)i0, (uint32_t)w, (uint32_t)h};
  result = avifImageSetViewRect(croppedImage, image, &rect);
  if (result != AVIF_RESULT_OK) {
    // Handle error
  } else {
    // Access croppedImage data
  }
}
avifImageDestroy(croppedImage);
avifImageDestroy(image);

I though about using avifCropRect for that

Do not forget to check the avifResult output value of functions such as avifImageSetViewRect().


I am not aware of an API in libheif to decode only some area of a grid AVIF image either, but I am not very familiar with libheif.

An involved alternative would be to use libheif to parse heif_image_handles until finding the cells overlapping the crop rectangle. Then decoding only those cells, reconstructing and trimming the output should work.

rfezzani commented 1 year ago

Thank you for your answer @y-guyon and the code snipped. My goal was to avoid loading the entire image in memory :sweat_smile:. Your alternative solution seems reasonable, but is there any way to manipulate grid cells directly from libavif? If not this may be a great addition ;)

y-guyon commented 1 year ago

is there any way to manipulate grid cells directly from libavif?

Not that I know of, and adding this feature is not planned. Adding some avifCropRect cropOutput to avifDecoder might be worth discussing though.

rfezzani commented 1 year ago

Adding some avifCropRect cropOutput to avifDecoder...

That's what I meant :slightly_smiling_face:, thank you again!

seraphlee commented 1 year ago

i think i really need avif region decoder 😭, because some Android device performance is poor,i can't decode large image on it.