1 # include "bitmapConfig.h"
2
3 # include <stdlib.h>
4 # include <stdio.h>
5 # include <sioFileio.h>
6 # include "bmintern.h"
7 # include "bmio.h"
8 # include <time.h>
9
10 # include <jpeglib.h>
11 # include <setjmp.h>
12 # include <jerror.h>
13
14 # include <appDebugon.h>
15
16 /************************************************************************/
17 /* */
18 /* Declare additional routines. */
19 /* */
20 /************************************************************************/
21
22 # define INPUT_BUF_SIZE 4096
23 # define OUTPUT_BUF_SIZE 4096
24
25 typedef struct my_error_mgr
26 {
27 struct jpeg_error_mgr pub; /* "public" fields */
28 jmp_buf setjmp_buffer; /* for return to caller */
29 } my_error_mgr;
30
my_error_exit(j_common_ptr cinfo)31 static void my_error_exit (j_common_ptr cinfo)
32 {
33 /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
34 my_error_mgr * myerr = (my_error_mgr *) cinfo->err;
35
36 /* Always display the message. */
37 /* We could postpone this until after returning, if we chose. */
38 (*cinfo->err->output_message) (cinfo);
39
40 /* Return control to the setjmp point */
41 longjmp(myerr->setjmp_buffer, 1);
42 }
43
44 typedef struct BmJpegInputSource
45 {
46 struct jpeg_source_mgr pub; /* public fields */
47
48 BitmapDescription bjisBd;
49 unsigned char * bjisBitmapBuffer;
50 SimpleInputStream * bjisSis;
51 int bjisRowsReceived;
52
53 JOCTET * bjisReadBuffer;
54 int bjisAtBeginOfInput;
55 } BmJpegInputSource;
56
57 static int read_JPEG_file ( BmJpegInputSource * bjis );
58
59 /************************************************************************/
60
61 typedef struct BmJpegOutputDestination
62 {
63 struct jpeg_destination_mgr pub; /* public fields */
64
65 const BitmapDescription * bjodBd;
66 const unsigned char * bjodBuffer;
67 SimpleOutputStream * bjodSos;
68
69 unsigned char * bjodScratchBuffer;
70 JOCTET * bjodWriteBuffer;
71 } BmJpegOutputDestination;
72
73 typedef struct
74 {
75 struct jpeg_destination_mgr pub; /* public fields */
76 BmJpegOutputDestination * bjod; /* destination stream */
77 JOCTET * buffer; /* start of buffer */
78 } my_destination_mgr;
79
80 typedef my_destination_mgr * my_dest_ptr;
81
82 static int write_JPEG_file ( BmJpegOutputDestination * bjod );
83
84 /**/
85
86 /************************************************************************/
87 /* */
88 /* Read a JPEG File. */
89 /* */
90 /************************************************************************/
91
bmJpegStartInputSource(j_decompress_ptr cinfo)92 static void bmJpegStartInputSource( j_decompress_ptr cinfo )
93 {
94 BmJpegInputSource * bjis= (BmJpegInputSource *)cinfo->src;
95
96 bjis->bjisAtBeginOfInput= TRUE;
97
98 return;
99 }
100
bmJpegTerminateInputSource(j_decompress_ptr cinfo)101 static void bmJpegTerminateInputSource( j_decompress_ptr cinfo )
102 {
103 return;
104 }
105
bmJpegFillInputBuffer(j_decompress_ptr cinfo)106 static boolean bmJpegFillInputBuffer( j_decompress_ptr cinfo )
107 {
108 BmJpegInputSource * bjis= (BmJpegInputSource *)cinfo->src;
109 size_t nbytes;
110
111 nbytes= sioInReadBytes( bjis->bjisSis,
112 bjis->bjisReadBuffer, INPUT_BUF_SIZE );
113
114 if ( nbytes <= 0 )
115 {
116 if ( bjis->bjisAtBeginOfInput ) /* Treat empty input */
117 /* file as fatal error */
118 { ERREXIT( cinfo, JERR_INPUT_EMPTY ); }
119
120 WARNMS(cinfo, JWRN_JPEG_EOF);
121
122 /* Insert a fake EOI marker */
123 bjis->bjisReadBuffer[0] = (JOCTET) 0xFF;
124 bjis->bjisReadBuffer[1] = (JOCTET) JPEG_EOI;
125 nbytes = 2;
126 }
127
128 bjis->pub.next_input_byte= bjis->bjisReadBuffer;
129 bjis->pub.bytes_in_buffer= nbytes;
130 bjis->bjisAtBeginOfInput= FALSE;
131
132 return TRUE;
133 }
134
bmJpegSkipInputData(j_decompress_ptr cinfo,long num_bytes)135 static void bmJpegSkipInputData( j_decompress_ptr cinfo,
136 long num_bytes )
137 {
138 BmJpegInputSource * bjis= (BmJpegInputSource *)cinfo->src;
139
140 if ( num_bytes > 0 )
141 {
142 while( num_bytes > (long) bjis->pub.bytes_in_buffer )
143 {
144 num_bytes -= (long) bjis->pub.bytes_in_buffer;
145 (void) bmJpegFillInputBuffer( cinfo );
146 }
147
148 bjis->pub.next_input_byte += (size_t) num_bytes;
149 bjis->pub.bytes_in_buffer -= (size_t) num_bytes;
150 }
151 }
152
153 /************************************************************************/
154 /* */
155 /* Copy file information to the communication data areas */
156 /* */
157 /************************************************************************/
158
bmJpegGetReadParameters(struct jpeg_decompress_struct * cinfo)159 static int bmJpegGetReadParameters(
160 struct jpeg_decompress_struct * cinfo )
161 {
162 BmJpegInputSource * bjis= (BmJpegInputSource *)cinfo->src;
163
164 bjis->bjisBd.bdPixelsWide= cinfo->image_width;
165 bjis->bjisBd.bdPixelsHigh= cinfo->image_height;
166 bjis->bjisBd.bdBitsPerSample= cinfo->data_precision;
167
168 switch( cinfo->density_unit )
169 {
170 case 0:
171 /* LDEB(cinfo->density_unit); */
172 if ( cinfo->X_density == 1 && cinfo->Y_density == 1 )
173 {
174 int xd;
175 int yd;
176
177 if ( cinfo->image_width >= cinfo->image_height )
178 {
179 xd= ( 100* cinfo->image_width )/ 16;
180 yd= ( 100* cinfo->image_height )/ 12;
181 }
182 else{
183 xd= ( 100* cinfo->image_width )/ 12;
184 yd= ( 100* cinfo->image_height )/ 16;
185 }
186
187 if ( xd > yd ) { yd= xd; }
188 else { xd= yd; }
189
190 if ( xd > 80 )
191 {
192 xd= 100* ( ( xd+ 20 )/ 100 );
193 yd= 100* ( ( yd+ 20 )/ 100 );
194
195 bjis->bjisBd.bdUnit= BMunM;
196 bjis->bjisBd.bdXResolution= xd;
197 bjis->bjisBd.bdYResolution= yd;
198 break;
199 }
200 }
201
202 if ( cinfo->X_density < 5 || cinfo->Y_density < 5 )
203 {
204 pixel_density:
205 bjis->bjisBd.bdUnit= BMunPIXEL;
206 bjis->bjisBd.bdXResolution= 1;
207 bjis->bjisBd.bdYResolution= 1;
208 }
209 else{
210 bjis->bjisBd.bdUnit= BMunINCH;
211 bjis->bjisBd.bdXResolution= cinfo->X_density;
212 bjis->bjisBd.bdYResolution= cinfo->Y_density;
213 }
214 break;
215
216 case 1:
217 if ( cinfo->X_density < 5 || cinfo->Y_density < 5 )
218 {
219 LLLDEB(cinfo->density_unit,cinfo->X_density,cinfo->Y_density);
220 goto pixel_density;
221 }
222
223 bjis->bjisBd.bdUnit= BMunINCH;
224 bjis->bjisBd.bdXResolution= cinfo->X_density;
225 bjis->bjisBd.bdYResolution= cinfo->Y_density;
226 break;
227
228 case 2:
229 if ( cinfo->X_density < 2 || cinfo->Y_density < 2 )
230 {
231 LLLDEB(cinfo->density_unit,cinfo->X_density,cinfo->Y_density);
232 goto pixel_density;
233 }
234
235 bjis->bjisBd.bdUnit= BMunM;
236 bjis->bjisBd.bdXResolution= 100* cinfo->X_density;
237 bjis->bjisBd.bdYResolution= 100* cinfo->Y_density;
238 break;
239
240 default:
241 LDEB(cinfo->density_unit);
242 return -1;
243 break;
244 }
245
246 switch( cinfo->out_color_space )
247 {
248 case JCS_GRAYSCALE:
249 bjis->bjisBd.bdColorEncoding= BMcoWHITEBLACK;
250 bjis->bjisBd.bdSamplesPerPixel= 1;
251 bjis->bjisBd.bdBitsPerPixel= bjis->bjisBd.bdBitsPerSample;
252 break;
253
254 case JCS_RGB:
255 if ( cinfo->jpeg_color_space == JCS_GRAYSCALE )
256 {
257 cinfo->out_color_space= cinfo->jpeg_color_space;
258
259 bjis->bjisBd.bdColorEncoding= BMcoWHITEBLACK;
260 bjis->bjisBd.bdSamplesPerPixel= 1;
261 bjis->bjisBd.bdBitsPerPixel= bjis->bjisBd.bdBitsPerSample;
262 }
263 else{
264 bjis->bjisBd.bdColorEncoding= BMcoRGB;
265 bjis->bjisBd.bdSamplesPerPixel= 3;
266 bjis->bjisBd.bdBitsPerPixel= 3* bjis->bjisBd.bdBitsPerSample;
267 }
268 break;
269
270 case JCS_UNKNOWN:
271 LLDEB(JCS_UNKNOWN,cinfo->out_color_space); return -1;
272 case JCS_YCbCr:
273 LLDEB(JCS_YCbCr,cinfo->out_color_space); return -1;
274 case JCS_YCCK:
275 LLDEB(JCS_YCCK,cinfo->out_color_space); return -1;
276 case JCS_CMYK:
277 /* Illegal Inverted CMYK file from photoshop. */
278 LLDEB(JCS_CMYK,cinfo->out_color_space);
279 bjis->bjisBd.bdColorEncoding= BMcoRGB;
280 bjis->bjisBd.bdSamplesPerPixel= 3;
281 bjis->bjisBd.bdBitsPerPixel= 3* bjis->bjisBd.bdBitsPerSample;
282 break;
283 default:
284 LDEB(cinfo->out_color_space); return -1;
285 }
286
287 bjis->bjisBd.bdBytesPerRow= ( bjis->bjisBd.bdPixelsWide*
288 bjis->bjisBd.bdBitsPerPixel+ 7 )/8;
289 bjis->bjisBd.bdBufferLength= bjis->bjisBd.bdPixelsHigh*
290 bjis->bjisBd.bdBytesPerRow;
291
292 bjis->bjisBitmapBuffer= (unsigned char *)
293 malloc( bjis->bjisBd.bdBufferLength );
294 if ( ! bjis->bjisBitmapBuffer )
295 {
296 LLDEB(bjis->bjisBd.bdBufferLength,bjis->bjisBitmapBuffer);
297 return -1;
298 }
299
300 bjis->bjisRowsReceived= 0;
301
302 return 0;
303 }
304
305 /************************************************************************/
306 /* */
307 /* Remember one row of pixels. */
308 /* */
309 /************************************************************************/
310
bmJpegRememberScanline(JSAMPARRAY pixel_data,struct jpeg_decompress_struct * cinfo)311 static int bmJpegRememberScanline( JSAMPARRAY pixel_data,
312 struct jpeg_decompress_struct * cinfo )
313 {
314 BmJpegInputSource * bjis= (BmJpegInputSource *)cinfo->src;
315
316 unsigned char * to;
317 register JSAMPROW ptr0;
318 long col;
319
320 switch( cinfo->out_color_space )
321 {
322 case JCS_GRAYSCALE:
323 switch( bjis->bjisBd.bdBitsPerSample )
324 {
325 case 8:
326 to= bjis->bjisBitmapBuffer+
327 bjis->bjisBd.bdBytesPerRow*
328 (bjis->bjisRowsReceived++);
329
330 ptr0 = pixel_data[0];
331
332 for ( col = 0; col < cinfo->image_width; col++ )
333 { *(to++)= GETJSAMPLE(*(ptr0++)); }
334 break;
335 default:
336 LDEB(bjis->bjisBd.bdBitsPerSample);
337 return -1;
338 }
339 break;
340
341 case JCS_RGB:
342 switch( bjis->bjisBd.bdBitsPerSample )
343 {
344 case 8:
345 to= bjis->bjisBitmapBuffer+
346 bjis->bjisBd.bdBytesPerRow*
347 (bjis->bjisRowsReceived++);
348
349 ptr0 = pixel_data[0];
350
351 for ( col = 0; col < cinfo->image_width; col++ )
352 {
353 *(to++)= GETJSAMPLE(*(ptr0++)); /* red */
354 *(to++)= GETJSAMPLE(*(ptr0++)); /* green */
355 *(to++)= GETJSAMPLE(*(ptr0++)); /* blue */
356 }
357 break;
358 default:
359 LDEB(bjis->bjisBd.bdBitsPerSample);
360 return -1;
361 }
362 break;
363
364 case JCS_CMYK:
365 /************************************************************/
366 /* Illegal Inverted CMYK file from photoshop. */
367 /* Very much approximate: only to get the image on screen. */
368 /* Ted tries to emit the image to PostScript as jpeg */
369 /* anyway. (Though jfif requires YCbCr) */
370 /************************************************************/
371 switch( bjis->bjisBd.bdBitsPerSample )
372 {
373 case 8:
374 to= bjis->bjisBitmapBuffer+
375 bjis->bjisBd.bdBytesPerRow*
376 (bjis->bjisRowsReceived++);
377
378 ptr0 = pixel_data[0];
379
380 for ( col = 0; col < cinfo->image_width; col++ )
381 {
382 int c= 255- GETJSAMPLE(*(ptr0++));
383 int m= 255- GETJSAMPLE(*(ptr0++));
384 int y= 255- GETJSAMPLE(*(ptr0++));
385 int k= 255- GETJSAMPLE(*(ptr0++));
386
387 c= c- (c*k)/255+ k;
388 m= m- (m*k)/255+ k;
389 y= y- (y*k)/255+ k;
390
391 *(to++)= 255- c; /* red */
392 *(to++)= 255- m; /* green */
393 *(to++)= 255- y; /* blue */
394 }
395 break;
396
397 default:
398 LDEB(bjis->bjisBd.bdBitsPerSample);
399 return -1;
400 }
401 break;
402
403 case JCS_UNKNOWN:
404 case JCS_YCbCr:
405 case JCS_YCCK:
406 LDEB(cinfo->out_color_space);
407 return -1;
408 break;
409
410 default:
411 LDEB(cinfo->out_color_space);
412 return -1;
413 break;
414 }
415
416 return 0;
417 }
418
bmJpegReadJfif(BitmapDescription * bd,unsigned char ** pBuffer,SimpleInputStream * sis)419 int bmJpegReadJfif( BitmapDescription * bd,
420 unsigned char ** pBuffer,
421 SimpleInputStream * sis )
422 {
423 BmJpegInputSource bjis;
424
425 bmInitDescription( &(bjis.bjisBd) );
426
427 bjis.bjisBitmapBuffer= (unsigned char *)0;
428 bjis.bjisSis= (SimpleInputStream *)0;
429 bjis.bjisRowsReceived= 0;
430
431 bjis.pub.init_source= bmJpegStartInputSource;
432 bjis.pub.fill_input_buffer= bmJpegFillInputBuffer;
433 bjis.pub.skip_input_data= bmJpegSkipInputData;
434 bjis.pub.resync_to_restart= jpeg_resync_to_restart;
435 /* use default method */
436 bjis.pub.term_source= bmJpegTerminateInputSource;
437 bjis.pub.bytes_in_buffer= 0; /* forces fill_input_buffer */
438 /* on first read */
439 bjis.pub.next_input_byte = NULL; /* until buffer loaded */
440
441 bjis.bjisSis= sis;
442
443 if ( ! read_JPEG_file ( &bjis ) )
444 {
445 XDEB(sis);
446 if ( bjis.bjisBitmapBuffer )
447 { free( bjis.bjisBitmapBuffer ); }
448 bmCleanDescription( &(bjis.bjisBd) );
449
450 return -1;
451 }
452
453 *bd= bjis.bjisBd;
454 *pBuffer= bjis.bjisBitmapBuffer;
455
456 return 0;
457 }
458
bmReadJpegFile(const MemoryBuffer * filename,unsigned char ** pBuffer,BitmapDescription * bd,int * pPrivateFormat)459 int bmReadJpegFile( const MemoryBuffer * filename,
460 unsigned char ** pBuffer,
461 BitmapDescription * bd,
462 int * pPrivateFormat )
463 {
464 SimpleInputStream * sis;
465
466 sis= sioInFileioOpen( filename );
467 if ( ! sis )
468 { XDEB(sis); return -1; }
469
470 if ( bmJpegReadJfif( bd, pBuffer, sis ) )
471 { LDEB(1); sioInClose( sis ); return -1; }
472
473 *pPrivateFormat= 1;
474
475 sioInClose( sis );
476
477 return 0;
478 }
479
read_JPEG_file(BmJpegInputSource * bjis)480 static int read_JPEG_file( BmJpegInputSource * bjis )
481 {
482 struct jpeg_decompress_struct cinfo;
483 struct my_error_mgr jerr;
484
485 JSAMPARRAY buffer; /* Output row buffer */
486 int row_stride; /* physical row */
487 /* width in output */
488 /* buffer */
489
490 cinfo.err= jpeg_std_error( &jerr.pub );
491 jerr.pub.error_exit = my_error_exit;
492
493 if ( setjmp( jerr.setjmp_buffer ) )
494 {
495 jpeg_destroy_decompress( &cinfo );
496 return 0;
497 }
498
499 jpeg_create_decompress( &cinfo );
500
501 cinfo.src= (struct jpeg_source_mgr *)bjis;
502
503 bjis->bjisReadBuffer= (JOCTET *)
504 (*cinfo.mem->alloc_small) ((j_common_ptr) &cinfo, JPOOL_PERMANENT,
505 INPUT_BUF_SIZE * sizeof(JOCTET));
506
507 (void) jpeg_read_header( &cinfo, TRUE );
508
509 if ( bmJpegGetReadParameters( &cinfo ) )
510 {
511 LDEB(1);
512 jpeg_destroy_decompress( &cinfo );
513 return 0;
514 }
515
516 jpeg_start_decompress( &cinfo );
517
518 row_stride= cinfo.output_width * cinfo.output_components;
519 buffer= (*cinfo.mem->alloc_sarray)
520 ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1 );
521
522 while( cinfo.output_scanline < cinfo.output_height )
523 {
524 (void)jpeg_read_scanlines( &cinfo, buffer, 1 );
525
526 bmJpegRememberScanline( buffer, &cinfo );
527 }
528
529 (void)jpeg_finish_decompress( &cinfo );
530
531 jpeg_destroy_decompress( &cinfo );
532
533 return 1;
534 }
535
536 /************************************************************************/
537 /* */
538 /* Can the file be written in JPEG format? */
539 /* */
540 /************************************************************************/
541
bmCanWriteJpegFile(const BitmapDescription * bd,int privateFormat)542 int bmCanWriteJpegFile( const BitmapDescription * bd,
543 int privateFormat )
544 {
545 if ( bd->bdBitsPerSample != 8 )
546 { /* LDEB(bd->bdBitsPerSample); */ return -1; }
547
548 /* colorspace of input image */
549 switch( bd->bdColorEncoding )
550 {
551 case BMcoBLACKWHITE:
552 case BMcoWHITEBLACK:
553 case BMcoRGB:
554 case BMcoRGB8PALETTE:
555 break;
556 default:
557 /* LDEB(bd->bdColorEncoding); */ return -1;
558 }
559
560 return 0;
561 }
562
563 /************************************************************************/
564 /* */
565 /* Write JPEG File. */
566 /* */
567 /************************************************************************/
568
569 /************************************************************************/
570 /* */
571 /* Output: derive the contents of the jpeg compressor struct from the */
572 /* bitmap description. */
573 /* */
574 /************************************************************************/
575
bmJpegFillCompressor(struct jpeg_compress_struct * cinfo,const BitmapDescription * bd)576 static int bmJpegFillCompressor( struct jpeg_compress_struct * cinfo,
577 const BitmapDescription * bd )
578 {
579 if ( bd->bdBitsPerSample != 8 )
580 { LDEB(bd->bdBitsPerSample); return -1; }
581
582 cinfo->image_width= bd->bdPixelsWide;
583 cinfo->image_height= bd->bdPixelsHigh;
584
585 switch( bd->bdColorEncoding )
586 {
587 case BMcoBLACKWHITE:
588 case BMcoWHITEBLACK:
589 cinfo->input_components= 1;
590 cinfo->in_color_space= JCS_GRAYSCALE;
591 break;
592
593 case BMcoRGB:
594 case BMcoRGB8PALETTE:
595 cinfo->input_components= 3;
596 cinfo->in_color_space= JCS_RGB;
597 break;
598
599 default:
600 LDEB(bd->bdColorEncoding);
601 return -1;
602 }
603
604 jpeg_set_defaults( cinfo );
605
606 switch( bd->bdUnit )
607 {
608 case BMunINCH:
609 cinfo->density_unit= 1;
610 cinfo->X_density= bd->bdXResolution;
611 cinfo->Y_density= bd->bdYResolution;
612 break;
613
614 case BMunM:
615 cinfo->density_unit= 2;
616 cinfo->X_density= ( bd->bdXResolution+ 50 )/ 100;
617 cinfo->Y_density= ( bd->bdYResolution+ 50 )/ 100;
618 break;
619
620 case BMunPOINT:
621 cinfo->density_unit= 1;
622 cinfo->X_density= 72* bd->bdXResolution;
623 cinfo->Y_density= 72* bd->bdYResolution;
624 break;
625
626 case BMunPIXEL:
627 break;
628
629 default:
630 LDEB(bd->bdUnit);
631 /************************************/
632 /* giving nothing works for jpeg. */
633 /************************************/
634 break;
635 }
636
637 return 0;
638 }
639
640 /************************************************************************/
641 /* */
642 /* Output: Handle one row to the jpeg compressor. */
643 /* */
644 /************************************************************************/
645
bmJpegCompressRow(struct jpeg_compress_struct * cinfo,BmJpegOutputDestination * bjod)646 static int bmJpegCompressRow( struct jpeg_compress_struct * cinfo,
647 BmJpegOutputDestination * bjod )
648 {
649 JSAMPROW row_pointer[1];
650 const unsigned char * from;
651 unsigned char * to;
652 int i;
653 int res;
654
655 const BitmapDescription * bd= bjod->bjodBd;
656 const unsigned char * buffer= bjod->bjodBuffer;
657
658 from= &(buffer[cinfo->next_scanline* bd->bdBytesPerRow]);
659
660 switch( bd->bdColorEncoding )
661 {
662 case BMcoBLACKWHITE:
663 to= bjod->bjodScratchBuffer;
664
665 if ( bd->bdHasAlpha )
666 {
667 for ( i= 0; i < bd->bdPixelsWide; to++, from += 2, i++ )
668 { *to= 255- *from; }
669 }
670 else{
671 for ( i= 0; i < bd->bdPixelsWide; to++, from++, i++ )
672 { *to= 255- *from; }
673 }
674
675 row_pointer[0]= (JSAMPROW)bjod->bjodScratchBuffer;
676 res= jpeg_write_scanlines( cinfo, row_pointer, 1 );
677 break;
678
679 case BMcoRGB8PALETTE:
680 bmExpandRGB8Palette( bjod->bjodScratchBuffer, from,
681 bd->bdPixelsWide, bd->bdBitsPerPixel,
682 &(bd->bdPalette), bd->bdHasAlpha );
683
684 row_pointer[0]= (JSAMPROW)bjod->bjodScratchBuffer;
685 res= jpeg_write_scanlines( cinfo, row_pointer, 1 );
686 break;
687
688 case BMcoWHITEBLACK:
689 if ( bd->bdHasAlpha )
690 {
691 to= bjod->bjodScratchBuffer;
692
693 for ( i= 0; i < bd->bdPixelsWide; i++ )
694 {
695 *(to++)= *(from++);
696 from++;
697 }
698
699 row_pointer[0]= (JSAMPROW)bjod->bjodScratchBuffer;
700 res= jpeg_write_scanlines( cinfo, row_pointer, 1 );
701 }
702 else{
703 row_pointer[0]= (JSAMPROW)from;
704 res= jpeg_write_scanlines( cinfo, row_pointer, 1 );
705 }
706 break;
707
708 case BMcoRGB:
709 if ( bd->bdHasAlpha )
710 {
711 to= bjod->bjodScratchBuffer;
712
713 for ( i= 0; i < bd->bdPixelsWide; i++ )
714 {
715 if ( from[3] >= 128 )
716 {
717 *(to++)= *(from++);
718 *(to++)= *(from++);
719 *(to++)= *(from++);
720 from++;
721 }
722 else{
723 *(to++)= 255;
724 *(to++)= 255;
725 *(to++)= 255;
726 from += 4;
727 }
728 }
729
730 row_pointer[0]= (JSAMPROW)bjod->bjodScratchBuffer;
731 res= jpeg_write_scanlines( cinfo, row_pointer, 1 );
732 }
733 else{
734 row_pointer[0]= (JSAMPROW)from;
735 res= jpeg_write_scanlines( cinfo, row_pointer, 1 );
736 }
737 break;
738
739 default:
740 LDEB(bd->bdColorEncoding); return -1;
741 }
742
743 if ( res != 1 )
744 { LDEB(res); return -1; }
745
746 return 0;
747 }
748
bmJpegInitDestination(j_compress_ptr cinfo)749 static void bmJpegInitDestination( j_compress_ptr cinfo )
750 {
751 BmJpegOutputDestination * bjod= (BmJpegOutputDestination *)cinfo->dest;
752
753 bjod->bjodWriteBuffer = (JOCTET *)
754 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
755 OUTPUT_BUF_SIZE * sizeof(JOCTET));
756
757 bjod->pub.next_output_byte= bjod->bjodWriteBuffer;
758 bjod->pub.free_in_buffer= OUTPUT_BUF_SIZE;
759
760 return;
761 }
762
bmJpegWriteOutputBuffer(j_compress_ptr cinfo)763 static boolean bmJpegWriteOutputBuffer( j_compress_ptr cinfo )
764 {
765 BmJpegOutputDestination * bjod= (BmJpegOutputDestination *)cinfo->dest;
766
767 if ( sioOutWriteBytes( bjod->bjodSos, bjod->bjodWriteBuffer,
768 OUTPUT_BUF_SIZE ) != (size_t) OUTPUT_BUF_SIZE )
769 { ERREXIT(cinfo, JERR_FILE_WRITE); }
770
771 bjod->pub.next_output_byte= bjod->bjodWriteBuffer;
772 bjod->pub.free_in_buffer= OUTPUT_BUF_SIZE;
773
774 return TRUE;
775 }
776
bmJpegFinishDestination(j_compress_ptr cinfo)777 static void bmJpegFinishDestination( j_compress_ptr cinfo )
778 {
779 BmJpegOutputDestination * bjod= (BmJpegOutputDestination *)cinfo->dest;
780 size_t datacount;
781
782 datacount= OUTPUT_BUF_SIZE- bjod->pub.free_in_buffer;
783
784 if ( datacount > 0 )
785 {
786 if ( sioOutWriteBytes( bjod->bjodSos, bjod->bjodWriteBuffer,
787 datacount ) != datacount )
788 { ERREXIT( cinfo, JERR_FILE_WRITE ); }
789 }
790
791 return;
792 }
793
bmJpegWriteJfif(const BitmapDescription * bd,const unsigned char * buffer,SimpleOutputStream * sos)794 int bmJpegWriteJfif( const BitmapDescription * bd,
795 const unsigned char * buffer,
796 SimpleOutputStream * sos )
797 {
798 int rval= 0;
799 BmJpegOutputDestination bjod;
800
801 bjod.bjodBd= bd;
802 bjod.bjodBuffer= buffer;
803 bjod.bjodSos= sos;
804 bjod.bjodScratchBuffer= (unsigned char *)0;
805
806 bjod.pub.init_destination= bmJpegInitDestination;
807 bjod.pub.empty_output_buffer= bmJpegWriteOutputBuffer;
808 bjod.pub.term_destination= bmJpegFinishDestination;
809
810 switch( bd->bdColorEncoding )
811 {
812 case BMcoBLACKWHITE:
813 bjod.bjodScratchBuffer= (unsigned char *)malloc( bd->bdBytesPerRow );
814 if ( ! bjod.bjodScratchBuffer )
815 {
816 LXDEB(bd->bdBytesPerRow,bjod.bjodScratchBuffer);
817 rval= -1; goto ready;
818 }
819 break;
820
821 case BMcoRGB8PALETTE:
822 bjod.bjodScratchBuffer=
823 (unsigned char *)malloc( 3* bd->bdPixelsWide );
824 if ( ! bjod.bjodScratchBuffer )
825 {
826 LXDEB(bd->bdBytesPerRow,bjod.bjodScratchBuffer);
827 rval= -1; goto ready;
828 }
829 break;
830
831 case BMcoRGB:
832 if ( bd->bdHasAlpha )
833 {
834 bjod.bjodScratchBuffer= (unsigned char *)malloc( 3* bd->bdPixelsWide );
835 if ( ! bjod.bjodScratchBuffer )
836 {
837 LXDEB(bd->bdBytesPerRow,bjod.bjodScratchBuffer);
838 rval= -1; goto ready;
839 }
840 }
841 break;
842
843 default:
844 break;
845 }
846
847 if ( write_JPEG_file( &bjod ) )
848 { LDEB(1); rval= -1; goto ready; }
849
850 ready:
851
852 if ( bjod.bjodScratchBuffer )
853 { free( bjod.bjodScratchBuffer ); }
854
855 return rval;
856 }
857
bmWriteJpegFile(const MemoryBuffer * filename,const unsigned char * buffer,const BitmapDescription * bd,int privateFormat)858 int bmWriteJpegFile( const MemoryBuffer * filename,
859 const unsigned char * buffer,
860 const BitmapDescription * bd,
861 int privateFormat )
862 {
863 SimpleOutputStream * sos;
864
865 sos= sioOutFileioOpen( filename );
866 if ( ! sos )
867 { XDEB(sos); return -1; }
868
869 if ( bmJpegWriteJfif( bd, buffer, sos ) )
870 { LDEB(1); sioOutClose( sos ); return -1; }
871
872 sioOutClose( sos );
873
874 return 0;
875 }
876
write_JPEG_file(BmJpegOutputDestination * bjod)877 static int write_JPEG_file( BmJpegOutputDestination * bjod )
878 {
879 struct jpeg_compress_struct cinfo;
880 struct jpeg_error_mgr jerr;
881
882 cinfo.err = jpeg_std_error(&jerr);
883 jpeg_create_compress(&cinfo);
884
885 # if 0
886 jpeg_sio_dest( &cinfo, bjod );
887 # else
888 cinfo.dest= (struct jpeg_destination_mgr *)bjod;
889 # endif
890
891 if ( bmJpegFillCompressor( &cinfo, bjod->bjodBd ) )
892 { LDEB(1); return -1; }
893
894 # if 0
895 jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
896 # endif
897
898 jpeg_start_compress( &cinfo, TRUE );
899
900 while( cinfo.next_scanline < cinfo.image_height )
901 {
902 if( bmJpegCompressRow( &cinfo, bjod ) )
903 { LDEB(1); return -1; }
904 }
905
906 jpeg_finish_compress( &cinfo );
907
908 jpeg_destroy_compress( &cinfo );
909
910 return 0;
911 }
912
913