Skip to content
Browse files
JPEG output: enable optimized coding
Add OPTIMIZED=YES/NO/ARITHMETIC (default YES) format option to turn on optimized
Huffman coding.
If set to NO, use standard Huffman tables (a little bit faster in theory, but
less efficient for output size).
If set to ARITHMETIC, will use Arithmetic entropy coding instead of Huffman, for
smaller size. Note that Arithmetic coding/decoding is available in libjpeg-turbo
implementation, but not in IJG libjpeg-6b or later. So must only be used in
combinations with clients that are known to be able to decode Arithmetic encoded
  • Loading branch information
rouault committed Dec 25, 2014
1 parent 960d31c commit 9b6b7dbefa8fb53300c31edef36d9c3546b96449
Showing 1 changed file with 51 additions and 4 deletions.
@@ -127,17 +127,50 @@ int jpeg_buffer_empty_output_buffer (j_compress_ptr cinfo)
return TRUE;

static void msJPEGErrorExit(j_common_ptr cinfo)
jmp_buf* pJmpBuffer = (jmp_buf* ) cinfo->client_data;
char buffer[JMSG_LENGTH_MAX];

/* Create the message */
(*cinfo->err->format_message) (cinfo, buffer);

msSetError(MS_MISCERR,"libjpeg: %s","jpeg_ErrorExit()", buffer);

int saveAsJPEG(mapObj *map /*not used*/, rasterBufferObj *rb, streamInfo *info,
/* Return control to the setjmp point */
longjmp(*pJmpBuffer, 1);

int saveAsJPEG(mapObj *map, rasterBufferObj *rb, streamInfo *info,
outputFormatObj *format)
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
int quality = atoi(msGetOutputFormatOption( format, "QUALITY", "75"));
int quality;
const char* pszOptimized;
int optimized;
int arithmetic;
ms_destination_mgr *dest;
JSAMPLE *rowdata;
JSAMPLE *rowdata = NULL;
unsigned int row;
jmp_buf setjmp_buffer;

quality = atoi(msGetOutputFormatOption( format, "QUALITY", "75"));
pszOptimized = msGetOutputFormatOption( format, "OPTIMIZED", "YES");
optimized = EQUAL(pszOptimized, "YES") || EQUAL(pszOptimized, "ON") ||
EQUAL(pszOptimized, "TRUE");
arithmetic = EQUAL(pszOptimized, "ARITHMETIC");

if (setjmp(setjmp_buffer))
return MS_FAILURE;

cinfo.err = jpeg_std_error(&jerr);
jerr.error_exit = msJPEGErrorExit;
cinfo.client_data = (void *) &(setjmp_buffer);

if (cinfo.dest == NULL) {
@@ -167,9 +200,23 @@ int saveAsJPEG(mapObj *map /*not used*/, rasterBufferObj *rb, streamInfo *info,
cinfo.in_color_space = JCS_RGB;
jpeg_set_quality(&cinfo, quality, TRUE);
jpeg_start_compress(&cinfo, TRUE);
if( arithmetic )
cinfo.arith_code = TRUE;
else if( optimized )
cinfo.optimize_coding = TRUE;

if( arithmetic || optimized ) {
if (map == NULL || msGetConfigOption(map, "JPEGMEM") == NULL) {
/* If the user doesn't provide a value for JPEGMEM, we want to be sure */
/* that at least the image size will be used before creating the temporary file */
cinfo.mem->max_memory_to_use =
MAX(cinfo.mem->max_memory_to_use, cinfo.input_components * rb->width * rb->height);

jpeg_start_compress(&cinfo, TRUE);
rowdata = (JSAMPLE*)malloc(rb->width*cinfo.input_components*sizeof(JSAMPLE));

for(row=0; row<rb->height; row++) {
JSAMPLE *pixptr = rowdata;
int col;

0 comments on commit 9b6b7db

Please sign in to comment.