Merge pull request #1989 from uploadcare/jpeg-loading-without-convertion

Use RGBX rawmode for RGB JPEG images
This commit is contained in:
wiredfool 2017-08-31 15:10:38 +01:00 committed by GitHub
commit 9797e7bbfa
6 changed files with 58 additions and 0 deletions

View File

@ -819,6 +819,7 @@ PyImaging_JpegDecoderNew(PyObject* self, PyObject* args)
char* jpegmode; /* what's in the file */ char* jpegmode; /* what's in the file */
int scale = 1; int scale = 1;
int draft = 0; int draft = 0;
if (!PyArg_ParseTuple(args, "ssz|ii", &mode, &rawmode, &jpegmode, if (!PyArg_ParseTuple(args, "ssz|ii", &mode, &rawmode, &jpegmode,
&scale, &draft)) &scale, &draft))
return NULL; return NULL;
@ -830,6 +831,13 @@ PyImaging_JpegDecoderNew(PyObject* self, PyObject* args)
if (decoder == NULL) if (decoder == NULL)
return 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) if (get_unpacker(decoder, mode, rawmode) < 0)
return NULL; return NULL;

View File

@ -691,6 +691,13 @@ PyImaging_JpegEncoderNew(PyObject* self, PyObject* args)
if (encoder == NULL) if (encoder == NULL)
return 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) if (get_packer(encoder, mode, rawmode) < 0)
return NULL; return NULL;
@ -719,6 +726,8 @@ PyImaging_JpegEncoderNew(PyObject* self, PyObject* args)
encoder->encode = ImagingJpegEncode; encoder->encode = ImagingJpegEncode;
strncpy(((JPEGENCODERSTATE*)encoder->state.context)->rawmode, rawmode, 8);
((JPEGENCODERSTATE*)encoder->state.context)->quality = quality; ((JPEGENCODERSTATE*)encoder->state.context)->quality = quality;
((JPEGENCODERSTATE*)encoder->state.context)->qtables = qarrays; ((JPEGENCODERSTATE*)encoder->state.context)->qtables = qarrays;
((JPEGENCODERSTATE*)encoder->state.context)->qtablesLen = qtablesLen; ((JPEGENCODERSTATE*)encoder->state.context)->qtablesLen = qtablesLen;

View File

@ -407,6 +407,7 @@ extern int ImagingHexDecode(Imaging im, ImagingCodecState state,
extern int ImagingJpegDecode(Imaging im, ImagingCodecState state, extern int ImagingJpegDecode(Imaging im, ImagingCodecState state,
UINT8* buffer, int bytes); UINT8* buffer, int bytes);
extern int ImagingJpegDecodeCleanup(ImagingCodecState state); extern int ImagingJpegDecodeCleanup(ImagingCodecState state);
extern int ImagingJpegUseJCSExtensions(void);
extern int ImagingJpegEncode(Imaging im, ImagingCodecState state, extern int ImagingJpegEncode(Imaging im, ImagingCodecState state,
UINT8* buffer, int bytes); UINT8* buffer, int bytes);

View File

@ -88,6 +88,9 @@ typedef struct {
/* Chroma Subsampling (-1=default, 0=none, 1=medium, 2=high) */ /* Chroma Subsampling (-1=default, 0=none, 1=medium, 2=high) */
int subsampling; int subsampling;
/* Converter input mode (input to the shuffler) */
char rawmode[8+1];
/* Custom quantization tables () */ /* Custom quantization tables () */
unsigned int *qtables; unsigned int *qtables;

View File

@ -38,6 +38,35 @@
#include "Jpeg.h" #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 */ /* Suspending input handler */
/* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */
@ -189,6 +218,10 @@ ImagingJpegDecode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
context->cinfo.out_color_space = JCS_GRAYSCALE; context->cinfo.out_color_space = JCS_GRAYSCALE;
else if (strcmp(context->rawmode, "RGB") == 0) else if (strcmp(context->rawmode, "RGB") == 0)
context->cinfo.out_color_space = JCS_RGB; 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 || else if (strcmp(context->rawmode, "CMYK") == 0 ||
strcmp(context->rawmode, "CMYK;I") == 0) strcmp(context->rawmode, "CMYK;I") == 0)
context->cinfo.out_color_space = JCS_CMYK; context->cinfo.out_color_space = JCS_CMYK;

View File

@ -135,6 +135,10 @@ ImagingJpegEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
case 32: case 32:
context->cinfo.input_components = 4; context->cinfo.input_components = 4;
context->cinfo.in_color_space = JCS_CMYK; 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; break;
default: default:
state->errcode = IMAGING_CODEC_CONFIG; state->errcode = IMAGING_CODEC_CONFIG;