GraphicsMagick: 2 new changesets
GraphicsMagick Commits <[email protected]>
| Newsgroups | gmane.comp.video.graphicsmagick.cvs |
|---|---|
| Message-ID | <mailman.33462.1671310508.1567.graphicsmagick-commit@lists.sourceforge.net> |
changeset 7cc829119e01 in /hg/GraphicsMagick details: http://hg.GraphicsMagick.org/hg/GraphicsMagick?cmd=changeset;node=7cc829119e01 summary: ReadPNMImage(): Do not promote gray images to PseudoClass unless the image dimensions make it worthwhile. changeset e7b1a383576c in /hg/GraphicsMagick details: http://hg.GraphicsMagick.org/hg/GraphicsMagick?cmd=changeset;node=e7b1a383576c summary: JXL: Fix grayscale writer error. Eliminate use of deprecated functions. Support 16-bits/sample. diffstat: ChangeLog | 8 + VisualMagick/installer/inc/version.isx | 4 +- coders/jxl.c | 351 ++++++++++++++++++++++++++++---- coders/pnm.c | 3 +- magick/version.h | 4 +- www/Changelog.html | 9 + 6 files changed, 321 insertions(+), 58 deletions(-) diffs (truncated from 561 to 500 lines): diff -r 705edb404b5a -r e7b1a383576c ChangeLog --- a/ChangeLog Tue Dec 13 14:12:01 2022 -0600 +++ b/ChangeLog Sat Dec 17 14:54:56 2022 -0600 @@ -1,5 +1,13 @@ +2022-12-17 Bob Friesenhahn <[email protected]> + + * coders/jxl.c: Fix grayscale writer error. Eliminate use of + deprecated functions. Support 16-bits/sample. + 2022-12-13 Bob Friesenhahn <[email protected]> + * coders/pnm.c (ReadPNMImage): Do not promote gray images to + PseudoClass unless the image dimensions make it worthwhile. + * coders/gif.c (ReadGIFImage): Allocate cleared memory. Remove two redundant memsets. diff -r 705edb404b5a -r e7b1a383576c VisualMagick/installer/inc/version.isx --- a/VisualMagick/installer/inc/version.isx Tue Dec 13 14:12:01 2022 -0600 +++ b/VisualMagick/installer/inc/version.isx Sat Dec 17 14:54:56 2022 -0600 @@ -10,5 +10,5 @@ #define public MagickPackageName "GraphicsMagick" #define public MagickPackageVersion "1.4" -#define public MagickPackageVersionAddendum ".020221213" -#define public MagickPackageReleaseDate "snapshot-20221213" +#define public MagickPackageVersionAddendum ".020221217" +#define public MagickPackageReleaseDate "snapshot-20221217" diff -r 705edb404b5a -r e7b1a383576c coders/jxl.c --- a/coders/jxl.c Tue Dec 13 14:12:01 2022 -0600 +++ b/coders/jxl.c Sat Dec 17 14:54:56 2022 -0600 @@ -177,6 +177,42 @@ return MagickTrue; } +static MagickBool fill_pixels_short(Image *image, + ExceptionInfo *exception, + unsigned short *p) +{ + long + x, + y; + + PixelPacket + *q; + + if (image->matte) { + FOR_PIXEL_PACKETS + { + SetRedSample(q,ScaleShortToQuantum(*p)); p++; + SetGreenSample(q,ScaleShortToQuantum(*p)); p++; + SetBlueSample(q,ScaleShortToQuantum(*p)); p++; + SetOpacitySample(q,MaxRGB-ScaleShortToQuantum(*p)); p++; + q++; + } + END_FOR_PIXEL_PACKETS + } else { + FOR_PIXEL_PACKETS + { + SetRedSample(q,ScaleShortToQuantum(*p)); p++; + SetGreenSample(q,ScaleShortToQuantum(*p)); p++; + SetBlueSample(q,ScaleShortToQuantum(*p)); p++; + SetOpacitySample(q,OpaqueOpacity); + q++; + } + END_FOR_PIXEL_PACKETS + } + + return MagickTrue; +} + static MagickBool fill_pixels_float(Image *image, ExceptionInfo *exception, float *p) @@ -223,34 +259,131 @@ PixelPacket *q; - IndexPacket - index; + if (image->storage_class == PseudoClass) + { + IndexPacket + index; - for (y=0; y < (long)image->rows; y++) - { - register IndexPacket - *indexes; + for (y=0; y < (long)image->rows; y++) + { + register IndexPacket + *indexes; + + q=SetImagePixelsEx(image,0,y,image->columns,1,exception); + if (q == (PixelPacket *) NULL) + return MagickFail; - q=SetImagePixelsEx(image,0,y,image->columns,1,exception); - if (q == (PixelPacket *) NULL) - return MagickFail; + indexes=AccessMutableIndexes(image); + if (indexes == NULL) + return MagickFail; - indexes=AccessMutableIndexes(image); - if (indexes == NULL) - return MagickFail; + for (x=0; x < (long)image->columns; x++) + { + index=(IndexPacket)(*p++); + VerifyColormapIndex(image,index); + indexes[x]=index; + *q++=image->colormap[index]; + } + } - for (x=0; x < (long)image->columns; x++) { - index=(IndexPacket)(*p++); - VerifyColormapIndex(image,index); - indexes[x]=index; - *q++=image->colormap[index]; - } if (!SyncImagePixels(image)) return MagickFail; } + else + { + if (image->matte) { + FOR_PIXEL_PACKETS + { + SetRedSample(q,ScaleCharToQuantum(*p)); + SetGreenSample(q,ScaleCharToQuantum(*p)); + SetBlueSample(q,ScaleCharToQuantum(*p)); p++; + SetOpacitySample(q,MaxRGB-ScaleCharToQuantum(*p)); p++; + q++; + } + END_FOR_PIXEL_PACKETS + } else { + FOR_PIXEL_PACKETS + { + SetRedSample(q,ScaleCharToQuantum(*p)); + SetGreenSample(q,ScaleCharToQuantum(*p)); + SetBlueSample(q,ScaleCharToQuantum(*p)); p++; + SetOpacitySample(q,OpaqueOpacity); + q++; + } + END_FOR_PIXEL_PACKETS + } + } return MagickTrue; } +static MagickBool fill_pixels_short_grayscale(Image *image, ExceptionInfo *exception, + unsigned short *p) +{ + long + x, + y; + + PixelPacket + *q; + + if (image->storage_class == PseudoClass) + { + IndexPacket + index; + + for (y=0; y < (long)image->rows; y++) + { + register IndexPacket + *indexes; + + q=SetImagePixelsEx(image,0,y,image->columns,1,exception); + if (q == (PixelPacket *) NULL) + return MagickFail; + + indexes=AccessMutableIndexes(image); + if (indexes == NULL) + return MagickFail; + + for (x=0; x < (long)image->columns; x++) + { + index=(IndexPacket)(*p++); + VerifyColormapIndex(image,index); + indexes[x]=index; + *q++=image->colormap[index]; + } + } + + if (!SyncImagePixels(image)) + return MagickFail; + } + else + { + if (image->matte) { + FOR_PIXEL_PACKETS + { + SetRedSample(q,ScaleShortToQuantum(*p)); + SetGreenSample(q,ScaleShortToQuantum(*p)); + SetBlueSample(q,ScaleShortToQuantum(*p)); p++; + SetOpacitySample(q,MaxRGB-ScaleShortToQuantum(*p)); p++; + q++; + } + END_FOR_PIXEL_PACKETS + } else { + FOR_PIXEL_PACKETS + { + SetRedSample(q,ScaleShortToQuantum(*p)); + SetGreenSample(q,ScaleShortToQuantum(*p)); + SetBlueSample(q,ScaleShortToQuantum(*p)); p++; + SetOpacitySample(q,OpaqueOpacity); + q++; + } + END_FOR_PIXEL_PACKETS + } + } + return MagickTrue; +} + + /** Convert any linear RGB to SRGB * Formula from wikipedia: * https://en.wikipedia.org/wiki/SRGB @@ -312,6 +445,17 @@ return RoundFloatToQuantum(p * MaxRGBFloat); } +static Quantum linear2nonlinear_short(unsigned short s) +{ + double p = s * (1.0/256.0); + if (p < 0.0031308) { + p=p * 12.92; + } else { + p=1.055 * pow(p, 1.0/2.4) - 0.055; + } + return RoundDoubleToQuantum(p * MaxRGBDouble); +} + static MagickBool fill_pixels_char_linear(Image *image, ExceptionInfo *exception, unsigned char *p) @@ -348,6 +492,43 @@ return MagickTrue; } +static MagickBool fill_pixels_short_linear(Image *image, + ExceptionInfo *exception, + unsigned short *p) +{ + long + x, + y; + + PixelPacket + *q; + + if (image->matte) { + FOR_PIXEL_PACKETS + { + SetRedSample(q,linear2nonlinear_short(*p++)); + SetGreenSample(q,linear2nonlinear_short(*p++)); + SetBlueSample(q,linear2nonlinear_short(*p++)); + SetOpacitySample(q,MaxRGB-linear2nonlinear_short(*p++)); + q++; + } + END_FOR_PIXEL_PACKETS + } else { + FOR_PIXEL_PACKETS + { + SetRedSample(q,linear2nonlinear_short(*p++)); + SetGreenSample(q,linear2nonlinear_short(*p++)); + SetBlueSample(q,linear2nonlinear_short(*p++)); + SetOpacitySample(q,OpaqueOpacity); + q++; + } + END_FOR_PIXEL_PACKETS + } + + return MagickTrue; +} + + static const char *JxlTransferFunctionAsString(const JxlTransferFunction fn) { const char *str = "Unknown"; @@ -383,6 +564,29 @@ return str; } +static const char *JxlColorSpaceAsString(const JxlColorSpace color_space) +{ + const char *str = "Unknown"; + + switch (color_space) + { + case JXL_COLOR_SPACE_RGB: + str = "Tristimulus RGB"; + break; + case JXL_COLOR_SPACE_GRAY: + str = "Luminance based (Gray)"; + break; + case JXL_COLOR_SPACE_XYB: + str = "XYB (opsin)"; + break; + case JXL_COLOR_SPACE_UNKNOWN: + str = "Unknown"; + break; + } + + return str; +} + #define JXLReadCleanup() \ MagickFreeResourceLimitedMemory(out_buf); \ MagickFreeResourceLimitedMemory(in_buf); \ @@ -519,9 +723,6 @@ JxlBasicInfo basic_info; - unsigned long - max_value_given_bits; - JxlEncoderInitBasicInfo(&basic_info); status=JxlDecoderGetBasicInfo(jxl,&basic_info); @@ -553,35 +754,40 @@ image->matte=MagickTrue; image->orientation=convert_orientation(basic_info.orientation); - max_value_given_bits=MaxValueGivenBits(basic_info.bits_per_sample); - (void) LogMagickEvent(CoderEvent,GetMagickModule(), - "max_value_given_bits=%lu",max_value_given_bits); + + format.endianness=JXL_NATIVE_ENDIAN; + format.align=0; + if (basic_info.num_color_channels == 1) + { + unsigned long + max_value_given_bits; - if ((basic_info.num_color_channels == 1) && (max_value_given_bits < MaxColormapSize)) - { - if (!AllocateImageColormap(image,max_value_given_bits+1)) - ThrowJXLReaderException(ResourceLimitError,MemoryAllocationFailed,image); + max_value_given_bits=MaxValueGivenBits(basic_info.bits_per_sample); + (void) LogMagickEvent(CoderEvent,GetMagickModule(), + "max_value_given_bits=%lu",max_value_given_bits); + + if ((basic_info.bits_per_sample <= 8) && (!image->matte)) + { + if (!AllocateImageColormap(image,max_value_given_bits+1)) + ThrowJXLReaderException(ResourceLimitError,MemoryAllocationFailed,image); + } grayscale=MagickTrue; format.num_channels=1; - format.data_type=JXL_TYPE_UINT8; + format.data_type=(basic_info.bits_per_sample <= 8 ? JXL_TYPE_UINT8 : + (basic_info.bits_per_sample <= 16 ? JXL_TYPE_UINT16 : JXL_TYPE_FLOAT)); + /* format.data_type=(basic_info.bits_per_sample > 8) ? JXL_TYPE_FLOAT : JXL_TYPE_UINT8; */ } - else if (basic_info.num_color_channels != 3) + else if (basic_info.num_color_channels == 3) + { + format.num_channels=image->matte ? 4 : 3; + format.data_type=(basic_info.bits_per_sample <= 8 ? JXL_TYPE_UINT8 : + (basic_info.bits_per_sample <= 16 ? JXL_TYPE_UINT16 : JXL_TYPE_FLOAT)); + /* format.data_type=(basic_info.bits_per_sample > 8) ? JXL_TYPE_FLOAT : JXL_TYPE_UINT8; */ + } + else { ThrowJXLReaderException(CoderError, ImageTypeNotSupported, image); } - else - { - /* use encoder suggested pixel format if possible */ - if ((JxlDecoderDefaultPixelFormat(jxl, &format) != JXL_DEC_SUCCESS) - || (format.data_type != JXL_TYPE_FLOAT && JXL_TYPE_FLOAT != JXL_TYPE_UINT8)) - { - format.data_type=(image->depth > 8) ? JXL_TYPE_FLOAT : JXL_TYPE_UINT8; - } - format.endianness=JXL_NATIVE_ENDIAN; - format.num_channels=image->matte ? 4 : 3; - format.align=0; - } - break; } @@ -648,6 +854,10 @@ ThrowJXLReaderException(CoderError, ImageTypeNotSupported, image); } + (void) LogMagickEvent(CoderEvent,GetMagickModule(), + "Color Space: %s", + JxlColorSpaceAsString(color_encoding.color_space)); + switch (color_encoding.color_space) { case JXL_COLOR_SPACE_RGB: if (color_encoding.white_point == JXL_WHITE_POINT_D65 && @@ -671,7 +881,7 @@ } break; case JXL_COLOR_SPACE_GRAY: - if(!grayscale || isLinear) /* FIXME: Can't read linear gray */ + if(!grayscale /*|| isLinear */) /* FIXME: Can't properly read linear gray */ ThrowJXLReaderException(CoderError, ImageTypeNotSupported, image); break; case JXL_COLOR_SPACE_XYB: @@ -720,7 +930,14 @@ else res=fill_pixels_char(image, exception, out_buf); } - else + else if (format.data_type == JXL_TYPE_UINT16) + { + if (isLinear) + res=fill_pixels_short_linear(image, exception, (unsigned short *) out_buf); + else + res=fill_pixels_short(image, exception, (unsigned short *) out_buf); + } + else if (format.data_type == JXL_TYPE_FLOAT) { if (isLinear) res=fill_pixels_float_linear(image, exception, (float*)out_buf); @@ -728,9 +945,16 @@ res=fill_pixels_float(image, exception, (float*)out_buf); } } - else if (format.data_type == JXL_TYPE_UINT8) + else { - res=fill_pixels_char_grayscale(image, exception, out_buf); + if (format.data_type == JXL_TYPE_UINT8) + { + res=fill_pixels_char_grayscale(image, exception, out_buf); + } + else if (format.data_type == JXL_TYPE_UINT16) + { + res=fill_pixels_short_grayscale(image, exception, (unsigned short *) out_buf); + } } if (!res) @@ -894,6 +1118,7 @@ != JXL_ENC_SUCCESS) ThrowJXLWriterException(ResourceLimitError,MemoryAllocationFailed,image); + /* Use one color channel for grayscale image */ if (characteristics.grayscale) pixel_format.num_channels = 1; else @@ -901,6 +1126,8 @@ image->storage_class=DirectClass; pixel_format.num_channels = characteristics.opaque ? 3 : 4; } + + /* Support writing integer depths 8 and 16 */ if (image->depth <= 8) pixel_format.data_type = JXL_TYPE_UINT8; else if (image->depth <= 16) @@ -919,12 +1146,24 @@ /* JXL_TYPE_FLOAT requires a nominal range of 0 to 1 */ - if (pixel_format.data_type == JXL_TYPE_UINT8) - basic_info.bits_per_sample = 8; - else if (pixel_format.data_type == JXL_TYPE_UINT16) - basic_info.bits_per_sample = 16; - else if ((pixel_format.data_type == JXL_TYPE_UINT32) || (pixel_format.data_type == JXL_TYPE_FLOAT)) - basic_info.bits_per_sample = 32; + switch (pixel_format.data_type) + { + case JXL_TYPE_FLOAT: + basic_info.bits_per_sample = 32; + break; + case JXL_TYPE_UINT8: + basic_info.bits_per_sample = 8; + break; + case JXL_TYPE_UINT16: + basic_info.bits_per_sample = 16; + break; + case JXL_TYPE_FLOAT16: + basic_info.bits_per_sample = 16; + break; + default: + ThrowJXLWriterException(CoderError,DataStorageTypeIsNotSupported,image); + } + pixel_format.endianness = JXL_NATIVE_ENDIAN; pixel_format.align = 0; @@ -935,6 +1174,11 @@ (void) LogMagickEvent(CoderEvent,GetMagickModule(), "Using %u bits per sample", basic_info.bits_per_sample); + basic_info.num_color_channels = characteristics.grayscale ? 1 : 3; + (void) LogMagickEvent(CoderEvent,GetMagickModule(), + "Using %u channel%s", basic_info.num_color_channels, + basic_info.num_color_channels > 1 ? "s" : "");