avifdec: Add PNG compression level arg Fixes: #706
diff --git a/apps/avifdec.c b/apps/avifdec.c index 39273fb..eb7d93b 100644 --- a/apps/avifdec.c +++ b/apps/avifdec.c
@@ -33,6 +33,7 @@ printf(" -c,--codec C : AV1 codec to use (choose from versions list below)\n"); printf(" -d,--depth D : Output depth [8,16]. (PNG only; For y4m, depth is retained, and JPEG is always 8bpc)\n"); printf(" -q,--quality Q : Output quality [0-100]. (JPEG only, default: %d)\n", DEFAULT_JPEG_QUALITY); + printf(" --png-compress L : Set PNG compression level (PNG only; 0-9, 0=none, 9=max). Defaults to libpng's builtin default.\n"); printf(" -u,--upsampling U : Chroma upsampling (for 420/422). automatic (default), fastest, best, nearest, or bilinear\n"); printf(" -r,--raw-color : Output raw RGB values instead of multiplying by alpha when saving to opaque formats\n"); printf(" (JPEG only; not applicable to y4m)\n"); @@ -53,6 +54,7 @@ int requestedDepth = 0; int jobs = 1; int jpegQuality = DEFAULT_JPEG_QUALITY; + int pngCompressionLevel = -1; // -1 is a sentinel to avifPNGWrite() to skip calling png_set_compression_level() avifCodecChoice codecChoice = AVIF_CODEC_CHOICE_AUTO; avifBool infoOnly = AVIF_FALSE; avifChromaUpsampling chromaUpsampling = AVIF_CHROMA_UPSAMPLING_AUTOMATIC; @@ -115,6 +117,14 @@ } else if (jpegQuality > 100) { jpegQuality = 100; } + } else if (!strcmp(arg, "--png-compress")) { + NEXTARG(); + pngCompressionLevel = atoi(arg); + if (pngCompressionLevel < 0) { + pngCompressionLevel = 0; + } else if (pngCompressionLevel > 9) { + pngCompressionLevel = 9; + } } else if (!strcmp(arg, "-u") || !strcmp(arg, "--upsampling")) { NEXTARG(); if (!strcmp(arg, "automatic")) { @@ -291,7 +301,7 @@ returnCode = 1; } } else if (outputFormat == AVIF_APP_FILE_FORMAT_PNG) { - if (!avifPNGWrite(outputFilename, decoder->image, requestedDepth, chromaUpsampling)) { + if (!avifPNGWrite(outputFilename, decoder->image, requestedDepth, chromaUpsampling, pngCompressionLevel)) { returnCode = 1; } } else {
diff --git a/apps/shared/avifpng.c b/apps/shared/avifpng.c index 5af38ea..21a0557 100644 --- a/apps/shared/avifpng.c +++ b/apps/shared/avifpng.c
@@ -121,7 +121,8 @@ avif->yuvFormat = requestedFormat; if (avif->yuvFormat == AVIF_PIXEL_FORMAT_NONE) { // Identity is only valid with YUV444. - avif->yuvFormat = (avif->matrixCoefficients == AVIF_MATRIX_COEFFICIENTS_IDENTITY) ? AVIF_PIXEL_FORMAT_YUV444 : AVIF_APP_DEFAULT_PIXEL_FORMAT; + avif->yuvFormat = (avif->matrixCoefficients == AVIF_MATRIX_COEFFICIENTS_IDENTITY) ? AVIF_PIXEL_FORMAT_YUV444 + : AVIF_APP_DEFAULT_PIXEL_FORMAT; } avif->depth = requestedDepth; if (avif->depth == 0) { @@ -160,7 +161,7 @@ return readResult; } -avifBool avifPNGWrite(const char * outputFilename, const avifImage * avif, uint32_t requestedDepth, avifChromaUpsampling chromaUpsampling) +avifBool avifPNGWrite(const char * outputFilename, const avifImage * avif, uint32_t requestedDepth, avifChromaUpsampling chromaUpsampling, int compressionLevel) { volatile avifBool writeResult = AVIF_FALSE; png_structp png = NULL; @@ -217,6 +218,10 @@ // It is up to the enduser to decide if they want to keep their ICC profiles or not. png_set_option(png, PNG_SKIP_sRGB_CHECK_PROFILE, 1); + if (compressionLevel >= 0) { + png_set_compression_level(png, compressionLevel); + } + png_set_IHDR(png, info, avif->width, avif->height, rgb.depth, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); if (avif->icc.data && (avif->icc.size > 0)) { png_set_iCCP(png, info, "libavif", 0, avif->icc.data, (png_uint_32)avif->icc.size);
diff --git a/apps/shared/avifpng.h b/apps/shared/avifpng.h index 45c7f75..d3dba8e 100644 --- a/apps/shared/avifpng.h +++ b/apps/shared/avifpng.h
@@ -8,6 +8,10 @@ // if (requestedDepth == 0), do best-fit avifBool avifPNGRead(const char * inputFilename, avifImage * avif, avifPixelFormat requestedFormat, uint32_t requestedDepth, uint32_t * outPNGDepth); -avifBool avifPNGWrite(const char * outputFilename, const avifImage * avif, uint32_t requestedDepth, avifChromaUpsampling chromaUpsampling); +avifBool avifPNGWrite(const char * outputFilename, + const avifImage * avif, + uint32_t requestedDepth, + avifChromaUpsampling chromaUpsampling, + int compressionLevel); #endif // ifndef LIBAVIF_APPS_SHARED_AVIFPNG_H