Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / lib / DtHelp / JpegUtils.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
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)
10  * any later version.
11  *
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
16  * details.
17  *
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
22  */
23 /* $XConsortium: JpegUtils.c /main/3 1996/10/06 19:38:48 rws $ */
24 /*
25 ** JpegUtils.c
26 **
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 
30 ** attached below).
31 */
32
33 /*
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.
37  *
38  */
39
40 /*
41 ** Include files
42 */
43
44 #include <stdio.h>
45 #include <malloc.h>
46 #include <string.h>
47 #include <math.h>
48 #include <setjmp.h>
49 #include "GraphicsP.h"
50 #include "jpeglib.h"
51 #include "cdjpeg.h"
52 #include "JpegUtilsI.h"
53
54 /*
55 ** Macro definitions
56 */
57
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 */
64
65 /*
66 ** Type definitions
67 */
68
69 /* 
70 ** Custom destination manager structure 
71 */
72 typedef struct {
73   struct djpeg_dest_struct pub; /* public fields */
74   JSAMPROW pixrow;              /* decompressor output buffer */
75   XImage *ximage;               /* XImage to put pixel info into */
76 } ximg_dest_struct;
77
78 typedef ximg_dest_struct * ximg_dest_ptr;
79
80 /* 
81 ** Custom source manager structure 
82 */
83 typedef struct {
84   struct jpeg_source_mgr pub;   /* public fields */
85
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? */
90 } stream_source_mgr;
91
92 typedef stream_source_mgr * stream_src_ptr;
93
94 /* 
95 ** Custom error handler structure
96 */
97
98 struct my_error_mgr {
99   struct jpeg_error_mgr pub;    /* "public" fields */
100
101   jmp_buf setjmp_buffer;        /* for return to caller */
102 };
103
104 typedef struct my_error_mgr * my_error_ptr;
105
106 /*
107 ** Routines
108 */
109
110 /******************************************************************************
111  *
112  * Function my_error_exit
113  *
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.
117  *
118  *****************************************************************************/
119 static void my_error_exit (j_common_ptr cinfo)
120 {
121     my_error_ptr myerr = (my_error_ptr) cinfo->err;
122
123     (*cinfo->err->output_message) (cinfo);
124
125     /* Return control to the setjmp point */
126     longjmp(myerr->setjmp_buffer, 1);
127 }
128
129 /******************************************************************************
130  *
131  * Function my_output_message
132  *
133  * This routine replaces the standard error message outputter.  Instead
134  * of outputting JPEG library error and warning messages to stderr, it
135  * suppresses them.
136  *
137  *****************************************************************************/
138 static void my_output_message (j_common_ptr cinfo)
139 {
140     char buffer[JMSG_LENGTH_MAX];
141
142     /* 
143     ** Uncommenting the lines below will cause error and warning messages
144     ** from the JPEG library to be displayed to stderr instead of suppressed
145     */
146
147     /* 
148     ** Create the message 
149     **
150     ** (*cinfo->err->format_message) (cinfo, buffer); 
151     */
152
153     /* 
154     ** Send it to stderr, adding a newline 
155     **
156     ** fprintf(stderr, "%s\n", buffer);  
157     */
158 }
159
160 /******************************************************************************
161  *
162  * Function init_source
163  *
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
166  * nothing.
167  *
168  *****************************************************************************/
169 static void init_source (
170     j_decompress_ptr cinfo)
171 {
172     stream_src_ptr src = (stream_src_ptr) cinfo->src;
173 }
174
175 /******************************************************************************
176  *
177  * Function fill_input_buffer
178  *
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.
182  *
183  *****************************************************************************/
184 static boolean fill_input_buffer (
185     j_decompress_ptr cinfo)
186 {
187     stream_src_ptr src = (stream_src_ptr) cinfo->src;
188     size_t nbytes;
189
190     /*
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.
197     */
198     if (src->stream->type == _DtGrBUFFER)
199     {
200         nbytes = 0;
201         src->buffer = (JOCTET *) (*cinfo->mem->alloc_small) (
202                                           (j_common_ptr) cinfo, JPOOL_IMAGE,
203                                           2 * SIZEOF(JOCTET));
204     }
205     else /* _DtGrFILE, read the next chunk of data */
206         nbytes = _DtGrRead (src->buffer, 1, src->input_buf_size, src->stream);
207  
208     if (nbytes <= 0) 
209     {
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;
216         nbytes = 2;
217     }
218
219     src->pub.next_input_byte = src->buffer;
220     src->pub.bytes_in_buffer = nbytes;
221     src->start_of_file = FALSE;
222
223     return TRUE;
224 }
225
226 /******************************************************************************
227  *
228  * Function skip_input_data
229  *
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).
233  *
234  *****************************************************************************/
235 static void skip_input_data (
236     j_decompress_ptr cinfo, 
237     long num_bytes)
238 {
239     stream_src_ptr src = (stream_src_ptr) cinfo->src;
240
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.
244     */
245     if (num_bytes > 0) 
246     {
247         while (num_bytes > (long) src->pub.bytes_in_buffer) 
248         {
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.
253             */
254         }
255         src->pub.next_input_byte += (size_t) num_bytes;
256         src->pub.bytes_in_buffer -= (size_t) num_bytes;
257     }
258 }
259
260 /******************************************************************************
261  *
262  * Function term_source
263  *
264  * This is the custom source manager's termination routine, it currently
265  * does nothing.
266  *
267  *****************************************************************************/
268 static void term_source (
269     j_decompress_ptr cinfo)
270 {
271   /* no work necessary here */
272   return;
273 }
274
275 /******************************************************************************
276  *
277  * Function jpeg_stream_src
278  *
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.
282  *
283  *****************************************************************************/
284 static void jpeg_stream_src (
285     j_decompress_ptr cinfo, 
286     _DtGrStream *stream)
287 {
288     stream_src_ptr src;
289
290     /*
291     ** Create the custom source manager structure
292     */
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;
297
298     src->stream = stream;
299
300     /*
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.
307     */
308     if (stream->type == _DtGrFILE)
309     {
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;
317     }
318     else /* _DtGrBUFFER */
319     {
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;
325     }
326
327     /*
328     ** Initialize the method procedures
329     */
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;
335 }
336
337 /******************************************************************************
338  *
339  * Function copy_pixels
340  *
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.
344  *
345  *****************************************************************************/
346 static void copy_pixels(
347     j_decompress_ptr cinfo, 
348     djpeg_dest_ptr   dinfo,
349     JDIMENSION       rows_supplied)
350 {
351     register int pixval;
352     register JSAMPROW ptr;
353     register JDIMENSION col;
354     ximg_dest_ptr dest = (ximg_dest_ptr) dinfo;
355
356     ptr = dest->pub.buffer[0];
357     for (col=0; col < cinfo->output_width; col++) 
358     {
359         pixval = GETJSAMPLE(*ptr++);
360         XPutPixel(dest->ximage,col,cinfo->output_scanline-1, pixval);
361     }
362 }
363
364
365 /******************************************************************************
366  *
367  * Function start_output_ximg
368  *
369  * This is the data destination manager startup routine, it currently does
370  * nothing.
371  *
372  *****************************************************************************/
373 static void start_output_ximg (
374     j_decompress_ptr cinfo, 
375     djpeg_dest_ptr dinfo)
376 {
377     return;
378 }
379
380 /******************************************************************************
381  *
382  * Function finish_output_ximg
383  *
384  * This is the data destination manager shutdown routine, it currently does 
385  * nothing.
386  *
387  *****************************************************************************/
388 static void finish_output_ximg (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
389 {
390 }
391
392 /******************************************************************************
393  *
394  * Function init_jpeg_dest_mgr
395  *
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.
399  *
400  *****************************************************************************/
401 djpeg_dest_ptr init_jpeg_dest_mgr (
402     j_decompress_ptr cinfo)
403 {
404     ximg_dest_ptr dest;
405
406     /* 
407     ** Create module interface object, fill in the method pointers 
408     */
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;
415
416     /*
417     ** Calculate the output image dimensions so we can allocate the
418     ** right amount of space 
419     */
420     jpeg_calc_output_dimensions(cinfo);
421
422     /*
423     ** Create a buffer for the JPEG library to write decompressed
424     ** scanline data into.
425     */
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;
431
432     /*
433     ** Return the initialized destination manager 
434     */
435     return (djpeg_dest_ptr) dest;
436 }
437
438 /******************************************************************************
439  *
440  * Function jpeg_to_ximage
441  *
442  * This routine converts compressed jpeg data associated with a _DtGrStream 
443  * into an XImage.  
444  *
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.
452  *
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.
458  *
459  *****************************************************************************/
460 enum _DtGrLoadStatus jpeg_to_ximage (
461     _DtGrStream           *stream,
462     Screen                *screen,
463     Visual                *visual,
464     Dimension             *in_out_width,
465     Dimension             *in_out_height,
466     XImage                **ximage,
467     XColor                **xcolors,
468     int                    *ncolors,
469     int                    *xres)
470 {
471     struct jpeg_decompress_struct cinfo;
472     struct my_error_mgr jerr;
473     djpeg_dest_ptr dest_mgr = NULL;
474     ximg_dest_ptr dest;
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;
480
481     /*
482     ** Initialize the return values 
483     */
484     *ximage = NULL;
485     *xres = *ncolors = *in_out_width = *in_out_height = 0;
486
487     /*
488     ** Initialize the jpeg library error handler with our custom routines
489     */
490
491     cinfo.err = jpeg_std_error(&jerr.pub);
492     jerr.pub.error_exit = my_error_exit;
493     jerr.pub.output_message = my_output_message;
494
495     /* 
496     ** Establish the setjmp return context for my_error_exit to use
497     */
498     if (setjmp(jerr.setjmp_buffer)) 
499     {
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.
502         */
503         if (*ximage != NULL)
504             XDestroyImage (*ximage);
505         if (colors != NULL)
506             free (colors);
507         jpeg_destroy_decompress(&cinfo);
508         return (_DtGrCONVERT_FAILURE);
509     }
510
511     /*
512     ** Create a jpeg decompression object
513     */
514     jpeg_create_decompress(&cinfo);
515
516     /*
517     ** Create a custom source data manager
518     */
519     jpeg_stream_src(&cinfo, stream);
520
521     /*
522     ** Read the jpeg header 
523     */
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;
529         else
530             *xres = cinfo.X_density * 2.54 + 0.5;
531     }
532
533     /*
534     ** Initialize our desired post-processing attributes
535     */
536     cinfo.quantize_colors = TRUE;
537     cinfo.desired_number_of_colors = MAX_COLORS;
538
539     /*
540     ** Create a custom data destination manager to allow our processed data
541     ** to be channeled into an XImage.
542     */
543     dest_mgr = init_jpeg_dest_mgr(&cinfo);
544
545     /*
546     ** Initialize the decompression state
547     */
548     jpeg_start_decompress(&cinfo);
549     (*dest_mgr->start_output) (&cinfo, dest_mgr);
550
551     /*
552     ** Create an XImage to hold the processed data
553     */
554         
555     nullCount = (4 - (cinfo.output_width % 4)) & 0x03;
556     ximWidth = cinfo.output_width + nullCount;
557
558     if (nplanes > 8 )
559         ximData = (unsigned char *) malloc(ximWidth * 
560                                            cinfo.output_height * 4 );
561     else
562         ximData = (unsigned char *) malloc(ximWidth * cinfo.output_height );
563
564     if (!ximData) 
565     {
566         jpeg_destroy_decompress(&cinfo);
567         return (_DtGrNO_MEMORY);
568     }
569
570     *ximage = XCreateImage(display, visual, nplanes,
571                            (nplanes == 1) ? XYPixmap : ZPixmap, 
572                            0, (char *)ximData, cinfo.output_width, 
573                            cinfo.output_height, 32, 0);
574
575     if (!*ximage) 
576     {
577         free (ximData);
578         jpeg_destroy_decompress(&cinfo);
579         return (_DtGrCONVERT_FAILURE);
580     }
581
582     /*
583     ** Store the XImage in the custom destination manager
584     */
585     dest = (ximg_dest_ptr) dest_mgr;
586     dest->ximage = *ximage;
587
588     /*
589     ** Process scanlines until there are none left
590     */
591
592     while (cinfo.output_scanline < cinfo.output_height) 
593     {
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);
598     }
599
600     /*
601     ** Return the colormap info as an array of XColors which can be
602     ** used later for X color allocation purposes.
603     */
604
605     if (cinfo.actual_number_of_colors) 
606     {
607         colors = (XColor *) malloc((unsigned) sizeof(XColor) * 
608                                    cinfo.actual_number_of_colors);
609         if (!colors)
610         {
611             XDestroyImage (*ximage);
612             jpeg_destroy_decompress(&cinfo);
613             return (_DtGrNO_MEMORY);
614         }
615         for (i=0; i<cinfo.actual_number_of_colors; i++)
616         {
617             if (cinfo.out_color_space == JCS_GRAYSCALE)
618             {
619                 colors[i].red = colors[i].green = colors[i].blue = 
620                     INTERP_TO_XCOLORSPACE(cinfo.colormap[0][i]);
621             }
622             else /* JCS_RGB */
623             {
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]);
627             }
628         }
629
630         *xcolors = colors;            
631         *ncolors = cinfo.actual_number_of_colors;
632     }
633
634     /*
635     ** Set the other return parameters
636     */
637     *in_out_width = cinfo.output_width;
638     *in_out_height = cinfo.output_height;
639  
640     /*
641     ** Shut down the decompression engine and free the allocated memory
642     */
643     (*dest_mgr->finish_output) (&cinfo, dest_mgr);
644     jpeg_finish_decompress(&cinfo);
645     jpeg_destroy_decompress(&cinfo);
646
647     /*
648     ** Return success
649     */
650     return (_DtGrSUCCESS);
651 }