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