Merge branch 'ijg.lossless' into dev

Lossless: Accommodate LJT colorspace/SIMD exts

In libjpeg-turbo, grayscale_convert() and null_convert() aren't the only
lossless color conversion algorithms.  We can also losslessly convert
RGB to and from any of the extended RGB colorspaces, and some platforms
have SIMD-accelerated null color conversion.

This commit also disallows RGB565 output in lossless mode, and it moves
the IsExtRGB() macro from cdjpeg.h to jpegint.h and repurposes it to
make jinit_color_converter() and jinit_color_deconverter() more
readable.
This commit is contained in:
DRC
2022-11-16 12:18:45 -06:00
7 changed files with 44 additions and 63 deletions

View File

@@ -164,6 +164,3 @@ EXTERN(FILE *) write_stdout(void);
#ifndef EXIT_WARNING
#define EXIT_WARNING 2
#endif
#define IsExtRGB(cs) \
(cs == JCS_RGB || (cs >= JCS_EXT_RGB && cs <= JCS_EXT_ARGB))

View File

@@ -1,4 +1,4 @@
.TH CJPEG 1 "14 November 2022"
.TH CJPEG 1 "16 November 2022"
.SH NAME
cjpeg \- compress an image file to a JPEG file
.SH SYNOPSIS
@@ -176,8 +176,8 @@ unavailable when compressing or decompressing a lossless JPEG file:
.IP
- Quality/quantization table selection
.IP
- Color conversion (the JPEG image will use the same color space as the input
image)
- Color space conversion (the JPEG image will use the same color space as the
input image)
.IP
- DCT/IDCT algorithm selection
.IP

View File

@@ -577,24 +577,20 @@ _jinit_color_converter(j_compress_ptr cinfo)
break;
}
/* Check num_components, set conversion method based on requested space */
/* Check num_components, set conversion method based on requested space.
* NOTE: We do not allow any lossy color conversion algorithms in lossless
* mode.
*/
switch (cinfo->jpeg_color_space) {
case JCS_GRAYSCALE:
if (cinfo->master->lossless &&
cinfo->in_color_space != cinfo->jpeg_color_space)
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
if (cinfo->num_components != 1)
ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
if (cinfo->in_color_space == JCS_GRAYSCALE)
cconvert->pub._color_convert = grayscale_convert;
else if (cinfo->in_color_space == JCS_RGB ||
cinfo->in_color_space == JCS_EXT_RGB ||
cinfo->in_color_space == JCS_EXT_RGBX ||
cinfo->in_color_space == JCS_EXT_BGR ||
cinfo->in_color_space == JCS_EXT_BGRX ||
cinfo->in_color_space == JCS_EXT_XBGR ||
cinfo->in_color_space == JCS_EXT_XRGB ||
cinfo->in_color_space == JCS_EXT_RGBA ||
cinfo->in_color_space == JCS_EXT_BGRA ||
cinfo->in_color_space == JCS_EXT_ABGR ||
cinfo->in_color_space == JCS_EXT_ARGB) {
else if (IsExtRGB(cinfo->in_color_space)) {
#ifdef WITH_SIMD
if (jsimd_can_rgb_gray())
cconvert->pub._color_convert = jsimd_rgb_gray_convert;
@@ -611,6 +607,8 @@ _jinit_color_converter(j_compress_ptr cinfo)
break;
case JCS_RGB:
if (cinfo->master->lossless && !IsExtRGB(cinfo->in_color_space))
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
if (cinfo->num_components != 3)
ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
if (rgb_red[cinfo->in_color_space] == 0 &&
@@ -623,36 +621,19 @@ _jinit_color_converter(j_compress_ptr cinfo)
else
#endif
cconvert->pub._color_convert = null_convert;
} else if (cinfo->in_color_space == JCS_RGB ||
cinfo->in_color_space == JCS_EXT_RGB ||
cinfo->in_color_space == JCS_EXT_RGBX ||
cinfo->in_color_space == JCS_EXT_BGR ||
cinfo->in_color_space == JCS_EXT_BGRX ||
cinfo->in_color_space == JCS_EXT_XBGR ||
cinfo->in_color_space == JCS_EXT_XRGB ||
cinfo->in_color_space == JCS_EXT_RGBA ||
cinfo->in_color_space == JCS_EXT_BGRA ||
cinfo->in_color_space == JCS_EXT_ABGR ||
cinfo->in_color_space == JCS_EXT_ARGB)
} else if (IsExtRGB(cinfo->in_color_space))
cconvert->pub._color_convert = rgb_rgb_convert;
else
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
break;
case JCS_YCbCr:
if (cinfo->master->lossless &&
cinfo->in_color_space != cinfo->jpeg_color_space)
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
if (cinfo->num_components != 3)
ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
if (cinfo->in_color_space == JCS_RGB ||
cinfo->in_color_space == JCS_EXT_RGB ||
cinfo->in_color_space == JCS_EXT_RGBX ||
cinfo->in_color_space == JCS_EXT_BGR ||
cinfo->in_color_space == JCS_EXT_BGRX ||
cinfo->in_color_space == JCS_EXT_XBGR ||
cinfo->in_color_space == JCS_EXT_XRGB ||
cinfo->in_color_space == JCS_EXT_RGBA ||
cinfo->in_color_space == JCS_EXT_BGRA ||
cinfo->in_color_space == JCS_EXT_ABGR ||
cinfo->in_color_space == JCS_EXT_ARGB) {
if (IsExtRGB(cinfo->in_color_space)) {
#ifdef WITH_SIMD
if (jsimd_can_rgb_ycc())
cconvert->pub._color_convert = jsimd_rgb_ycc_convert;
@@ -674,6 +655,9 @@ _jinit_color_converter(j_compress_ptr cinfo)
break;
case JCS_CMYK:
if (cinfo->master->lossless &&
cinfo->in_color_space != cinfo->jpeg_color_space)
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
if (cinfo->num_components != 4)
ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
if (cinfo->in_color_space == JCS_CMYK) {
@@ -688,6 +672,9 @@ _jinit_color_converter(j_compress_ptr cinfo)
break;
case JCS_YCCK:
if (cinfo->master->lossless &&
cinfo->in_color_space != cinfo->jpeg_color_space)
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
if (cinfo->num_components != 4)
ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
if (cinfo->in_color_space == JCS_CMYK) {
@@ -716,13 +703,4 @@ _jinit_color_converter(j_compress_ptr cinfo)
cconvert->pub._color_convert = null_convert;
break;
}
/* Prevent lossy color conversion in lossless mode */
if (cinfo->master->lossless) {
if ((cinfo->jpeg_color_space == JCS_GRAYSCALE &&
cinfo->in_color_space != JCS_GRAYSCALE) ||
(cinfo->jpeg_color_space != JCS_GRAYSCALE &&
cconvert->pub._color_convert != null_convert))
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
}
}

View File

@@ -776,10 +776,15 @@ _jinit_color_deconverter(j_decompress_ptr cinfo)
/* Set out_color_components and conversion method based on requested space.
* Also clear the component_needed flags for any unused components,
* so that earlier pipeline stages can avoid useless computation.
* NOTE: We do not allow any lossy color conversion algorithms in lossless
* mode.
*/
switch (cinfo->out_color_space) {
case JCS_GRAYSCALE:
if (cinfo->master->lossless &&
cinfo->jpeg_color_space != cinfo->out_color_space)
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
cinfo->out_color_components = 1;
if (cinfo->jpeg_color_space == JCS_GRAYSCALE ||
cinfo->jpeg_color_space == JCS_YCbCr) {
@@ -805,6 +810,8 @@ _jinit_color_deconverter(j_decompress_ptr cinfo)
case JCS_EXT_BGRA:
case JCS_EXT_ABGR:
case JCS_EXT_ARGB:
if (cinfo->master->lossless && cinfo->jpeg_color_space != JCS_RGB)
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
cinfo->out_color_components = rgb_pixelsize[cinfo->out_color_space];
if (cinfo->jpeg_color_space == JCS_YCbCr) {
#ifdef WITH_SIMD
@@ -831,6 +838,8 @@ _jinit_color_deconverter(j_decompress_ptr cinfo)
break;
case JCS_RGB565:
if (cinfo->master->lossless)
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
cinfo->out_color_components = 3;
if (cinfo->dither_mode == JDITHER_NONE) {
if (cinfo->jpeg_color_space == JCS_YCbCr) {
@@ -864,6 +873,9 @@ _jinit_color_deconverter(j_decompress_ptr cinfo)
break;
case JCS_CMYK:
if (cinfo->master->lossless &&
cinfo->jpeg_color_space != cinfo->out_color_space)
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
cinfo->out_color_components = 4;
if (cinfo->jpeg_color_space == JCS_YCCK) {
cconvert->pub._color_convert = ycck_cmyk_convert;
@@ -884,15 +896,6 @@ _jinit_color_deconverter(j_decompress_ptr cinfo)
break;
}
/* Prevent lossy color conversion in lossless mode */
if (cinfo->master->lossless) {
if ((cinfo->out_color_space == JCS_GRAYSCALE &&
cinfo->jpeg_color_space != JCS_GRAYSCALE) ||
(cinfo->out_color_space != JCS_GRAYSCALE &&
cconvert->pub._color_convert != null_convert))
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
}
if (cinfo->quantize_colors)
cinfo->output_components = 1; /* single colormapped output component */
else

View File

@@ -7,7 +7,7 @@
* Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison.
* libjpeg-turbo Modifications:
* Copyright (C) 2015-2016, 2019, 2021-2022, D. R. Commander.
* Copyright (C) 2015-2017, 2019, 2021-2022, D. R. Commander.
* Copyright (C) 2015, Google, Inc.
* Copyright (C) 2021, Alex Richardson.
* For conditions of distribution and use, see the accompanying README.ijg
@@ -74,6 +74,9 @@ typedef __UINTPTR_TYPE__ JUINTPTR;
typedef size_t JUINTPTR;
#endif
#define IsExtRGB(cs) \
(cs == JCS_RGB || (cs >= JCS_EXT_RGB && cs <= JCS_EXT_ARGB))
/*
* Left shift macro that handles a negative operand without causing any
* sanitizer warnings

View File

@@ -1010,8 +1010,8 @@ jpeg_enable_lossless (j_compress_ptr cinfo, int predictor_selection_value,
* DCT/IDCT algorithm selection
* Smoothing
* Downsampling/upsampling
* Color conversion (the JPEG image will use the same color space as
the input image)
* Color space conversion (the JPEG image will use the same color
space as the input image)
* IDCT scaling
* Raw (downsampled) data input/output
* Transcoding of DCT coefficients

View File

@@ -177,8 +177,8 @@ Switches for advanced users:
following features will be unavailable when compressing
or decompressing a lossless JPEG file:
* Quality/quantization table selection
* Color conversion (the JPEG image will use the same
color space as the input image)
* Color space conversion (the JPEG image will use the
same color space as the input image)
* DCT/IDCT algorithm selection
* Smoothing
* Downsampling/upsampling