diff --git a/decode.c b/decode.c index f749a40a7..022912ffb 100644 --- a/decode.c +++ b/decode.c @@ -819,6 +819,7 @@ PyImaging_JpegDecoderNew(PyObject* self, PyObject* args) char* jpegmode; /* what's in the file */ int scale = 1; int draft = 0; + if (!PyArg_ParseTuple(args, "ssz|ii", &mode, &rawmode, &jpegmode, &scale, &draft)) return NULL; @@ -830,6 +831,13 @@ PyImaging_JpegDecoderNew(PyObject* self, PyObject* args) if (decoder == NULL) return NULL; + // libjpeg-turbo supports different output formats. + // We are choosing Pillow's native format (3 color bytes + 1 padding) + // to avoid extra conversion in Unpack.c. + if (ImagingJpegUseJCSExtensions() && strcmp(rawmode, "RGB") == 0) { + rawmode = "RGBX"; + } + if (get_unpacker(decoder, mode, rawmode) < 0) return NULL; diff --git a/encode.c b/encode.c index 7e8f6b125..ae4277c04 100644 --- a/encode.c +++ b/encode.c @@ -691,6 +691,13 @@ PyImaging_JpegEncoderNew(PyObject* self, PyObject* args) if (encoder == NULL) return NULL; + // libjpeg-turbo supports different output formats. + // We are choosing Pillow's native format (3 color bytes + 1 padding) + // to avoid extra conversion in Pack.c. + if (ImagingJpegUseJCSExtensions() && strcmp(rawmode, "RGB") == 0) { + rawmode = "RGBX"; + } + if (get_packer(encoder, mode, rawmode) < 0) return NULL; @@ -719,6 +726,8 @@ PyImaging_JpegEncoderNew(PyObject* self, PyObject* args) encoder->encode = ImagingJpegEncode; + strncpy(((JPEGENCODERSTATE*)encoder->state.context)->rawmode, rawmode, 8); + ((JPEGENCODERSTATE*)encoder->state.context)->quality = quality; ((JPEGENCODERSTATE*)encoder->state.context)->qtables = qarrays; ((JPEGENCODERSTATE*)encoder->state.context)->qtablesLen = qtablesLen; diff --git a/libImaging/Imaging.h b/libImaging/Imaging.h index 00c7493c0..1afbeee90 100644 --- a/libImaging/Imaging.h +++ b/libImaging/Imaging.h @@ -407,6 +407,7 @@ extern int ImagingHexDecode(Imaging im, ImagingCodecState state, extern int ImagingJpegDecode(Imaging im, ImagingCodecState state, UINT8* buffer, int bytes); extern int ImagingJpegDecodeCleanup(ImagingCodecState state); +extern int ImagingJpegUseJCSExtensions(void); extern int ImagingJpegEncode(Imaging im, ImagingCodecState state, UINT8* buffer, int bytes); diff --git a/libImaging/Jpeg.h b/libImaging/Jpeg.h index 0e95ba012..82e1b449f 100644 --- a/libImaging/Jpeg.h +++ b/libImaging/Jpeg.h @@ -88,6 +88,9 @@ typedef struct { /* Chroma Subsampling (-1=default, 0=none, 1=medium, 2=high) */ int subsampling; + /* Converter input mode (input to the shuffler) */ + char rawmode[8+1]; + /* Custom quantization tables () */ unsigned int *qtables; diff --git a/libImaging/JpegDecode.c b/libImaging/JpegDecode.c index 4bb929b6a..33cc5d095 100644 --- a/libImaging/JpegDecode.c +++ b/libImaging/JpegDecode.c @@ -38,6 +38,35 @@ #include "Jpeg.h" +#define STRINGIFY(x) #x +#define TOSTRING(x) STRINGIFY(x) + +// There is no way to compare versions on compile time, +// so we have to do that in runtime. +#ifdef LIBJPEG_TURBO_VERSION +char *libjpeg_turbo_version = TOSTRING(LIBJPEG_TURBO_VERSION); +#else +char *libjpeg_turbo_version = NULL; +#endif + +int +ImagingJpegUseJCSExtensions() +{ + int use_jcs_extensions = 0; + #ifdef JCS_EXTENSIONS + #if defined(LIBJPEG_TURBO_VERSION_NUMBER) + #if LIBJPEG_TURBO_VERSION_NUMBER >= 1002010 + use_jcs_extensions = 1; + #endif + #else + if (libjpeg_turbo_version) { + use_jcs_extensions = strcmp(libjpeg_turbo_version, "1.2.1") >= 0; + } + #endif + #endif + return use_jcs_extensions; +} + /* -------------------------------------------------------------------- */ /* Suspending input handler */ /* -------------------------------------------------------------------- */ @@ -189,6 +218,10 @@ ImagingJpegDecode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) context->cinfo.out_color_space = JCS_GRAYSCALE; else if (strcmp(context->rawmode, "RGB") == 0) context->cinfo.out_color_space = JCS_RGB; + #ifdef JCS_EXTENSIONS + else if (strcmp(context->rawmode, "RGBX") == 0) + context->cinfo.out_color_space = JCS_EXT_RGBX; + #endif else if (strcmp(context->rawmode, "CMYK") == 0 || strcmp(context->rawmode, "CMYK;I") == 0) context->cinfo.out_color_space = JCS_CMYK; diff --git a/libImaging/JpegEncode.c b/libImaging/JpegEncode.c index 61a90ca5c..10ad886e0 100644 --- a/libImaging/JpegEncode.c +++ b/libImaging/JpegEncode.c @@ -135,6 +135,10 @@ ImagingJpegEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) case 32: context->cinfo.input_components = 4; context->cinfo.in_color_space = JCS_CMYK; + #ifdef JCS_EXTENSIONS + if (strcmp(context->rawmode, "RGBX") == 0) + context->cinfo.in_color_space = JCS_EXT_RGBX; + #endif break; default: state->errcode = IMAGING_CODEC_CONFIG;