1 /*
2  * This software is copyrighted as noted below.  It may be freely copied,
3  * modified, and redistributed, provided that the copyright notice is
4  * preserved on all copies.
5  *
6  * There is no warranty or other guarantee of fitness for this software,
7  * it is provided solely "as is".  Bug reports or fixes may be sent
8  * to the author, who may or may not act on them as he desires.
9  *
10  * You may not include this software in a program or other software product
11  * without supplying the source, or without informing the end-user that the
12  * source is available for no extra charge.
13  *
14  * If you modify this software, you should include a notice giving the
15  * name of the person performing the modification, the date of modification,
16  * and the reason for such modification.
17  */
18 /*
19  * jpeg.c - interface with the JPEG format.
20  *
21  * Author:      Raul Rivero
22  *              Mathematics Dept.
23  *              University of Oviedo
24  * Date:        Fri Mar 12 1993
25  * Copyright (c) 1993, Raul Rivero
26  *
27  */
28 /*
29  * Raul Rivero  -  09/26/94
30  *
31  *      New code has been added to support the new "The Independent JPEG
32  *      Group's Library", the 5.?.
33  *
34  *      There is a problem to known the version of the IJL library, the
35  *      include headers have changed ( jinclude.h --> jpeglib.h ) so we
36  *      cannot get the version from the JPEG_LIB_VERSION define.
37  *
38  *      You'll need define iJPEGNEW to get the new code, sorry :).
39  *
40  */
41 
42 #include <lug.h>
43 #include <lugfnts.h>
44 
45 
46 /*
47  * Look here !!!
48  * =============
49  *
50  * This code is valid only if we have defined the iJPEG or iJPEGNEW
51  * macro ( read the root Makefile for more information ).
52  *
53  */
54 
55 #ifdef iJPEG
56 
57 #include <jinclude.h>
58 
59 static bitmap_hdr *jpeg_image;
60 byte *jpeg_r, *jpeg_g, *jpeg_b;
61 extern int LUGverbose;
62 
63 /*
64  * Predefine what we'll need.
65  */
66 void
67 set_jpeg_header(
68 #ifdef USE_PROTOTYPES
69         compress_info_ptr
70 #endif
71 );
72 
73 void
74 set_jpeg_row(
75 #ifdef USE_PROTOTYPES
76         compress_info_ptr ,
77         JSAMPARRAY
78 #endif
79 );
80 
81 void
82 end_set_jpeg(
83 #ifdef USE_PROTOTYPES
84         compress_info_ptr
85 #endif
86 );
87 
88 void
89 c_ui_method_selection(
90 #ifdef USE_PROTOTYPES
91         compress_info_ptr
92 #endif
93 );
94 
95 void
96 get_jpeg_header(
97 #ifdef USE_PROTOTYPES
98         decompress_info_ptr
99 #endif
100 );
101 
102 void
103 get_jpeg_cmap(
104 #ifdef USE_PROTOTYPES
105         decompress_info_ptr ,
106         int ,
107         JSAMPARRAY
108 #endif
109 );
110 
111 void
112 get_jpeg_row(
113 #ifdef USE_PROTOTYPES
114         decompress_info_ptr ,
115         int ,
116         JSAMPIMAGE
117 #endif
118 );
119 
120 void
121 end_put_jpeg(
122 #ifdef USE_PROTOTYPES
123         decompress_info_ptr
124 #endif
125 );
126 
127 void
128 d_ui_method_selection(
129 #ifdef USE_PROTOTYPES
130         decompress_info_ptr
131 #endif
132 );
133 
134 
write_jpeg_file(name,bitmap)135 write_jpeg_file( name, bitmap )
136 char *name;
137 bitmap_hdr *bitmap;
138 {
139   FILE *handle;
140 
141   if ( name )
142     handle = (FILE *) Fopen( name, "wb" );
143   else handle = stdout;
144 
145   /* Do it ! */
146   write_jpeg( handle, bitmap );
147 
148   Fclose( handle );
149 }
150 
write_jpeg(handle,bitmap)151 write_jpeg( handle, bitmap )
152 FILE *handle;
153 bitmap_hdr *bitmap;
154 {
155   /* Write the JPEG image with a quality = 75 */
156   write_jpeg_opt( handle, bitmap, 75 );
157 }
158 
write_jpeg_opt(handle,bitmap,quality)159 write_jpeg_opt( handle, bitmap, quality )
160 FILE *handle;
161 bitmap_hdr *bitmap;
162 int quality;
163 {
164   struct Compress_info_struct cinfo;
165   struct Compress_methods_struct c_methods;
166   struct External_methods_struct e_methods;
167 
168   if ( bitmap->magic != LUGUSED )
169     error( 19 );
170 
171   VPRINTF( stderr, "Writing a JPEG image ( quality = %d )\n", quality );
172   /* Initialize the system-dependent method pointers. */
173   cinfo.methods = &c_methods;   /* links to method structs */
174   cinfo.emethods = &e_methods;
175 
176   /* Select std error/trace message & memory allocation routines */
177   jselerror( &e_methods );
178   jselmemmgr( &e_methods );
179 
180   /* Initialize pointer to raw data */
181   jpeg_image = bitmap;
182   jpeg_r = jpeg_image->r;
183   jpeg_g = jpeg_image->g;
184   jpeg_b = jpeg_image->b;
185 
186   /* Define our own routines for input data handling */
187   c_methods.input_init    = set_jpeg_header;
188   c_methods.get_input_row = set_jpeg_row;
189   c_methods.input_term    = end_set_jpeg;
190   c_methods.c_ui_method_selection = c_ui_method_selection;
191 
192   /* Set up JPEG parameters in the cinfo data structure. */
193   j_c_defaults( &cinfo, quality, FALSE );
194 #ifdef ENTROPY_OPT_SUPPORTED
195   /* Best results */
196   cinfo.optimize_coding = TRUE;
197 #endif
198 
199   /* No input file */
200   cinfo.input_file = NULL;
201 
202   /* Assign the output file */
203   cinfo.output_file = handle;
204 
205   /* Here we go! */
206   VPRINTF( stderr, "Encoding JPEG\n" );
207   jpeg_compress( &cinfo );
208 }
209 
210 void
set_jpeg_header(cinfo)211 set_jpeg_header( cinfo )
212 compress_info_ptr cinfo;
213 /* Initialize for input; return image size and component data. */
214 {
215   cinfo->image_width  = jpeg_image->xsize;
216   cinfo->image_height = jpeg_image->ysize;
217   cinfo->input_components = 3;          /* or 1 for grayscale */
218   cinfo->in_color_space = CS_RGB;       /* or CS_GRAYSCALE for grayscale */
219   cinfo->data_precision = 8;            /* bits per pixel component value */
220 }
221 
222 void
set_jpeg_row(cinfo,pixel_row)223 set_jpeg_row( cinfo, pixel_row )
224 compress_info_ptr cinfo;
225 JSAMPARRAY pixel_row;
226 /* Read next row of pixels into pixel_row[][] */
227 {
228   register FILE * infile = cinfo->input_file;
229   register JSAMPROW ptr0, ptr1, ptr2;
230   register long col;
231 
232   ptr0 = pixel_row[0];
233   ptr1 = pixel_row[1];
234   ptr2 = pixel_row[2];
235   for (col = 0; col < cinfo->image_width; col++) {
236     *ptr0++ = (JSAMPLE) *jpeg_r++; /* red */
237     *ptr1++ = (JSAMPLE) *jpeg_g++; /* green */
238     *ptr2++ = (JSAMPLE) *jpeg_b++; /* blue */
239   }
240 }
241 
242 void
end_set_jpeg(cinfo)243 end_set_jpeg( cinfo )
244 compress_info_ptr cinfo;
245 /* Finish up at the end of the input */
246 {
247   /* Defined only for compatibility reasons */
248   VPRINTF( stderr, "JPEG process finished\n" );
249 }
250 
251 void
c_ui_method_selection(cinfo)252 c_ui_method_selection( cinfo )
253 compress_info_ptr cinfo;
254 {
255   /* If the input is gray scale, generate a monochrome JPEG file. */
256   if (cinfo->in_color_space == CS_GRAYSCALE)
257     j_monochrome_default(cinfo);
258   /* For now, always select JFIF output format. */
259   jselwjfif(cinfo);
260 }
261 
read_jpeg_file(name,bitmap)262 read_jpeg_file( name, bitmap )
263 char *name;
264 bitmap_hdr *bitmap;
265 {
266   FILE *handle;
267 
268   /* Open the file descriptor */
269   if ( name != NULL )
270     handle = Fopen( name, "rb" );
271   else handle = stdin;
272 
273   /* Read the bitmap */
274   read_jpeg( handle, bitmap );
275   rm_compress();
276 
277   /* Close the file */
278   Fclose( handle );
279 }
280 
read_jpeg(handle,bitmap)281 read_jpeg( handle, bitmap )
282 FILE *handle;
283 bitmap_hdr *bitmap;
284 {
285   struct Decompress_info_struct cinfo;
286   struct Decompress_methods_struct dc_methods;
287   struct External_methods_struct e_methods;
288 
289   jpeg_image = bitmap;
290 
291   cinfo.input_file = handle;
292   cinfo.output_file = NULL;     /* if no actual output file involved */
293 
294   /* Initialize the system-dependent method pointers. */
295   cinfo.methods  = &dc_methods;
296   cinfo.emethods = &e_methods;
297 
298   /* Select std error/trace message & memory allocation routines */
299   jselerror( &e_methods );
300   jselmemmgr( &e_methods );
301 
302   dc_methods.d_ui_method_selection = d_ui_method_selection;
303 
304   /* Set up default decompression parameters. */
305   j_d_defaults( &cinfo, TRUE );
306 
307   /* Set up to read a JFIF or baseline-JPEG file. */
308   jselrjfif( &cinfo );
309 
310   /* Here we go! */
311   jpeg_decompress( &cinfo );
312 }
313 
314 void
get_jpeg_header(cinfo)315 get_jpeg_header( cinfo )
316 decompress_info_ptr cinfo;
317 /* This routine should do any setup required */
318 {
319   int totalsize = cinfo->image_width * cinfo->image_height;
320 
321   VPRINTF( stderr, "Reading JPEG header\n" );
322   /* Fill our bitmap header */
323   jpeg_image->xsize  = cinfo->image_width;
324   jpeg_image->ysize  = cinfo->image_height;
325   jpeg_image->depth  = 24;
326   jpeg_image->colors = ( 1 << jpeg_image->depth );
327   jpeg_image->magic  = LUGUSED;
328 
329   /* Alloc memory */
330   jpeg_r = jpeg_image->r = (byte *) Malloc( totalsize );
331   jpeg_g = jpeg_image->g = (byte *) Malloc( totalsize );
332   jpeg_b = jpeg_image->b = (byte *) Malloc( totalsize );
333 }
334 
335 void
get_jpeg_cmap(cinfo,num_colors,colormap)336 get_jpeg_cmap( cinfo, num_colors, colormap )
337 decompress_info_ptr cinfo;
338 int num_colors;
339 JSAMPARRAY colormap;
340 /* Write the color map */
341 {
342   /* You need not provide this routine if you always set cinfo->quantize_colors
343    * FALSE; but a safer practice is to provide it and have it just print an
344    * error message, like this:
345    */
346   fprintf(stderr, "get_jpeg_camp called: there's a bug here somewhere!\n");
347 }
348 
349 void
get_jpeg_row(cinfo,num_rows,pixel_data)350 get_jpeg_row( cinfo, num_rows, pixel_data )
351 decompress_info_ptr cinfo;
352 int num_rows;
353 JSAMPIMAGE pixel_data;
354 /* Write some rows of output data */
355 {
356   register FILE * outfile = cinfo->output_file;
357   register JSAMPROW ptr0, ptr1, ptr2;
358   register long col;
359   register int row;
360 
361   VPRINTF( stderr, "\rUncoding JPEG ( position %d )",
362            jpeg_r - jpeg_image->r );
363   VFLUSH( stderr );
364   for ( row = 0; row < num_rows; row++ ) {
365     ptr0 = pixel_data[0][row];
366     ptr1 = pixel_data[1][row];
367     ptr2 = pixel_data[2][row];
368     for ( col = 0; col < cinfo->image_width; col++ ) {
369       *jpeg_r++ = GETJSAMPLE(*ptr0); ptr0++;    /* red */
370       *jpeg_g++ = GETJSAMPLE(*ptr1); ptr1++;    /* green */
371       *jpeg_b++ = GETJSAMPLE(*ptr2); ptr2++;    /* blue */
372     }
373   }
374 }
375 
376 void
end_put_jpeg(cinfo)377 end_put_jpeg( cinfo )
378 decompress_info_ptr cinfo;
379 /* Finish up at the end of the input */
380 {
381   /* Defined only for compatibility reasons */
382   VPRINTF( stderr, "\nJPEG process finished\n" );
383 }
384 
385 void
d_ui_method_selection(cinfo)386 d_ui_method_selection( cinfo )
387 decompress_info_ptr cinfo;
388 {
389   /* if grayscale input, force grayscale output; */
390   /* else leave the output colorspace as set by main routine. */
391   if (cinfo->jpeg_color_space == CS_GRAYSCALE)
392     cinfo->out_color_space = CS_GRAYSCALE;
393 
394   /* select output routines */
395   cinfo->methods->output_init = get_jpeg_header;
396   cinfo->methods->put_color_map = get_jpeg_cmap;
397   cinfo->methods->put_pixel_rows = get_jpeg_row;
398   cinfo->methods->output_term = end_put_jpeg;
399 }
400 
401 
402 #else  /* iJPEG */
403 
404 #  ifdef iJPEGNEW
405 
406 #include <jpeglib.h>
407 #include <jerror.h>
408 
409 extern LUGverbose;
410 
411 
read_jpeg_file(name,bitmap)412 read_jpeg_file( name, bitmap )
413 char *name;
414 bitmap_hdr *bitmap;
415 {
416   FILE *handle;
417 
418   /* Open the file descriptor */
419   if ( name != NULL )
420     handle = Fopen( name, "rb" );
421   else handle = stdin;
422 
423   /* Read the bitmap */
424   read_jpeg( handle, bitmap );
425   rm_compress();
426 
427   /* Close the file */
428   Fclose( handle );
429 }
430 
read_jpeg(handle,bitmap)431 read_jpeg( handle, bitmap )
432 FILE *handle;
433 bitmap_hdr *bitmap;
434 {
435   int i, j;
436   struct jpeg_decompress_struct cinfo;
437   struct jpeg_error_mgr jerr;
438   byte *rptr, *gptr, *bptr;
439   JSAMPLE *rgb_aux[1], *aux_ptr;
440 
441   /* Use the default IJL's error handlers */
442   cinfo.err = jpeg_std_error( &jerr );
443 
444   /* Create the decompression object */
445  jpeg_create_decompress( &cinfo );
446 
447   /* Read the file's header ... */
448   jpeg_stdio_src( &cinfo, handle );
449   (void) jpeg_read_header( &cinfo, TRUE );
450 
451   /* ... and fill our header */
452   bitmap->magic = LUGUSED;
453   bitmap->xsize = cinfo.image_width;
454   bitmap->ysize = cinfo.image_height;
455 
456   VPRINTF( stderr, "Reading a JPEG image\n" );
457   VPRINTF( stderr, "\t%dx%d pixels\n", bitmap->xsize, bitmap->ysize );
458 
459   /* What kind of image ? */
460   switch ( cinfo.num_components ) {
461     case 1:
462 	/* A grayscaled image */
463         bitmap->depth  = 8;
464         bitmap->colors = 1 << bitmap->depth;
465         bitmap->cmap   = create_bw_pallete();
466         rptr = bitmap->r = (byte *) Malloc( bitmap->xsize * bitmap->ysize );
467         VPRINTF( stderr, "\tgrayscaled colorspace\n");
468         break;
469     case 3:
470     case 4:
471         /* A true color image */
472         bitmap->depth  = 24;
473         bitmap->colors = 1 << bitmap->depth;
474         rptr = bitmap->r = (byte *) Malloc( bitmap->xsize * bitmap->ysize );
475         gptr = bitmap->g = (byte *) Malloc( bitmap->xsize * bitmap->ysize );
476         bptr = bitmap->b = (byte *) Malloc( bitmap->xsize * bitmap->ysize );
477         /* We wanna rgb values from the IJL routines */
478         cinfo.out_color_space = JCS_RGB;
479         VPRINTF( stderr, "\ttrue color space\n" );
480         break;
481     default:
482         /* Hmmmmmmm ?! */
483         jpeg_destroy_decompress( &cinfo );
484         /* Unset the LUG mark */
485         bitmap->magic = LUGUSED - 1;
486         fprintf( stderr, "I don't know how to handle %d components in a JPEG file\n",
487                  cinfo.num_components );
488         error( 99 );
489         return;  /* not used now, but ... */
490         break;
491   }
492 
493   /* Start decompressor */
494   jpeg_start_decompress( &cinfo );
495   VPRINTF( stderr, "\tdecompressor started\n" );
496 
497   /* Get memory for our tmp array */
498   rgb_aux[0] = (JSAMPLE *) Malloc( sizeof(JSAMPLE) * cinfo.output_width * cinfo.output_components );
499 
500   j = 0;
501   while ( cinfo.output_scanline < cinfo.output_height ) {
502     /* Get the next sacnline */
503     (void) jpeg_read_scanlines( &cinfo, rgb_aux, 1 );
504     if ( ++j % 10 == 0 ) {
505       VPRINTF( stderr, "\r\tprocessing line %d",
506                cinfo.output_scanline);
507       VFLUSH( stderr );
508       j = 0;
509     }
510     /* Unpack it */
511     for ( i = 0, aux_ptr = rgb_aux[0]; i < bitmap->xsize; i++ ) {
512       *rptr++ = *aux_ptr++;
513       if ( cinfo.output_components == 3 ) {
514         *gptr++ = *aux_ptr++;
515         *bptr++ = *aux_ptr++;
516       }
517     }
518   }
519 
520   VPRINTF( stderr, "\r\tprocessed %d lines   \n\tdone.\n", cinfo.output_scanline);
521 
522   /* Release our memory */
523   Free( rgb_aux[0] );
524 
525   /* Say bye to the decompressor :) */
526   (void) jpeg_finish_decompress( &cinfo );
527   jpeg_destroy_decompress( &cinfo );
528 }
529 
530 
write_jpeg_file(name,bitmap)531 write_jpeg_file( name, bitmap )
532 char *name;
533 bitmap_hdr *bitmap;
534 {
535   FILE *handle;
536 
537   if ( name )
538     handle = (FILE *) Fopen( name, "wb" );
539   else handle = stdout;
540 
541   /* Do it ! */
542   write_jpeg( handle, bitmap );
543 
544   Fclose( handle );
545 }
546 
write_jpeg(handle,bitmap)547 write_jpeg( handle, bitmap )
548 FILE *handle;
549 bitmap_hdr *bitmap;
550 {
551   /* Write the JPEG image with a quality = 75 */
552   write_jpeg_opt( handle, bitmap, 75 );
553 }
554 
write_jpeg_opt(handle,bitmap,quality)555 write_jpeg_opt( handle, bitmap, quality )
556 FILE *handle;
557 bitmap_hdr *bitmap;
558 int quality;
559 {
560   int i, j;
561   struct jpeg_compress_struct cinfo;
562   struct jpeg_error_mgr jerr;
563   byte *rptr, *gptr, *bptr;
564   JSAMPLE *rgb_aux[1], *aux_ptr;
565 
566 
567   if ( bitmap->magic != LUGUSED )
568     error( 19 );
569 
570   /* We need a true color or gray mapped image. Really ? */
571   if ( bitmap->depth < 24 && !isagrayscaled(bitmap) ){
572     /*
573      * Ok, we have a mapped image ==> not supported. So it'll be converted
574      * to true clor and ... voila.
575      */
576     bitmap_hdr out;
577 
578     to24( bitmap, &out );
579     write_jpeg_opt( handle, &out, quality );
580     return 1;
581   }
582 
583   /* Use the default IJL's error handlers */
584   cinfo.err = jpeg_std_error( &jerr );
585 
586   /* Create the compression object */
587  jpeg_create_compress( &cinfo );
588 
589   /* The destination is ... */
590   jpeg_stdio_dest( &cinfo, handle );
591 
592   /* Fill the IJL's image header */
593   cinfo.image_width = bitmap->xsize;
594   cinfo.image_height = bitmap->ysize;
595   cinfo.input_components = ( bitmap->depth < 24 ? 1 : 3 );
596   cinfo.in_color_space = ( bitmap->depth < 24 ? JCS_GRAYSCALE : JCS_RGB );
597 
598   VPRINTF( stderr, "Writting a JPEG file\n" );
599   VPRINTF( stderr, "\t%dx%d pixels\n", bitmap->xsize, bitmap->ysize );
600   VPRINTF( stderr, "\t%s color space\n",
601            ( bitmap->depth < 24 ? "JCS_GRAYSCALE" : "JCS_RGB" ));
602 
603   /* Fix these stored values and the quality */
604   jpeg_set_defaults( &cinfo );
605   jpeg_set_quality( &cinfo, quality, TRUE );
606   VPRINTF( stderr, "\tquality fixed to %d\n", quality );
607 
608   /* Start the compressor */
609   jpeg_start_compress(&cinfo, TRUE);
610   VPRINTF( stderr, "\tcompressor started\n" );
611 
612   /* Get memory for our tmp array */
613   rgb_aux[0] = (JSAMPLE *) Malloc( sizeof(JSAMPLE) * cinfo.image_width * cinfo.input_components );
614 
615   /* Initialize our pointers */
616   rptr = bitmap->r;
617   if ( cinfo.input_components == 3 ) {
618     gptr = bitmap->g;
619     bptr = bitmap->b;
620   }
621 
622   /* And ... the loop! :) */
623   while (cinfo.next_scanline < cinfo.image_height) {
624     if ( ++j % 10 == 0 ) {
625       VPRINTF( stderr, "\r\tprocessing line %d",
626                cinfo.next_scanline);
627       VFLUSH( stderr );
628       j = 0;
629     }
630     /* Pack the r-g-b data */
631     for ( i = 0, aux_ptr = rgb_aux[0]; i < bitmap->xsize; i++ ) {
632       *aux_ptr++ = *rptr++;
633       if ( cinfo.input_components == 3 ) {
634         *aux_ptr++ = *gptr++;
635         *aux_ptr++ = *bptr++;
636       }
637     }
638     (void) jpeg_write_scanlines( &cinfo, rgb_aux, 1 );
639   }
640 
641   VPRINTF( stderr, "\r\tprocessed %d lines   \n\tdone.\n", cinfo.image_height );
642 
643   /* Free our memory */
644   Free( rgb_aux[0] );
645 
646   /* And close the compressor */
647   jpeg_finish_compress( &cinfo );
648   jpeg_destroy_compress( &cinfo );
649 
650   return 1;
651 }
652 
653 #  endif  /* iJPEGNEW */
654 
655 #endif  /* iJPEG */
656