2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these libraries and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $XConsortium: JpegUtils.c /main/3 1996/10/06 19:38:48 rws $ */
27 ** This module provides utilities for converting jpeg data associated with
28 ** a _DtGrStream into an XImage. The module is based on code from several
29 ** of the files from the Independent JPEG library, version 6a (copyright
34 * Copyright (C) 1991-1996, Thomas G. Lane.
35 * This file is part of the Independent JPEG Group's software.
36 * For conditions of distribution and use, see the accompanying README file.
49 #include "GraphicsP.h"
51 #include "JpegUtilsI.h"
58 #define BYTESPERSAMPLE 1
59 #define MAX_COLORS 64 /* Not allowed to be higher than 256 */
60 #define BYTE_MAXVAL 0xFF
61 #define XCOL_MAXVAL 0xFFFF
62 #define INTERP_TO_XCOLORSPACE(val) ((XCOL_MAXVAL/BYTE_MAXVAL) * val)
63 #define INPUT_BUF_SIZE 4096 /* choose an efficiently fread'able size */
70 ** Custom destination manager structure
73 struct djpeg_dest_struct pub; /* public fields */
74 JSAMPROW pixrow; /* decompressor output buffer */
75 XImage *ximage; /* XImage to put pixel info into */
78 typedef ximg_dest_struct * ximg_dest_ptr;
81 ** Custom source manager structure
84 struct jpeg_source_mgr pub; /* public fields */
86 _DtGrStream *stream; /* source stream */
87 unsigned long input_buf_size; /* size of input buffer */
88 JOCTET * buffer; /* start of buffer */
89 boolean start_of_file; /* have we gotten any data yet? */
92 typedef stream_source_mgr * stream_src_ptr;
95 ** Custom error handler structure
99 struct jpeg_error_mgr pub; /* "public" fields */
101 jmp_buf setjmp_buffer; /* for return to caller */
104 typedef struct my_error_mgr * my_error_ptr;
110 /******************************************************************************
112 * Function my_error_exit
114 * This routine replaces the standard fatal error handling routine. Instead
115 * of exiting the program, the routine longjmps back to jpeg_to_ximage,
116 * which cleans up and returns a _DtGrCONVERT_FAILURE.
118 *****************************************************************************/
119 static void my_error_exit (j_common_ptr cinfo)
121 my_error_ptr myerr = (my_error_ptr) cinfo->err;
123 (*cinfo->err->output_message) (cinfo);
125 /* Return control to the setjmp point */
126 longjmp(myerr->setjmp_buffer, 1);
129 /******************************************************************************
131 * Function my_output_message
133 * This routine replaces the standard error message outputter. Instead
134 * of outputting JPEG library error and warning messages to stderr, it
137 *****************************************************************************/
138 static void my_output_message (j_common_ptr cinfo)
141 ** Uncommenting the lines below will cause error and warning messages
142 ** from the JPEG library to be displayed to stderr instead of suppressed
146 ** char buffer[JMSG_LENGTH_MAX];
150 ** Create the message
152 ** (*cinfo->err->format_message) (cinfo, buffer);
156 ** Send it to stderr, adding a newline
158 ** fprintf(stderr, "%s\n", buffer);
162 /******************************************************************************
164 * Function init_source
166 * This is the custom source manager's initialization routine, called by
167 * jpeg_read_header before any data is actually read. It currently does
170 *****************************************************************************/
171 static void init_source (
172 j_decompress_ptr cinfo)
174 /* stream_src_ptr src = (stream_src_ptr) cinfo->src; */
177 /******************************************************************************
179 * Function fill_input_buffer
181 * This is the custom source manager's fill input buffer routine, called by
182 * the JPEG library whenever it has finished processing the data in the
183 * source buffer and needs it to be refilled with the next chunk of data.
185 *****************************************************************************/
186 static boolean fill_input_buffer (
187 j_decompress_ptr cinfo)
189 stream_src_ptr src = (stream_src_ptr) cinfo->src;
193 ** Since we always process buffer-based streams in a single chunk, the
194 ** only reason read_input_buffer should be called for one is if the data
195 ** in the buffer was truncated or otherwise bogus. If this is the case
196 ** we set nbytes to zero, allocate a new buffer to hold a fake EOI marker
197 ** so the stream buffer isn't overwritten, and let the error-handling
198 ** code below take care of things.
200 if (src->stream->type == _DtGrBUFFER)
203 src->buffer = (JOCTET *) (*cinfo->mem->alloc_small) (
204 (j_common_ptr) cinfo, JPOOL_IMAGE,
207 else /* _DtGrFILE, read the next chunk of data */
208 nbytes = _DtGrRead (src->buffer, 1, src->input_buf_size, src->stream);
212 if (src->start_of_file) /* Treat empty input file as fatal error */
213 ERREXIT(cinfo, JERR_INPUT_EMPTY);
214 WARNMS(cinfo, JWRN_JPEG_EOF);
215 /* Insert a fake EOI marker */
216 src->buffer[0] = (JOCTET) 0xFF;
217 src->buffer[1] = (JOCTET) JPEG_EOI;
221 src->pub.next_input_byte = src->buffer;
222 src->pub.bytes_in_buffer = nbytes;
223 src->start_of_file = FALSE;
228 /******************************************************************************
230 * Function skip_input_data
232 * This is the custom source manager's skip input data function, called
233 * by the JPEG library when it wants to skip over a potentially large
234 * amount of uninteresting data (such as an APPn marker).
236 *****************************************************************************/
237 static void skip_input_data (
238 j_decompress_ptr cinfo,
241 stream_src_ptr src = (stream_src_ptr) cinfo->src;
243 /* Just a dumb implementation for now. Could use fseek() except
244 ** it doesn't work on pipes. Not clear that being smart is worth
245 ** any trouble anyway --- large skips are infrequent.
249 while (num_bytes > (long) src->pub.bytes_in_buffer)
251 num_bytes -= (long) src->pub.bytes_in_buffer;
252 (void) fill_input_buffer(cinfo);
253 /* note we assume that fill_input_buffer will never return FALSE,
254 ** so suspension need not be handled.
257 src->pub.next_input_byte += (size_t) num_bytes;
258 src->pub.bytes_in_buffer -= (size_t) num_bytes;
262 /******************************************************************************
264 * Function term_source
266 * This is the custom source manager's termination routine, it currently
269 *****************************************************************************/
270 static void term_source (
271 j_decompress_ptr cinfo)
273 /* no work necessary here */
277 /******************************************************************************
279 * Function jpeg_stream_src
281 * This is the custom source manager's creation routine. Most of the custom
282 * source manager code is based on the JPEG library's stdio source manager
283 * code in the jdatasrc.c file included with the JPEG library distribution.
285 *****************************************************************************/
286 static void jpeg_stream_src (
287 j_decompress_ptr cinfo,
293 ** Create the custom source manager structure
295 cinfo->src = (struct jpeg_source_mgr *) (*cinfo->mem->alloc_small) (
296 (j_common_ptr) cinfo, JPOOL_IMAGE,
297 sizeof(stream_source_mgr));
298 src = (stream_src_ptr) cinfo->src;
300 src->stream = stream;
303 ** If this is a file-based stream, we need to allocate a buffer to
304 ** read data into. If this is a buffer-based stream, we just use the
305 ** buffer already attached to the stream. Note that this implies that
306 ** we always process buffer-based streams in a single chunk, if there
307 ** is ever a reason to do otherwise, this routine and fill_input_buffer
308 ** will need to be modified appropriately.
310 if (stream->type == _DtGrFILE)
312 src->buffer = (JOCTET *) (*cinfo->mem->alloc_small) (
313 (j_common_ptr) cinfo, JPOOL_IMAGE,
314 INPUT_BUF_SIZE * sizeof(JOCTET));
315 src->input_buf_size = INPUT_BUF_SIZE;
316 src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer call */
317 src->pub.next_input_byte = NULL; /* on first read */
318 src->start_of_file = TRUE;
320 else /* _DtGrBUFFER */
322 src->buffer = (unsigned char *) stream->source.buffer.base;
323 src->input_buf_size = stream->source.buffer.size;
324 src->pub.bytes_in_buffer = src->input_buf_size;
325 src->pub.next_input_byte = src->buffer;
326 src->start_of_file = FALSE;
330 ** Initialize the method procedures
332 src->pub.init_source = init_source;
333 src->pub.fill_input_buffer = fill_input_buffer;
334 src->pub.skip_input_data = skip_input_data;
335 src->pub.resync_to_restart = jpeg_resync_to_restart; /* default method */
336 src->pub.term_source = term_source;
339 /******************************************************************************
341 * Function copy_pixels
343 * This routine loops through a scanline of decompressed, quantized
344 * JPEG data and uses XPutPixel to copy the pixel values into the
345 * XImage associated with the destination manager.
347 *****************************************************************************/
348 static void copy_pixels(
349 j_decompress_ptr cinfo,
350 djpeg_dest_ptr dinfo,
351 JDIMENSION rows_supplied)
356 ximg_dest_ptr dest = (ximg_dest_ptr) dinfo;
358 ptr = dest->pub.buffer[0];
359 for (col=0; col < cinfo->output_width; col++)
361 pixval = GETJSAMPLE(*ptr++);
362 XPutPixel(dest->ximage,col,cinfo->output_scanline-1, pixval);
367 /******************************************************************************
369 * Function start_output_ximg
371 * This is the data destination manager startup routine, it currently does
374 *****************************************************************************/
375 static void start_output_ximg (
376 j_decompress_ptr cinfo,
377 djpeg_dest_ptr dinfo)
382 /******************************************************************************
384 * Function finish_output_ximg
386 * This is the data destination manager shutdown routine, it currently does
389 *****************************************************************************/
390 static void finish_output_ximg (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
394 /******************************************************************************
396 * Function init_jpeg_dest_mgr
398 * This routine allocates and initializes a data destination manager
399 * that the JPEG library will use as a sink for JPEG data after the
400 * data has been decompressed.
402 *****************************************************************************/
403 djpeg_dest_ptr init_jpeg_dest_mgr (
404 j_decompress_ptr cinfo)
409 ** Create module interface object, fill in the method pointers
411 dest = (ximg_dest_ptr) (*cinfo->mem->alloc_small) (
412 (j_common_ptr) cinfo, JPOOL_IMAGE,
413 sizeof(ximg_dest_struct));
414 dest->pub.start_output = start_output_ximg;
415 dest->pub.finish_output = finish_output_ximg;
416 dest->pub.put_pixel_rows = copy_pixels;
419 ** Calculate the output image dimensions so we can allocate the
420 ** right amount of space
422 jpeg_calc_output_dimensions(cinfo);
425 ** Create a buffer for the JPEG library to write decompressed
426 ** scanline data into.
428 dest->pixrow = (JSAMPROW) (*cinfo->mem->alloc_small) (
429 (j_common_ptr) cinfo, JPOOL_IMAGE,
430 cinfo->output_width * cinfo->out_color_components );
431 dest->pub.buffer = &dest->pixrow;
432 dest->pub.buffer_height = 1;
435 ** Return the initialized destination manager
437 return (djpeg_dest_ptr) dest;
440 /******************************************************************************
442 * Function jpeg_to_ximage
444 * This routine converts compressed jpeg data associated with a _DtGrStream
447 * No X color allocation is done. The image is quantized down to MAX_COLORS
448 * during decompression, and an array of XColor structures with the red,
449 * green, and blue fields initialized to the colors used in the image is
450 * returned to the caller. Each pixel value in the XImage data is an index
451 * into this array. The caller must use this information to allocate X
452 * color cells and substitute the appropriate pixel values into the XImage
453 * data array before using the XImage.
455 * The routine makes use of a custom source data manager to allow the JPEG
456 * data source to be a _DtGrStream, a custom data destination manager to
457 * allow the decompressed and post-processed data to be written to an XImage,
458 * and a custom error handler to allow standard _DtGr error codes to be
459 * returned to the caller in the event of a JPEG library error.
461 *****************************************************************************/
462 enum _DtGrLoadStatus jpeg_to_ximage (
466 Dimension *in_out_width,
467 Dimension *in_out_height,
473 struct jpeg_decompress_struct cinfo;
474 struct my_error_mgr jerr;
475 djpeg_dest_ptr dest_mgr = NULL;
477 int i, num_scanlines, nullCount, ximWidth;
478 unsigned char *ximData = NULL;
479 Display *display = DisplayOfScreen(screen);
480 int nplanes = DisplayPlanes(display,XScreenNumberOfScreen(screen));
481 XColor *colors = NULL;
484 ** Initialize the return values
487 *xres = *ncolors = *in_out_width = *in_out_height = 0;
490 ** Initialize the jpeg library error handler with our custom routines
493 cinfo.err = jpeg_std_error(&jerr.pub);
494 jerr.pub.error_exit = my_error_exit;
495 jerr.pub.output_message = my_output_message;
498 ** Establish the setjmp return context for my_error_exit to use
500 if (setjmp(jerr.setjmp_buffer))
502 /* If we get here, the JPEG code has signaled an error. We need to
503 ** free memory, clean up the JPEG object, and return a failure code.
506 XDestroyImage (*ximage);
509 jpeg_destroy_decompress(&cinfo);
510 return (_DtGrCONVERT_FAILURE);
514 ** Create a jpeg decompression object
516 jpeg_create_decompress(&cinfo);
519 ** Create a custom source data manager
521 jpeg_stream_src(&cinfo, stream);
524 ** Read the jpeg header
526 jpeg_read_header(&cinfo, TRUE);
527 if (cinfo.X_density > 0 &&
528 (cinfo.density_unit == 1 || cinfo.density_unit == 2)) {
529 if (cinfo.density_unit == 1)
530 *xres = cinfo.X_density;
532 *xres = cinfo.X_density * 2.54 + 0.5;
536 ** Initialize our desired post-processing attributes
538 cinfo.quantize_colors = TRUE;
539 cinfo.desired_number_of_colors = MAX_COLORS;
542 ** Create a custom data destination manager to allow our processed data
543 ** to be channeled into an XImage.
545 dest_mgr = init_jpeg_dest_mgr(&cinfo);
548 ** Initialize the decompression state
550 jpeg_start_decompress(&cinfo);
551 (*dest_mgr->start_output) (&cinfo, dest_mgr);
554 ** Create an XImage to hold the processed data
557 nullCount = (4 - (cinfo.output_width % 4)) & 0x03;
558 ximWidth = cinfo.output_width + nullCount;
561 ximData = (unsigned char *) malloc(ximWidth *
562 cinfo.output_height * 4 );
564 ximData = (unsigned char *) malloc(ximWidth * cinfo.output_height );
568 jpeg_destroy_decompress(&cinfo);
569 return (_DtGrNO_MEMORY);
572 *ximage = XCreateImage(display, visual, nplanes,
573 (nplanes == 1) ? XYPixmap : ZPixmap,
574 0, (char *)ximData, cinfo.output_width,
575 cinfo.output_height, 32, 0);
580 jpeg_destroy_decompress(&cinfo);
581 return (_DtGrCONVERT_FAILURE);
585 ** Store the XImage in the custom destination manager
587 dest = (ximg_dest_ptr) dest_mgr;
588 dest->ximage = *ximage;
591 ** Process scanlines until there are none left
594 while (cinfo.output_scanline < cinfo.output_height)
596 num_scanlines = jpeg_read_scanlines(&cinfo,
597 (JSAMPARRAY)dest_mgr->buffer,
598 dest_mgr->buffer_height);
599 (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines);
603 ** Return the colormap info as an array of XColors which can be
604 ** used later for X color allocation purposes.
607 if (cinfo.actual_number_of_colors)
609 colors = (XColor *) malloc((unsigned) sizeof(XColor) *
610 cinfo.actual_number_of_colors);
613 XDestroyImage (*ximage);
614 jpeg_destroy_decompress(&cinfo);
615 return (_DtGrNO_MEMORY);
617 for (i=0; i<cinfo.actual_number_of_colors; i++)
619 if (cinfo.out_color_space == JCS_GRAYSCALE)
621 colors[i].red = colors[i].green = colors[i].blue =
622 INTERP_TO_XCOLORSPACE(cinfo.colormap[0][i]);
626 colors[i].red = INTERP_TO_XCOLORSPACE(cinfo.colormap[0][i]);
627 colors[i].green = INTERP_TO_XCOLORSPACE(cinfo.colormap[1][i]);
628 colors[i].blue = INTERP_TO_XCOLORSPACE(cinfo.colormap[2][i]);
633 *ncolors = cinfo.actual_number_of_colors;
637 ** Set the other return parameters
639 *in_out_width = cinfo.output_width;
640 *in_out_height = cinfo.output_height;
643 ** Shut down the decompression engine and free the allocated memory
645 (*dest_mgr->finish_output) (&cinfo, dest_mgr);
646 jpeg_finish_decompress(&cinfo);
647 jpeg_destroy_decompress(&cinfo);
652 return (_DtGrSUCCESS);