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