@@ -627,8 +627,8 @@ avifBool avifPNGWrite(const char * outputFilename, const avifImage * avif, uint3
627627 png_bytep * volatile rowPointers = NULL ;
628628 FILE * volatile f = NULL ;
629629
630- avifRGBImage rgb ;
631- memset (& rgb , 0 , sizeof (avifRGBImage ));
630+ avifRGBImage rgbData ;
631+ memset (& rgbData , 0 , sizeof (avifRGBImage ));
632632
633633 volatile int rgbDepth = requestedDepth ;
634634 if (rgbDepth == 0 ) {
@@ -651,39 +651,55 @@ avifBool avifPNGWrite(const char * outputFilename, const avifImage * avif, uint3
651651 rgbDepth = 8 ;
652652 }
653653
654- volatile avifBool monochrome8bit = (avif -> yuvFormat == AVIF_PIXEL_FORMAT_YUV400 ) && !avif -> alphaPlane && (avif -> depth == 8 ) &&
655- (rgbDepth == 8 );
654+ volatile avifBool hasClap = avif -> transformFlags & AVIF_TRANSFORM_CLAP ;
655+ volatile avifBool copyYPlane = (avif -> yuvFormat == AVIF_PIXEL_FORMAT_YUV400 ) && !avif -> alphaPlane && (avif -> depth == 8 ) &&
656+ (rgbDepth == 8 ) && !hasClap ;
656657
657658 volatile int colorType ;
658- if (monochrome8bit ) {
659+ if (copyYPlane ) {
659660 colorType = PNG_COLOR_TYPE_GRAY ;
660661 } else {
661- avifRGBImageSetDefaults (& rgb , avif );
662- rgb .depth = rgbDepth ;
662+ avifRGBImageSetDefaults (& rgbData , avif );
663+ rgbData .depth = rgbDepth ;
663664 if (avif -> yuvFormat == AVIF_PIXEL_FORMAT_YUV400 && avif -> alphaPlane ) {
664665 colorType = PNG_COLOR_TYPE_GRAY_ALPHA ;
665- rgb .format = AVIF_RGB_FORMAT_GRAYA ;
666+ rgbData .format = AVIF_RGB_FORMAT_GRAYA ;
666667 } else if (avif -> yuvFormat == AVIF_PIXEL_FORMAT_YUV400 && !avif -> alphaPlane ) {
667668 colorType = PNG_COLOR_TYPE_GRAY ;
668- rgb .format = AVIF_RGB_FORMAT_GRAY ;
669+ rgbData .format = AVIF_RGB_FORMAT_GRAY ;
669670 } else {
670- rgb .chromaUpsampling = chromaUpsampling ;
671+ rgbData .chromaUpsampling = chromaUpsampling ;
671672 colorType = PNG_COLOR_TYPE_RGBA ;
672673 if (avifImageIsOpaque (avif )) {
673674 colorType = PNG_COLOR_TYPE_RGB ;
674- rgb .format = AVIF_RGB_FORMAT_RGB ;
675+ rgbData .format = AVIF_RGB_FORMAT_RGB ;
675676 }
676677 }
677- if (avifRGBImageAllocatePixels (& rgb ) != AVIF_RESULT_OK ) {
678+ if (avifRGBImageAllocatePixels (& rgbData ) != AVIF_RESULT_OK ) {
678679 fprintf (stderr , "Conversion to RGB failed: %s (out of memory)\n" , outputFilename );
679680 goto cleanup ;
680681 }
681- if (avifImageYUVToRGB (avif , & rgb ) != AVIF_RESULT_OK ) {
682+ if (avifImageYUVToRGB (avif , & rgbData ) != AVIF_RESULT_OK ) {
682683 fprintf (stderr , "Conversion to RGB failed: %s\n" , outputFilename );
683684 goto cleanup ;
684685 }
685686 }
686687
688+ volatile uint32_t width = avif -> width ;
689+ volatile uint32_t height = avif -> height ;
690+
691+ avifRGBImage rgbView = rgbData ;
692+ if (hasClap ) {
693+ avifCropRect cropRect ;
694+ avifDiagnostics diag ;
695+ if (avifCropRectFromCleanApertureBox (& cropRect , & avif -> clap , avif -> width , avif -> height , & diag ) &&
696+ (cropRect .x != 0 || cropRect .y != 0 || cropRect .width != avif -> width || cropRect .height != avif -> height )) {
697+ avifRGBImageSetViewRect (& rgbView , & rgbData , & cropRect );
698+ width = cropRect .width ;
699+ height = cropRect .height ;
700+ }
701+ }
702+
687703 f = fopen (outputFilename , "wb" );
688704 if (!f ) {
689705 fprintf (stderr , "Can't open PNG file for write: %s\n" , outputFilename );
@@ -721,7 +737,7 @@ avifBool avifPNGWrite(const char * outputFilename, const avifImage * avif, uint3
721737 png_set_compression_level (png , compressionLevel );
722738 }
723739
724- png_set_IHDR (png , info , avif -> width , avif -> height , rgbDepth , colorType , PNG_INTERLACE_NONE , PNG_COMPRESSION_TYPE_DEFAULT , PNG_FILTER_TYPE_DEFAULT );
740+ png_set_IHDR (png , info , width , height , rgbDepth , colorType , PNG_INTERLACE_NONE , PNG_COMPRESSION_TYPE_DEFAULT , PNG_FILTER_TYPE_DEFAULT );
725741
726742 const avifBool hasIcc = avif -> icc .data && (avif -> icc .size > 0 );
727743 if (hasIcc ) {
@@ -811,39 +827,25 @@ avifBool avifPNGWrite(const char * outputFilename, const avifImage * avif, uint3
811827 png_write_chunk (png , cicp , cicpData , 4 );
812828 }
813829
814- rowPointers = (png_bytep * )malloc (sizeof (png_bytep ) * avif -> height );
830+ rowPointers = (png_bytep * )malloc (sizeof (png_bytep ) * height );
815831 if (rowPointers == NULL ) {
816832 fprintf (stderr , "Error writing PNG: memory allocation failure" );
817833 goto cleanup ;
818834 }
819835 uint8_t * row ;
820836 uint32_t rowBytes ;
821- if (monochrome8bit ) {
837+ if (copyYPlane ) {
822838 row = avif -> yuvPlanes [AVIF_CHAN_Y ];
823839 rowBytes = avif -> yuvRowBytes [AVIF_CHAN_Y ];
824840 } else {
825- row = rgb .pixels ;
826- rowBytes = rgb .rowBytes ;
841+ row = rgbView .pixels ;
842+ rowBytes = rgbView .rowBytes ;
827843 }
828- for (uint32_t y = 0 ; y < avif -> height ; ++ y ) {
844+ for (uint32_t y = 0 ; y < height ; ++ y ) {
829845 rowPointers [y ] = row ;
830846 row += rowBytes ;
831847 }
832848
833- if (avif -> transformFlags & AVIF_TRANSFORM_CLAP ) {
834- avifCropRect cropRect ;
835- avifDiagnostics diag ;
836- if (avifCropRectFromCleanApertureBox (& cropRect , & avif -> clap , avif -> width , avif -> height , & diag ) &&
837- (cropRect .x != 0 || cropRect .y != 0 || cropRect .width != avif -> width || cropRect .height != avif -> height )) {
838- // TODO: https://github.com/AOMediaCodec/libavif/issues/2427 - Implement.
839- fprintf (stderr ,
840- "Warning: Clean Aperture values were ignored, the output image was NOT cropped to rectangle {%u,%u,%u,%u}\n" ,
841- cropRect .x ,
842- cropRect .y ,
843- cropRect .width ,
844- cropRect .height );
845- }
846- }
847849 if (avifImageGetExifOrientationFromIrotImir (avif ) != 1 ) {
848850 // TODO: https://github.com/AOMediaCodec/libavif/issues/2427 - Rotate the samples.
849851 fprintf (stderr ,
@@ -871,6 +873,6 @@ avifBool avifPNGWrite(const char * outputFilename, const avifImage * avif, uint3
871873 if (rowPointers ) {
872874 free (rowPointers );
873875 }
874- avifRGBImageFreePixels (& rgb );
876+ avifRGBImageFreePixels (& rgbData );
875877 return writeResult ;
876878}
0 commit comments