1 #include "loader_common.h"
2 #include <jpeglib.h>
3 #include <setjmp.h>
4 
5 typedef struct {
6    struct jpeg_error_mgr jem;
7    sigjmp_buf          setjmp_buffer;
8    DATA8              *data;
9 } ImLib_JPEG_data;
10 
11 static void
_JPEGFatalErrorHandler(j_common_ptr cinfo)12 _JPEGFatalErrorHandler(j_common_ptr cinfo)
13 {
14    ImLib_JPEG_data    *jd = (ImLib_JPEG_data *) cinfo->err;
15 
16 #if 0
17    cinfo->err->output_message(cinfo);
18 #endif
19    siglongjmp(jd->setjmp_buffer, 1);
20 }
21 
22 static void
_JPEGErrorHandler(j_common_ptr cinfo)23 _JPEGErrorHandler(j_common_ptr cinfo)
24 {
25 #if 0
26    ImLib_JPEG_data    *jd = (ImLib_JPEG_data *) cinfo->err;
27 
28    cinfo->err->output_message(cinfo);
29    siglongjmp(jd->setjmp_buffer, 1);
30 #endif
31 }
32 
33 static void
_JPEGErrorHandler2(j_common_ptr cinfo,int msg_level)34 _JPEGErrorHandler2(j_common_ptr cinfo, int msg_level)
35 {
36 #if 0
37    ImLib_JPEG_data    *jd = (ImLib_JPEG_data *) cinfo->err;
38 
39    cinfo->err->output_message(cinfo);
40    siglongjmp(jd->setjmp_buffer, 1);
41 #endif
42 }
43 
44 static struct jpeg_error_mgr *
_jdata_init(ImLib_JPEG_data * jd)45 _jdata_init(ImLib_JPEG_data * jd)
46 {
47    struct jpeg_error_mgr *jem;
48 
49    jem = jpeg_std_error(&jd->jem);
50 
51    jd->jem.error_exit = _JPEGFatalErrorHandler;
52    jd->jem.emit_message = _JPEGErrorHandler2;
53    jd->jem.output_message = _JPEGErrorHandler;
54 
55    jd->data = NULL;
56 
57    return jem;
58 }
59 
60 int
load2(ImlibImage * im,int load_data)61 load2(ImlibImage * im, int load_data)
62 {
63    int                 w, h, rc;
64    struct jpeg_decompress_struct cinfo;
65    ImLib_JPEG_data     jdata;
66    DATA8              *ptr, *line[16];
67    DATA32             *ptr2;
68    int                 x, y, l, i, scans;
69 
70    /* set up error handling */
71    cinfo.err = _jdata_init(&jdata);
72    if (sigsetjmp(jdata.setjmp_buffer, 1))
73      {
74         rc = LOAD_FAIL;
75         goto quit;
76      }
77 
78    rc = LOAD_FAIL;
79 
80    jpeg_create_decompress(&cinfo);
81    jpeg_stdio_src(&cinfo, im->fp);
82    jpeg_read_header(&cinfo, TRUE);
83 
84    im->w = w = cinfo.image_width;
85    im->h = h = cinfo.image_height;
86    if (!IMAGE_DIMENSIONS_OK(w, h))
87       goto quit;
88 
89    UNSET_FLAG(im->flags, F_HAS_ALPHA);
90 
91    if (!load_data)
92      {
93         rc = LOAD_SUCCESS;
94         goto quit;
95      }
96 
97    /* Load data */
98 
99    cinfo.do_fancy_upsampling = FALSE;
100    cinfo.do_block_smoothing = FALSE;
101    jpeg_start_decompress(&cinfo);
102 
103    if ((cinfo.rec_outbuf_height > 16) || (cinfo.output_components <= 0))
104       goto quit;
105 
106    jdata.data = malloc(w * 16 * cinfo.output_components);
107    if (!jdata.data)
108       goto quit;
109 
110    /* must set the im->data member before callign progress function */
111    ptr2 = __imlib_AllocateData(im);
112    if (!ptr2)
113       goto quit;
114 
115    for (i = 0; i < cinfo.rec_outbuf_height; i++)
116       line[i] = jdata.data + (i * w * cinfo.output_components);
117 
118    for (l = 0; l < h; l += cinfo.rec_outbuf_height)
119      {
120         jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height);
121 
122         scans = cinfo.rec_outbuf_height;
123         if ((h - l) < scans)
124            scans = h - l;
125         ptr = jdata.data;
126 
127         for (y = 0; y < scans; y++)
128           {
129              switch (cinfo.out_color_space)
130                {
131                default:
132                   goto quit;
133                case JCS_GRAYSCALE:
134                   for (x = 0; x < w; x++)
135                     {
136                        *ptr2 = PIXEL_ARGB(0xff, ptr[0], ptr[0], ptr[0]);
137                        ptr++;
138                        ptr2++;
139                     }
140                   break;
141                case JCS_RGB:
142                   for (x = 0; x < w; x++)
143                     {
144                        *ptr2 = PIXEL_ARGB(0xff, ptr[0], ptr[1], ptr[2]);
145                        ptr += cinfo.output_components;
146                        ptr2++;
147                     }
148                   break;
149                case JCS_CMYK:
150                   for (x = 0; x < w; x++)
151                     {
152                        *ptr2 = PIXEL_ARGB(0xff, ptr[0] * ptr[3] / 255,
153                                           ptr[1] * ptr[3] / 255,
154                                           ptr[2] * ptr[3] / 255);
155                        ptr += cinfo.output_components;
156                        ptr2++;
157                     }
158                   break;
159                }
160           }
161 
162         if (im->lc && __imlib_LoadProgressRows(im, l, scans))
163           {
164              rc = LOAD_BREAK;
165              goto done;
166           }
167      }
168 
169  done:
170    jpeg_finish_decompress(&cinfo);
171 
172    rc = LOAD_SUCCESS;
173 
174  quit:
175    jpeg_destroy_decompress(&cinfo);
176    free(jdata.data);
177    if (rc <= 0)
178       __imlib_FreeData(im);
179 
180    return rc;
181 }
182 
183 char
save(ImlibImage * im,ImlibProgressFunction progress,char progress_granularity)184 save(ImlibImage * im, ImlibProgressFunction progress, char progress_granularity)
185 {
186    int                 rc;
187    struct jpeg_compress_struct cinfo;
188    ImLib_JPEG_data     jdata;
189    FILE               *f;
190    DATA8              *buf;
191    DATA32             *ptr;
192    JSAMPROW           *jbuf;
193    int                 y, quality, compression;
194    ImlibImageTag      *tag;
195    int                 i, j;
196 
197    /* allocate a small buffer to convert image data */
198    buf = malloc(im->w * 3 * sizeof(DATA8));
199    if (!buf)
200       return LOAD_FAIL;
201 
202    rc = LOAD_FAIL;
203 
204    f = fopen(im->real_file, "wb");
205    if (!f)
206       goto quit;
207 
208    /* set up error handling */
209    cinfo.err = _jdata_init(&jdata);
210    if (sigsetjmp(jdata.setjmp_buffer, 1))
211       goto quit;
212 
213    /* setup compress params */
214    jpeg_create_compress(&cinfo);
215    jpeg_stdio_dest(&cinfo, f);
216    cinfo.image_width = im->w;
217    cinfo.image_height = im->h;
218    cinfo.input_components = 3;
219    cinfo.in_color_space = JCS_RGB;
220 
221    /* look for tags attached to image to get extra parameters like quality */
222    /* settigns etc. - this is the "api" to hint for extra information for */
223    /* saver modules */
224 
225    /* compression */
226    compression = 2;
227    tag = __imlib_GetTag(im, "compression");
228    if (tag)
229      {
230         compression = tag->val;
231         if (compression < 0)
232            compression = 0;
233         if (compression > 9)
234            compression = 9;
235      }
236    /* convert to quality */
237    quality = (9 - compression) * 10;
238    quality = quality * 10 / 9;
239    /* quality */
240    tag = __imlib_GetTag(im, "quality");
241    if (tag)
242       quality = tag->val;
243    if (quality < 1)
244       quality = 1;
245    if (quality > 100)
246       quality = 100;
247 
248    /* set up jepg compression parameters */
249    jpeg_set_defaults(&cinfo);
250    jpeg_set_quality(&cinfo, quality, TRUE);
251    jpeg_start_compress(&cinfo, TRUE);
252    /* get the start pointer */
253    ptr = im->data;
254    /* go one scanline at a time... and save */
255    for (y = 0; cinfo.next_scanline < cinfo.image_height; y++)
256      {
257         /* convcert scaline from ARGB to RGB packed */
258         for (j = 0, i = 0; i < im->w; i++)
259           {
260              DATA32              pixel = *ptr++;
261 
262              buf[j++] = PIXEL_R(pixel);
263              buf[j++] = PIXEL_G(pixel);
264              buf[j++] = PIXEL_B(pixel);
265           }
266         /* write scanline */
267         jbuf = (JSAMPROW *) (&buf);
268         jpeg_write_scanlines(&cinfo, jbuf, 1);
269 
270         if (im->lc && __imlib_LoadProgressRows(im, y, 1))
271           {
272              rc = LOAD_BREAK;
273              goto quit;
274           }
275      }
276 
277    rc = LOAD_SUCCESS;
278 
279  quit:
280    /* finish off */
281    jpeg_finish_compress(&cinfo);
282    jpeg_destroy_compress(&cinfo);
283    free(buf);
284    fclose(f);
285 
286    return rc;
287 }
288 
289 void
formats(ImlibLoader * l)290 formats(ImlibLoader * l)
291 {
292    static const char  *const list_formats[] = { "jpg", "jpeg", "jfif", "jfi" };
293    __imlib_LoaderSetFormats(l, list_formats,
294                             sizeof(list_formats) / sizeof(char *));
295 }
296