]> git.imager.perl.org - imager.git/blobdiff - jpeg.c
hide or rename any symbols that are likely to conflict with other
[imager.git] / jpeg.c
diff --git a/jpeg.c b/jpeg.c
index 6aba12524aa6f2febc568623a4716c1437423906..6aa9eb0d12665683769f2010dcb3a0871511f490 100644 (file)
--- a/jpeg.c
+++ b/jpeg.c
@@ -1,3 +1,25 @@
+/*
+=head1 NAME
+
+jpeg.c - implement saving and loading JPEG images
+
+=head1 SYNOPSIS
+
+  io_glue *ig;
+  if (!i_writejpeg_wiol(im, ig, quality)) {
+    .. error ..
+  }
+  im = i_readjpeg_wiol(ig, length, iptc_text, itlength);
+
+=head1 DESCRIPTION
+
+Reads and writes JPEG images
+
+=over
+
+=cut
+*/
+
 #include <stdio.h>
 #include <sys/stat.h>
 #ifndef _MSC_VER
 #include "iolayer.h"
 #include "image.h"
 #include "jpeglib.h"
+#include "jerror.h"
+#include <errno.h>
 
 #define JPEG_APP13       0xED    /* APP13 marker code */
-#define JPGS 1024
+#define JPGS 16384
 
-unsigned char fake_eoi[]={(JOCTET) 0xFF,(JOCTET) JPEG_EOI};
+static unsigned char fake_eoi[]={(JOCTET) 0xFF,(JOCTET) JPEG_EOI};
 
 /* Bad design right here */
 
@@ -177,14 +201,25 @@ wiol_init_destination (j_compress_ptr cinfo) {
 static boolean
 wiol_empty_output_buffer(j_compress_ptr cinfo) {
   wiol_dest_ptr dest = (wiol_dest_ptr) cinfo->dest;
-  ssize_t nbytes     = JPGS - dest->pub.free_in_buffer;
   ssize_t rc;
+  /*
+    Previously this code was checking free_in_buffer to see how much 
+    needed to be written.  This does not follow the documentation:
 
-  mm_log((1,"wiol_emtpy_output_buffer(cinfo 0x%p)\n"));
-  rc = dest->data->writecb(dest->data, dest->buffer, nbytes);
-  
-  if (rc != nbytes) { /* XXX: Should raise some jpeg error */
-    mm_log((1, "wiol_empty_output_buffer: Error: nbytes = %d != rc = %d\n", nbytes, rc));
+                       "In typical applications, it should write out the
+        *entire* buffer (use the saved start address and buffer length;
+        ignore the current state of next_output_byte and free_in_buffer)."
+
+  ssize_t nbytes     = JPGS - dest->pub.free_in_buffer;
+  */
+
+  mm_log((1,"wiol_empty_output_buffer(cinfo 0x%p)\n"));
+  rc = dest->data->writecb(dest->data, dest->buffer, JPGS);
+
+  if (rc != JPGS) { /* XXX: Should raise some jpeg error */
+    myfree(dest->buffer);
+    mm_log((1, "wiol_empty_output_buffer: Error: nbytes = %d != rc = %d\n", JPGS, rc));
+    ERREXIT(cinfo, JERR_FILE_WRITE);
   }
   dest->pub.free_in_buffer = JPGS;
   dest->pub.next_output_byte = dest->buffer;
@@ -194,8 +229,15 @@ wiol_empty_output_buffer(j_compress_ptr cinfo) {
 static void
 wiol_term_destination (j_compress_ptr cinfo) {
   wiol_dest_ptr dest = (wiol_dest_ptr) cinfo->dest;
-  mm_log((1, "wiol_term_destination(cinfo %p)\n", cinfo));
-  mm_log((1, "wiol_term_destination: dest %p\n", cinfo->dest));
+  size_t nbytes = JPGS - dest->pub.free_in_buffer;
+  /* yes, this needs to flush the buffer */
+  /* needs error handling */
+
+  if (dest->data->writecb(dest->data, dest->buffer, nbytes) != nbytes) {
+    myfree(dest->buffer);
+    ERREXIT(cinfo, JERR_FILE_WRITE);
+  }
+  
   if (dest != NULL) myfree(dest->buffer);
 }
 
@@ -224,10 +266,6 @@ jpeg_wiol_dest(j_compress_ptr cinfo, io_glue *ig) {
   dest->pub.next_output_byte    = dest->buffer;
 }
 
-
-
-
-
 LOCAL(unsigned int)
 jpeg_getc (j_decompress_ptr cinfo)
 /* Read next byte */
@@ -267,6 +305,8 @@ my_output_message (j_common_ptr cinfo) {
   /* Create the message */
   (*cinfo->err->format_message) (cinfo, buffer);
 
+  i_push_error(0, buffer);
+
   /* Send it to stderr, adding a newline */
   mm_log((1, "%s\n", buffer));
 }
@@ -288,15 +328,16 @@ my_error_exit (j_common_ptr cinfo) {
   /* Always display the message. */
   /* We could postpone this until after returning, if we chose. */
   (*cinfo->err->output_message) (cinfo);
-  
+
   /* Return control to the setjmp point */
   longjmp(myerr->setjmp_buffer, 1);
 }
 
+/*
+=item i_readjpeg_wiol(data, length, iptc_itext, itlength)
 
-
-
-
+=cut
+*/
 i_img*
 i_readjpeg_wiol(io_glue *data, int length, char** iptc_itext, int *itlength) {
   i_img *im;
@@ -308,6 +349,8 @@ i_readjpeg_wiol(io_glue *data, int length, char** iptc_itext, int *itlength) {
 
   mm_log((1,"i_readjpeg_wiol(data 0x%p, length %d,iptc_itext 0x%p)\n", data, iptc_itext));
 
+  i_clear_error();
+
   iptc_text = iptc_itext;
   cinfo.err = jpeg_std_error(&jerr.pub);
   jerr.pub.error_exit     = my_error_exit;
@@ -341,8 +384,11 @@ i_readjpeg_wiol(io_glue *data, int length, char** iptc_itext, int *itlength) {
   return im;
 }
 
+/*
+=item i_writejpeg_wiol(im, ig, qfactor)
 
-
+=cut
+*/
 
 undef_int
 i_writejpeg_wiol(i_img *im, io_glue *ig, int qfactor) {
@@ -351,20 +397,35 @@ i_writejpeg_wiol(i_img *im, io_glue *ig, int qfactor) {
   int quality;
 
   struct jpeg_compress_struct cinfo;
-  struct jpeg_error_mgr jerr;
+  struct my_error_mgr jerr;
 
   JSAMPROW row_pointer[1];     /* pointer to JSAMPLE row[s] */
   int row_stride;              /* physical row width in image buffer */
+  unsigned char * data = NULL;
 
   mm_log((1,"i_writejpeg(im %p, ig %p, qfactor %d)\n", im, ig, qfactor));
   
-  if (!(im->channels==1 || im->channels==3)) { fprintf(stderr,"Unable to write JPEG, improper colorspace.\n"); exit(3); }
-  quality = qfactor;
+  i_clear_error();
 
-  cinfo.err = jpeg_std_error(&jerr);
+  if (!(im->channels==1 || im->channels==3)) { 
+    i_push_error(0, "only 1 or 3 channels images can be saved as JPEG");
+    return 0;
+  }
+  quality = qfactor;
 
+  cinfo.err = jpeg_std_error(&jerr.pub);
+  jerr.pub.error_exit = my_error_exit;
+  jerr.pub.output_message = my_output_message;
+  
   jpeg_create_compress(&cinfo);
 
+  if (setjmp(jerr.setjmp_buffer)) {
+    jpeg_destroy_compress(&cinfo);
+    if (data)
+      myfree(data);
+    return 0;
+  }
+
   io_glue_commit_types(ig);
   jpeg_wiol_dest(&cinfo, ig);
 
@@ -401,7 +462,7 @@ i_writejpeg_wiol(i_img *im, io_glue *ig, int qfactor) {
     }
   }
   else {
-    unsigned char *data = mymalloc(im->xsize * im->channels);
+    data = mymalloc(im->xsize * im->channels);
     if (data) {
       while (cinfo.next_scanline < cinfo.image_height) {
         /* jpeg_write_scanlines expects an array of pointers to scanlines.
@@ -415,8 +476,8 @@ i_writejpeg_wiol(i_img *im, io_glue *ig, int qfactor) {
       }
     }
     else {
-      jpeg_finish_compress(&cinfo);
       jpeg_destroy_compress(&cinfo);
+      i_push_error(0, "out of memory");
       return 0; /* out of memory? */
     }
   }
@@ -427,5 +488,21 @@ i_writejpeg_wiol(i_img *im, io_glue *ig, int qfactor) {
 
   jpeg_destroy_compress(&cinfo);
 
+  ig->closecb(ig);
+
   return(1);
 }
+
+/*
+=back
+
+=head1 AUTHOR
+
+Arnar M. Hrafnkelsson, addi@umich.edu
+
+=head1 SEE ALSO
+
+Imager(3)
+
+=cut
+*/