2 * Image Library -- libjpeg
4 * (c) 2006 Pavel Charvat <pchar@ucw.cz>
6 * This software may be freely distributed and used according to the terms
7 * of the GNU Lesser General Public License.
13 #include "lib/mempool.h"
14 #include "lib/fastbuf.h"
15 #include "images/images.h"
16 #include "images/io-main.h"
18 #include <sys/types.h>
23 struct jpeg_error_mgr pub;
28 struct libjpeg_read_internals {
29 struct jpeg_decompress_struct cinfo;
30 struct jpeg_source_mgr src;
31 struct libjpeg_err err;
32 struct fastbuf *fastbuf;
36 struct libjpeg_write_internals {
37 struct jpeg_compress_struct cinfo;
38 struct jpeg_destination_mgr dest;
39 struct libjpeg_err err;
40 struct fastbuf *fastbuf;
45 libjpeg_read_error_exit(j_common_ptr cinfo)
47 DBG("libjpeg_error_exit()");
48 struct libjpeg_err *e = (struct libjpeg_err *)cinfo->err;
49 byte buf[JMSG_LENGTH_MAX];
50 e->pub.format_message(cinfo, buf);
51 image_thread_err_dup(e->io->thread, IMAGE_ERR_READ_FAILED, buf);
52 longjmp(e->setjmp_buf, 1);
56 libjpeg_write_error_exit(j_common_ptr cinfo)
58 DBG("libjpeg_error_exit()");
59 struct libjpeg_err *e = (struct libjpeg_err *)cinfo->err;
60 byte buf[JMSG_LENGTH_MAX];
61 e->pub.format_message(cinfo, buf);
62 image_thread_err_dup(e->io->thread, IMAGE_ERR_WRITE_FAILED, buf);
63 longjmp(e->setjmp_buf, 1);
67 libjpeg_emit_message(j_common_ptr cinfo UNUSED, int msg_level UNUSED)
70 byte buf[JMSG_LENGTH_MAX];
71 cinfo->err->format_message(cinfo, buf);
72 DBG("libjpeg_emit_message(): [%d] %s", msg_level, buf);
74 if (unlikely(msg_level == -1))
75 longjmp(((struct libjpeg_err *)(cinfo)->err)->setjmp_buf, 1);
79 libjpeg_fastbuf_read_prepare(struct libjpeg_read_internals *i)
82 uns len = bdirect_read_prepare(i->fastbuf, &start);
83 i->fastbuf_pos = start + len;
84 i->src.next_input_byte = start;
85 i->src.bytes_in_buffer = len;
90 libjpeg_fastbuf_read_commit(struct libjpeg_read_internals *i)
92 bdirect_read_commit(i->fastbuf, i->fastbuf_pos);
96 libjpeg_init_source(j_decompress_ptr cinfo)
98 DBG("libjpeg_init_source()");
99 libjpeg_fastbuf_read_prepare((struct libjpeg_read_internals *)cinfo);
103 libjpeg_term_source(j_decompress_ptr cinfo UNUSED)
105 DBG("libjpeg_term_source()");
106 //libjpeg_fastbuf_read_commit((struct libjpeg_read_internals *)cinfo);
110 libjpeg_fill_input_buffer(j_decompress_ptr cinfo)
112 DBG("libjpeg_fill_input_buffer()");
113 struct libjpeg_read_internals *i = (struct libjpeg_read_internals *)cinfo;
114 libjpeg_fastbuf_read_commit(i);
115 return !!libjpeg_fastbuf_read_prepare(i);
119 libjpeg_skip_input_data(j_decompress_ptr cinfo, long num_bytes)
121 DBG("libjpeg_skip_input_data(num_bytes=%d)", (int)num_bytes);
124 struct libjpeg_read_internals *i = (struct libjpeg_read_internals *)cinfo;
125 if ((unsigned long)num_bytes <= i->src.bytes_in_buffer)
127 i->src.next_input_byte += num_bytes;
128 i->src.bytes_in_buffer -= num_bytes;
132 num_bytes -= i->src.bytes_in_buffer;
133 libjpeg_fastbuf_read_commit(i);
134 bskip(i->fastbuf, num_bytes);
135 libjpeg_fastbuf_read_prepare(i);
141 libjpeg_fastbuf_write_prepare(struct libjpeg_write_internals *i)
144 uns len = bdirect_write_prepare(i->fastbuf, &start);
145 i->fastbuf_pos = start + len;
146 i->dest.next_output_byte = start;
147 i->dest.free_in_buffer = len;
150 image_thread_err(i->err.io->thread, IMAGE_ERR_WRITE_FAILED, "Unexpected end of stream");
151 longjmp(i->err.setjmp_buf, 1);
156 libjpeg_init_destination(j_compress_ptr cinfo)
158 DBG("libjpeg_init_destination()");
159 libjpeg_fastbuf_write_prepare((struct libjpeg_write_internals *)cinfo);
163 libjpeg_term_destination(j_compress_ptr cinfo)
165 DBG("libjpeg_term_destination()");
166 struct libjpeg_write_internals *i = (struct libjpeg_write_internals *)cinfo;
167 bdirect_write_commit(i->fastbuf, (byte *)i->dest.next_output_byte);
171 libjpeg_empty_output_buffer(j_compress_ptr cinfo)
173 DBG("libjpeg_empty_output_buffer()");
174 struct libjpeg_write_internals *i = (struct libjpeg_write_internals *)cinfo;
175 bdirect_write_commit(i->fastbuf, i->fastbuf_pos);
176 libjpeg_fastbuf_write_prepare(i);
181 libjpeg_read_cancel(struct image_io *io)
183 DBG("libjpeg_read_cancel()");
184 struct libjpeg_read_internals *i = io->read_data;
185 jpeg_destroy_decompress(&i->cinfo);
189 libjpeg_read_header(struct image_io *io)
191 DBG("libjpeg_read_header()");
192 struct libjpeg_read_internals *i = io->read_data = mp_alloc(io->internal_pool, sizeof(*i));
193 i->fastbuf = io->fastbuf;
195 /* Create libjpeg read structure */
196 DBG("Creating libjpeg read structure");
197 i->cinfo.err = jpeg_std_error(&i->err.pub);
198 i->err.pub.error_exit = libjpeg_read_error_exit;
199 i->err.pub.emit_message = libjpeg_emit_message;
201 if (setjmp(i->err.setjmp_buf))
203 DBG("Libjpeg failed to read the image, longjump saved us");
204 jpeg_destroy_decompress(&i->cinfo);
207 jpeg_create_decompress(&i->cinfo);
209 /* Initialize source manager */
210 i->cinfo.src = &i->src;
211 i->src.init_source = libjpeg_init_source;
212 i->src.fill_input_buffer = libjpeg_fill_input_buffer;
213 i->src.skip_input_data = libjpeg_skip_input_data;
214 i->src.resync_to_restart = jpeg_resync_to_restart;
215 i->src.term_source = libjpeg_term_source;
217 /* Read JPEG header and setup decompression options */
218 DBG("Reading image header");
219 jpeg_read_header(&i->cinfo, TRUE);
220 switch (i->cinfo.jpeg_color_space)
223 io->flags = COLOR_SPACE_GRAYSCALE;
224 io->number_of_colors = 1 << 8;
227 io->flags = COLOR_SPACE_RGB;
228 io->number_of_colors = 1 << 24;
231 io->cols = i->cinfo.image_width;
232 io->rows = i->cinfo.image_height;
234 io->read_cancel = libjpeg_read_cancel;
239 libjpeg_read_data(struct image_io *io)
241 DBG("libjpeg_read_data()");
243 struct libjpeg_read_internals *i = io->read_data;
245 /* Select color space */
246 switch (io->flags & IMAGE_COLOR_SPACE)
248 case COLOR_SPACE_GRAYSCALE:
249 i->cinfo.out_color_space = JCS_GRAYSCALE;
251 case COLOR_SPACE_RGB:
252 i->cinfo.out_color_space = JCS_RGB;
255 jpeg_destroy_decompress(&i->cinfo);
256 image_thread_err(io->thread, IMAGE_ERR_INVALID_PIXEL_FORMAT, "Unsupported color space.");
260 /* Prepare the image */
261 struct image_io_read_data_internals rdi;
262 if (io->cols <= (i->cinfo.image_width >> 3) && io->rows <= (i->cinfo.image_height >> 3))
264 DBG("Scaling to 1/8");
265 i->cinfo.scale_num = 1;
266 i->cinfo.scale_denom = 8;
268 else if (io->cols <= (i->cinfo.image_width >> 2) && io->rows <= (i->cinfo.image_height >> 2))
270 DBG("Scaling to 1/4");
271 i->cinfo.scale_num = 1;
272 i->cinfo.scale_denom = 4;
274 else if (io->cols <= (i->cinfo.image_width >> 1) && io->rows <= (i->cinfo.image_height >> 1))
276 DBG("Scaling to 1/2");
277 i->cinfo.scale_num = 1;
278 i->cinfo.scale_denom = 2;
280 jpeg_calc_output_dimensions(&i->cinfo);
281 DBG("Output dimensions %ux%u", (uns)i->cinfo.output_width, (uns)i->cinfo.output_height);
282 if (unlikely(!image_io_read_data_prepare(&rdi, io, i->cinfo.output_width, i->cinfo.output_height, io->flags)))
284 jpeg_destroy_decompress(&i->cinfo);
289 if (setjmp(i->err.setjmp_buf))
291 DBG("Libjpeg failed to read the image, longjump saved us");
292 jpeg_destroy_decompress(&i->cinfo);
293 image_io_read_data_break(&rdi, io);
297 /* Decompress the image */
298 struct image *img = rdi.image;
299 jpeg_start_decompress(&i->cinfo);
300 switch (img->pixel_size)
302 /* grayscale or RGB */
306 byte *pixels = img->pixels;
307 for (uns r = img->rows; r--; )
309 jpeg_read_scanlines(&i->cinfo, (JSAMPLE **)&pixels, 1);
310 pixels += img->row_size;
314 /* grayscale with alpha */
317 byte buf[img->cols], *src;
318 # define IMAGE_WALK_PREFIX(x) walk_##x
319 # define IMAGE_WALK_INLINE
320 # define IMAGE_WALK_IMAGE img
321 # define IMAGE_WALK_UNROLL 4
322 # define IMAGE_WALK_COL_STEP 2
323 # define IMAGE_WALK_DO_ROW_START do{ src = buf; jpeg_read_scanlines(&i->cinfo, (JSAMPLE **)&src, 1); }while(0)
324 # define IMAGE_WALK_DO_STEP do{ walk_pos[0] = *src++; walk_pos[1] = 255; }while(0)
325 # include "images/image-walk.h"
328 /* RGBA or aligned RGB */
331 byte buf[img->cols * 3], *src;
332 # define IMAGE_WALK_PREFIX(x) walk_##x
333 # define IMAGE_WALK_INLINE
334 # define IMAGE_WALK_IMAGE img
335 # define IMAGE_WALK_UNROLL 4
336 # define IMAGE_WALK_COL_STEP 4
337 # define IMAGE_WALK_DO_ROW_START do{ src = buf; jpeg_read_scanlines(&i->cinfo, (JSAMPLE **)&src, 1); }while(0)
338 # define IMAGE_WALK_DO_STEP do{ *(u32 *)walk_pos = *(u32 *)src; walk_pos[3] = 255; src += 3; }while(0)
339 # include "images/image-walk.h"
345 ASSERT(i->cinfo.output_scanline == i->cinfo.output_height);
347 /* Destroy libjpeg object */
348 jpeg_finish_decompress(&i->cinfo);
349 jpeg_destroy_decompress(&i->cinfo);
351 /* Finish the image */
352 return image_io_read_data_finish(&rdi, io);
356 libjpeg_write(struct image_io *io)
358 DBG("libjpeg_write()");
359 struct libjpeg_write_internals i;
360 i.fastbuf = io->fastbuf;
362 /* Create libjpeg write structure */
363 DBG("Creating libjpeg write structure");
364 i.cinfo.err = jpeg_std_error(&i.err.pub);
365 i.err.pub.error_exit = libjpeg_write_error_exit;
366 i.err.pub.emit_message = libjpeg_emit_message;
368 if (setjmp(i.err.setjmp_buf))
370 DBG("Libjpeg failed to write the image, longjump saved us");
371 jpeg_destroy_compress(&i.cinfo);
374 jpeg_create_compress(&i.cinfo);
376 /* Initialize destination manager */
377 i.cinfo.dest = &i.dest;
378 i.dest.init_destination = libjpeg_init_destination;
379 i.dest.term_destination = libjpeg_term_destination;
380 i.dest.empty_output_buffer = libjpeg_empty_output_buffer;
382 /* Set output parameters */
383 struct image *img = io->image;
384 i.cinfo.image_width = img->cols;
385 i.cinfo.image_height = img->rows;
386 switch (img->flags & IMAGE_COLOR_SPACE)
388 case COLOR_SPACE_GRAYSCALE:
389 i.cinfo.input_components = 1;
390 i.cinfo.in_color_space = JCS_GRAYSCALE;
392 case COLOR_SPACE_RGB:
393 i.cinfo.input_components = 3;
394 i.cinfo.in_color_space = JCS_RGB;
397 jpeg_destroy_compress(&i.cinfo);
398 image_thread_err(io->thread, IMAGE_ERR_INVALID_PIXEL_FORMAT, "Unsupported pixel format.");
401 jpeg_set_defaults(&i.cinfo);
402 if (io->jpeg_quality)
403 jpeg_set_quality(&i.cinfo, MIN(io->jpeg_quality, 100), 1);
405 /* Compress the image */
406 jpeg_start_compress(&i.cinfo, TRUE);
407 switch (img->pixel_size)
409 /* grayscale or RGB */
413 byte *pixels = img->pixels;
414 for (uns r = img->rows; r--; )
416 jpeg_write_scanlines(&i.cinfo, (JSAMPLE **)&pixels, 1);
417 pixels += img->row_size;
421 /* grayscale with alpha (ignore alpha) */
424 byte buf[img->cols], *dest = buf;
425 # define IMAGE_WALK_PREFIX(x) walk_##x
426 # define IMAGE_WALK_INLINE
427 # define IMAGE_WALK_IMAGE img
428 # define IMAGE_WALK_UNROLL 4
429 # define IMAGE_WALK_COL_STEP 2
430 # define IMAGE_WALK_DO_ROW_END do{ dest = buf; jpeg_write_scanlines(&i.cinfo, (JSAMPLE **)&dest, 1); }while(0)
431 # define IMAGE_WALK_DO_STEP do{ *dest++ = walk_pos[0]; }while(0)
432 # include "images/image-walk.h"
435 /* RGBA (ignore alpha) or aligned RGB */
438 byte buf[img->cols * 3], *dest = buf;
439 # define IMAGE_WALK_PREFIX(x) walk_##x
440 # define IMAGE_WALK_INLINE
441 # define IMAGE_WALK_IMAGE img
442 # define IMAGE_WALK_UNROLL 4
443 # define IMAGE_WALK_COL_STEP 4
444 # define IMAGE_WALK_DO_ROW_END do{ dest = buf; jpeg_write_scanlines(&i.cinfo, (JSAMPLE **)&dest, 1); }while(0)
445 # define IMAGE_WALK_DO_STEP do{ *dest++ = walk_pos[0]; *dest++ = walk_pos[1]; *dest++ = walk_pos[2]; }while(0)
446 # include "images/image-walk.h"
452 ASSERT(i.cinfo.next_scanline == i.cinfo.image_height);
453 jpeg_finish_compress(&i.cinfo);
454 jpeg_destroy_compress(&i.cinfo);