]> git.imager.perl.org - imager.git/blob - jpeg.c
rename APIRef.pm, API.pm to *.pod since they contain no code
[imager.git] / jpeg.c
1 /*
2 =head1 NAME
3
4 jpeg.c - implement saving and loading JPEG images
5
6 =head1 SYNOPSIS
7
8   io_glue *ig;
9   if (!i_writejpeg_wiol(im, ig, quality)) {
10     .. error ..
11   }
12   im = i_readjpeg_wiol(ig, length, iptc_text, itlength);
13
14 =head1 DESCRIPTION
15
16 Reads and writes JPEG images
17
18 =over
19
20 =cut
21 */
22
23 #include <stdio.h>
24 #include <sys/stat.h>
25 #ifndef _MSC_VER
26 #include <unistd.h>
27 #endif
28 #include <setjmp.h>
29
30 #include "iolayer.h"
31 #include "imageri.h"
32 #include "jpeglib.h"
33 #include "jerror.h"
34 #include <errno.h>
35 #ifdef IMEXIF_ENABLE
36 #include "imexif.h"
37 #endif
38
39 #define JPEG_APP13       0xED    /* APP13 marker code */
40 #define JPEG_APP1 (JPEG_APP0 + 1)
41 #define JPGS 16384
42
43 static unsigned char fake_eoi[]={(JOCTET) 0xFF,(JOCTET) JPEG_EOI};
44
45 /* Bad design right here */
46
47 static int tlength=0;
48 static char **iptc_text=NULL;
49
50
51 /* Source and Destination managers */
52
53
54 typedef struct {
55   struct jpeg_source_mgr pub;   /* public fields */
56   io_glue *data;
57   JOCTET *buffer;               /* start of buffer */
58   int length;                   /* Do I need this? */
59   boolean start_of_file;        /* have we gotten any data yet? */
60 } wiol_source_mgr;
61
62 typedef struct {
63   struct jpeg_destination_mgr pub; /* public fields */
64   io_glue *data;
65   JOCTET *buffer;               /* start of buffer */
66   boolean start_of_file;        /* have we gotten any data yet? */
67 } wiol_destination_mgr;
68
69 typedef wiol_source_mgr *wiol_src_ptr;
70 typedef wiol_destination_mgr *wiol_dest_ptr;
71
72
73 /*
74  * Methods for io manager objects 
75  * 
76  * Methods for source managers: 
77  *
78  * init_source         (j_decompress_ptr cinfo);
79  * skip_input_data     (j_decompress_ptr cinfo, long num_bytes);
80  * fill_input_buffer   (j_decompress_ptr cinfo);
81  * term_source         (j_decompress_ptr cinfo);
82  */
83
84
85
86 static void
87 wiol_init_source (j_decompress_ptr cinfo) {
88   wiol_src_ptr src = (wiol_src_ptr) cinfo->src;
89   
90   /* We reset the empty-input-file flag for each image, but we don't clear
91    * the input buffer.   This is correct behavior for reading a series of
92    * images from one source.
93    */
94   src->start_of_file = TRUE;
95 }
96
97
98
99 static boolean
100 wiol_fill_input_buffer(j_decompress_ptr cinfo) {
101   wiol_src_ptr src = (wiol_src_ptr) cinfo->src;
102   ssize_t nbytes; /* We assume that reads are "small" */
103   
104   mm_log((1,"wiol_fill_input_buffer(cinfo 0x%p)\n", cinfo));
105   
106   nbytes = src->data->readcb(src->data, src->buffer, JPGS);
107   
108   if (nbytes <= 0) { /* Insert a fake EOI marker */
109     src->pub.next_input_byte = fake_eoi;
110     src->pub.bytes_in_buffer = 2;
111   } else {
112     src->pub.next_input_byte = src->buffer;
113     src->pub.bytes_in_buffer = nbytes;
114   }
115   src->start_of_file = FALSE;
116   return TRUE;
117 }
118
119
120 static void
121 wiol_skip_input_data (j_decompress_ptr cinfo, long num_bytes) {
122   wiol_src_ptr src = (wiol_src_ptr) cinfo->src;
123   
124   /* Just a dumb implementation for now.  Could use fseek() except
125    * it doesn't work on pipes.  Not clear that being smart is worth
126    * any trouble anyway --- large skips are infrequent.
127    */
128   
129   if (num_bytes > 0) {
130     while (num_bytes > (long) src->pub.bytes_in_buffer) {
131       num_bytes -= (long) src->pub.bytes_in_buffer;
132       (void) wiol_fill_input_buffer(cinfo);
133       /* note we assume that fill_input_buffer will never return FALSE,
134        * so suspension need not be handled.
135        */
136     }
137     src->pub.next_input_byte += (size_t) num_bytes;
138     src->pub.bytes_in_buffer -= (size_t) num_bytes;
139   }
140 }
141
142 static void
143 wiol_term_source (j_decompress_ptr cinfo) {
144   /* no work necessary here */ 
145   wiol_src_ptr src;
146   if (cinfo->src != NULL) {
147     src = (wiol_src_ptr) cinfo->src;
148     myfree(src->buffer);
149   }
150 }
151
152
153 /* Source manager Constructor */
154
155 static void
156 jpeg_wiol_src(j_decompress_ptr cinfo, io_glue *ig, int length) {
157   wiol_src_ptr src;
158   
159   if (cinfo->src == NULL) {     /* first time for this JPEG object? */
160     cinfo->src = (struct jpeg_source_mgr *) (*cinfo->mem->alloc_small) 
161       ((j_common_ptr) cinfo, JPOOL_PERMANENT,sizeof(wiol_source_mgr));
162     src = (wiol_src_ptr) cinfo->src;
163   }
164
165   /* put the request method call in here later */
166   io_glue_commit_types(ig);
167   
168   src         = (wiol_src_ptr) cinfo->src;
169   src->data   = ig;
170   src->buffer = mymalloc( JPGS );
171   src->length = length;
172
173   src->pub.init_source       = wiol_init_source;
174   src->pub.fill_input_buffer = wiol_fill_input_buffer;
175   src->pub.skip_input_data   = wiol_skip_input_data;
176   src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
177   src->pub.term_source       = wiol_term_source;
178   src->pub.bytes_in_buffer   = 0; /* forces fill_input_buffer on first read */
179   src->pub.next_input_byte   = NULL; /* until buffer loaded */
180 }
181
182
183
184
185 /*
186  * Methods for destination managers:
187  *
188  * init_destination    (j_compress_ptr cinfo);
189  * empty_output_buffer (j_compress_ptr cinfo);
190  * term_destination    (j_compress_ptr cinfo);
191  *
192  */
193
194 static void
195 wiol_init_destination (j_compress_ptr cinfo) {
196   wiol_dest_ptr dest = (wiol_dest_ptr) cinfo->dest;
197   
198   /* We reset the empty-input-file flag for each image, but we don't clear
199    * the input buffer.   This is correct behavior for reading a series of
200    * images from one source.
201    */
202   dest->start_of_file = TRUE;
203 }
204
205 static boolean
206 wiol_empty_output_buffer(j_compress_ptr cinfo) {
207   wiol_dest_ptr dest = (wiol_dest_ptr) cinfo->dest;
208   ssize_t rc;
209   /*
210     Previously this code was checking free_in_buffer to see how much 
211     needed to be written.  This does not follow the documentation:
212
213                        "In typical applications, it should write out the
214         *entire* buffer (use the saved start address and buffer length;
215         ignore the current state of next_output_byte and free_in_buffer)."
216
217   ssize_t nbytes     = JPGS - dest->pub.free_in_buffer;
218   */
219
220   mm_log((1,"wiol_empty_output_buffer(cinfo 0x%p)\n"));
221   rc = dest->data->writecb(dest->data, dest->buffer, JPGS);
222
223   if (rc != JPGS) { /* XXX: Should raise some jpeg error */
224     myfree(dest->buffer);
225     mm_log((1, "wiol_empty_output_buffer: Error: nbytes = %d != rc = %d\n", JPGS, rc));
226     ERREXIT(cinfo, JERR_FILE_WRITE);
227   }
228   dest->pub.free_in_buffer = JPGS;
229   dest->pub.next_output_byte = dest->buffer;
230   return TRUE;
231 }
232
233 static void
234 wiol_term_destination (j_compress_ptr cinfo) {
235   wiol_dest_ptr dest = (wiol_dest_ptr) cinfo->dest;
236   size_t nbytes = JPGS - dest->pub.free_in_buffer;
237   /* yes, this needs to flush the buffer */
238   /* needs error handling */
239
240   if (dest->data->writecb(dest->data, dest->buffer, nbytes) != nbytes) {
241     myfree(dest->buffer);
242     ERREXIT(cinfo, JERR_FILE_WRITE);
243   }
244   
245   if (dest != NULL) myfree(dest->buffer);
246 }
247
248
249 /* Destination manager Constructor */
250
251 static void
252 jpeg_wiol_dest(j_compress_ptr cinfo, io_glue *ig) {
253   wiol_dest_ptr dest;
254   
255   if (cinfo->dest == NULL) {    /* first time for this JPEG object? */
256     cinfo->dest = 
257       (struct jpeg_destination_mgr *)
258       (*cinfo->mem->alloc_small) 
259       ((j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof(wiol_destination_mgr));
260   }
261   
262   dest = (wiol_dest_ptr) cinfo->dest;
263   dest->data                    = ig;
264   dest->buffer                  = mymalloc( JPGS );
265
266   dest->pub.init_destination    = wiol_init_destination;
267   dest->pub.empty_output_buffer = wiol_empty_output_buffer;
268   dest->pub.term_destination    = wiol_term_destination;
269   dest->pub.free_in_buffer      = JPGS;
270   dest->pub.next_output_byte    = dest->buffer;
271 }
272
273 LOCAL(unsigned int)
274 jpeg_getc (j_decompress_ptr cinfo)
275 /* Read next byte */
276 {
277   struct jpeg_source_mgr * datasrc = cinfo->src;
278
279   if (datasrc->bytes_in_buffer == 0) {
280     if (! (*datasrc->fill_input_buffer) (cinfo))
281       { fprintf(stderr,"Jpeglib: cant suspend.\n"); exit(3); }
282       /*      ERREXIT(cinfo, JERR_CANT_SUSPEND);*/
283   }
284   datasrc->bytes_in_buffer--;
285   return GETJOCTET(*datasrc->next_input_byte++);
286 }
287
288 METHODDEF(boolean)
289 APP13_handler (j_decompress_ptr cinfo) {
290   INT32 length;
291   unsigned int cnt=0;
292   
293   length = jpeg_getc(cinfo) << 8;
294   length += jpeg_getc(cinfo);
295   length -= 2;  /* discount the length word itself */
296   
297   tlength=length;
298
299   if ( ((*iptc_text)=mymalloc(length)) == NULL ) return FALSE;
300   while (--length >= 0) (*iptc_text)[cnt++] = jpeg_getc(cinfo); 
301  
302   return TRUE;
303 }
304
305 METHODDEF(void)
306 my_output_message (j_common_ptr cinfo) {
307   char buffer[JMSG_LENGTH_MAX];
308
309   /* Create the message */
310   (*cinfo->err->format_message) (cinfo, buffer);
311
312   i_push_error(0, buffer);
313
314   /* Send it to stderr, adding a newline */
315   mm_log((1, "%s\n", buffer));
316 }
317
318 struct my_error_mgr {
319   struct jpeg_error_mgr pub;    /* "public" fields */
320   jmp_buf setjmp_buffer;        /* for return to caller */
321 };
322
323 typedef struct my_error_mgr * my_error_ptr;
324
325 /* Here's the routine that will replace the standard error_exit method */
326
327 METHODDEF(void)
328 my_error_exit (j_common_ptr cinfo) {
329   /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
330   my_error_ptr myerr = (my_error_ptr) cinfo->err;
331   
332   /* Always display the message. */
333   /* We could postpone this until after returning, if we chose. */
334   (*cinfo->err->output_message) (cinfo);
335
336   /* Return control to the setjmp point */
337   longjmp(myerr->setjmp_buffer, 1);
338 }
339
340 /*
341 =item i_readjpeg_wiol(data, length, iptc_itext, itlength)
342
343 =cut
344 */
345 i_img*
346 i_readjpeg_wiol(io_glue *data, int length, char** iptc_itext, int *itlength) {
347   i_img *im;
348 #ifdef IMEXIF_ENABLE
349   int seen_exif = 0;
350 #endif
351
352   struct jpeg_decompress_struct cinfo;
353   struct my_error_mgr jerr;
354   JSAMPARRAY buffer;            /* Output row buffer */
355   int row_stride;               /* physical row width in output buffer */
356   jpeg_saved_marker_ptr markerp;
357
358   mm_log((1,"i_readjpeg_wiol(data 0x%p, length %d,iptc_itext 0x%p)\n", data, length, iptc_itext));
359
360   i_clear_error();
361
362   iptc_text = iptc_itext;
363   cinfo.err = jpeg_std_error(&jerr.pub);
364   jerr.pub.error_exit     = my_error_exit;
365   jerr.pub.output_message = my_output_message;
366
367   /* Set error handler */
368   if (setjmp(jerr.setjmp_buffer)) {
369     jpeg_destroy_decompress(&cinfo); 
370     *iptc_itext=NULL;
371     *itlength=0;
372     return NULL;
373   }
374   
375   jpeg_create_decompress(&cinfo);
376   jpeg_set_marker_processor(&cinfo, JPEG_APP13, APP13_handler);
377   jpeg_save_markers(&cinfo, JPEG_APP1, 0xFFFF);
378   jpeg_save_markers(&cinfo, JPEG_COM, 0xFFFF);
379   jpeg_wiol_src(&cinfo, data, length);
380
381   (void) jpeg_read_header(&cinfo, TRUE);
382   (void) jpeg_start_decompress(&cinfo);
383   if (!i_int_check_image_file_limits(cinfo.output_width, cinfo.output_height,
384                                      cinfo.output_components, sizeof(i_sample_t))) {
385     mm_log((1, "i_readjpeg: image size exceeds limits\n"));
386     wiol_term_source(&cinfo);
387     jpeg_destroy_decompress(&cinfo);
388     return NULL;
389   }
390   im=i_img_empty_ch(NULL,cinfo.output_width,cinfo.output_height,cinfo.output_components);
391   if (!im) {
392     wiol_term_source(&cinfo);
393     jpeg_destroy_decompress(&cinfo);
394     return NULL;
395   }
396   row_stride = cinfo.output_width * cinfo.output_components;
397   buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
398   while (cinfo.output_scanline < cinfo.output_height) {
399     (void) jpeg_read_scanlines(&cinfo, buffer, 1);
400     memcpy(im->idata+im->channels*im->xsize*(cinfo.output_scanline-1),buffer[0],row_stride);
401   }
402
403   /* check for APP1 marker and save */
404   markerp = cinfo.marker_list;
405   while (markerp != NULL) {
406     if (markerp->marker == JPEG_COM) {
407       i_tags_add(&im->tags, "jpeg_comment", 0, markerp->data,
408                  markerp->data_length, 0);
409     }
410 #ifdef IMEXIF_ENABLE
411     else if (markerp->marker == JPEG_APP1 && !seen_exif) {
412       seen_exif = i_int_decode_exif(im, markerp->data, markerp->data_length);
413     }
414 #endif      
415
416     markerp = markerp->next;
417   }
418
419   if (cinfo.saw_JFIF_marker) {
420     double xres = cinfo.X_density;
421     double yres = cinfo.Y_density;
422     
423     i_tags_addn(&im->tags, "jpeg_density_unit", 0, cinfo.density_unit);
424     switch (cinfo.density_unit) {
425     case 0: /* values are just the aspect ratio */
426       i_tags_addn(&im->tags, "i_aspect_only", 0, 1);
427       i_tags_add(&im->tags, "jpeg_density_unit_name", 0, "none", -1, 0);
428       break;
429
430     case 1: /* per inch */
431       i_tags_add(&im->tags, "jpeg_density_unit_name", 0, "inch", -1, 0);
432       break;
433
434     case 2: /* per cm */
435       i_tags_add(&im->tags, "jpeg_density_unit_name", 0, "centimeter", -1, 0);
436       xres *= 2.54;
437       yres *= 2.54;
438       break;
439     }
440     i_tags_set_float2(&im->tags, "i_xres", 0, xres, 6);
441     i_tags_set_float2(&im->tags, "i_yres", 0, yres, 6);
442   }
443
444   (void) jpeg_finish_decompress(&cinfo);
445   jpeg_destroy_decompress(&cinfo);
446   *itlength=tlength;
447
448   i_tags_add(&im->tags, "i_format", 0, "jpeg", 4, 0);
449
450   mm_log((1,"i_readjpeg_wiol -> (0x%x)\n",im));
451   return im;
452 }
453
454 /*
455 =item i_writejpeg_wiol(im, ig, qfactor)
456
457 =cut
458 */
459
460 undef_int
461 i_writejpeg_wiol(i_img *im, io_glue *ig, int qfactor) {
462   JSAMPLE *image_buffer;
463   int quality;
464   int got_xres, got_yres, aspect_only, resunit;
465   double xres, yres;
466   int comment_entry;
467
468   struct jpeg_compress_struct cinfo;
469   struct my_error_mgr jerr;
470
471   JSAMPROW row_pointer[1];      /* pointer to JSAMPLE row[s] */
472   int row_stride;               /* physical row width in image buffer */
473   unsigned char * data = NULL;
474
475   mm_log((1,"i_writejpeg(im %p, ig %p, qfactor %d)\n", im, ig, qfactor));
476   
477   i_clear_error();
478   io_glue_commit_types(ig);
479
480   if (!(im->channels==1 || im->channels==3)) { 
481     i_push_error(0, "only 1 or 3 channels images can be saved as JPEG");
482     return 0;
483   }
484   quality = qfactor;
485
486   cinfo.err = jpeg_std_error(&jerr.pub);
487   jerr.pub.error_exit = my_error_exit;
488   jerr.pub.output_message = my_output_message;
489   
490   jpeg_create_compress(&cinfo);
491
492   if (setjmp(jerr.setjmp_buffer)) {
493     jpeg_destroy_compress(&cinfo);
494     if (data)
495       myfree(data);
496     return 0;
497   }
498
499   jpeg_wiol_dest(&cinfo, ig);
500
501   cinfo.image_width  = im -> xsize;     /* image width and height, in pixels */
502   cinfo.image_height = im -> ysize;
503
504   if (im->channels==3) {
505     cinfo.input_components = 3;         /* # of color components per pixel */
506     cinfo.in_color_space = JCS_RGB;     /* colorspace of input image */
507   }
508
509   if (im->channels==1) {
510     cinfo.input_components = 1;         /* # of color components per pixel */
511     cinfo.in_color_space = JCS_GRAYSCALE;       /* colorspace of input image */
512   }
513
514   jpeg_set_defaults(&cinfo);
515   jpeg_set_quality(&cinfo, quality, TRUE);  /* limit to baseline-JPEG values */
516
517   got_xres = i_tags_get_float(&im->tags, "i_xres", 0, &xres);
518   got_yres = i_tags_get_float(&im->tags, "i_yres", 0, &yres);
519   if (!i_tags_get_int(&im->tags, "i_aspect_only", 0,&aspect_only))
520     aspect_only = 0;
521   if (!i_tags_get_int(&im->tags, "jpeg_density_unit", 0, &resunit))
522     resunit = 1; /* per inch */
523   if (resunit < 0 || resunit > 2) /* default to inch if invalid */
524     resunit = 1;
525   if (got_xres || got_yres) {
526     if (!got_xres)
527       xres = yres;
528     else if (!got_yres)
529       yres = xres;
530     if (aspect_only)
531       resunit = 0; /* standard tags override format tags */
532     if (resunit == 2) {
533       /* convert to per cm */
534       xres /= 2.54;
535       yres /= 2.54;
536     }
537     cinfo.density_unit = resunit;
538     cinfo.X_density = (int)(xres + 0.5);
539     cinfo.Y_density = (int)(yres + 0.5);
540   }
541
542   jpeg_start_compress(&cinfo, TRUE);
543
544   if (i_tags_find(&im->tags, "jpeg_comment", 0, &comment_entry)) {
545     jpeg_write_marker(&cinfo, JPEG_COM, im->tags.tags[comment_entry].data,
546                       im->tags.tags[comment_entry].size);
547   }
548
549   row_stride = im->xsize * im->channels;        /* JSAMPLEs per row in image_buffer */
550
551   if (!im->virtual && im->type == i_direct_type && im->bits == i_8_bits) {
552     image_buffer=im->idata;
553
554     while (cinfo.next_scanline < cinfo.image_height) {
555       /* jpeg_write_scanlines expects an array of pointers to scanlines.
556        * Here the array is only one element long, but you could pass
557        * more than one scanline at a time if that's more convenient.
558        */
559       row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride];
560       (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
561     }
562   }
563   else {
564     data = mymalloc(im->xsize * im->channels);
565     if (data) {
566       while (cinfo.next_scanline < cinfo.image_height) {
567         /* jpeg_write_scanlines expects an array of pointers to scanlines.
568          * Here the array is only one element long, but you could pass
569          * more than one scanline at a time if that's more convenient.
570          */
571         i_gsamp(im, 0, im->xsize, cinfo.next_scanline, data, 
572                 NULL, im->channels);
573         row_pointer[0] = data;
574         (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
575       }
576     }
577     else {
578       jpeg_destroy_compress(&cinfo);
579       i_push_error(0, "out of memory");
580       return 0; /* out of memory? */
581     }
582   }
583
584   /* Step 6: Finish compression */
585
586   jpeg_finish_compress(&cinfo);
587
588   jpeg_destroy_compress(&cinfo);
589
590   ig->closecb(ig);
591
592   return(1);
593 }
594
595 /*
596 =back
597
598 =head1 AUTHOR
599
600 Arnar M. Hrafnkelsson, addi@umich.edu
601
602 =head1 SEE ALSO
603
604 Imager(3)
605
606 =cut
607 */