]> git.imager.perl.org - imager.git/blobdiff - jpeg.c
add i_gsamp_bg/i_gsampf_bg functions, sample based versions of
[imager.git] / jpeg.c
diff --git a/jpeg.c b/jpeg.c
index ab32e3df2c674e3cdeeff584d5780c9332cc8689..f886df2561e728956d7c9e91ec48143076f4a143 100644 (file)
--- a/jpeg.c
+++ b/jpeg.c
@@ -383,7 +383,7 @@ typedef void (*transfer_function_t)(i_color *out, JSAMPARRAY in, int width);
 */
 i_img*
 i_readjpeg_wiol(io_glue *data, int length, char** iptc_itext, int *itlength) {
-  i_img *im;
+  i_img * volatile im = NULL;
 #ifdef IMEXIF_ENABLE
   int seen_exif = 0;
 #endif
@@ -395,6 +395,7 @@ i_readjpeg_wiol(io_glue *data, int length, char** iptc_itext, int *itlength) {
   jpeg_saved_marker_ptr markerp;
   transfer_function_t transfer_f;
   int channels;
+  volatile int src_set = 0;
 
   mm_log((1,"i_readjpeg_wiol(data 0x%p, length %d,iptc_itext 0x%p)\n", data, length, iptc_itext));
 
@@ -407,11 +408,15 @@ i_readjpeg_wiol(io_glue *data, int length, char** iptc_itext, int *itlength) {
 
   /* Set error handler */
   if (setjmp(jerr.setjmp_buffer)) {
+    if (src_set)
+      wiol_term_source(&cinfo);
     jpeg_destroy_decompress(&cinfo); 
     *iptc_itext=NULL;
     *itlength=0;
     if (line_buffer)
       myfree(line_buffer);
+    if (im)
+      i_img_destroy(im);
     return NULL;
   }
   
@@ -420,6 +425,7 @@ i_readjpeg_wiol(io_glue *data, int length, char** iptc_itext, int *itlength) {
   jpeg_save_markers(&cinfo, JPEG_APP1, 0xFFFF);
   jpeg_save_markers(&cinfo, JPEG_COM, 0xFFFF);
   jpeg_wiol_src(&cinfo, data, length);
+  src_set = 1;
 
   (void) jpeg_read_header(&cinfo, TRUE);
   (void) jpeg_start_decompress(&cinfo);
@@ -427,11 +433,25 @@ i_readjpeg_wiol(io_glue *data, int length, char** iptc_itext, int *itlength) {
   channels = cinfo.output_components;
   switch (cinfo.out_color_space) {
   case JCS_GRAYSCALE:
+    if (cinfo.output_components != 1) {
+      mm_log((1, "i_readjpeg: grayscale image with %d channels\n", cinfo.output_components));
+      i_push_errorf(0, "grayscale image with invalid components %d", cinfo.output_components);
+      wiol_term_source(&cinfo);
+      jpeg_destroy_decompress(&cinfo);
+      return NULL;
+    }
     transfer_f = transfer_gray;
     break;
   
   case JCS_RGB:
     transfer_f = transfer_rgb;
+    if (cinfo.output_components != 3) {
+      mm_log((1, "i_readjpeg: RGB image with %d channels\n", cinfo.output_components));
+      i_push_errorf(0, "RGB image with invalid components %d", cinfo.output_components);
+      wiol_term_source(&cinfo);
+      jpeg_destroy_decompress(&cinfo);
+      return NULL;
+    }
     break;
 
   case JCS_CMYK:
@@ -489,7 +509,7 @@ i_readjpeg_wiol(io_glue *data, int length, char** iptc_itext, int *itlength) {
   markerp = cinfo.marker_list;
   while (markerp != NULL) {
     if (markerp->marker == JPEG_COM) {
-      i_tags_add(&im->tags, "jpeg_comment", 0, markerp->data,
+      i_tags_add(&im->tags, "jpeg_comment", 0, (const char *)markerp->data,
                 markerp->data_length, 0);
     }
 #ifdef IMEXIF_ENABLE
@@ -552,6 +572,7 @@ i_writejpeg_wiol(i_img *im, io_glue *ig, int qfactor) {
   int got_xres, got_yres, aspect_only, resunit;
   double xres, yres;
   int comment_entry;
+  int want_channels = im->channels;
 
   struct jpeg_compress_struct cinfo;
   struct my_error_mgr jerr;
@@ -559,6 +580,7 @@ i_writejpeg_wiol(i_img *im, io_glue *ig, int qfactor) {
   JSAMPROW row_pointer[1];     /* pointer to JSAMPLE row[s] */
   int row_stride;              /* physical row width in image buffer */
   unsigned char * data = NULL;
+  i_color *line_buf = NULL;
 
   mm_log((1,"i_writejpeg(im %p, ig %p, qfactor %d)\n", im, ig, qfactor));
   
@@ -566,8 +588,7 @@ i_writejpeg_wiol(i_img *im, io_glue *ig, int qfactor) {
   io_glue_commit_types(ig);
 
   if (!(im->channels==1 || im->channels==3)) { 
-    i_push_error(0, "only 1 or 3 channels images can be saved as JPEG");
-    return 0;
+    want_channels = im->channels - 1;
   }
   quality = qfactor;
 
@@ -581,6 +602,8 @@ i_writejpeg_wiol(i_img *im, io_glue *ig, int qfactor) {
     jpeg_destroy_compress(&cinfo);
     if (data)
       myfree(data);
+    if (line_buf)
+      myfree(line_buf);
     return 0;
   }
 
@@ -589,12 +612,12 @@ i_writejpeg_wiol(i_img *im, io_glue *ig, int qfactor) {
   cinfo.image_width  = im -> xsize;    /* image width and height, in pixels */
   cinfo.image_height = im -> ysize;
 
-  if (im->channels==3) {
+  if (want_channels==3) {
     cinfo.input_components = 3;                /* # of color components per pixel */
     cinfo.in_color_space = JCS_RGB;    /* colorspace of input image */
   }
 
-  if (im->channels==1) {
+  if (want_channels==1) {
     cinfo.input_components = 1;                /* # of color components per pixel */
     cinfo.in_color_space = JCS_GRAYSCALE;      /* colorspace of input image */
   }
@@ -630,13 +653,15 @@ i_writejpeg_wiol(i_img *im, io_glue *ig, int qfactor) {
   jpeg_start_compress(&cinfo, TRUE);
 
   if (i_tags_find(&im->tags, "jpeg_comment", 0, &comment_entry)) {
-    jpeg_write_marker(&cinfo, JPEG_COM, im->tags.tags[comment_entry].data,
+    jpeg_write_marker(&cinfo, JPEG_COM, 
+                      (const JOCTET *)im->tags.tags[comment_entry].data,
                      im->tags.tags[comment_entry].size);
   }
 
   row_stride = im->xsize * im->channels;       /* JSAMPLEs per row in image_buffer */
 
-  if (!im->virtual && im->type == i_direct_type && im->bits == i_8_bits) {
+  if (!im->virtual && im->type == i_direct_type && im->bits == i_8_bits
+      && im->channels == want_channels) {
     image_buffer=im->idata;
 
     while (cinfo.next_scanline < cinfo.image_height) {
@@ -649,6 +674,9 @@ i_writejpeg_wiol(i_img *im, io_glue *ig, int qfactor) {
     }
   }
   else {
+    i_color bg;
+
+    i_get_file_background(im, &bg);
     data = mymalloc(im->xsize * im->channels);
     if (data) {
       while (cinfo.next_scanline < cinfo.image_height) {
@@ -656,8 +684,8 @@ i_writejpeg_wiol(i_img *im, io_glue *ig, int qfactor) {
          * Here the array is only one element long, but you could pass
          * more than one scanline at a time if that's more convenient.
          */
-        i_gsamp(im, 0, im->xsize, cinfo.next_scanline, data, 
-                NULL, im->channels);
+        i_gsamp_bg(im, 0, im->xsize, cinfo.next_scanline, data, 
+                  want_channels, &bg);
         row_pointer[0] = data;
         (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
       }