1 #   include	"bitmapConfig.h"
2 
3 #   include	<stdlib.h>
4 #   include	<stdio.h>
5 #   include	<ctype.h>
6 #   include	<string.h>
7 
8 #   include	"bmintern.h"
9 #   include	<appDebugon.h>
10 #   include	<sioFileio.h>
11 
12 /************************************************************************/
13 /*									*/
14 /*  Read a PBM/PGM/PPM file.						*/
15 /*									*/
16 /************************************************************************/
17 
bmPbmGetNumber(int * pNum,SimpleInputStream * sis)18 static int bmPbmGetNumber(	int *			pNum,
19 				SimpleInputStream *	sis )
20     {
21     int		num= 0;
22     int		c= sioInGetByte( sis );
23 
24     for (;;)
25 	{
26 	if  ( isspace( c ) )
27 	    { c= sioInGetByte( sis ); continue;	}
28 
29 	if  ( isdigit( c ) )
30 	    { break;	}
31 
32 	if  ( c == '#' )
33 	    {
34 	    for (;;)
35 		{
36 		c= sioInGetByte( sis );
37 		if  ( c == EOF )
38 		    { CDEB(c); return -1;	}
39 		if  ( c == '\n' )
40 		    { c= sioInGetByte( sis ); break;	}
41 		}
42 
43 	    continue;
44 	    }
45 
46 	CDEB(c); return -1;
47 	}
48 
49     while( isdigit( c ) )
50 	{ num= 10* num+ c- '0'; c= sioInGetByte( sis ); }
51 
52     sioInUngetLastRead( sis ); *pNum= num; return 0;
53     }
54 
bmReadPbmFile(const MemoryBuffer * filename,unsigned char ** pBuf,BitmapDescription * bd,int * pPrivateFormat)55 int bmReadPbmFile(	const MemoryBuffer *	filename,
56 			unsigned char **	pBuf,
57 			BitmapDescription *	bd,
58 			int *			pPrivateFormat )
59     {
60     SimpleInputStream *		sis;
61     int				privateFormat;
62     int				c;
63     int				row;
64     int				col;
65 
66     int				wide;
67     int				high;
68     int				mval= 1;
69     int				shift;
70 
71     unsigned char *		buffer;
72     unsigned char *		to;
73 
74     sis= sioInFileioOpen( filename );
75     if  ( ! sis )
76 	{ XDEB(sis); return -1;	}
77 
78     c= sioInGetByte( sis );
79     if  ( c != 'P' )
80 	{ CDEB(c); sioInClose( sis ); return -1;	}
81 
82     c= sioInGetByte( sis );
83     switch( c )
84 	{
85 	case '1': case '2': case '3': case '4': case '5': case '6':
86 	    privateFormat= c- '0'; break;
87 	default:
88 	    CDEB(c); sioInClose( sis ); return -1;
89 	}
90 
91     if  ( bmPbmGetNumber( &wide, sis ) )
92 	{ LDEB(1); sioInClose( sis ); return -1;	}
93     if  ( bmPbmGetNumber( &high, sis ) )
94 	{ LDEB(1); sioInClose( sis ); return -1;	}
95 
96     bd->bdXResolution= bd->bdYResolution= 1;
97     bd->bdUnit= BMunPIXEL;
98 
99     bd->bdHasAlpha= 0;
100 
101     bd->bdPixelsWide= wide;
102     bd->bdPixelsHigh= high;
103 
104     switch( privateFormat )
105 	{
106 	case 1: case 4:
107 	    bd->bdColorEncoding= BMcoBLACKWHITE;
108 	    bd->bdSamplesPerPixel= 1;
109 	    bd->bdBitsPerSample= 1;
110 	    break;
111 
112 	case 2: case 5:
113 	    if  ( bmPbmGetNumber( &mval, sis ) )
114 		{ LDEB(1); sioInClose( sis ); return -1;	}
115 
116 	    bd->bdColorEncoding= BMcoWHITEBLACK;
117 	    bd->bdSamplesPerPixel= 1;
118 	    bd->bdBitsPerSample= 8;
119 	    break;
120 
121 	case 3: case 6:
122 	    if  ( bmPbmGetNumber( &mval, sis ) )
123 		{ LDEB(1); sioInClose( sis ); return -1;	}
124 
125 	    bd->bdColorEncoding= BMcoRGB;
126 	    bd->bdBitsPerSample= 8;
127 	    break;
128 
129 	default:
130 	    CDEB(c); sioInClose( sis ); return -1;
131 	}
132 
133     bmCalculateSizes( bd );
134 
135     buffer= (unsigned char *)malloc( bd->bdBufferLength );
136     if  ( ! buffer )
137 	{ XDEB(buffer); sioInClose( sis ); return -1;	}
138 
139     switch( privateFormat )
140 	{
141 	case 1:
142 	    memset( buffer, 0, bd->bdBufferLength );
143 	    for ( row= 0; row < high; row++ )
144 		{
145 		to= buffer+ row* bd->bdBytesPerRow; shift= 7;
146 		for ( col= 0; col < wide; col++ )
147 		    {
148 		    if  ( bmPbmGetNumber( &c, sis ) )
149 			{
150 			LLDEB(row,col);
151 			free( buffer ); sioInClose( sis ); return -1;
152 			}
153 		    *to |= ( c != 0 ) << shift;
154 		    if  ( shift == 0 )
155 			{ shift= 7; to++;	}
156 		    else{ shift--;		}
157 		    }
158 		}
159 	    break;
160 
161 	case 4:
162 	    c= sioInGetByte( sis );
163 	    for ( row= 0; row < high; row++ )
164 		{
165 		to= buffer+ row* bd->bdBytesPerRow;
166 		if  ( sioInReadBytes( sis, to, bd->bdBytesPerRow ) !=
167 							bd->bdBytesPerRow )
168 		    {
169 		    LDEB(bd->bdBufferLength);
170 		    free( buffer ); sioInClose( sis ); return -1;
171 		    }
172 		}
173 	    break;
174 
175 	case 5:
176 	    switch( bd->bdBitsPerPixel )
177 		{
178 		case 8:
179 		    c= sioInGetByte( sis );
180 		    if  ( sioInReadBytes( sis, buffer, bd->bdBufferLength ) !=
181 							bd->bdBufferLength )
182 			{
183 			LDEB(bd->bdBufferLength);
184 			free( buffer ); sioInClose( sis ); return -1;
185 			}
186 		    break;
187 		case 1: case 2: case 4:
188 		default:
189 		    LLDEB(privateFormat,bd->bdBitsPerPixel);
190 		    free( buffer ); sioInClose( sis ); return -1;
191 		}
192 	    break;
193 
194 	case 2:
195 	    switch( bd->bdBitsPerPixel )
196 		{
197 		case 8:
198 		    to= buffer;
199 		    for ( col= 0; col < bd->bdBufferLength; col++ )
200 			{
201 			if  ( bmPbmGetNumber( &c, sis ) )
202 			    {
203 			    LDEB(col);
204 			    free( buffer ); sioInClose( sis );
205 			    return -1;
206 			    }
207 			if  ( c > 255 )
208 			    { CDEB(c); c= 255;	}
209 			*(to++)= ( 255* c )/ mval;
210 			}
211 		    break;
212 		case 1: case 2: case 4:
213 		default:
214 		    LLDEB(privateFormat,bd->bdBitsPerPixel);
215 		    free( buffer ); sioInClose( sis ); return -1;
216 		}
217 	    break;
218 
219 	case 3:
220 	    switch( bd->bdBitsPerSample )
221 		{
222 		case 8:
223 		    to= buffer;
224 		    for ( col= 0; col < bd->bdBufferLength; col++ )
225 			{
226 			if  ( bmPbmGetNumber( &c, sis ) )
227 			    {
228 			    LDEB(col);
229 			    free( buffer ); sioInClose( sis );
230 			    return -1;
231 			    }
232 			if  ( c > 255 )
233 			    { CDEB(c); c= 255;	}
234 			*(to++)= ( 255* c )/ mval;
235 			}
236 		    break;
237 		case 1: case 2: case 4:
238 		default:
239 		    LLDEB(privateFormat,bd->bdBitsPerSample);
240 		    free( buffer ); sioInClose( sis ); return -1;
241 		}
242 	    break;
243 
244 	case 6:
245 	    switch( bd->bdBitsPerSample )
246 		{
247 		case 8:
248 		    c= sioInGetByte( sis );
249 		    if  ( sioInReadBytes( sis, buffer, bd->bdBufferLength ) !=
250 							bd->bdBufferLength )
251 			{
252 			LDEB(bd->bdBufferLength);
253 			free( buffer ); sioInClose( sis ); return -1;
254 			}
255 		    break;
256 		case 1: case 2: case 4:
257 		default:
258 		    LLDEB(privateFormat,bd->bdBitsPerSample);
259 		    free( buffer ); sioInClose( sis ); return -1;
260 		}
261 	    break;
262 
263 	default:
264 	    free( buffer );
265 	    LDEB(privateFormat); sioInClose( sis ); return -1;
266 	}
267 
268     sioInClose( sis );
269 
270     *pBuf= buffer;
271     *pPrivateFormat= privateFormat;
272 
273     return 0;
274     }
275 
276 /************************************************************************/
277 /*									*/
278 /*  Write a PGM file.							*/
279 /*									*/
280 /************************************************************************/
281 
bmCanWritePbmFile(const BitmapDescription * bd,int privateFormat)282 int bmCanWritePbmFile(	const BitmapDescription *	bd,
283 			int				privateFormat )
284     {
285     if  ( bd->bdHasAlpha )
286 	{ return -1;	}
287 
288     if  ( privateFormat == 1			&&
289 	  bd->bdColorEncoding == BMcoWHITEBLACK	&&
290 	  bd->bdBitsPerPixel == 1		)
291 	{ return 0; }
292     if  ( privateFormat == 1			&&
293 	  bd->bdColorEncoding == BMcoBLACKWHITE	&&
294 	  bd->bdBitsPerPixel == 1		)
295 	{ return 0; }
296 
297     if  ( privateFormat == 2			&&
298 	  bd->bdColorEncoding == BMcoWHITEBLACK	&&
299 	  bd->bdBitsPerPixel == 1		)
300 	{ return 0; }
301     if  ( privateFormat == 2			&&
302 	  bd->bdColorEncoding == BMcoBLACKWHITE	&&
303 	  bd->bdBitsPerPixel == 1		)
304 	{ return 0; }
305 
306     if  ( privateFormat == 4			&&
307 	  bd->bdColorEncoding == BMcoBLACKWHITE	&&
308 	  bd->bdBitsPerPixel == 1		)
309 	{ return 0; }
310 
311     if  ( privateFormat == 5			&&
312 	  bd->bdColorEncoding == BMcoWHITEBLACK	&&
313 	  bd->bdBitsPerPixel == 8		)
314 	{ return 0; }
315 
316     return -1;
317     }
318 
319 /************************************************************************/
320 /*									*/
321 /*  Write some kinds of pbm files. Code is written to visually inspect	*/
322 /*  the files do debug images. Simplicity is preferred over efficiency.	*/
323 /*									*/
324 /************************************************************************/
325 
bmWriteBitmapBitsAscii(SimpleOutputStream * sos,const unsigned char * buffer,const BitmapDescription * bd,const char * b1,const char * b0)326 static void bmWriteBitmapBitsAscii(
327 			SimpleOutputStream *		sos,
328 			const unsigned char *		buffer,
329 			const BitmapDescription *	bd,
330 			const char *			b1,
331 			const char *			b0 )
332     {
333     int		row;
334 
335     for ( row= 0; row < bd->bdPixelsHigh; row++ )
336 	{
337 	int			col;
338 	const unsigned char *	r= buffer+ row* bd->bdBytesPerRow;
339 
340 	for ( col= 0; col < bd->bdPixelsWide; col++ )
341 	    {
342 	    if  ( r[col/8] & ( 0x80 >> ( col % 8 ) ) )
343 		{ sioOutPutString( b1, sos );	}
344 	    else{ sioOutPutString( b0, sos );	}
345 	    }
346 
347 	sioOutPrintf( sos, "\n" );
348 	}
349 
350     return;
351     }
352 
bmStartPbm(SimpleOutputStream * sos,int privateFormat,const BitmapDescription * bd)353 static void bmStartPbm(	SimpleOutputStream *		sos,
354 			int				privateFormat,
355 			const BitmapDescription *	bd )
356     {
357     sioOutPrintf( sos, "P%d\n", privateFormat );
358 
359     sioOutPrintf( sos, "%d %d\n\n", bd->bdPixelsWide, bd->bdPixelsHigh );
360     return;
361     }
362 
bmStartPnm(SimpleOutputStream * sos,int privateFormat,const BitmapDescription * bd)363 static void bmStartPnm(	SimpleOutputStream *		sos,
364 			int				privateFormat,
365 			const BitmapDescription *	bd )
366     {
367     int		mval= ( 1 << bd->bdBitsPerSample )- 1;
368 
369 
370     sioOutPrintf( sos, "P%d\n", privateFormat );
371 
372     sioOutPrintf( sos, "%d %d %d\n\n",
373 				bd->bdPixelsWide, bd->bdPixelsHigh, mval );
374     return;
375     }
376 
bmPbmRuler(SimpleOutputStream * sos,const BitmapDescription * bd)377 static void bmPbmRuler(	SimpleOutputStream *		sos,
378 			const BitmapDescription *	bd )
379     {
380     int	col;
381 
382     sioOutPrintf( sos, "#0" );
383 
384     for ( col= 1; col < bd->bdPixelsWide; col++ )
385 	{ sioOutPrintf( sos, " %d", col % 10 ); }
386 
387     sioOutPrintf( sos, "\n" );
388     }
389 
bmWritePbmFile(const MemoryBuffer * filename,const unsigned char * buffer,const BitmapDescription * bd,int privateFormat)390 int bmWritePbmFile(	const MemoryBuffer *		filename,
391 			const unsigned char *		buffer,
392 			const BitmapDescription *	bd,
393 			int				privateFormat )
394     {
395     SimpleOutputStream *	sos= (SimpleOutputStream *)0;
396     int				rval= 0;
397 
398     if  ( bd->bdHasAlpha )
399 	{ LDEB(bd->bdHasAlpha); rval= -1; goto ready;	}
400 
401     sos= sioOutFileioOpen( filename );
402     if  ( ! sos )
403 	{ XDEB(sos); rval= -1; goto ready;	}
404 
405     switch( privateFormat )
406 	{
407 	case 1:
408 	    switch( bd->bdColorEncoding )
409 		{
410 		case BMcoWHITEBLACK:
411 		    switch( bd->bdBitsPerPixel )
412 			{
413 			case 1:
414 			    bmStartPbm( sos, privateFormat, bd );
415 
416 			    if  ( bd->bdPixelsWide <= 40	)
417 				{ bmPbmRuler( sos, bd );	}
418 
419 			    bmWriteBitmapBitsAscii( sos, buffer, bd,
420 								" 0", " 1" );
421 			    break;
422 
423 			default:
424 			    LDEB(bd->bdBitsPerPixel); rval= -1; goto ready;
425 			}
426 		    break;
427 
428 		case BMcoBLACKWHITE:
429 		    switch( bd->bdBitsPerPixel )
430 			{
431 			case 1:
432 			    bmStartPbm( sos, privateFormat, bd );
433 
434 			    if  ( bd->bdPixelsWide <= 40	)
435 				{ bmPbmRuler( sos, bd );	}
436 
437 			    bmWriteBitmapBitsAscii( sos, buffer, bd,
438 								" 1", " 0" );
439 			    break;
440 
441 			default:
442 			    LDEB(bd->bdBitsPerPixel); rval= -1; goto ready;
443 			}
444 		    break;
445 
446 		default:
447 		    LDEB(bd->bdColorEncoding); rval= -1; goto ready;
448 		}
449 	    break;
450 
451 	case 2:
452 	    switch( bd->bdColorEncoding )
453 		{
454 		case BMcoWHITEBLACK:
455 		    switch( bd->bdBitsPerPixel )
456 			{
457 			case 1:
458 			    bmStartPnm( sos, privateFormat, bd );
459 
460 			    if  ( bd->bdPixelsWide <= 40	)
461 				{ bmPbmRuler( sos, bd );	}
462 
463 			    bmWriteBitmapBitsAscii( sos, buffer, bd,
464 								" 1", " 0" );
465 			    break;
466 
467 			default:
468 			    LDEB(bd->bdBitsPerPixel); rval= -1; goto ready;
469 			}
470 		    break;
471 
472 		case BMcoBLACKWHITE:
473 		    switch( bd->bdBitsPerPixel )
474 			{
475 			case 1:
476 			    bmStartPnm( sos, privateFormat, bd );
477 
478 			    if  ( bd->bdPixelsWide <= 40	)
479 				{ bmPbmRuler( sos, bd );	}
480 
481 			    bmWriteBitmapBitsAscii( sos, buffer, bd,
482 								" 0", " 1" );
483 			    break;
484 
485 			default:
486 			    LDEB(bd->bdBitsPerPixel); rval= -1; goto ready;
487 			}
488 		    break;
489 
490 		default:
491 		    LDEB(bd->bdColorEncoding); rval= -1; goto ready;
492 		}
493 	    break;
494 
495 	case 4:
496 	    switch( bd->bdColorEncoding )
497 		{
498 		case BMcoBLACKWHITE:
499 		    switch( bd->bdBitsPerPixel )
500 			{
501 			case 1:
502 			    bmStartPbm( sos, privateFormat, bd );
503 			    sioOutWriteBytes( sos, buffer, bd->bdBufferLength );
504 			    break;
505 
506 			default:
507 			    LDEB(bd->bdBitsPerPixel); rval= -1; goto ready;
508 			}
509 		    break;
510 
511 		case BMcoWHITEBLACK:
512 		default:
513 		    LDEB(bd->bdColorEncoding); rval= -1; goto ready;
514 		}
515 	    break;
516 
517 	case 5:
518 	    switch( bd->bdColorEncoding )
519 		{
520 		case BMcoWHITEBLACK:
521 		    switch( bd->bdBitsPerPixel )
522 			{
523 			case 8:
524 			    bmStartPnm( sos, privateFormat, bd );
525 
526 			    sioOutWriteBytes( sos, buffer, bd->bdBufferLength );
527 			    break;
528 
529 			default:
530 			    LDEB(bd->bdBitsPerPixel); rval= -1; goto ready;
531 			}
532 		    break;
533 
534 		case BMcoBLACKWHITE:
535 		default:
536 		    LDEB(bd->bdColorEncoding); rval= -1; goto ready;
537 		}
538 	    break;
539 
540 
541 	default:
542 	    LDEB(privateFormat); rval= -1; goto ready;
543 	}
544 
545   ready:
546 
547     if  ( sos )
548 	{ sioOutClose( sos );	}
549 
550     return rval;
551     }
552