]> git.imager.perl.org - imager.git/blob - jpeg.c
added test to check for crash in set_internal() (and it's normal
[imager.git] / jpeg.c
1 #include <stdio.h>
2 #include <sys/stat.h>
3 #include <unistd.h>
4 #include <setjmp.h>
5
6 #include "iolayer.h"
7 #include "image.h"
8 #include "jpeglib.h"
9
10
11 unsigned char fake_eoi[]={(JOCTET) 0xFF,(JOCTET) JPEG_EOI};
12
13 /* Handlers to read from memory */
14
15 typedef struct {
16   struct jpeg_source_mgr pub;   /* public fields */
17   char *data;
18   int length;
19   JOCTET * buffer;              /* start of buffer */
20   boolean start_of_file;        /* have we gotten any data yet? */
21 } scalar_source_mgr;
22
23 typedef scalar_source_mgr *scalar_src_ptr;
24
25
26
27
28
29
30
31
32
33 static void
34 scalar_init_source (j_decompress_ptr cinfo) {
35   scalar_src_ptr src = (scalar_src_ptr) cinfo->src;
36   
37   /* We reset the empty-input-file flag for each image,
38    * but we don't clear the input buffer.
39    * This is correct behavior for reading a series of images from one source.
40    */
41   src->start_of_file = TRUE;
42 }
43
44 static boolean
45 scalar_fill_input_buffer (j_decompress_ptr cinfo) {
46   scalar_src_ptr src = (scalar_src_ptr) cinfo->src;
47   size_t nbytes;
48   
49   if (src->start_of_file) {
50     nbytes=src->length;
51     src->buffer=src->data;
52   } else {
53     /* Insert a fake EOI marker */
54     src->buffer = fake_eoi;
55     nbytes = 2;
56   }
57
58   src->pub.next_input_byte = src->buffer;
59   src->pub.bytes_in_buffer = nbytes;
60   src->start_of_file = FALSE;
61   return TRUE;
62 }
63
64 static void
65 scalar_skip_input_data (j_decompress_ptr cinfo, long num_bytes) {
66   scalar_src_ptr src = (scalar_src_ptr) cinfo->src;
67   
68   /* Just a dumb implementation for now.  Could use fseek() except
69    * it doesn't work on pipes.  Not clear that being smart is worth
70    * any trouble anyway --- large skips are infrequent.
71    */
72   
73   if (num_bytes > 0) {
74     while (num_bytes > (long) src->pub.bytes_in_buffer) {
75       num_bytes -= (long) src->pub.bytes_in_buffer;
76       (void) scalar_fill_input_buffer(cinfo);
77       /* note we assume that fill_input_buffer will never return FALSE,
78        * so suspension need not be handled.
79        */
80     }
81     src->pub.next_input_byte += (size_t) num_bytes;
82     src->pub.bytes_in_buffer -= (size_t) num_bytes;
83   }
84 }
85
86 static void
87 scalar_term_source (j_decompress_ptr cinfo) {  /* no work necessary here */ }
88
89 static void
90 jpeg_scalar_src(j_decompress_ptr cinfo, char *data, int length) {
91   scalar_src_ptr src;
92   
93   if (cinfo->src == NULL) {     /* first time for this JPEG object? */
94     cinfo->src = (struct jpeg_source_mgr *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,sizeof(scalar_source_mgr));
95     src = (scalar_src_ptr) cinfo->src;
96   }
97   
98   src = (scalar_src_ptr) cinfo->src;
99   src->data = data;
100   src->length = length;
101   src->pub.init_source = scalar_init_source;
102   src->pub.fill_input_buffer = scalar_fill_input_buffer;
103   src->pub.skip_input_data = scalar_skip_input_data;
104   src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
105   src->pub.term_source = scalar_term_source;
106   src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
107   src->pub.next_input_byte = NULL; /* until buffer loaded */
108 }
109
110
111
112
113 undef_int
114 i_writejpeg(i_img *im,int fd,int qfactor) {
115   struct stat stbuf;
116   JSAMPLE *image_buffer;
117   int quality;
118
119   struct jpeg_compress_struct cinfo;
120   struct jpeg_error_mgr jerr;
121
122   FILE *outfile;                /* target file */
123   JSAMPROW row_pointer[1];      /* pointer to JSAMPLE row[s] */
124   int row_stride;               /* physical row width in image buffer */
125
126   mm_log((1,"i_writejpeg(0x%x,fd %d,qfactor %d)\n",im,fd,qfactor));
127   
128   if (!(im->channels==1 || im->channels==3)) { fprintf(stderr,"Unable to write JPEG, improper colorspace.\n"); exit(3); }
129   quality = qfactor;
130
131   image_buffer=im->data;
132
133   /* Step 1: allocate and initialize JPEG compression object */
134
135   /* We have to set up the error handler first, in case the initialization
136    * step fails.  (Unlikely, but it could happen if you are out of memory.)
137    * This routine fills in the contents of struct jerr, and returns jerr's
138    * address which we place into the link field in cinfo.
139    */
140   cinfo.err = jpeg_std_error(&jerr);
141   /* Now we can initialize the JPEG compression object. */
142   jpeg_create_compress(&cinfo);
143
144   /* Step 2: specify data destination (eg, a file) */
145   /* Note: steps 2 and 3 can be done in either order. */
146
147   /* Here we use the library-supplied code to send compressed data to a
148    * stdio stream.  You can also write your own code to do something else.
149    * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
150    * requires it in order to write binary files.
151    */
152   
153   if (fstat(fd,&stbuf)<0) { fprintf(stderr,"Unable to stat fd.\n"); exit(1); }
154   
155   if ((outfile = fdopen(fd,"w")) == NULL) {
156     fprintf(stderr, "can't fdopen.\n");
157     exit(1);
158   }
159
160   jpeg_stdio_dest(&cinfo, outfile);
161
162   /* Step 3: set parameters for compression */
163
164   /* First we supply a description of the input image.
165    * Four fields of the cinfo struct must be filled in:
166    */
167   cinfo.image_width = im->xsize;        /* image width and height, in pixels */
168   cinfo.image_height = im->ysize;
169
170   if (im->channels==3) {
171     cinfo.input_components = 3;         /* # of color components per pixel */
172     cinfo.in_color_space = JCS_RGB;     /* colorspace of input image */
173   }
174
175   if (im->channels==1) {
176     cinfo.input_components = 1;         /* # of color components per pixel */
177     cinfo.in_color_space = JCS_GRAYSCALE;       /* colorspace of input image */
178   }
179
180   /* Now use the library's routine to set default compression parameters.
181    * (You must set at least cinfo.in_color_space before calling this,
182    * since the defaults depend on the source color space.)
183    */
184   jpeg_set_defaults(&cinfo);
185   /* Now you can set any non-default parameters you wish to.
186    * Here we just illustrate the use of quality (quantization table) scaling:
187    */
188
189   jpeg_set_quality(&cinfo, quality, TRUE);  /* limit to baseline-JPEG values */
190
191   /* Step 4: Start compressor */
192   
193   /* TRUE ensures that we will write a complete interchange-JPEG file.
194    * Pass TRUE unless you are very sure of what you're doing.
195    */
196   jpeg_start_compress(&cinfo, TRUE);
197
198   /* Step 5: while (scan lines remain to be written) */
199   /*           jpeg_write_scanlines(...); */
200
201   /* Here we use the library's state variable cinfo.next_scanline as the
202    * loop counter, so that we don't have to keep track ourselves.
203    * To keep things simple, we pass one scanline per call; you can pass
204    * more if you wish, though.
205    */
206   row_stride = im->xsize * im->channels;        /* JSAMPLEs per row in image_buffer */
207
208   while (cinfo.next_scanline < cinfo.image_height) {
209     /* jpeg_write_scanlines expects an array of pointers to scanlines.
210      * Here the array is only one element long, but you could pass
211      * more than one scanline at a time if that's more convenient.
212      */
213     row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride];
214     (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
215   }
216
217   /* Step 6: Finish compression */
218
219   jpeg_finish_compress(&cinfo);
220   /* After finish_compress, we can close the output file. */
221   fclose(outfile);
222
223   /* Step 7: release JPEG compression object */
224
225   /* This is an important step since it will release a good deal of memory. */
226   jpeg_destroy_compress(&cinfo);
227
228   return(1);
229 }
230
231
232 static int tlength=0;
233 static char **iptc_text=NULL;
234
235 #define JPEG_APP13       0xED    /* APP13 marker code */
236
237 LOCAL(unsigned int)
238 jpeg_getc (j_decompress_ptr cinfo)
239 /* Read next byte */
240 {
241   struct jpeg_source_mgr * datasrc = cinfo->src;
242
243   if (datasrc->bytes_in_buffer == 0) {
244     if (! (*datasrc->fill_input_buffer) (cinfo))
245       { fprintf(stderr,"Jpeglib: cant suspend.\n"); exit(3); }
246       /*      ERREXIT(cinfo, JERR_CANT_SUSPEND);*/
247   }
248   datasrc->bytes_in_buffer--;
249   return GETJOCTET(*datasrc->next_input_byte++);
250 }
251
252 METHODDEF(boolean)
253 APP13_handler (j_decompress_ptr cinfo) {
254   INT32 length;
255   unsigned int cnt=0;
256   
257   length = jpeg_getc(cinfo) << 8;
258   length += jpeg_getc(cinfo);
259   length -= 2;  /* discount the length word itself */
260   
261   tlength=length;
262
263   if ( ((*iptc_text)=mymalloc(length)) == NULL ) return FALSE;
264   while (--length >= 0) (*iptc_text)[cnt++] = jpeg_getc(cinfo); 
265  
266   return TRUE;
267 }
268
269
270
271
272
273
274
275
276
277
278
279
280 METHODDEF(void)
281 my_output_message (j_common_ptr cinfo)
282 {
283   char buffer[JMSG_LENGTH_MAX];
284
285   /* Create the message */
286   (*cinfo->err->format_message) (cinfo, buffer);
287
288   /* Send it to stderr, adding a newline */
289   mm_log((1, "%s\n", buffer));
290 }
291
292
293
294
295
296
297 struct my_error_mgr {
298   struct jpeg_error_mgr pub;    /* "public" fields */
299   jmp_buf setjmp_buffer;        /* for return to caller */
300 };
301
302 typedef struct my_error_mgr * my_error_ptr;
303
304 /* Here's the routine that will replace the standard error_exit method */
305
306 METHODDEF(void)
307 my_error_exit (j_common_ptr cinfo) {
308   /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
309   my_error_ptr myerr = (my_error_ptr) cinfo->err;
310   
311   /* Always display the message. */
312   /* We could postpone this until after returning, if we chose. */
313   (*cinfo->err->output_message) (cinfo);
314   
315   /* Return control to the setjmp point */
316   longjmp(myerr->setjmp_buffer, 1);
317 }
318
319
320
321
322
323
324 i_img*
325 i_readjpeg(int fd,char** iptc_itext,int *itlength) {
326   i_img *im;
327
328   struct jpeg_decompress_struct cinfo;
329   /* We use our private extension JPEG error handler.
330    * Note that this struct must live as long as the main JPEG parameter
331    * struct, to avoid dangling-pointer problems.
332    */
333
334   /*   struct jpeg_error_mgr jerr;*/
335   struct my_error_mgr jerr;
336   FILE * infile;                /* source file */
337   JSAMPARRAY buffer;            /* Output row buffer */
338   int row_stride;               /* physical row width in output buffer */
339
340   mm_log((1,"i_readjpeg(fd %d,iptc_itext 0x%x)\n",fd,iptc_itext));
341
342   iptc_text=iptc_itext;
343
344   if ((infile = fdopen(fd,"r")) == NULL) {
345     fprintf(stderr, "can't fdopen.\n");
346     exit(1);
347   }
348   
349   /* Step 1: allocate and initialize JPEG decompression object */
350
351   /* We set up the normal JPEG error routines, then override error_exit. */
352   cinfo.err = jpeg_std_error(&jerr.pub);
353   jerr.pub.error_exit = my_error_exit;
354   jerr.pub.output_message = my_output_message;
355   /* Establish the setjmp return context for my_error_exit to use. */
356   if (setjmp(jerr.setjmp_buffer)) {
357     /* If we get here, the JPEG code has signaled an error.
358      * We need to clean up the JPEG object, close the input file, and return.
359      */
360     jpeg_destroy_decompress(&cinfo); 
361     fclose(infile);
362     *iptc_itext=NULL;
363     *itlength=0;
364     return NULL;
365   }
366   
367   /* Now we can initialize the JPEG decompression object. */
368   jpeg_create_decompress(&cinfo);
369   jpeg_set_marker_processor(&cinfo, JPEG_APP13, APP13_handler);
370   /* Step 2: specify data source (eg, a file) */
371
372   jpeg_stdio_src(&cinfo, infile);
373
374   /* Step 3: read file parameters with jpeg_read_header() */
375
376   (void) jpeg_read_header(&cinfo, TRUE);
377   
378   /* We can ignore the return value from jpeg_read_header since
379    *   (a) suspension is not possible with the stdio data source, and
380    *   (b) we passed TRUE to reject a tables-only JPEG file as an error.
381    * See libjpeg.doc for more info.
382    */
383
384   /* Step 4: set parameters for decompression */
385
386   /* In this example, we don't need to change any of the defaults set by
387    * jpeg_read_header(), so we do nothing here.
388    */
389   
390   /* Step 5: Start decompressor */
391
392   (void) jpeg_start_decompress(&cinfo);
393   /* We can ignore the return value since suspension is not possible
394    * with the stdio data source.
395    */
396
397   /* We may need to do some setup of our own at this point before reading
398    * the data.  After jpeg_start_decompress() we have the correct scaled
399    * output image dimensions available, as well as the output colormap
400    * if we asked for color quantization.
401    * In this example, we need to make an output work buffer of the right size.
402    */ 
403
404   im=i_img_empty_ch(NULL,cinfo.output_width,cinfo.output_height,cinfo.output_components);
405
406   /*  fprintf(stderr,"JPEG info:\n  xsize:%d\n  ysize:%d\n  channels:%d.\n",xsize,ysize,channels);*/ 
407
408   /* JSAMPLEs per row in output buffer */
409   row_stride = cinfo.output_width * cinfo.output_components;
410   /* Make a one-row-high sample array that will go away when done with image */
411   buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
412
413   /* Step 6: while (scan lines remain to be read) */
414   /*           jpeg_read_scanlines(...); */
415
416   /* Here we use the library's state variable cinfo.output_scanline as the
417    * loop counter, so that we don't have to keep track ourselves.
418    */
419
420   while (cinfo.output_scanline < cinfo.output_height) {
421     /* jpeg_read_scanlines expects an array of pointers to scanlines.
422      * Here the array is only one element long, but you could ask for
423      * more than one scanline at a time if that's more convenient.
424      */
425     (void) jpeg_read_scanlines(&cinfo, buffer, 1);
426     /* Assume put_scanline_someplace wants a pointer and sample count. */
427     memcpy(im->data+im->channels*im->xsize*(cinfo.output_scanline-1),buffer[0],row_stride);
428   }
429
430   /* Step 7: Finish decompression */
431
432   (void) jpeg_finish_decompress(&cinfo);
433   /* We can ignore the return value since suspension is not possible
434    * with the stdio data source.
435    */
436
437   /* Step 8: Release JPEG decompression object */
438
439   /* This is an important step since it will release a good deal of memory. */
440   jpeg_destroy_decompress(&cinfo);
441
442   /* After finish_decompress, we can close the input file.
443    * Here we postpone it until after no more JPEG errors are possible,
444    * so as to simplify the setjmp error logic above.  (Actually, I don't
445    * think that jpeg_destroy can do an error exit, but why assume anything...)
446    */
447
448 /*  fclose(infile); DO NOT fclose() BECAUSE THEN close() WILL FAIL*/
449
450   /* At this point you may want to check to see whether any corrupt-data
451    * warnings occurred (test whether jerr.pub.num_warnings is nonzero).
452    */
453
454   /* And we're done! */
455
456   *itlength=tlength;
457   mm_log((1,"i_readjpeg -> (0x%x)\n",im));
458   return im;
459 }
460
461
462
463 i_img*
464 i_readjpeg_scalar(char *data, int length,char** iptc_itext,int *itlength) {
465   i_img *im;
466
467   struct jpeg_decompress_struct cinfo;
468   struct my_error_mgr jerr;
469   JSAMPARRAY buffer;            /* Output row buffer */
470   int row_stride;               /* physical row width in output buffer */
471
472   mm_log((1,"i_readjpeg_scalar(data 0x%08x, length %d,iptc_itext 0x%x)\n",data,length,iptc_itext));
473   iptc_text=iptc_itext;
474
475   cinfo.err = jpeg_std_error(&jerr.pub);
476   jerr.pub.error_exit = my_error_exit;
477   jerr.pub.output_message = my_output_message;
478   if (setjmp(jerr.setjmp_buffer)) {
479     jpeg_destroy_decompress(&cinfo); 
480     *iptc_itext=NULL;
481     *itlength=0;
482     return NULL;
483   }
484   
485   jpeg_create_decompress(&cinfo);
486   jpeg_set_marker_processor(&cinfo, JPEG_APP13, APP13_handler);
487   jpeg_scalar_src(&cinfo, data, length );
488   (void) jpeg_read_header(&cinfo, TRUE);
489   (void) jpeg_start_decompress(&cinfo);
490   im=i_img_empty_ch(NULL,cinfo.output_width,cinfo.output_height,cinfo.output_components);
491   row_stride = cinfo.output_width * cinfo.output_components;
492   buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
493   while (cinfo.output_scanline < cinfo.output_height) {
494     (void) jpeg_read_scanlines(&cinfo, buffer, 1);
495     memcpy(im->data+im->channels*im->xsize*(cinfo.output_scanline-1),buffer[0],row_stride);
496   }
497   (void) jpeg_finish_decompress(&cinfo);
498   jpeg_destroy_decompress(&cinfo);
499   *itlength=tlength;
500   mm_log((1,"i_readjpeg_scalar -> (0x%x)\n",im));
501   return im;
502 }
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556 #define JPGS 1024
557
558
559
560 typedef struct {
561   struct jpeg_source_mgr pub;   /* public fields */
562   io_glue *data;
563   JOCTET *buffer;               /* start of buffer */
564   int length;                   /* Do I need this? */
565   boolean start_of_file;        /* have we gotten any data yet? */
566 } wiol_source_mgr;
567
568 typedef wiol_source_mgr *wiol_src_ptr;
569
570 static void
571 wiol_init_source (j_decompress_ptr cinfo) {
572   wiol_src_ptr src = (wiol_src_ptr) cinfo->src;
573   
574   /* We reset the empty-input-file flag for each image,
575    * but we don't clear the input buffer.
576    * This is correct behavior for reading a series of images from one source.
577    */
578   src->start_of_file = TRUE;
579 }
580
581 static boolean
582 wiol_fill_input_buffer(j_decompress_ptr cinfo) {
583   wiol_src_ptr src = (wiol_src_ptr) cinfo->src;
584   ssize_t nbytes; /* We assume that reads are "small" */
585   
586   mm_log((1,"wiol_fill_input_buffer(cinfo 0x%p)\n"));
587   
588   nbytes = src->data->readcb(src->data, src->buffer, JPGS);
589   
590   if (nbytes <= 0) { /* Insert a fake EOI marker */
591     src->pub.next_input_byte = fake_eoi;
592     src->pub.bytes_in_buffer = 2;
593   } else {
594     src->pub.next_input_byte = src->buffer;
595     src->pub.bytes_in_buffer = nbytes;
596   }
597   src->start_of_file = FALSE;
598   return TRUE;
599 }
600
601 static void
602 wiol_skip_input_data (j_decompress_ptr cinfo, long num_bytes) {
603   wiol_src_ptr src = (wiol_src_ptr) cinfo->src;
604   
605   /* Just a dumb implementation for now.  Could use fseek() except
606    * it doesn't work on pipes.  Not clear that being smart is worth
607    * any trouble anyway --- large skips are infrequent.
608    */
609   
610   if (num_bytes > 0) {
611     while (num_bytes > (long) src->pub.bytes_in_buffer) {
612       num_bytes -= (long) src->pub.bytes_in_buffer;
613       (void) wiol_fill_input_buffer(cinfo);
614       /* note we assume that fill_input_buffer will never return FALSE,
615        * so suspension need not be handled.
616        */
617     }
618     src->pub.next_input_byte += (size_t) num_bytes;
619     src->pub.bytes_in_buffer -= (size_t) num_bytes;
620   }
621 }
622
623 static void
624 wiol_term_source (j_decompress_ptr cinfo) {
625   /* no work necessary here */ 
626   wiol_src_ptr src;
627   if (cinfo->src != NULL) {
628     src = (wiol_src_ptr) cinfo->src;
629     myfree(src->buffer);
630   }
631 }
632
633 static void
634 jpeg_wiol_src(j_decompress_ptr cinfo, io_glue *ig, int length) {
635   wiol_src_ptr src;
636   
637   if (cinfo->src == NULL) {     /* first time for this JPEG object? */
638     cinfo->src = (struct jpeg_source_mgr *) (*cinfo->mem->alloc_small) 
639       ((j_common_ptr) cinfo, JPOOL_PERMANENT,sizeof(wiol_source_mgr));
640     src = (wiol_src_ptr) cinfo->src;
641   }
642
643   /* put the request method call in here later */
644   io_glue_commit_types(ig);
645   
646   src         = (wiol_src_ptr) cinfo->src;
647   src->data   = ig;
648   src->buffer = mymalloc( JPGS );
649   src->length = length;
650
651   src->pub.init_source       = wiol_init_source;
652   src->pub.fill_input_buffer = wiol_fill_input_buffer;
653   src->pub.skip_input_data   = wiol_skip_input_data;
654   src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
655   src->pub.term_source       = wiol_term_source;
656   src->pub.bytes_in_buffer   = 0; /* forces fill_input_buffer on first read */
657   src->pub.next_input_byte   = NULL; /* until buffer loaded */
658 }
659
660
661
662
663
664
665
666
667
668
669
670
671 i_img*
672 i_readjpeg_wiol(io_glue *data, int length, char** iptc_itext, int *itlength) {
673   i_img *im;
674
675   struct jpeg_decompress_struct cinfo;
676   struct my_error_mgr jerr;
677   JSAMPARRAY buffer;            /* Output row buffer */
678   int row_stride;               /* physical row width in output buffer */
679
680   mm_log((1,"i_readjpeg_wiol(data 0x%p, length %d,iptc_itext 0x%p)\n", data, iptc_itext));
681
682   iptc_text = iptc_itext;
683   cinfo.err = jpeg_std_error(&jerr.pub);
684   jerr.pub.error_exit     = my_error_exit;
685   jerr.pub.output_message = my_output_message;
686
687   /* Set error handler */
688   if (setjmp(jerr.setjmp_buffer)) {
689     jpeg_destroy_decompress(&cinfo); 
690     *iptc_itext=NULL;
691     *itlength=0;
692     return NULL;
693   }
694   
695   jpeg_create_decompress(&cinfo);
696   jpeg_set_marker_processor(&cinfo, JPEG_APP13, APP13_handler);
697   jpeg_wiol_src(&cinfo, data, length);
698
699   (void) jpeg_read_header(&cinfo, TRUE);
700   (void) jpeg_start_decompress(&cinfo);
701   im=i_img_empty_ch(NULL,cinfo.output_width,cinfo.output_height,cinfo.output_components);
702   row_stride = cinfo.output_width * cinfo.output_components;
703   buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
704   while (cinfo.output_scanline < cinfo.output_height) {
705     (void) jpeg_read_scanlines(&cinfo, buffer, 1);
706     memcpy(im->data+im->channels*im->xsize*(cinfo.output_scanline-1),buffer[0],row_stride);
707   }
708   (void) jpeg_finish_decompress(&cinfo);
709   jpeg_destroy_decompress(&cinfo);
710   *itlength=tlength;
711   mm_log((1,"i_readjpeg_wiol -> (0x%x)\n",im));
712   return im;
713 }
714
715