Switched all of jpeg to iolayer functions, removed older functions and did some
authorArnar Mar Hrafnkelsson <addi@cpan.org>
Fri, 8 Jun 2001 18:48:15 +0000 (18:48 +0000)
committerArnar Mar Hrafnkelsson <addi@cpan.org>
Fri, 8 Jun 2001 18:48:15 +0000 (18:48 +0000)
clean up.

Imager.pm
Imager.xs
image.h
io.c
jpeg.c
t/t101jpeg.t

index a78dc33..f92d79a 100644 (file)
--- a/Imager.pm
+++ b/Imager.pm
@@ -16,17 +16,17 @@ use Imager::Font;
                DSO_close
                DSO_funclist
                DSO_call
-               
+
                load_plugin
                unload_plugin
-               
+
                i_list_formats
                i_has_format
-               
+
                i_color_new
                i_color_set
                i_color_info
-               
+
                i_img_empty
                i_img_empty_ch
                i_img_exorcise
@@ -43,7 +43,7 @@ use Imager::Font;
                i_box_filled
                i_arc
                i_circle_aa
-               
+
                i_bezier_multi
                i_poly_aa
 
@@ -53,14 +53,14 @@ use Imager::Font;
                i_scale_nn
                i_haar
                i_count_colors
-               
-               
+
+
                i_gaussian
                i_conv
-               
+
                i_convert
                i_map
-               
+
                i_img_diff
 
                i_init_fonts
@@ -77,9 +77,6 @@ use Imager::Font;
                i_tt_text
                i_tt_bbox
 
-               i_readjpeg
-               i_writejpeg
-
                i_readjpeg_wiol
                i_writejpeg_wiol
 
@@ -110,11 +107,11 @@ use Imager::Font;
                i_postlevels
                i_mosaic
                i_watermark
-               
+
                malloc_state
 
                list_formats
-               
+
                i_gifquant
 
                newfont
@@ -122,7 +119,6 @@ use Imager::Font;
                newcolour
                NC
                NF
-               
 );
 
 
@@ -460,6 +456,9 @@ sub read {
 
   # FIXME: Find the format here if not specified
   # yes the code isn't here yet - next week maybe?
+  # Next week?  Are you high or something?  That comment
+  # has been there for half a year dude.
+
 
   if (!$input{type} and $input{file}) {
     $input{type}=$FORMATGUESS->($input{file});
@@ -592,20 +591,16 @@ sub read {
        return undef;
       }
       $self->{DEBUG} && print "loading a gif file\n";
+    }
 
-
-    } elsif ( $input{type} eq 'jpeg' ) {
-      if (exists $input{data}) {
-       ($self->{IMG},$self->{IPTCRAW})=i_readjpeg_scalar($input{data});
-      } else {
-       ($self->{IMG},$self->{IPTCRAW})=i_readjpeg( $fd );
-      }
-      if ( !defined($self->{IMG}) ) {
-       $self->{ERRSTR}='unable to read jpeg image';
+    if ( $input{type} eq 'jpeg' ) {
+      if ( !i_writejpeg_wiol($self->{IMG}, $IO, $input{jpegquality})) {
+       $self->{ERRSTR}='unable to write jpeg image'; 
        return undef;
       }
-      $self->{DEBUG} && print "loading a jpeg file\n";
+      $self->{DEBUG} && print "writing a jpeg file\n";
     }
+
   }
   return $self;
 }
@@ -741,12 +736,6 @@ sub write {
       }
       $self->{DEBUG} && print "writing a gif file\n";
 
-    } elsif ( $input{type} eq 'jpeg' ) {
-      $rc = i_writejpeg($self->{IMG},$fd,$input{jpegquality});
-      if ( !defined($rc) ) {
-       $self->{ERRSTR}='unable to write jpeg image'; return undef;
-      }
-      $self->{DEBUG} && print "writing a jpeg file\n";
     }
   }
   return $self;
index 8fa7b4a..3c9b461 100644 (file)
--- a/Imager.xs
+++ b/Imager.xs
@@ -1018,66 +1018,11 @@ i_tt_bbox(handle,point,str,len)
 
 #ifdef HAVE_LIBJPEG
 undef_int
-i_writejpeg(im,fd,qfactor)
+i_writejpeg_wiol(im, ig, qfactor)
     Imager::ImgRaw     im
-              int     fd
+        Imager::IO     ig
               int     qfactor
 
-void
-i_readjpeg(fd)
-              int     fd
-            PREINIT:
-             char*    iptc_itext;
-              int     tlength;
-            i_img*    rimg;
-                SV*    r;
-            PPCODE:
-             iptc_itext = NULL;
-             rimg=i_readjpeg(fd,&iptc_itext,&tlength);
-             if (iptc_itext == NULL) {
-                   r = sv_newmortal();
-                   EXTEND(SP,1);
-                   sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg);
-                   PUSHs(r);
-             } else {
-                   r = sv_newmortal();
-                   EXTEND(SP,2);
-                   sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg);
-                   PUSHs(r);
-                   PUSHs(sv_2mortal(newSVpv(iptc_itext,tlength)));
-                    myfree(iptc_itext);
-             }
-
-
-void
-i_readjpeg_scalar(...)
-          PROTOTYPE: $
-            PREINIT:
-             char*    data;
-      unsigned int     length;
-             char*    iptc_itext;
-              int     tlength;
-            i_img*    rimg;
-                SV*    r;
-            PPCODE:
-             iptc_itext = NULL;
-              data = (char *)SvPV(ST(0), length);
-             rimg=i_readjpeg_scalar(data,length,&iptc_itext,&tlength);
-             mm_log((1,"i_readjpeg_scalar: 0x%08X\n",rimg));
-             if (iptc_itext == NULL) {
-                   r = sv_newmortal();
-                   EXTEND(SP,1);
-                   sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg);
-                   PUSHs(r);
-             } else {
-                   r = sv_newmortal();
-                   EXTEND(SP,2);
-                   sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg);
-                   PUSHs(r);
-                   PUSHs(sv_2mortal(newSVpv(iptc_itext,tlength)));
-                    myfree(iptc_itext);
-             }
-
 
 void
 i_readjpeg_wiol(ig)
diff --git a/image.h b/image.h
index e48ed35..ac8979c 100644 (file)
--- a/image.h
+++ b/image.h
@@ -352,11 +352,9 @@ extern i_palidx *quant_translate(i_quantize *quant, i_img *img);
 extern void quant_transparent(i_quantize *quant, i_palidx *indices, i_img *img, i_palidx trans_index);
 
 #ifdef HAVE_LIBJPEG
-i_img* i_readjpeg(int fd,char** iptc_itext,int *tlength);
-i_img* i_readjpeg_scalar(char *data, int length,char** iptc_itext,int *itlength);
-i_img* i_readjpeg_wiol(io_glue *ig, int length, char** iptc_itext, int *itlength);
-i_img* i_readjpeg_extra2(int fd,char** iptc_itext);
-undef_int i_writejpeg(i_img *im,int fd,int qfactor);
+i_img *   
+i_readjpeg_wiol(io_glue *ig, int length, char** iptc_itext, int *itlength);
+undef_int i_writejpeg_wiol(i_img *im, io_glue *ig, int qfactor);
 #endif /* HAVE_LIBJPEG */
 
 #ifdef HAVE_LIBTIFF
diff --git a/io.c b/io.c
index 6bc0bbf..0d9dd82 100644 (file)
--- a/io.c
+++ b/io.c
@@ -188,6 +188,7 @@ mymalloc(int size) {
 
 void
 myfree(void *p) {
+  mm_log((1, "myfree(p %p)\n", p));
   free(p);
 }
 
diff --git a/jpeg.c b/jpeg.c
index b751f19..578d0f9 100644 (file)
--- a/jpeg.c
+++ b/jpeg.c
@@ -9,63 +9,89 @@
 #include "image.h"
 #include "jpeglib.h"
 
+#define JPEG_APP13       0xED    /* APP13 marker code */
+#define JPGS 1024
 
 unsigned char fake_eoi[]={(JOCTET) 0xFF,(JOCTET) JPEG_EOI};
 
-/* Handlers to read from memory */
+/* Bad design right here */
 
-typedef struct {
-  struct jpeg_source_mgr pub;  /* public fields */
-  char *data;
-  int length;
-  JOCTET * buffer;             /* start of buffer */
-  boolean start_of_file;       /* have we gotten any data yet? */
-} scalar_source_mgr;
+static int tlength=0;
+static char **iptc_text=NULL;
 
-typedef scalar_source_mgr *scalar_src_ptr;
 
+/* Source and Destination managers */
 
 
+typedef struct {
+  struct jpeg_source_mgr pub;  /* public fields */
+  io_glue *data;
+  JOCTET *buffer;              /* start of buffer */
+  int length;                  /* Do I need this? */
+  boolean start_of_file;       /* have we gotten any data yet? */
+} wiol_source_mgr;
 
+typedef struct {
+  struct jpeg_destination_mgr pub; /* public fields */
+  io_glue *data;
+  JOCTET *buffer;              /* start of buffer */
+  boolean start_of_file;       /* have we gotten any data yet? */
+} wiol_destination_mgr;
 
+typedef wiol_source_mgr *wiol_src_ptr;
+typedef wiol_destination_mgr *wiol_dest_ptr;
 
 
+/*
+ * Methods for io manager objects 
+ * 
+ * Methods for source managers: 
+ *
+ * init_source         (j_decompress_ptr cinfo);
+ * skip_input_data     (j_decompress_ptr cinfo, long num_bytes);
+ * fill_input_buffer   (j_decompress_ptr cinfo);
+ * term_source         (j_decompress_ptr cinfo);
+ */
+
 
 
 static void
-scalar_init_source (j_decompress_ptr cinfo) {
-  scalar_src_ptr src = (scalar_src_ptr) cinfo->src;
+wiol_init_source (j_decompress_ptr cinfo) {
+  wiol_src_ptr src = (wiol_src_ptr) cinfo->src;
   
-  /* We reset the empty-input-file flag for each image,
-   * but we don't clear the input buffer.
-   * This is correct behavior for reading a series of images from one source.
+  /* We reset the empty-input-file flag for each image, but we don't clear
+   * the input buffer.   This is correct behavior for reading a series of
+   * images from one source.
    */
   src->start_of_file = TRUE;
 }
 
+
+
 static boolean
-scalar_fill_input_buffer (j_decompress_ptr cinfo) {
-  scalar_src_ptr src = (scalar_src_ptr) cinfo->src;
-  size_t nbytes;
+wiol_fill_input_buffer(j_decompress_ptr cinfo) {
+  wiol_src_ptr src = (wiol_src_ptr) cinfo->src;
+  ssize_t nbytes; /* We assume that reads are "small" */
+  
+  mm_log((1,"wiol_fill_input_buffer(cinfo 0x%p)\n"));
   
-  if (src->start_of_file) {
-    nbytes=src->length;
-    src->buffer=src->data;
+  nbytes = src->data->readcb(src->data, src->buffer, JPGS);
+  
+  if (nbytes <= 0) { /* Insert a fake EOI marker */
+    src->pub.next_input_byte = fake_eoi;
+    src->pub.bytes_in_buffer = 2;
   } else {
-    /* Insert a fake EOI marker */
-    src->buffer = fake_eoi;
-    nbytes = 2;
+    src->pub.next_input_byte = src->buffer;
+    src->pub.bytes_in_buffer = nbytes;
   }
-
-  src->pub.next_input_byte = src->buffer;
-  src->pub.bytes_in_buffer = nbytes;
   src->start_of_file = FALSE;
   return TRUE;
 }
 
+
 static void
-scalar_skip_input_data (j_decompress_ptr cinfo, long num_bytes) {
-  scalar_src_ptr src = (scalar_src_ptr) cinfo->src;
+wiol_skip_input_data (j_decompress_ptr cinfo, long num_bytes) {
+  wiol_src_ptr src = (wiol_src_ptr) cinfo->src;
   
   /* Just a dumb implementation for now.  Could use fseek() except
    * it doesn't work on pipes.  Not clear that being smart is worth
@@ -75,7 +101,7 @@ scalar_skip_input_data (j_decompress_ptr cinfo, long num_bytes) {
   if (num_bytes > 0) {
     while (num_bytes > (long) src->pub.bytes_in_buffer) {
       num_bytes -= (long) src->pub.bytes_in_buffer;
-      (void) scalar_fill_input_buffer(cinfo);
+      (void) wiol_fill_input_buffer(cinfo);
       /* note we assume that fill_input_buffer will never return FALSE,
        * so suspension need not be handled.
        */
@@ -86,155 +112,121 @@ scalar_skip_input_data (j_decompress_ptr cinfo, long num_bytes) {
 }
 
 static void
-scalar_term_source (j_decompress_ptr cinfo) {  /* no work necessary here */ }
+wiol_term_source (j_decompress_ptr cinfo) {
+  /* no work necessary here */ 
+  wiol_src_ptr src;
+  if (cinfo->src != NULL) {
+    src = (wiol_src_ptr) cinfo->src;
+    myfree(src->buffer);
+  }
+}
+
+
+/* Source manager Constructor */
 
 static void
-jpeg_scalar_src(j_decompress_ptr cinfo, char *data, int length) {
-  scalar_src_ptr src;
+jpeg_wiol_src(j_decompress_ptr cinfo, io_glue *ig, int length) {
+  wiol_src_ptr src;
   
   if (cinfo->src == NULL) {    /* first time for this JPEG object? */
-    cinfo->src = (struct jpeg_source_mgr *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,sizeof(scalar_source_mgr));
-    src = (scalar_src_ptr) cinfo->src;
+    cinfo->src = (struct jpeg_source_mgr *) (*cinfo->mem->alloc_small) 
+      ((j_common_ptr) cinfo, JPOOL_PERMANENT,sizeof(wiol_source_mgr));
+    src = (wiol_src_ptr) cinfo->src;
   }
+
+  /* put the request method call in here later */
+  io_glue_commit_types(ig);
   
-  src = (scalar_src_ptr) cinfo->src;
-  src->data = data;
+  src         = (wiol_src_ptr) cinfo->src;
+  src->data   = ig;
+  src->buffer = mymalloc( JPGS );
   src->length = length;
-  src->pub.init_source = scalar_init_source;
-  src->pub.fill_input_buffer = scalar_fill_input_buffer;
-  src->pub.skip_input_data = scalar_skip_input_data;
+
+  src->pub.init_source       = wiol_init_source;
+  src->pub.fill_input_buffer = wiol_fill_input_buffer;
+  src->pub.skip_input_data   = wiol_skip_input_data;
   src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
-  src->pub.term_source = scalar_term_source;
-  src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
-  src->pub.next_input_byte = NULL; /* until buffer loaded */
+  src->pub.term_source       = wiol_term_source;
+  src->pub.bytes_in_buffer   = 0; /* forces fill_input_buffer on first read */
+  src->pub.next_input_byte   = NULL; /* until buffer loaded */
 }
 
 
 
 
-undef_int
-i_writejpeg(i_img *im,int fd,int qfactor) {
-  struct stat stbuf;
-  JSAMPLE *image_buffer;
-  int quality;
-
-  struct jpeg_compress_struct cinfo;
-  struct jpeg_error_mgr jerr;
-
-  FILE *outfile;               /* target file */
-  JSAMPROW row_pointer[1];     /* pointer to JSAMPLE row[s] */
-  int row_stride;              /* physical row width in image buffer */
+/*
+ * Methods for destination managers:
+ *
+ * init_destination    (j_compress_ptr cinfo);
+ * empty_output_buffer (j_compress_ptr cinfo);
+ * term_destination    (j_compress_ptr cinfo);
+ *
+ */
 
-  mm_log((1,"i_writejpeg(0x%x,fd %d,qfactor %d)\n",im,fd,qfactor));
+static void
+wiol_init_destination (j_compress_ptr cinfo) {
+  wiol_dest_ptr dest = (wiol_dest_ptr) cinfo->dest;
   
-  if (!(im->channels==1 || im->channels==3)) { fprintf(stderr,"Unable to write JPEG, improper colorspace.\n"); exit(3); }
-  quality = qfactor;
-
-  image_buffer=im->data;
-
-  /* Step 1: allocate and initialize JPEG compression object */
-
-  /* We have to set up the error handler first, in case the initialization
-   * step fails.  (Unlikely, but it could happen if you are out of memory.)
-   * This routine fills in the contents of struct jerr, and returns jerr's
-   * address which we place into the link field in cinfo.
+  /* We reset the empty-input-file flag for each image, but we don't clear
+   * the input buffer.   This is correct behavior for reading a series of
+   * images from one source.
    */
-  cinfo.err = jpeg_std_error(&jerr);
-  /* Now we can initialize the JPEG compression object. */
-  jpeg_create_compress(&cinfo);
+  dest->start_of_file = TRUE;
+}
 
-  /* Step 2: specify data destination (eg, a file) */
-  /* Note: steps 2 and 3 can be done in either order. */
+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;
 
-  /* Here we use the library-supplied code to send compressed data to a
-   * stdio stream.  You can also write your own code to do something else.
-   * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
-   * requires it in order to write binary files.
-   */
+  mm_log((1,"wiol_emtpy_output_buffer(cinfo 0x%p)\n"));
+  rc = dest->data->writecb(dest->data, dest->buffer, nbytes);
   
-  if (fstat(fd,&stbuf)<0) { fprintf(stderr,"Unable to stat fd.\n"); exit(1); }
-  
-  if ((outfile = fdopen(fd,"w")) == NULL) {
-    fprintf(stderr, "can't fdopen.\n");
-    exit(1);
-  }
-
-  jpeg_stdio_dest(&cinfo, outfile);
-
-  /* Step 3: set parameters for compression */
-
-  /* First we supply a description of the input image.
-   * Four fields of the cinfo struct must be filled in:
-   */
-  cinfo.image_width = im->xsize;       /* image width and height, in pixels */
-  cinfo.image_height = im->ysize;
-
-  if (im->channels==3) {
-    cinfo.input_components = 3;                /* # of color components per pixel */
-    cinfo.in_color_space = JCS_RGB;    /* colorspace of input image */
+  if (rc != nbytes) { /* XXX: Should raise some jpeg error */
+    mm_log((1, "wiol_empty_output_buffer: Error: nbytes = %d != rc = %d\n", nbytes, rc));
   }
+  dest->pub.free_in_buffer = JPGS;
+  dest->pub.next_output_byte = dest->buffer;
+  return TRUE;
+}
 
-  if (im->channels==1) {
-    cinfo.input_components = 1;                /* # of color components per pixel */
-    cinfo.in_color_space = JCS_GRAYSCALE;      /* colorspace of input image */
-  }
+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));
+  if (dest != NULL) myfree(dest->buffer);
+}
 
-  /* Now use the library's routine to set default compression parameters.
-   * (You must set at least cinfo.in_color_space before calling this,
-   * since the defaults depend on the source color space.)
-   */
-  jpeg_set_defaults(&cinfo);
-  /* Now you can set any non-default parameters you wish to.
-   * Here we just illustrate the use of quality (quantization table) scaling:
-   */
 
-  jpeg_set_quality(&cinfo, quality, TRUE);  /* limit to baseline-JPEG values */
+/* Destination manager Constructor */
 
-  /* Step 4: Start compressor */
+static void
+jpeg_wiol_dest(j_compress_ptr cinfo, io_glue *ig) {
+  wiol_dest_ptr dest;
   
-  /* TRUE ensures that we will write a complete interchange-JPEG file.
-   * Pass TRUE unless you are very sure of what you're doing.
-   */
-  jpeg_start_compress(&cinfo, TRUE);
-
-  /* Step 5: while (scan lines remain to be written) */
-  /*           jpeg_write_scanlines(...); */
-
-  /* Here we use the library's state variable cinfo.next_scanline as the
-   * loop counter, so that we don't have to keep track ourselves.
-   * To keep things simple, we pass one scanline per call; you can pass
-   * more if you wish, though.
-   */
-  row_stride = im->xsize * im->channels;       /* JSAMPLEs per row in image_buffer */
-
-  while (cinfo.next_scanline < cinfo.image_height) {
-    /* jpeg_write_scanlines expects an array of pointers to scanlines.
-     * Here the array is only one element long, but you could pass
-     * more than one scanline at a time if that's more convenient.
-     */
-    row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride];
-    (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
+  if (cinfo->dest == NULL) {   /* first time for this JPEG object? */
+    cinfo->dest = 
+      (struct jpeg_destination_mgr *)
+      (*cinfo->mem->alloc_small) 
+      ((j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof(wiol_destination_mgr));
   }
-
-  /* Step 6: Finish compression */
-
-  jpeg_finish_compress(&cinfo);
-  /* After finish_compress, we can close the output file. */
-  fclose(outfile);
-
-  /* Step 7: release JPEG compression object */
-
-  /* This is an important step since it will release a good deal of memory. */
-  jpeg_destroy_compress(&cinfo);
-
-  return(1);
+  
+  dest = (wiol_dest_ptr) cinfo->dest;
+  dest->data                    = ig;
+  dest->buffer                  = mymalloc( JPGS );
+
+  dest->pub.init_destination    = wiol_init_destination;
+  dest->pub.empty_output_buffer = wiol_empty_output_buffer;
+  dest->pub.term_destination    = wiol_term_destination;
+  dest->pub.free_in_buffer      = JPGS;
+  dest->pub.next_output_byte    = dest->buffer;
 }
 
 
-static int tlength=0;
-static char **iptc_text=NULL;
 
-#define JPEG_APP13       0xED    /* APP13 marker code */
+
 
 LOCAL(unsigned int)
 jpeg_getc (j_decompress_ptr cinfo)
@@ -268,20 +260,8 @@ APP13_handler (j_decompress_ptr cinfo) {
   return TRUE;
 }
 
-
-
-
-
-
-
-
-
-
-
-
 METHODDEF(void)
-my_output_message (j_common_ptr cinfo)
-{
+my_output_message (j_common_ptr cinfo) {
   char buffer[JMSG_LENGTH_MAX];
 
   /* Create the message */
@@ -291,11 +271,6 @@ my_output_message (j_common_ptr cinfo)
   mm_log((1, "%s\n", buffer));
 }
 
-
-
-
-
-
 struct my_error_mgr {
   struct jpeg_error_mgr pub;   /* "public" fields */
   jmp_buf setjmp_buffer;       /* for return to caller */
@@ -322,161 +297,23 @@ my_error_exit (j_common_ptr cinfo) {
 
 
 
-
 i_img*
-i_readjpeg(int fd,char** iptc_itext,int *itlength) {
+i_readjpeg_wiol(io_glue *data, int length, char** iptc_itext, int *itlength) {
   i_img *im;
 
   struct jpeg_decompress_struct cinfo;
-  /* We use our private extension JPEG error handler.
-   * Note that this struct must live as long as the main JPEG parameter
-   * struct, to avoid dangling-pointer problems.
-   */
-
-  /*   struct jpeg_error_mgr jerr;*/
   struct my_error_mgr jerr;
-  FILE * infile;               /* source file */
   JSAMPARRAY buffer;           /* Output row buffer */
   int row_stride;              /* physical row width in output buffer */
 
-  mm_log((1,"i_readjpeg(fd %d,iptc_itext 0x%x)\n",fd,iptc_itext));
-
-  iptc_text=iptc_itext;
-
-  if ((infile = fdopen(fd,"r")) == NULL) {
-    fprintf(stderr, "can't fdopen.\n");
-    exit(1);
-  }
-  
-  /* Step 1: allocate and initialize JPEG decompression object */
+  mm_log((1,"i_readjpeg_wiol(data 0x%p, length %d,iptc_itext 0x%p)\n", data, iptc_itext));
 
-  /* We set up the normal JPEG error routines, then override error_exit. */
+  iptc_text = iptc_itext;
   cinfo.err = jpeg_std_error(&jerr.pub);
-  jerr.pub.error_exit = my_error_exit;
+  jerr.pub.error_exit     = my_error_exit;
   jerr.pub.output_message = my_output_message;
-  /* Establish the setjmp return context for my_error_exit to use. */
-  if (setjmp(jerr.setjmp_buffer)) {
-    /* If we get here, the JPEG code has signaled an error.
-     * We need to clean up the JPEG object, close the input file, and return.
-     */
-    jpeg_destroy_decompress(&cinfo); 
-    fclose(infile);
-    *iptc_itext=NULL;
-    *itlength=0;
-    return NULL;
-  }
-  
-  /* Now we can initialize the JPEG decompression object. */
-  jpeg_create_decompress(&cinfo);
-  jpeg_set_marker_processor(&cinfo, JPEG_APP13, APP13_handler);
-  /* Step 2: specify data source (eg, a file) */
-
-  jpeg_stdio_src(&cinfo, infile);
-
-  /* Step 3: read file parameters with jpeg_read_header() */
-
-  (void) jpeg_read_header(&cinfo, TRUE);
-  
-  /* We can ignore the return value from jpeg_read_header since
-   *   (a) suspension is not possible with the stdio data source, and
-   *   (b) we passed TRUE to reject a tables-only JPEG file as an error.
-   * See libjpeg.doc for more info.
-   */
-
-  /* Step 4: set parameters for decompression */
-
-  /* In this example, we don't need to change any of the defaults set by
-   * jpeg_read_header(), so we do nothing here.
-   */
-  
-  /* Step 5: Start decompressor */
-
-  (void) jpeg_start_decompress(&cinfo);
-  /* We can ignore the return value since suspension is not possible
-   * with the stdio data source.
-   */
-
-  /* We may need to do some setup of our own at this point before reading
-   * the data.  After jpeg_start_decompress() we have the correct scaled
-   * output image dimensions available, as well as the output colormap
-   * if we asked for color quantization.
-   * In this example, we need to make an output work buffer of the right size.
-   */ 
-
-  im=i_img_empty_ch(NULL,cinfo.output_width,cinfo.output_height,cinfo.output_components);
-
-  /*  fprintf(stderr,"JPEG info:\n  xsize:%d\n  ysize:%d\n  channels:%d.\n",xsize,ysize,channels);*/ 
-
-  /* JSAMPLEs per row in output buffer */
-  row_stride = cinfo.output_width * cinfo.output_components;
-  /* Make a one-row-high sample array that will go away when done with image */
-  buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
-
-  /* Step 6: while (scan lines remain to be read) */
-  /*           jpeg_read_scanlines(...); */
-
-  /* Here we use the library's state variable cinfo.output_scanline as the
-   * loop counter, so that we don't have to keep track ourselves.
-   */
-
-  while (cinfo.output_scanline < cinfo.output_height) {
-    /* jpeg_read_scanlines expects an array of pointers to scanlines.
-     * Here the array is only one element long, but you could ask for
-     * more than one scanline at a time if that's more convenient.
-     */
-    (void) jpeg_read_scanlines(&cinfo, buffer, 1);
-    /* Assume put_scanline_someplace wants a pointer and sample count. */
-    memcpy(im->data+im->channels*im->xsize*(cinfo.output_scanline-1),buffer[0],row_stride);
-  }
-
-  /* Step 7: Finish decompression */
-
-  (void) jpeg_finish_decompress(&cinfo);
-  /* We can ignore the return value since suspension is not possible
-   * with the stdio data source.
-   */
-
-  /* Step 8: Release JPEG decompression object */
-
-  /* This is an important step since it will release a good deal of memory. */
-  jpeg_destroy_decompress(&cinfo);
-
-  /* After finish_decompress, we can close the input file.
-   * Here we postpone it until after no more JPEG errors are possible,
-   * so as to simplify the setjmp error logic above.  (Actually, I don't
-   * think that jpeg_destroy can do an error exit, but why assume anything...)
-   */
-
-/*  fclose(infile); DO NOT fclose() BECAUSE THEN close() WILL FAIL*/
-
-  /* At this point you may want to check to see whether any corrupt-data
-   * warnings occurred (test whether jerr.pub.num_warnings is nonzero).
-   */
-
-  /* And we're done! */
-
-  *itlength=tlength;
-  mm_log((1,"i_readjpeg -> (0x%x)\n",im));
-  return im;
-}
-
 
-
-i_img*
-i_readjpeg_scalar(char *data, int length,char** iptc_itext,int *itlength) {
-  i_img *im;
-
-  struct jpeg_decompress_struct cinfo;
-  struct my_error_mgr jerr;
-  JSAMPARRAY buffer;           /* Output row buffer */
-  int row_stride;              /* physical row width in output buffer */
-
-  mm_log((1,"i_readjpeg_scalar(data 0x%08x, length %d,iptc_itext 0x%x)\n",data,length,iptc_itext));
-  iptc_text=iptc_itext;
-
-  cinfo.err = jpeg_std_error(&jerr.pub);
-  jerr.pub.error_exit = my_error_exit;
-  jerr.pub.output_message = my_output_message;
+  /* Set error handler */
   if (setjmp(jerr.setjmp_buffer)) {
     jpeg_destroy_decompress(&cinfo); 
     *iptc_itext=NULL;
@@ -486,7 +323,8 @@ i_readjpeg_scalar(char *data, int length,char** iptc_itext,int *itlength) {
   
   jpeg_create_decompress(&cinfo);
   jpeg_set_marker_processor(&cinfo, JPEG_APP13, APP13_handler);
-  jpeg_scalar_src(&cinfo, data, length );
+  jpeg_wiol_src(&cinfo, data, length);
+
   (void) jpeg_read_header(&cinfo, TRUE);
   (void) jpeg_start_decompress(&cinfo);
   im=i_img_empty_ch(NULL,cinfo.output_width,cinfo.output_height,cinfo.output_components);
@@ -499,219 +337,69 @@ i_readjpeg_scalar(char *data, int length,char** iptc_itext,int *itlength) {
   (void) jpeg_finish_decompress(&cinfo);
   jpeg_destroy_decompress(&cinfo);
   *itlength=tlength;
-  mm_log((1,"i_readjpeg_scalar -> (0x%x)\n",im));
+  mm_log((1,"i_readjpeg_wiol -> (0x%x)\n",im));
   return im;
 }
 
 
 
 
+undef_int
+i_writejpeg_wiol(i_img *im, io_glue *ig, int qfactor) {
+  struct stat stbuf;
+  JSAMPLE *image_buffer;
+  int quality;
 
+  struct jpeg_compress_struct cinfo;
+  struct jpeg_error_mgr jerr;
 
+  JSAMPROW row_pointer[1];     /* pointer to JSAMPLE row[s] */
+  int row_stride;              /* physical row width in image buffer */
 
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-#define JPGS 1024
-
-
-
-typedef struct {
-  struct jpeg_source_mgr pub;  /* public fields */
-  io_glue *data;
-  JOCTET *buffer;              /* start of buffer */
-  int length;                  /* Do I need this? */
-  boolean start_of_file;       /* have we gotten any data yet? */
-} wiol_source_mgr;
-
-typedef wiol_source_mgr *wiol_src_ptr;
-
-static void
-wiol_init_source (j_decompress_ptr cinfo) {
-  wiol_src_ptr src = (wiol_src_ptr) cinfo->src;
-  
-  /* We reset the empty-input-file flag for each image,
-   * but we don't clear the input buffer.
-   * This is correct behavior for reading a series of images from one source.
-   */
-  src->start_of_file = TRUE;
-}
-
-static boolean
-wiol_fill_input_buffer(j_decompress_ptr cinfo) {
-  wiol_src_ptr src = (wiol_src_ptr) cinfo->src;
-  ssize_t nbytes; /* We assume that reads are "small" */
-  
-  mm_log((1,"wiol_fill_input_buffer(cinfo 0x%p)\n"));
-  
-  nbytes = src->data->readcb(src->data, src->buffer, JPGS);
+  mm_log((1,"i_writejpeg(im %p, ig %p, qfactor %d)\n", im, ig, qfactor));
   
-  if (nbytes <= 0) { /* Insert a fake EOI marker */
-    src->pub.next_input_byte = fake_eoi;
-    src->pub.bytes_in_buffer = 2;
-  } else {
-    src->pub.next_input_byte = src->buffer;
-    src->pub.bytes_in_buffer = nbytes;
-  }
-  src->start_of_file = FALSE;
-  return TRUE;
-}
+  if (!(im->channels==1 || im->channels==3)) { fprintf(stderr,"Unable to write JPEG, improper colorspace.\n"); exit(3); }
+  quality = qfactor;
 
-static void
-wiol_skip_input_data (j_decompress_ptr cinfo, long num_bytes) {
-  wiol_src_ptr src = (wiol_src_ptr) cinfo->src;
-  
-  /* Just a dumb implementation for now.  Could use fseek() except
-   * it doesn't work on pipes.  Not clear that being smart is worth
-   * any trouble anyway --- large skips are infrequent.
-   */
-  
-  if (num_bytes > 0) {
-    while (num_bytes > (long) src->pub.bytes_in_buffer) {
-      num_bytes -= (long) src->pub.bytes_in_buffer;
-      (void) wiol_fill_input_buffer(cinfo);
-      /* note we assume that fill_input_buffer will never return FALSE,
-       * so suspension need not be handled.
-       */
-    }
-    src->pub.next_input_byte += (size_t) num_bytes;
-    src->pub.bytes_in_buffer -= (size_t) num_bytes;
-  }
-}
+  image_buffer = im->data;
 
-static void
-wiol_term_source (j_decompress_ptr cinfo) {
-  /* no work necessary here */ 
-  wiol_src_ptr src;
-  if (cinfo->src != NULL) {
-    src = (wiol_src_ptr) cinfo->src;
-    myfree(src->buffer);
-  }
-}
+  cinfo.err = jpeg_std_error(&jerr);
 
-static void
-jpeg_wiol_src(j_decompress_ptr cinfo, io_glue *ig, int length) {
-  wiol_src_ptr src;
-  
-  if (cinfo->src == NULL) {    /* first time for this JPEG object? */
-    cinfo->src = (struct jpeg_source_mgr *) (*cinfo->mem->alloc_small) 
-      ((j_common_ptr) cinfo, JPOOL_PERMANENT,sizeof(wiol_source_mgr));
-    src = (wiol_src_ptr) cinfo->src;
-  }
+  jpeg_create_compress(&cinfo);
 
-  /* put the request method call in here later */
   io_glue_commit_types(ig);
-  
-  src         = (wiol_src_ptr) cinfo->src;
-  src->data   = ig;
-  src->buffer = mymalloc( JPGS );
-  src->length = length;
-
-  src->pub.init_source       = wiol_init_source;
-  src->pub.fill_input_buffer = wiol_fill_input_buffer;
-  src->pub.skip_input_data   = wiol_skip_input_data;
-  src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
-  src->pub.term_source       = wiol_term_source;
-  src->pub.bytes_in_buffer   = 0; /* forces fill_input_buffer on first read */
-  src->pub.next_input_byte   = NULL; /* until buffer loaded */
-}
-
-
-
-
-
-
+  jpeg_wiol_dest(&cinfo, ig);
 
+  cinfo.image_width  = im -> xsize;    /* image width and height, in pixels */
+  cinfo.image_height = im -> ysize;
 
+  if (im->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) {
+    cinfo.input_components = 1;                /* # of color components per pixel */
+    cinfo.in_color_space = JCS_GRAYSCALE;      /* colorspace of input image */
+  }
 
+  jpeg_set_defaults(&cinfo);
+  jpeg_set_quality(&cinfo, quality, TRUE);  /* limit to baseline-JPEG values */
 
+  jpeg_start_compress(&cinfo, TRUE);
 
-i_img*
-i_readjpeg_wiol(io_glue *data, int length, char** iptc_itext, int *itlength) {
-  i_img *im;
+  row_stride = im->xsize * im->channels;       /* JSAMPLEs per row in image_buffer */
 
-  struct jpeg_decompress_struct cinfo;
-  struct my_error_mgr jerr;
-  JSAMPARRAY buffer;           /* Output row buffer */
-  int row_stride;              /* physical row width in output buffer */
+  while (cinfo.next_scanline < cinfo.image_height) {
+    row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride];
+    (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
+  }
 
-  mm_log((1,"i_readjpeg_wiol(data 0x%p, length %d,iptc_itext 0x%p)\n", data, iptc_itext));
+  /* Step 6: Finish compression */
 
-  iptc_text = iptc_itext;
-  cinfo.err = jpeg_std_error(&jerr.pub);
-  jerr.pub.error_exit     = my_error_exit;
-  jerr.pub.output_message = my_output_message;
+  jpeg_finish_compress(&cinfo);
 
-  /* Set error handler */
-  if (setjmp(jerr.setjmp_buffer)) {
-    jpeg_destroy_decompress(&cinfo); 
-    *iptc_itext=NULL;
-    *itlength=0;
-    return NULL;
-  }
-  
-  jpeg_create_decompress(&cinfo);
-  jpeg_set_marker_processor(&cinfo, JPEG_APP13, APP13_handler);
-  jpeg_wiol_src(&cinfo, data, length);
+  jpeg_destroy_compress(&cinfo);
 
-  (void) jpeg_read_header(&cinfo, TRUE);
-  (void) jpeg_start_decompress(&cinfo);
-  im=i_img_empty_ch(NULL,cinfo.output_width,cinfo.output_height,cinfo.output_components);
-  row_stride = cinfo.output_width * cinfo.output_components;
-  buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
-  while (cinfo.output_scanline < cinfo.output_height) {
-    (void) jpeg_read_scanlines(&cinfo, buffer, 1);
-    memcpy(im->data+im->channels*im->xsize*(cinfo.output_scanline-1),buffer[0],row_stride);
-  }
-  (void) jpeg_finish_decompress(&cinfo);
-  jpeg_destroy_decompress(&cinfo);
-  *itlength=tlength;
-  mm_log((1,"i_readjpeg_wiol -> (0x%x)\n",im));
-  return im;
+  return(1);
 }
-
-
index c78c67b..8043c8c 100644 (file)
@@ -23,17 +23,20 @@ if (!i_has_format("jpeg")) {
 } else {
   open(FH,">testout/t101.jpg") || die "cannot open testout/t101.jpg for writing\n";
   binmode(FH);
-  i_writejpeg($img,fileno(FH),30);
+  $IO = Imager::io_new_fd(fileno(FH));
+  i_writejpeg_wiol($img,$IO,30);
   close(FH);
 
   print "ok 1\n";
   
-  open(FH,"testout/t101.jpg") || die "cannot open testout/t101.jpg\n";
+  open(FH, "testout/t101.jpg") || die "cannot open testout/t101.jpg\n";
   binmode(FH);
-
-  ($cmpimg,undef)=i_readjpeg(fileno(FH));
+  $IO = Imager::io_new_fd(fileno(FH));
+  ($cmpimg,undef) = i_readjpeg_wiol($IO);
   close(FH);
 
+  print "$cmpimg\n";
+
   print "# jpeg average mean square pixel difference: ",sqrt(i_img_diff($img,$cmpimg))/150*150,"\n";
   print "ok 2\n";
 }