From: Arnar Mar Hrafnkelsson Date: Fri, 8 Jun 2001 18:48:15 +0000 (+0000) Subject: Switched all of jpeg to iolayer functions, removed older functions and did some X-Git-Tag: Imager-0.48^2~605 X-Git-Url: http://git.imager.perl.org/imager.git/commitdiff_plain/dd55acc83c6339f654a7311912c83a83efb2fbf1 Switched all of jpeg to iolayer functions, removed older functions and did some clean up. --- diff --git a/Imager.pm b/Imager.pm index a78dc333..f92d79a5 100644 --- 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; diff --git a/Imager.xs b/Imager.xs index 8fa7b4a9..3c9b4617 100644 --- 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 e48ed352..ac8979c2 100644 --- 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 6bc0bbf1..0d9dd824 100644 --- 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 b751f19e..578d0f95 100644 --- 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); } - - diff --git a/t/t101jpeg.t b/t/t101jpeg.t index c78c67b9..8043c8cb 100644 --- a/t/t101jpeg.t +++ b/t/t101jpeg.t @@ -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"; }