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