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 librararies 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"
52 #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)
140 char buffer[JMSG_LENGTH_MAX];
143 ** Uncommenting the lines below will cause error and warning messages
144 ** from the JPEG library to be displayed to stderr instead of suppressed
148 ** Create the message
150 ** (*cinfo->err->format_message) (cinfo, buffer);
154 ** Send it to stderr, adding a newline
156 ** fprintf(stderr, "%s\n", buffer);
160 /******************************************************************************
162 * Function init_source
164 * This is the custom source manager's initialization routine, called by
165 * jpeg_read_header before any data is actually read. It currently does
168 *****************************************************************************/
169 static void init_source (
170 j_decompress_ptr cinfo)
172 stream_src_ptr src = (stream_src_ptr) cinfo->src;
175 /******************************************************************************
177 * Function fill_input_buffer
179 * This is the custom source manager's fill input buffer routine, called by
180 * the JPEG library whenever it has finished processing the data in the
181 * source buffer and needs it to be refilled with the next chunk of data.
183 *****************************************************************************/
184 static boolean fill_input_buffer (
185 j_decompress_ptr cinfo)
187 stream_src_ptr src = (stream_src_ptr) cinfo->src;
191 ** Since we always process buffer-based streams in a single chunk, the
192 ** only reason read_input_buffer should be called for one is if the data
193 ** in the buffer was truncated or otherwise bogus. If this is the case
194 ** we set nbytes to zero, allocate a new buffer to hold a fake EOI marker
195 ** so the stream buffer isn't overwritten, and let the error-handling
196 ** code below take care of things.
198 if (src->stream->type == _DtGrBUFFER)
201 src->buffer = (JOCTET *) (*cinfo->mem->alloc_small) (
202 (j_common_ptr) cinfo, JPOOL_IMAGE,
205 else /* _DtGrFILE, read the next chunk of data */
206 nbytes = _DtGrRead (src->buffer, 1, src->input_buf_size, src->stream);
210 if (src->start_of_file) /* Treat empty input file as fatal error */
211 ERREXIT(cinfo, JERR_INPUT_EMPTY);
212 WARNMS(cinfo, JWRN_JPEG_EOF);
213 /* Insert a fake EOI marker */
214 src->buffer[0] = (JOCTET) 0xFF;
215 src->buffer[1] = (JOCTET) JPEG_EOI;
219 src->pub.next_input_byte = src->buffer;
220 src->pub.bytes_in_buffer = nbytes;
221 src->start_of_file = FALSE;
226 /******************************************************************************
228 * Function skip_input_data
230 * This is the custom source manager's skip input data function, called
231 * by the JPEG library when it wants to skip over a potentially large
232 * amount of uninteresting data (such as an APPn marker).
234 *****************************************************************************/
235 static void skip_input_data (
236 j_decompress_ptr cinfo,
239 stream_src_ptr src = (stream_src_ptr) cinfo->src;
241 /* Just a dumb implementation for now. Could use fseek() except
242 ** it doesn't work on pipes. Not clear that being smart is worth
243 ** any trouble anyway --- large skips are infrequent.
247 while (num_bytes > (long) src->pub.bytes_in_buffer)
249 num_bytes -= (long) src->pub.bytes_in_buffer;
250 (void) fill_input_buffer(cinfo);
251 /* note we assume that fill_input_buffer will never return FALSE,
252 ** so suspension need not be handled.
255 src->pub.next_input_byte += (size_t) num_bytes;
256 src->pub.bytes_in_buffer -= (size_t) num_bytes;
260 /******************************************************************************
262 * Function term_source
264 * This is the custom source manager's termination routine, it currently
267 *****************************************************************************/
268 static void term_source (
269 j_decompress_ptr cinfo)
271 /* no work necessary here */
275 /******************************************************************************
277 * Function jpeg_stream_src
279 * This is the custom source manager's creation routine. Most of the custom
280 * source manager code is based on the JPEG library's stdio source manager
281 * code in the jdatasrc.c file included with the JPEG library distribution.
283 *****************************************************************************/
284 static void jpeg_stream_src (
285 j_decompress_ptr cinfo,
291 ** Create the custom source manager structure
293 cinfo->src = (struct jpeg_source_mgr *) (*cinfo->mem->alloc_small) (
294 (j_common_ptr) cinfo, JPOOL_IMAGE,
295 SIZEOF(stream_source_mgr));
296 src = (stream_src_ptr) cinfo->src;
298 src->stream = stream;
301 ** If this is a file-based stream, we need to allocate a buffer to
302 ** read data into. If this is a buffer-based stream, we just use the
303 ** buffer already attached to the stream. Note that this implies that
304 ** we always process buffer-based streams in a single chunk, if there
305 ** is ever a reason to do otherwise, this routine and fill_input_buffer
306 ** will need to be modified appropriately.
308 if (stream->type == _DtGrFILE)
310 src->buffer = (JOCTET *) (*cinfo->mem->alloc_small) (
311 (j_common_ptr) cinfo, JPOOL_IMAGE,
312 INPUT_BUF_SIZE * SIZEOF(JOCTET));
313 src->input_buf_size = INPUT_BUF_SIZE;
314 src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer call */
315 src->pub.next_input_byte = NULL; /* on first read */
316 src->start_of_file = TRUE;
318 else /* _DtGrBUFFER */
320 src->buffer = (unsigned char *) stream->source.buffer.base;
321 src->input_buf_size = stream->source.buffer.size;
322 src->pub.bytes_in_buffer = src->input_buf_size;
323 src->pub.next_input_byte = src->buffer;
324 src->start_of_file = FALSE;
328 ** Initialize the method procedures
330 src->pub.init_source = init_source;
331 src->pub.fill_input_buffer = fill_input_buffer;
332 src->pub.skip_input_data = skip_input_data;
333 src->pub.resync_to_restart = jpeg_resync_to_restart; /* default method */
334 src->pub.term_source = term_source;
337 /******************************************************************************
339 * Function copy_pixels
341 * This routine loops through a scanline of decompressed, quantized
342 * JPEG data and uses XPutPixel to copy the pixel values into the
343 * XImage associated with the destination manager.
345 *****************************************************************************/
346 static void copy_pixels(
347 j_decompress_ptr cinfo,
348 djpeg_dest_ptr dinfo,
349 JDIMENSION rows_supplied)
352 register JSAMPROW ptr;
353 register JDIMENSION col;
354 ximg_dest_ptr dest = (ximg_dest_ptr) dinfo;
356 ptr = dest->pub.buffer[0];
357 for (col=0; col < cinfo->output_width; col++)
359 pixval = GETJSAMPLE(*ptr++);
360 XPutPixel(dest->ximage,col,cinfo->output_scanline-1, pixval);
365 /******************************************************************************
367 * Function start_output_ximg
369 * This is the data destination manager startup routine, it currently does
372 *****************************************************************************/
373 static void start_output_ximg (
374 j_decompress_ptr cinfo,
375 djpeg_dest_ptr dinfo)
380 /******************************************************************************
382 * Function finish_output_ximg
384 * This is the data destination manager shutdown routine, it currently does
387 *****************************************************************************/
388 static void finish_output_ximg (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
392 /******************************************************************************
394 * Function init_jpeg_dest_mgr
396 * This routine allocates and initializes a data destination manager
397 * that the JPEG library will use as a sink for JPEG data after the
398 * data has been decompressed.
400 *****************************************************************************/
401 djpeg_dest_ptr init_jpeg_dest_mgr (
402 j_decompress_ptr cinfo)
407 ** Create module interface object, fill in the method pointers
409 dest = (ximg_dest_ptr) (*cinfo->mem->alloc_small) (
410 (j_common_ptr) cinfo, JPOOL_IMAGE,
411 SIZEOF(ximg_dest_struct));
412 dest->pub.start_output = start_output_ximg;
413 dest->pub.finish_output = finish_output_ximg;
414 dest->pub.put_pixel_rows = copy_pixels;
417 ** Calculate the output image dimensions so we can allocate the
418 ** right amount of space
420 jpeg_calc_output_dimensions(cinfo);
423 ** Create a buffer for the JPEG library to write decompressed
424 ** scanline data into.
426 dest->pixrow = (JSAMPROW) (*cinfo->mem->alloc_small) (
427 (j_common_ptr) cinfo, JPOOL_IMAGE,
428 cinfo->output_width * cinfo->out_color_components );
429 dest->pub.buffer = &dest->pixrow;
430 dest->pub.buffer_height = 1;
433 ** Return the initialized destination manager
435 return (djpeg_dest_ptr) dest;
438 /******************************************************************************
440 * Function jpeg_to_ximage
442 * This routine converts compressed jpeg data associated with a _DtGrStream
445 * No X color allocation is done. The image is quantized down to MAX_COLORS
446 * during decompression, and an array of XColor structures with the red,
447 * green, and blue fields initialized to the colors used in the image is
448 * returned to the caller. Each pixel value in the XImage data is an index
449 * into this array. The caller must use this information to allocate X
450 * color cells and substitute the appropriate pixel values into the XImage
451 * data array before using the XImage.
453 * The routine makes use of a custom source data manager to allow the JPEG
454 * data source to be a _DtGrStream, a custom data destination manager to
455 * allow the decompressed and post-processed data to be written to an XImage,
456 * and a custom error handler to allow standard _DtGr error codes to be
457 * returned to the caller in the event of a JPEG library error.
459 *****************************************************************************/
460 enum _DtGrLoadStatus jpeg_to_ximage (
464 Dimension *in_out_width,
465 Dimension *in_out_height,
471 struct jpeg_decompress_struct cinfo;
472 struct my_error_mgr jerr;
473 djpeg_dest_ptr dest_mgr = NULL;
475 int i, num_scanlines, nullCount, ximWidth;
476 unsigned char *ximData = NULL;
477 Display *display = DisplayOfScreen(screen);
478 int nplanes = DisplayPlanes(display,XScreenNumberOfScreen(screen));
479 XColor *colors = NULL;
482 ** Initialize the return values
485 *xres = *ncolors = *in_out_width = *in_out_height = 0;
488 ** Initialize the jpeg library error handler with our custom routines
491 cinfo.err = jpeg_std_error(&jerr.pub);
492 jerr.pub.error_exit = my_error_exit;
493 jerr.pub.output_message = my_output_message;
496 ** Establish the setjmp return context for my_error_exit to use
498 if (setjmp(jerr.setjmp_buffer))
500 /* If we get here, the JPEG code has signaled an error. We need to
501 ** free memory, clean up the JPEG object, and return a failure code.
504 XDestroyImage (*ximage);
507 jpeg_destroy_decompress(&cinfo);
508 return (_DtGrCONVERT_FAILURE);
512 ** Create a jpeg decompression object
514 jpeg_create_decompress(&cinfo);
517 ** Create a custom source data manager
519 jpeg_stream_src(&cinfo, stream);
522 ** Read the jpeg header
524 jpeg_read_header(&cinfo, TRUE);
525 if (cinfo.X_density > 0 &&
526 (cinfo.density_unit == 1 || cinfo.density_unit == 2)) {
527 if (cinfo.density_unit == 1)
528 *xres = cinfo.X_density;
530 *xres = cinfo.X_density * 2.54 + 0.5;
534 ** Initialize our desired post-processing attributes
536 cinfo.quantize_colors = TRUE;
537 cinfo.desired_number_of_colors = MAX_COLORS;
540 ** Create a custom data destination manager to allow our processed data
541 ** to be channeled into an XImage.
543 dest_mgr = init_jpeg_dest_mgr(&cinfo);
546 ** Initialize the decompression state
548 jpeg_start_decompress(&cinfo);
549 (*dest_mgr->start_output) (&cinfo, dest_mgr);
552 ** Create an XImage to hold the processed data
555 nullCount = (4 - (cinfo.output_width % 4)) & 0x03;
556 ximWidth = cinfo.output_width + nullCount;
559 ximData = (unsigned char *) malloc(ximWidth *
560 cinfo.output_height * 4 );
562 ximData = (unsigned char *) malloc(ximWidth * cinfo.output_height );
566 jpeg_destroy_decompress(&cinfo);
567 return (_DtGrNO_MEMORY);
570 *ximage = XCreateImage(display, visual, nplanes,
571 (nplanes == 1) ? XYPixmap : ZPixmap,
572 0, (char *)ximData, cinfo.output_width,
573 cinfo.output_height, 32, 0);
578 jpeg_destroy_decompress(&cinfo);
579 return (_DtGrCONVERT_FAILURE);
583 ** Store the XImage in the custom destination manager
585 dest = (ximg_dest_ptr) dest_mgr;
586 dest->ximage = *ximage;
589 ** Process scanlines until there are none left
592 while (cinfo.output_scanline < cinfo.output_height)
594 num_scanlines = jpeg_read_scanlines(&cinfo,
595 (JSAMPARRAY)dest_mgr->buffer,
596 dest_mgr->buffer_height);
597 (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines);
601 ** Return the colormap info as an array of XColors which can be
602 ** used later for X color allocation purposes.
605 if (cinfo.actual_number_of_colors)
607 colors = (XColor *) malloc((unsigned) sizeof(XColor) *
608 cinfo.actual_number_of_colors);
611 XDestroyImage (*ximage);
612 jpeg_destroy_decompress(&cinfo);
613 return (_DtGrNO_MEMORY);
615 for (i=0; i<cinfo.actual_number_of_colors; i++)
617 if (cinfo.out_color_space == JCS_GRAYSCALE)
619 colors[i].red = colors[i].green = colors[i].blue =
620 INTERP_TO_XCOLORSPACE(cinfo.colormap[0][i]);
624 colors[i].red = INTERP_TO_XCOLORSPACE(cinfo.colormap[0][i]);
625 colors[i].green = INTERP_TO_XCOLORSPACE(cinfo.colormap[1][i]);
626 colors[i].blue = INTERP_TO_XCOLORSPACE(cinfo.colormap[2][i]);
631 *ncolors = cinfo.actual_number_of_colors;
635 ** Set the other return parameters
637 *in_out_width = cinfo.output_width;
638 *in_out_height = cinfo.output_height;
641 ** Shut down the decompression engine and free the allocated memory
643 (*dest_mgr->finish_output) (&cinfo, dest_mgr);
644 jpeg_finish_decompress(&cinfo);
645 jpeg_destroy_decompress(&cinfo);
650 return (_DtGrSUCCESS);