1 #include "JpegI.h"
2 #include <jerror.h>
3 #include <stdlib.h>
4 #include <X11/Intrinsic.h>
5 
6 void
_XmJpegErrorExit(j_common_ptr cinfo)7 _XmJpegErrorExit(j_common_ptr cinfo)
8 {
9     int rc;
10     XmJpegErrorMgr err = (XmJpegErrorMgr) cinfo->err;
11 
12     switch (cinfo->err->msg_code) {
13     case JERR_NO_SOI:
14         rc = 1;
15         break;
16     case JERR_OUT_OF_MEMORY:
17         rc = 4;
18         break;
19     default:
20         rc = 2;
21         break;
22     }
23     longjmp(err->setjmp_buffer, rc);
24 }
25 
26 int
load_jpeg(FILE * infile,unsigned long * pWidth,unsigned long * pHeight,CTable ** image_data)27 load_jpeg(FILE * infile, unsigned long *pWidth, unsigned long *pHeight,
28           CTable ** image_data)
29 {
30     CTable *buf;
31     struct jpeg_decompress_struct cinfo;
32     XmJpegErrorMgrRec jerr;
33     JSAMPROW row_pointer[1];
34     int x, y;
35     int rc;
36 
37     *image_data = NULL;
38     cinfo.err = jpeg_std_error((struct jpeg_error_mgr *) &jerr);
39     jerr.pub.error_exit = _XmJpegErrorExit;
40     if ((rc = setjmp(jerr.setjmp_buffer))) {
41         jpeg_destroy_decompress(&cinfo);
42         return rc;
43     }
44     jpeg_create_decompress(&cinfo);
45     jpeg_stdio_src(&cinfo, infile);
46     jpeg_read_header(&cinfo, TRUE);
47     jpeg_calc_output_dimensions(&cinfo);
48     jpeg_start_decompress(&cinfo);
49     *pWidth = cinfo.output_width;
50     *pHeight = cinfo.output_height;
51     *image_data =
52         malloc(cinfo.output_width * cinfo.output_height * sizeof(CTable));
53     for (buf = *image_data;
54          cinfo.output_scanline < cinfo.output_height;
55          buf += cinfo.output_width)
56         jpeg_read_scanlines(&cinfo, (JSAMPARRAY) (&buf), 1);
57     if (cinfo.out_color_space == JCS_GRAYSCALE) {
58         for (y = 0, buf = *image_data; y < cinfo.output_height;
59              y++, buf += cinfo.output_width)
60             for (x = cinfo.output_width - 1; x >= 0; x--)
61                 buf[x].red = buf[x].green = buf[x].blue =
62                     ((JSAMPLE *) buf)[x];
63     }
64     jpeg_finish_decompress(&cinfo);
65     jpeg_destroy_decompress(&cinfo);
66     return 0;
67 }
68 
69 Pixel
get_cval(unsigned char c,unsigned long mask)70 get_cval(unsigned char c, unsigned long mask)
71 {
72     Pixel value = c, x;
73     int i;
74     for (i = 0, x = 1; i < 32; i++, x <<= 1)
75         if (mask & x)
76             break;
77     for (; i < 32; i++, x <<= 1)
78         if (!(mask & x))
79             break;
80     if (i < 8)
81         value >>= 8 - i;
82     else if (i > 8)
83         value <<= i - 8;
84     return (value & mask);
85 }
86 
87 void
store_pixel(Screen * screen,CTable * p,int x,char * cdata)88 store_pixel(Screen * screen, CTable * p, int x, char *cdata)
89 {
90     Pixel px = get_cval(p->red, screen->root_visual->red_mask)
91         | get_cval(p->green, screen->root_visual->green_mask)
92         | get_cval(p->blue, screen->root_visual->blue_mask);
93     if (screen->root_depth <= 16) {
94         if (ImageByteOrder(screen->display) == MSBFirst) {
95             cdata[x * 2] = (px >> 8);
96             cdata[x * 2 + 1] = (px & 0xff);
97         } else {
98             cdata[x * 2] = (px & 0xff);
99             cdata[x * 2 + 1] = (px >> 8);
100         }
101     } else {
102         if (ImageByteOrder(screen->display) == MSBFirst) {
103             cdata[x * 4] = (px >> 24);
104             cdata[x * 4 + 1] = (px >> 16);
105             cdata[x * 4 + 2] = (px >> 8);
106             cdata[x * 4 + 3] = (px & 0xff);
107         } else {
108             cdata[x * 4 + 3] = (px >> 24);
109             cdata[x * 4 + 2] = (px >> 16);
110             cdata[x * 4 + 1] = (px >> 8);
111             cdata[x * 4] = (px & 0xff);
112         }
113     }
114 }
115 
116 int
_XmJpegGetImage(Screen * screen,FILE * infile,XImage ** ximage)117 _XmJpegGetImage(Screen * screen, FILE * infile, XImage ** ximage)
118 {
119     unsigned long image_width, image_height;
120     unsigned char *xdata;
121     int pad;
122     CTable *image_data;
123     int rc;
124 
125     if ((rc = load_jpeg(infile, &image_width, &image_height, &image_data)))
126         return rc;
127     if (screen->root_depth == 24 || screen->root_depth == 32) {
128         xdata = (unsigned char *) malloc(4 * image_width * image_height);
129         pad = 32;
130     } else if (screen->root_depth == 16) {
131         xdata = (unsigned char *) malloc(2 * image_width * image_height);
132         pad = 16;
133     } else {                    /* depth == 8 */
134         xdata = (unsigned char *) malloc(image_width * image_height);
135         pad = 8;
136     }
137 
138     if (!xdata)
139         return 4;
140 
141     *ximage =
142         XCreateImage(screen->display, screen->root_visual,
143                      screen->root_depth, ZPixmap, 0, (char *) xdata,
144                      image_width, image_height, pad, 0);
145     if (!*ximage) {
146         free(xdata);
147         return 4;
148     }
149 
150     {
151         int xx, yy;
152         CTable *p;
153         for (yy = 0; yy < (*ximage)->height; yy++) {
154             p = image_data + yy * (*ximage)->width;
155             for (xx = 0; xx < (*ximage)->width; xx++, p++)
156                 store_pixel(screen, p, xx + yy * (*ximage)->width,
157                             (*ximage)->data);
158         }
159     }
160 
161     if (image_data) {
162         free(image_data);
163         image_data = NULL;
164     }
165     return 0;
166 }
167