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