12 #define JPEG_APP13 0xED /* APP13 marker code */
15 unsigned char fake_eoi[]={(JOCTET) 0xFF,(JOCTET) JPEG_EOI};
17 /* Bad design right here */
20 static char **iptc_text=NULL;
23 /* Source and Destination managers */
27 struct jpeg_source_mgr pub; /* public fields */
29 JOCTET *buffer; /* start of buffer */
30 int length; /* Do I need this? */
31 boolean start_of_file; /* have we gotten any data yet? */
35 struct jpeg_destination_mgr pub; /* public fields */
37 JOCTET *buffer; /* start of buffer */
38 boolean start_of_file; /* have we gotten any data yet? */
39 } wiol_destination_mgr;
41 typedef wiol_source_mgr *wiol_src_ptr;
42 typedef wiol_destination_mgr *wiol_dest_ptr;
46 * Methods for io manager objects
48 * Methods for source managers:
50 * init_source (j_decompress_ptr cinfo);
51 * skip_input_data (j_decompress_ptr cinfo, long num_bytes);
52 * fill_input_buffer (j_decompress_ptr cinfo);
53 * term_source (j_decompress_ptr cinfo);
59 wiol_init_source (j_decompress_ptr cinfo) {
60 wiol_src_ptr src = (wiol_src_ptr) cinfo->src;
62 /* We reset the empty-input-file flag for each image, but we don't clear
63 * the input buffer. This is correct behavior for reading a series of
64 * images from one source.
66 src->start_of_file = TRUE;
72 wiol_fill_input_buffer(j_decompress_ptr cinfo) {
73 wiol_src_ptr src = (wiol_src_ptr) cinfo->src;
74 ssize_t nbytes; /* We assume that reads are "small" */
76 mm_log((1,"wiol_fill_input_buffer(cinfo 0x%p)\n"));
78 nbytes = src->data->readcb(src->data, src->buffer, JPGS);
80 if (nbytes <= 0) { /* Insert a fake EOI marker */
81 src->pub.next_input_byte = fake_eoi;
82 src->pub.bytes_in_buffer = 2;
84 src->pub.next_input_byte = src->buffer;
85 src->pub.bytes_in_buffer = nbytes;
87 src->start_of_file = FALSE;
93 wiol_skip_input_data (j_decompress_ptr cinfo, long num_bytes) {
94 wiol_src_ptr src = (wiol_src_ptr) cinfo->src;
96 /* Just a dumb implementation for now. Could use fseek() except
97 * it doesn't work on pipes. Not clear that being smart is worth
98 * any trouble anyway --- large skips are infrequent.
102 while (num_bytes > (long) src->pub.bytes_in_buffer) {
103 num_bytes -= (long) src->pub.bytes_in_buffer;
104 (void) wiol_fill_input_buffer(cinfo);
105 /* note we assume that fill_input_buffer will never return FALSE,
106 * so suspension need not be handled.
109 src->pub.next_input_byte += (size_t) num_bytes;
110 src->pub.bytes_in_buffer -= (size_t) num_bytes;
115 wiol_term_source (j_decompress_ptr cinfo) {
116 /* no work necessary here */
118 if (cinfo->src != NULL) {
119 src = (wiol_src_ptr) cinfo->src;
125 /* Source manager Constructor */
128 jpeg_wiol_src(j_decompress_ptr cinfo, io_glue *ig, int length) {
131 if (cinfo->src == NULL) { /* first time for this JPEG object? */
132 cinfo->src = (struct jpeg_source_mgr *) (*cinfo->mem->alloc_small)
133 ((j_common_ptr) cinfo, JPOOL_PERMANENT,sizeof(wiol_source_mgr));
134 src = (wiol_src_ptr) cinfo->src;
137 /* put the request method call in here later */
138 io_glue_commit_types(ig);
140 src = (wiol_src_ptr) cinfo->src;
142 src->buffer = mymalloc( JPGS );
143 src->length = length;
145 src->pub.init_source = wiol_init_source;
146 src->pub.fill_input_buffer = wiol_fill_input_buffer;
147 src->pub.skip_input_data = wiol_skip_input_data;
148 src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
149 src->pub.term_source = wiol_term_source;
150 src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
151 src->pub.next_input_byte = NULL; /* until buffer loaded */
158 * Methods for destination managers:
160 * init_destination (j_compress_ptr cinfo);
161 * empty_output_buffer (j_compress_ptr cinfo);
162 * term_destination (j_compress_ptr cinfo);
167 wiol_init_destination (j_compress_ptr cinfo) {
168 wiol_dest_ptr dest = (wiol_dest_ptr) cinfo->dest;
170 /* We reset the empty-input-file flag for each image, but we don't clear
171 * the input buffer. This is correct behavior for reading a series of
172 * images from one source.
174 dest->start_of_file = TRUE;
178 wiol_empty_output_buffer(j_compress_ptr cinfo) {
179 wiol_dest_ptr dest = (wiol_dest_ptr) cinfo->dest;
180 ssize_t nbytes = JPGS - dest->pub.free_in_buffer;
183 mm_log((1,"wiol_emtpy_output_buffer(cinfo 0x%p)\n"));
184 rc = dest->data->writecb(dest->data, dest->buffer, nbytes);
186 if (rc != nbytes) { /* XXX: Should raise some jpeg error */
187 mm_log((1, "wiol_empty_output_buffer: Error: nbytes = %d != rc = %d\n", nbytes, rc));
189 dest->pub.free_in_buffer = JPGS;
190 dest->pub.next_output_byte = dest->buffer;
195 wiol_term_destination (j_compress_ptr cinfo) {
196 wiol_dest_ptr dest = (wiol_dest_ptr) cinfo->dest;
197 mm_log((1, "wiol_term_destination(cinfo %p)\n", cinfo));
198 mm_log((1, "wiol_term_destination: dest %p\n", cinfo->dest));
199 if (dest != NULL) myfree(dest->buffer);
203 /* Destination manager Constructor */
206 jpeg_wiol_dest(j_compress_ptr cinfo, io_glue *ig) {
209 if (cinfo->dest == NULL) { /* first time for this JPEG object? */
211 (struct jpeg_destination_mgr *)
212 (*cinfo->mem->alloc_small)
213 ((j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof(wiol_destination_mgr));
216 dest = (wiol_dest_ptr) cinfo->dest;
218 dest->buffer = mymalloc( JPGS );
220 dest->pub.init_destination = wiol_init_destination;
221 dest->pub.empty_output_buffer = wiol_empty_output_buffer;
222 dest->pub.term_destination = wiol_term_destination;
223 dest->pub.free_in_buffer = JPGS;
224 dest->pub.next_output_byte = dest->buffer;
232 jpeg_getc (j_decompress_ptr cinfo)
235 struct jpeg_source_mgr * datasrc = cinfo->src;
237 if (datasrc->bytes_in_buffer == 0) {
238 if (! (*datasrc->fill_input_buffer) (cinfo))
239 { fprintf(stderr,"Jpeglib: cant suspend.\n"); exit(3); }
240 /* ERREXIT(cinfo, JERR_CANT_SUSPEND);*/
242 datasrc->bytes_in_buffer--;
243 return GETJOCTET(*datasrc->next_input_byte++);
247 APP13_handler (j_decompress_ptr cinfo) {
251 length = jpeg_getc(cinfo) << 8;
252 length += jpeg_getc(cinfo);
253 length -= 2; /* discount the length word itself */
257 if ( ((*iptc_text)=mymalloc(length)) == NULL ) return FALSE;
258 while (--length >= 0) (*iptc_text)[cnt++] = jpeg_getc(cinfo);
264 my_output_message (j_common_ptr cinfo) {
265 char buffer[JMSG_LENGTH_MAX];
267 /* Create the message */
268 (*cinfo->err->format_message) (cinfo, buffer);
270 /* Send it to stderr, adding a newline */
271 mm_log((1, "%s\n", buffer));
274 struct my_error_mgr {
275 struct jpeg_error_mgr pub; /* "public" fields */
276 jmp_buf setjmp_buffer; /* for return to caller */
279 typedef struct my_error_mgr * my_error_ptr;
281 /* Here's the routine that will replace the standard error_exit method */
284 my_error_exit (j_common_ptr cinfo) {
285 /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
286 my_error_ptr myerr = (my_error_ptr) cinfo->err;
288 /* Always display the message. */
289 /* We could postpone this until after returning, if we chose. */
290 (*cinfo->err->output_message) (cinfo);
292 /* Return control to the setjmp point */
293 longjmp(myerr->setjmp_buffer, 1);
301 i_readjpeg_wiol(io_glue *data, int length, char** iptc_itext, int *itlength) {
304 struct jpeg_decompress_struct cinfo;
305 struct my_error_mgr jerr;
306 JSAMPARRAY buffer; /* Output row buffer */
307 int row_stride; /* physical row width in output buffer */
309 mm_log((1,"i_readjpeg_wiol(data 0x%p, length %d,iptc_itext 0x%p)\n", data, iptc_itext));
311 iptc_text = iptc_itext;
312 cinfo.err = jpeg_std_error(&jerr.pub);
313 jerr.pub.error_exit = my_error_exit;
314 jerr.pub.output_message = my_output_message;
316 /* Set error handler */
317 if (setjmp(jerr.setjmp_buffer)) {
318 jpeg_destroy_decompress(&cinfo);
324 jpeg_create_decompress(&cinfo);
325 jpeg_set_marker_processor(&cinfo, JPEG_APP13, APP13_handler);
326 jpeg_wiol_src(&cinfo, data, length);
328 (void) jpeg_read_header(&cinfo, TRUE);
329 (void) jpeg_start_decompress(&cinfo);
330 im=i_img_empty_ch(NULL,cinfo.output_width,cinfo.output_height,cinfo.output_components);
331 row_stride = cinfo.output_width * cinfo.output_components;
332 buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
333 while (cinfo.output_scanline < cinfo.output_height) {
334 (void) jpeg_read_scanlines(&cinfo, buffer, 1);
335 memcpy(im->data+im->channels*im->xsize*(cinfo.output_scanline-1),buffer[0],row_stride);
337 (void) jpeg_finish_decompress(&cinfo);
338 jpeg_destroy_decompress(&cinfo);
340 mm_log((1,"i_readjpeg_wiol -> (0x%x)\n",im));
348 i_writejpeg_wiol(i_img *im, io_glue *ig, int qfactor) {
350 JSAMPLE *image_buffer;
353 struct jpeg_compress_struct cinfo;
354 struct jpeg_error_mgr jerr;
356 JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */
357 int row_stride; /* physical row width in image buffer */
359 mm_log((1,"i_writejpeg(im %p, ig %p, qfactor %d)\n", im, ig, qfactor));
361 if (!(im->channels==1 || im->channels==3)) { fprintf(stderr,"Unable to write JPEG, improper colorspace.\n"); exit(3); }
364 image_buffer = im->data;
366 cinfo.err = jpeg_std_error(&jerr);
368 jpeg_create_compress(&cinfo);
370 io_glue_commit_types(ig);
371 jpeg_wiol_dest(&cinfo, ig);
373 cinfo.image_width = im -> xsize; /* image width and height, in pixels */
374 cinfo.image_height = im -> ysize;
376 if (im->channels==3) {
377 cinfo.input_components = 3; /* # of color components per pixel */
378 cinfo.in_color_space = JCS_RGB; /* colorspace of input image */
381 if (im->channels==1) {
382 cinfo.input_components = 1; /* # of color components per pixel */
383 cinfo.in_color_space = JCS_GRAYSCALE; /* colorspace of input image */
386 jpeg_set_defaults(&cinfo);
387 jpeg_set_quality(&cinfo, quality, TRUE); /* limit to baseline-JPEG values */
389 jpeg_start_compress(&cinfo, TRUE);
391 row_stride = im->xsize * im->channels; /* JSAMPLEs per row in image_buffer */
393 while (cinfo.next_scanline < cinfo.image_height) {
394 row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride];
395 (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
398 /* Step 6: Finish compression */
400 jpeg_finish_compress(&cinfo);
402 jpeg_destroy_compress(&cinfo);