1 |
/* libpnmrw.c - PBM/PGM/PPM read/write library |
2 |
** |
3 |
** Copyright (C) 1988, 1989, 1991, 1992 by Jef Poskanzer. |
4 |
** |
5 |
** Permission to use, copy, modify, and distribute this software and its |
6 |
** documentation for any purpose and without fee is hereby granted, provided |
7 |
** that the above copyright notice appear in all copies and that both that |
8 |
** copyright notice and this permission notice appear in supporting |
9 |
** documentation. This software is provided "as is" without express or |
10 |
** implied warranty. |
11 |
*/ |
12 |
|
13 |
#define pm_error(x) exit(1) |
14 |
|
15 |
|
16 |
#if defined(SVR2) || defined(SVR3) || defined(SVR4) |
17 |
#define SYSV |
18 |
#endif |
19 |
#if ! ( defined(BSD) || defined(SYSV) || defined(MSDOS) ) |
20 |
/* CONFIGURE: If your system is >= 4.2BSD, set the BSD option; if you're a |
21 |
** System V site, set the SYSV option; and if you're IBM-compatible, set |
22 |
** MSDOS. If your compiler is ANSI C, you're probably better off setting |
23 |
** SYSV - all it affects is string handling. |
24 |
*/ |
25 |
#define BSD |
26 |
/* #define SYSV */ |
27 |
/* #define MSDOS */ |
28 |
#endif |
29 |
|
30 |
#include <stdio.h> |
31 |
#include "libpnmrw.h" |
32 |
|
33 |
/* if don't have string.h, try strings.h */ |
34 |
#include <string.h> |
35 |
#define rindex(s,c) strrchr(s,c) |
36 |
|
37 |
|
38 |
/* Definitions. */ |
39 |
|
40 |
#define pbm_allocarray( cols, rows ) ((bit**) pm_allocarray( cols, rows, sizeof(bit) )) |
41 |
#define pbm_allocrow( cols ) ((bit*) pm_allocrow( cols, sizeof(bit) )) |
42 |
#define pbm_freearray( bits, rows ) pm_freearray( (char**) bits, rows ) |
43 |
#define pbm_freerow( bitrow ) pm_freerow( (char*) bitrow ) |
44 |
#define pgm_allocarray( cols, rows ) ((gray**) pm_allocarray( cols, rows, sizeof(gray) )) |
45 |
#define pgm_allocrow( cols ) ((gray*) pm_allocrow( cols, sizeof(gray) )) |
46 |
#define pgm_freearray( grays, rows ) pm_freearray( (char**) grays, rows ) |
47 |
#define pgm_freerow( grayrow ) pm_freerow( (char*) grayrow ) |
48 |
#define ppm_allocarray( cols, rows ) ((pixel**) pm_allocarray( cols, rows, sizeof(pixel) )) |
49 |
#define ppm_allocrow( cols ) ((pixel*) pm_allocrow( cols, sizeof(pixel) )) |
50 |
#define ppm_freearray( pixels, rows ) pm_freearray( (char**) pixels, rows ) |
51 |
#define ppm_freerow( pixelrow ) pm_freerow( (char*) pixelrow ) |
52 |
|
53 |
|
54 |
/* Variables. */ |
55 |
|
56 |
static char* progname; |
57 |
|
58 |
|
59 |
/* Variable-sized arrays. */ |
60 |
|
61 |
char* |
62 |
pm_allocrow( cols, size ) |
63 |
int cols; |
64 |
int size; |
65 |
{ |
66 |
register char* itrow; |
67 |
|
68 |
itrow = (char*) malloc( cols * size ); |
69 |
if ( itrow == (char*) 0 ) |
70 |
{ |
71 |
(void) fprintf( |
72 |
stderr, "%s: out of memory allocating a row\n", progname ); |
73 |
return (char*) 0; |
74 |
} |
75 |
return itrow; |
76 |
} |
77 |
|
78 |
void |
79 |
pm_freerow( itrow ) |
80 |
char* itrow; |
81 |
{ |
82 |
free( itrow ); |
83 |
} |
84 |
|
85 |
char** |
86 |
pm_allocarray( cols, rows, size ) |
87 |
int cols, rows; |
88 |
int size; |
89 |
{ |
90 |
char** its; |
91 |
int i; |
92 |
|
93 |
its = (char**) malloc( rows * sizeof(char*) ); |
94 |
if ( its == (char**) 0 ) |
95 |
{ |
96 |
(void) fprintf( |
97 |
stderr, "%s: out of memory allocating an array\n", progname ); |
98 |
return (char**) 0; |
99 |
} |
100 |
its[0] = (char*) malloc( rows * cols * size ); |
101 |
if ( its[0] == (char*) 0 ) |
102 |
{ |
103 |
(void) fprintf( |
104 |
stderr, "%s: out of memory allocating an array\n", progname ); |
105 |
free( (char*) its ); |
106 |
return (char**) 0; |
107 |
} |
108 |
for ( i = 1; i < rows; ++i ) |
109 |
its[i] = &(its[0][i * cols * size]); |
110 |
return its; |
111 |
} |
112 |
|
113 |
void |
114 |
pm_freearray( its, rows ) |
115 |
char** its; |
116 |
int rows; |
117 |
{ |
118 |
free( its[0] ); |
119 |
free( its ); |
120 |
} |
121 |
|
122 |
|
123 |
/* File open/close that handles "-" as stdin and checks errors. */ |
124 |
|
125 |
static void |
126 |
pm_perror( reason ) |
127 |
char* reason; |
128 |
{ |
129 |
/* |
130 |
extern char* sys_errlist[]; |
131 |
extern int errno; |
132 |
char* e; |
133 |
|
134 |
e = sys_errlist[errno]; |
135 |
|
136 |
if ( reason != 0 && reason[0] != '\0' ) |
137 |
(void) fprintf( stderr, "%s: %s - %s\n", progname, reason, e ); |
138 |
else |
139 |
(void) fprintf( stderr, "%s: %s\n", progname, e ); |
140 |
*/ |
141 |
|
142 |
} |
143 |
|
144 |
FILE* |
145 |
pm_openr( name ) |
146 |
char* name; |
147 |
{ |
148 |
FILE* f; |
149 |
|
150 |
if ( strcmp( name, "-" ) == 0 ) |
151 |
f = stdin; |
152 |
else |
153 |
{ |
154 |
f = fopen( name, "rb" ); |
155 |
if ( f == NULL ) |
156 |
{ |
157 |
pm_perror( name ); |
158 |
return (FILE*) 0; |
159 |
} |
160 |
} |
161 |
return f; |
162 |
} |
163 |
|
164 |
FILE* |
165 |
pm_openw( name ) |
166 |
char* name; |
167 |
{ |
168 |
FILE* f; |
169 |
|
170 |
f = fopen( name, "wb" ); |
171 |
if ( f == NULL ) { |
172 |
pm_perror( name ); |
173 |
return (FILE*) 0; |
174 |
} |
175 |
return f; |
176 |
} |
177 |
|
178 |
int |
179 |
pm_closer( f ) |
180 |
FILE* f; |
181 |
{ |
182 |
if ( ferror( f ) ) |
183 |
{ |
184 |
(void) fprintf( |
185 |
stderr, "%s: a file read error occurred at some point\n", |
186 |
progname ); |
187 |
return -1; |
188 |
} |
189 |
if ( f != stdin ) |
190 |
if ( fclose( f ) != 0 ) |
191 |
{ |
192 |
pm_perror( "fclose" ); |
193 |
return -1; |
194 |
} |
195 |
return 0; |
196 |
} |
197 |
|
198 |
int |
199 |
pm_closew( f ) |
200 |
FILE* f; |
201 |
{ |
202 |
fflush( f ); |
203 |
if ( ferror( f ) ) |
204 |
{ |
205 |
(void) fprintf( |
206 |
stderr, "%s: a file write error occurred at some point\n", |
207 |
progname ); |
208 |
return -1; |
209 |
} |
210 |
if ( f != stdout ) |
211 |
if ( fclose( f ) != 0 ) |
212 |
{ |
213 |
pm_perror( "fclose" ); |
214 |
return -1; |
215 |
} |
216 |
return 0; |
217 |
} |
218 |
|
219 |
static int |
220 |
pbm_getc( file ) |
221 |
FILE* file; |
222 |
{ |
223 |
register int ich; |
224 |
|
225 |
ich = getc( file ); |
226 |
if ( ich == EOF ) |
227 |
{ |
228 |
(void) fprintf( stderr, "%s: EOF / read error\n", progname ); |
229 |
return EOF; |
230 |
} |
231 |
|
232 |
if ( ich == '#' ) |
233 |
{ |
234 |
do |
235 |
{ |
236 |
ich = getc( file ); |
237 |
if ( ich == EOF ) |
238 |
{ |
239 |
(void) fprintf( stderr, "%s: EOF / read error\n", progname ); |
240 |
return EOF; |
241 |
} |
242 |
} |
243 |
while ( ich != '\n' && ich != '\r' ); |
244 |
} |
245 |
|
246 |
return ich; |
247 |
} |
248 |
|
249 |
static bit |
250 |
pbm_getbit( file ) |
251 |
FILE* file; |
252 |
{ |
253 |
register int ich; |
254 |
|
255 |
do |
256 |
{ |
257 |
ich = pbm_getc( file ); |
258 |
if ( ich == EOF ) |
259 |
return -1; |
260 |
} |
261 |
while ( ich == ' ' || ich == '\t' || ich == '\n' || ich == '\r' ); |
262 |
|
263 |
if ( ich != '0' && ich != '1' ) |
264 |
{ |
265 |
(void) fprintf( |
266 |
stderr, "%s: junk in file where bits should be\n", progname ); |
267 |
return -1; |
268 |
} |
269 |
|
270 |
return ( ich == '1' ) ? 1 : 0; |
271 |
} |
272 |
|
273 |
static int |
274 |
pbm_readmagicnumber( file ) |
275 |
FILE* file; |
276 |
{ |
277 |
int ich1, ich2; |
278 |
|
279 |
ich1 = getc( file ); |
280 |
if ( ich1 == EOF ) |
281 |
{ |
282 |
(void) fprintf( |
283 |
stderr, "%s: EOF / read error reading magic number\n", progname ); |
284 |
return -1; |
285 |
} |
286 |
ich2 = getc( file ); |
287 |
if ( ich2 == EOF ) |
288 |
{ |
289 |
(void) fprintf( |
290 |
stderr, "%s: EOF / read error reading magic number\n", progname ); |
291 |
return -1; |
292 |
} |
293 |
return ich1 * 256 + ich2; |
294 |
} |
295 |
|
296 |
static int |
297 |
pbm_getint( file ) |
298 |
FILE* file; |
299 |
{ |
300 |
register int ich; |
301 |
register int i; |
302 |
|
303 |
do |
304 |
{ |
305 |
ich = pbm_getc( file ); |
306 |
if ( ich == EOF ) |
307 |
return -1; |
308 |
} |
309 |
while ( ich == ' ' || ich == '\t' || ich == '\n' || ich == '\r' ); |
310 |
|
311 |
if ( ich < '0' || ich > '9' ) |
312 |
{ |
313 |
(void) fprintf( |
314 |
stderr, "%s: junk in file where an integer should be\n", progname ); |
315 |
return -1; |
316 |
} |
317 |
|
318 |
i = 0; |
319 |
do |
320 |
{ |
321 |
i = i * 10 + ich - '0'; |
322 |
ich = pbm_getc( file ); |
323 |
if ( ich == EOF ) |
324 |
return -1; |
325 |
} |
326 |
while ( ich >= '0' && ich <= '9' ); |
327 |
|
328 |
return i; |
329 |
} |
330 |
|
331 |
static int |
332 |
pbm_readpbminitrest( file, colsP, rowsP ) |
333 |
FILE* file; |
334 |
int* colsP; |
335 |
int* rowsP; |
336 |
{ |
337 |
/* Read size. */ |
338 |
*colsP = pbm_getint( file ); |
339 |
*rowsP = pbm_getint( file ); |
340 |
if ( *colsP == -1 || *rowsP == -1 ) |
341 |
return -1; |
342 |
return 0; |
343 |
} |
344 |
|
345 |
static int |
346 |
pbm_getrawbyte( file ) |
347 |
FILE* file; |
348 |
{ |
349 |
register int iby; |
350 |
|
351 |
iby = getc( file ); |
352 |
if ( iby == EOF ) |
353 |
{ |
354 |
(void) fprintf( stderr, "%s: EOF / read error\n", progname ); |
355 |
return -1; |
356 |
} |
357 |
return iby; |
358 |
} |
359 |
|
360 |
static int |
361 |
pbm_readpbmrow( file, bitrow, cols, format ) |
362 |
FILE* file; |
363 |
bit* bitrow; |
364 |
int cols, format; |
365 |
{ |
366 |
register int col, bitshift, b; |
367 |
register int item; |
368 |
register bit* bP; |
369 |
|
370 |
switch ( format ) |
371 |
{ |
372 |
case PBM_FORMAT: |
373 |
for ( col = 0, bP = bitrow; col < cols; ++col, ++bP ) |
374 |
{ |
375 |
b = pbm_getbit( file ); |
376 |
if ( b == -1 ) |
377 |
return -1; |
378 |
*bP = b; |
379 |
} |
380 |
break; |
381 |
|
382 |
case RPBM_FORMAT: |
383 |
bitshift = -1; |
384 |
for ( col = 0, bP = bitrow; col < cols; ++col, ++bP ) |
385 |
{ |
386 |
if ( bitshift == -1 ) |
387 |
{ |
388 |
item = pbm_getrawbyte( file ); |
389 |
if ( item == -1 ) |
390 |
return -1; |
391 |
bitshift = 7; |
392 |
} |
393 |
*bP = ( item >> bitshift ) & 1; |
394 |
--bitshift; |
395 |
} |
396 |
break; |
397 |
|
398 |
default: |
399 |
(void) fprintf( stderr, "%s: can't happen\n", progname ); |
400 |
return -1; |
401 |
} |
402 |
return 0; |
403 |
} |
404 |
|
405 |
static void |
406 |
pbm_writepbminit( file, cols, rows, forceplain ) |
407 |
FILE* file; |
408 |
int cols, rows; |
409 |
int forceplain; |
410 |
{ |
411 |
if ( ! forceplain ) |
412 |
(void) fprintf( |
413 |
file, "%c%c\n%d %d\n", PBM_MAGIC1, RPBM_MAGIC2, cols, rows ); |
414 |
else |
415 |
(void) fprintf( |
416 |
file, "%c%c\n%d %d\n", PBM_MAGIC1, PBM_MAGIC2, cols, rows ); |
417 |
} |
418 |
|
419 |
static void |
420 |
pbm_writepbmrowraw( file, bitrow, cols ) |
421 |
FILE* file; |
422 |
bit* bitrow; |
423 |
int cols; |
424 |
{ |
425 |
register int col, bitshift; |
426 |
register unsigned char item; |
427 |
register bit* bP; |
428 |
|
429 |
bitshift = 7; |
430 |
item = 0; |
431 |
for ( col = 0, bP = bitrow; col < cols; ++col, ++bP ) |
432 |
{ |
433 |
if ( *bP ) |
434 |
item += 1 << bitshift; |
435 |
--bitshift; |
436 |
if ( bitshift == -1 ) |
437 |
{ |
438 |
(void) putc( item, file ); |
439 |
bitshift = 7; |
440 |
item = 0; |
441 |
} |
442 |
} |
443 |
if ( bitshift != 7 ) |
444 |
(void) putc( item, file ); |
445 |
} |
446 |
|
447 |
static void |
448 |
pbm_writepbmrowplain( file, bitrow, cols ) |
449 |
FILE* file; |
450 |
bit* bitrow; |
451 |
int cols; |
452 |
{ |
453 |
register int col, charcount; |
454 |
register bit* bP; |
455 |
|
456 |
charcount = 0; |
457 |
for ( col = 0, bP = bitrow; col < cols; ++col, ++bP ) |
458 |
{ |
459 |
if ( charcount >= 70 ) |
460 |
{ |
461 |
(void) putc( '\n', file ); |
462 |
charcount = 0; |
463 |
} |
464 |
putc( *bP ? '1' : '0', file ); |
465 |
++charcount; |
466 |
} |
467 |
(void) putc( '\n', file ); |
468 |
} |
469 |
|
470 |
static void |
471 |
pbm_writepbmrow( file, bitrow, cols, forceplain ) |
472 |
FILE* file; |
473 |
bit* bitrow; |
474 |
int cols; |
475 |
int forceplain; |
476 |
{ |
477 |
if ( ! forceplain ) |
478 |
pbm_writepbmrowraw( file, bitrow, cols ); |
479 |
else |
480 |
pbm_writepbmrowplain( file, bitrow, cols ); |
481 |
} |
482 |
|
483 |
static int |
484 |
pgm_readpgminitrest( file, colsP, rowsP, maxvalP ) |
485 |
FILE* file; |
486 |
int* colsP; |
487 |
int* rowsP; |
488 |
gray* maxvalP; |
489 |
{ |
490 |
int maxval; |
491 |
|
492 |
/* Read size. */ |
493 |
*colsP = pbm_getint( file ); |
494 |
*rowsP = pbm_getint( file ); |
495 |
if ( *colsP == -1 || *rowsP == -1 ) |
496 |
return -1; |
497 |
|
498 |
/* Read maxval. */ |
499 |
maxval = pbm_getint( file ); |
500 |
if ( maxval == -1 ) |
501 |
return -1; |
502 |
if ( maxval > PGM_MAXMAXVAL ) |
503 |
{ |
504 |
(void) fprintf( stderr, "%s: maxval is too large\n", progname ); |
505 |
return -1; |
506 |
} |
507 |
*maxvalP = maxval; |
508 |
return 0; |
509 |
} |
510 |
|
511 |
#if __STDC__ |
512 |
static int |
513 |
pgm_readpgmrow( FILE* file, gray* grayrow, int cols, gray maxval, int format ) |
514 |
#else /*__STDC__*/ |
515 |
static int |
516 |
pgm_readpgmrow( file, grayrow, cols, maxval, format ) |
517 |
FILE* file; |
518 |
gray* grayrow; |
519 |
int cols; |
520 |
gray maxval; |
521 |
int format; |
522 |
#endif /*__STDC__*/ |
523 |
{ |
524 |
register int col, val; |
525 |
register gray* gP; |
526 |
/* |
527 |
bit* bitrow; |
528 |
register bit* bP; |
529 |
*/ |
530 |
|
531 |
switch ( format ) |
532 |
{ |
533 |
case PGM_FORMAT: |
534 |
for ( col = 0, gP = grayrow; col < cols; ++col, ++gP ) |
535 |
{ |
536 |
val = pbm_getint( file ); |
537 |
if ( val == -1 ) |
538 |
return -1; |
539 |
*gP = val; |
540 |
} |
541 |
break; |
542 |
|
543 |
case RPGM_FORMAT: |
544 |
if ( fread( grayrow, 1, cols, file ) != cols ) |
545 |
{ |
546 |
(void) fprintf( stderr, "%s: EOF / read error\n", progname ); |
547 |
return -1; |
548 |
} |
549 |
break; |
550 |
|
551 |
default: |
552 |
(void) fprintf( stderr, "%s: can't happen\n", progname ); |
553 |
return -1; |
554 |
} |
555 |
return 0; |
556 |
} |
557 |
|
558 |
#if __STDC__ |
559 |
static void |
560 |
pgm_writepgminit( FILE* file, int cols, int rows, gray maxval, int forceplain ) |
561 |
#else /*__STDC__*/ |
562 |
static void |
563 |
pgm_writepgminit( file, cols, rows, maxval, forceplain ) |
564 |
FILE* file; |
565 |
int cols, rows; |
566 |
gray maxval; |
567 |
int forceplain; |
568 |
#endif /*__STDC__*/ |
569 |
{ |
570 |
if ( maxval <= 255 && ! forceplain ) |
571 |
fprintf( |
572 |
file, "%c%c\n%d %d\n%d\n", PGM_MAGIC1, RPGM_MAGIC2, |
573 |
cols, rows, maxval ); |
574 |
else |
575 |
fprintf( |
576 |
file, "%c%c\n%d %d\n%d\n", PGM_MAGIC1, PGM_MAGIC2, |
577 |
cols, rows, maxval ); |
578 |
} |
579 |
|
580 |
static void |
581 |
putus( n, file ) |
582 |
unsigned short n; |
583 |
FILE* file; |
584 |
{ |
585 |
if ( n >= 10 ) |
586 |
putus( n / 10, file ); |
587 |
putc( n % 10 + '0', file ); |
588 |
} |
589 |
|
590 |
static int |
591 |
pgm_writepgmrowraw( file, grayrow, cols, maxval ) |
592 |
FILE* file; |
593 |
gray* grayrow; |
594 |
int cols; |
595 |
gray maxval; |
596 |
{ |
597 |
if ( fwrite( grayrow, 1, cols, file ) != cols ) |
598 |
{ |
599 |
(void) fprintf( stderr, "%s: write error\n", progname ); |
600 |
return -1; |
601 |
} |
602 |
return 0; |
603 |
} |
604 |
|
605 |
static int |
606 |
pgm_writepgmrowplain( file, grayrow, cols, maxval ) |
607 |
FILE* file; |
608 |
gray* grayrow; |
609 |
int cols; |
610 |
gray maxval; |
611 |
{ |
612 |
register int col, charcount; |
613 |
register gray* gP; |
614 |
|
615 |
charcount = 0; |
616 |
for ( col = 0, gP = grayrow; col < cols; ++col, ++gP ) |
617 |
{ |
618 |
if ( charcount >= 65 ) |
619 |
{ |
620 |
(void) putc( '\n', file ); |
621 |
charcount = 0; |
622 |
} |
623 |
else if ( charcount > 0 ) |
624 |
{ |
625 |
(void) putc( ' ', file ); |
626 |
++charcount; |
627 |
} |
628 |
putus( (unsigned short) *gP, file ); |
629 |
charcount += 3; |
630 |
} |
631 |
if ( charcount > 0 ) |
632 |
(void) putc( '\n', file ); |
633 |
return 0; |
634 |
} |
635 |
|
636 |
#if __STDC__ |
637 |
static int |
638 |
pgm_writepgmrow( FILE* file, gray* grayrow, int cols, gray maxval, int forceplain ) |
639 |
#else /*__STDC__*/ |
640 |
static int |
641 |
pgm_writepgmrow( file, grayrow, cols, maxval, forceplain ) |
642 |
FILE* file; |
643 |
gray* grayrow; |
644 |
int cols; |
645 |
gray maxval; |
646 |
int forceplain; |
647 |
#endif /*__STDC__*/ |
648 |
{ |
649 |
if ( maxval <= 255 && ! forceplain ) |
650 |
return pgm_writepgmrowraw( file, grayrow, cols, maxval ); |
651 |
else |
652 |
return pgm_writepgmrowplain( file, grayrow, cols, maxval ); |
653 |
} |
654 |
|
655 |
static int |
656 |
ppm_readppminitrest( file, colsP, rowsP, maxvalP ) |
657 |
FILE* file; |
658 |
int* colsP; |
659 |
int* rowsP; |
660 |
pixval* maxvalP; |
661 |
{ |
662 |
int maxval; |
663 |
|
664 |
/* Read size. */ |
665 |
*colsP = pbm_getint( file ); |
666 |
*rowsP = pbm_getint( file ); |
667 |
if ( *colsP == -1 || *rowsP == -1 ) |
668 |
return -1; |
669 |
|
670 |
/* Read maxval. */ |
671 |
maxval = pbm_getint( file ); |
672 |
if ( maxval == -1 ) |
673 |
return -1; |
674 |
if ( maxval > PPM_MAXMAXVAL ) |
675 |
{ |
676 |
(void) fprintf( stderr, "%s: maxval is too large\n", progname ); |
677 |
return -1; |
678 |
} |
679 |
*maxvalP = maxval; |
680 |
return 0; |
681 |
} |
682 |
|
683 |
#if __STDC__ |
684 |
static int |
685 |
ppm_readppmrow( FILE* file, pixel* pixelrow, int cols, pixval maxval, int format ) |
686 |
#else /*__STDC__*/ |
687 |
static int |
688 |
ppm_readppmrow( file, pixelrow, cols, maxval, format ) |
689 |
FILE* file; |
690 |
pixel* pixelrow; |
691 |
int cols, format; |
692 |
pixval maxval; |
693 |
#endif /*__STDC__*/ |
694 |
{ |
695 |
register int col; |
696 |
register pixel* pP; |
697 |
register int r, g, b; |
698 |
gray* grayrow; |
699 |
register gray* gP; |
700 |
/* |
701 |
bit* bitrow; |
702 |
register bit* bP; |
703 |
*/ |
704 |
|
705 |
switch ( format ) |
706 |
{ |
707 |
case PPM_FORMAT: |
708 |
for ( col = 0, pP = pixelrow; col < cols; ++col, ++pP ) |
709 |
{ |
710 |
r = pbm_getint( file ); |
711 |
g = pbm_getint( file ); |
712 |
b = pbm_getint( file ); |
713 |
if ( r == -1 || g == -1 || b == -1 ) |
714 |
return -1; |
715 |
PPM_ASSIGN( *pP, r, g, b ); |
716 |
} |
717 |
break; |
718 |
|
719 |
case RPPM_FORMAT: |
720 |
grayrow = pgm_allocrow( 3 * cols ); |
721 |
if ( grayrow == (gray*) 0 ) |
722 |
return -1; |
723 |
if ( fread( grayrow, 1, 3 * cols, file ) != 3 * cols ) |
724 |
{ |
725 |
(void) fprintf( stderr, "%s: EOF / read error\n", progname ); |
726 |
return -1; |
727 |
} |
728 |
for ( col = 0, gP = grayrow, pP = pixelrow; col < cols; ++col, ++pP ) |
729 |
{ |
730 |
r = *gP++; |
731 |
g = *gP++; |
732 |
b = *gP++; |
733 |
PPM_ASSIGN( *pP, r, g, b ); |
734 |
} |
735 |
pgm_freerow( grayrow ); |
736 |
break; |
737 |
|
738 |
default: |
739 |
(void) fprintf( stderr, "%s: can't happen\n", progname ); |
740 |
return -1; |
741 |
} |
742 |
return 0; |
743 |
} |
744 |
|
745 |
#if __STDC__ |
746 |
static void |
747 |
ppm_writeppminit( FILE* file, int cols, int rows, pixval maxval, int forceplain ) |
748 |
#else /*__STDC__*/ |
749 |
static void |
750 |
ppm_writeppminit( file, cols, rows, maxval, forceplain ) |
751 |
FILE* file; |
752 |
int cols, rows; |
753 |
pixval maxval; |
754 |
int forceplain; |
755 |
#endif /*__STDC__*/ |
756 |
{ |
757 |
if ( maxval <= 255 && ! forceplain ) |
758 |
fprintf( |
759 |
file, "%c%c\n%d %d\n%d\n", PPM_MAGIC1, RPPM_MAGIC2, |
760 |
cols, rows, maxval ); |
761 |
else |
762 |
fprintf( |
763 |
file, "%c%c\n%d %d\n%d\n", PPM_MAGIC1, PPM_MAGIC2, |
764 |
cols, rows, maxval ); |
765 |
} |
766 |
|
767 |
static int |
768 |
ppm_writeppmrowraw( file, pixelrow, cols, maxval ) |
769 |
FILE* file; |
770 |
pixel* pixelrow; |
771 |
int cols; |
772 |
pixval maxval; |
773 |
{ |
774 |
register int col; |
775 |
register pixel* pP; |
776 |
gray* grayrow; |
777 |
register gray* gP; |
778 |
|
779 |
grayrow = pgm_allocrow( 3 * cols ); |
780 |
if ( grayrow == (gray*) 0 ) |
781 |
return -1; |
782 |
for ( col = 0, pP = pixelrow, gP = grayrow; col < cols; ++col, ++pP ) |
783 |
{ |
784 |
*gP++ = PPM_GETR( *pP ); |
785 |
*gP++ = PPM_GETG( *pP ); |
786 |
*gP++ = PPM_GETB( *pP ); |
787 |
} |
788 |
if ( fwrite( grayrow, 1, 3 * cols, file ) != 3 * cols ) |
789 |
{ |
790 |
(void) fprintf( stderr, "%s: write error\n", progname ); |
791 |
return -1; |
792 |
} |
793 |
pgm_freerow( grayrow ); |
794 |
return 0; |
795 |
} |
796 |
|
797 |
static int |
798 |
ppm_writeppmrowplain( file, pixelrow, cols, maxval ) |
799 |
FILE* file; |
800 |
pixel* pixelrow; |
801 |
int cols; |
802 |
pixval maxval; |
803 |
{ |
804 |
register int col, charcount; |
805 |
register pixel* pP; |
806 |
register pixval val; |
807 |
|
808 |
charcount = 0; |
809 |
for ( col = 0, pP = pixelrow; col < cols; ++col, ++pP ) |
810 |
{ |
811 |
if ( charcount >= 65 ) |
812 |
{ |
813 |
(void) putc( '\n', file ); |
814 |
charcount = 0; |
815 |
} |
816 |
else if ( charcount > 0 ) |
817 |
{ |
818 |
(void) putc( ' ', file ); |
819 |
(void) putc( ' ', file ); |
820 |
charcount += 2; |
821 |
} |
822 |
val = PPM_GETR( *pP ); |
823 |
putus( val, file ); |
824 |
(void) putc( ' ', file ); |
825 |
val = PPM_GETG( *pP ); |
826 |
putus( val, file ); |
827 |
(void) putc( ' ', file ); |
828 |
val = PPM_GETB( *pP ); |
829 |
putus( val, file ); |
830 |
charcount += 11; |
831 |
} |
832 |
if ( charcount > 0 ) |
833 |
(void) putc( '\n', file ); |
834 |
return 0; |
835 |
} |
836 |
|
837 |
#if __STDC__ |
838 |
static int |
839 |
ppm_writeppmrow( FILE* file, pixel* pixelrow, int cols, pixval maxval, int forceplain ) |
840 |
#else /*__STDC__*/ |
841 |
static int |
842 |
ppm_writeppmrow( file, pixelrow, cols, maxval, forceplain ) |
843 |
FILE* file; |
844 |
pixel* pixelrow; |
845 |
int cols; |
846 |
pixval maxval; |
847 |
int forceplain; |
848 |
#endif /*__STDC__*/ |
849 |
{ |
850 |
if ( maxval <= 255 && ! forceplain ) |
851 |
return ppm_writeppmrowraw( file, pixelrow, cols, maxval ); |
852 |
else |
853 |
return ppm_writeppmrowplain( file, pixelrow, cols, maxval ); |
854 |
} |
855 |
|
856 |
void |
857 |
pnm_init2( pn ) |
858 |
char* pn; |
859 |
{ |
860 |
/* Save program name. */ |
861 |
progname = pn; |
862 |
} |
863 |
|
864 |
xelval pnm_pbmmaxval = 1; |
865 |
|
866 |
int |
867 |
pnm_readpnminit( file, colsP, rowsP, maxvalP, formatP ) |
868 |
FILE* file; |
869 |
int* colsP; |
870 |
int* rowsP; |
871 |
int* formatP; |
872 |
xelval* maxvalP; |
873 |
{ |
874 |
gray gmaxval; |
875 |
|
876 |
/* Check magic number. */ |
877 |
*formatP = pbm_readmagicnumber( file ); |
878 |
if ( *formatP == -1 ) |
879 |
return -1; |
880 |
switch ( PNM_FORMAT_TYPE(*formatP) ) |
881 |
{ |
882 |
case PPM_TYPE: |
883 |
if ( ppm_readppminitrest( file, colsP, rowsP, (pixval*) maxvalP ) < 0 ) |
884 |
return -1; |
885 |
break; |
886 |
|
887 |
case PGM_TYPE: |
888 |
if ( pgm_readpgminitrest( file, colsP, rowsP, &gmaxval ) < 0 ) |
889 |
return -1; |
890 |
*maxvalP = (xelval) gmaxval; |
891 |
break; |
892 |
|
893 |
case PBM_TYPE: |
894 |
if ( pbm_readpbminitrest( file, colsP, rowsP ) < 0 ) |
895 |
return -1; |
896 |
*maxvalP = pnm_pbmmaxval; |
897 |
break; |
898 |
|
899 |
default: |
900 |
(void) fprintf( |
901 |
stderr, "%s: bad magic number - not a ppm, pgm, or pbm file\n", |
902 |
progname ); |
903 |
return -1; |
904 |
} |
905 |
return 0; |
906 |
} |
907 |
|
908 |
#if __STDC__ |
909 |
int |
910 |
pnm_readpnmrow( FILE* file, xel* xelrow, int cols, xelval maxval, int format ) |
911 |
#else /*__STDC__*/ |
912 |
int |
913 |
pnm_readpnmrow( file, xelrow, cols, maxval, format ) |
914 |
FILE* file; |
915 |
xel* xelrow; |
916 |
xelval maxval; |
917 |
int cols, format; |
918 |
#endif /*__STDC__*/ |
919 |
{ |
920 |
register int col; |
921 |
register xel* xP; |
922 |
gray* grayrow; |
923 |
register gray* gP; |
924 |
bit* bitrow; |
925 |
register bit* bP; |
926 |
|
927 |
switch ( PNM_FORMAT_TYPE(format) ) |
928 |
{ |
929 |
case PPM_TYPE: |
930 |
if ( ppm_readppmrow( file, (pixel*) xelrow, cols, (pixval) maxval, format ) < 0 ) |
931 |
return -1; |
932 |
break; |
933 |
|
934 |
case PGM_TYPE: |
935 |
grayrow = pgm_allocrow( cols ); |
936 |
if ( grayrow == (gray*) 0 ) |
937 |
return -1; |
938 |
if ( pgm_readpgmrow( file, grayrow, cols, (gray) maxval, format ) < 0 ) |
939 |
return -1; |
940 |
for ( col = 0, xP = xelrow, gP = grayrow; col < cols; ++col, ++xP, ++gP ) |
941 |
PNM_ASSIGN1( *xP, *gP ); |
942 |
pgm_freerow( grayrow ); |
943 |
break; |
944 |
|
945 |
case PBM_TYPE: |
946 |
bitrow = pbm_allocrow( cols ); |
947 |
if ( bitrow == (bit*) 0 ) |
948 |
return -1; |
949 |
if ( pbm_readpbmrow( file, bitrow, cols, format ) < 0 ) |
950 |
{ |
951 |
pbm_freerow( bitrow ); |
952 |
return -1; |
953 |
} |
954 |
for ( col = 0, xP = xelrow, bP = bitrow; col < cols; ++col, ++xP, ++bP ) |
955 |
PNM_ASSIGN1( *xP, *bP == PBM_BLACK ? 0: pnm_pbmmaxval ); |
956 |
pbm_freerow( bitrow ); |
957 |
break; |
958 |
|
959 |
default: |
960 |
(void) fprintf( stderr, "%s: can't happen\n", progname ); |
961 |
return -1; |
962 |
} |
963 |
return 0; |
964 |
} |
965 |
|
966 |
xel** |
967 |
pnm_readpnm( file, colsP, rowsP, maxvalP, formatP ) |
968 |
FILE* file; |
969 |
int* colsP; |
970 |
int* rowsP; |
971 |
int* formatP; |
972 |
xelval* maxvalP; |
973 |
{ |
974 |
xel** xels; |
975 |
int row; |
976 |
|
977 |
if ( pnm_readpnminit( file, colsP, rowsP, maxvalP, formatP ) < 0 ) |
978 |
return (xel**) 0; |
979 |
|
980 |
xels = pnm_allocarray( *colsP, *rowsP ); |
981 |
if ( xels == (xel**) 0 ) |
982 |
return (xel**) 0; |
983 |
|
984 |
for ( row = 0; row < *rowsP; ++row ) |
985 |
if ( pnm_readpnmrow( file, xels[row], *colsP, *maxvalP, *formatP ) < 0 ) |
986 |
{ |
987 |
pnm_freearray( xels, *rowsP ); |
988 |
return (xel**) 0; |
989 |
} |
990 |
|
991 |
return xels; |
992 |
} |
993 |
|
994 |
#if __STDC__ |
995 |
int |
996 |
pnm_writepnminit( FILE* file, int cols, int rows, xelval maxval, int format, int forceplain ) |
997 |
#else /*__STDC__*/ |
998 |
int |
999 |
pnm_writepnminit( file, cols, rows, maxval, format, forceplain ) |
1000 |
FILE* file; |
1001 |
int cols, rows, format; |
1002 |
xelval maxval; |
1003 |
int forceplain; |
1004 |
#endif /*__STDC__*/ |
1005 |
{ |
1006 |
switch ( PNM_FORMAT_TYPE(format) ) |
1007 |
{ |
1008 |
case PPM_TYPE: |
1009 |
ppm_writeppminit( file, cols, rows, (pixval) maxval, forceplain ); |
1010 |
break; |
1011 |
|
1012 |
case PGM_TYPE: |
1013 |
pgm_writepgminit( file, cols, rows, (gray) maxval, forceplain ); |
1014 |
break; |
1015 |
|
1016 |
case PBM_TYPE: |
1017 |
pbm_writepbminit( file, cols, rows, forceplain ); |
1018 |
break; |
1019 |
|
1020 |
default: |
1021 |
(void) fprintf( stderr, "%s: can't happen\n", progname ); |
1022 |
return -1; |
1023 |
} |
1024 |
return 0; |
1025 |
} |
1026 |
|
1027 |
#if __STDC__ |
1028 |
int |
1029 |
pnm_writepnmrow( FILE* file, xel* xelrow, int cols, xelval maxval, int format, int forceplain ) |
1030 |
#else /*__STDC__*/ |
1031 |
int |
1032 |
pnm_writepnmrow( file, xelrow, cols, maxval, format, forceplain ) |
1033 |
FILE* file; |
1034 |
xel* xelrow; |
1035 |
int cols, format; |
1036 |
xelval maxval; |
1037 |
int forceplain; |
1038 |
#endif /*__STDC__*/ |
1039 |
{ |
1040 |
register int col; |
1041 |
register xel* xP; |
1042 |
gray* grayrow; |
1043 |
register gray* gP; |
1044 |
bit* bitrow; |
1045 |
register bit* bP; |
1046 |
|
1047 |
switch ( PNM_FORMAT_TYPE(format) ) |
1048 |
{ |
1049 |
case PPM_TYPE: |
1050 |
if ( ppm_writeppmrow( file, (pixel*) xelrow, cols, (pixval) maxval, forceplain ) < 0 ) |
1051 |
return -1; |
1052 |
break; |
1053 |
|
1054 |
case PGM_TYPE: |
1055 |
grayrow = pgm_allocrow( cols ); |
1056 |
if ( grayrow == (gray*) 0 ) |
1057 |
return -1; |
1058 |
for ( col = 0, gP = grayrow, xP = xelrow; col < cols; ++col, ++gP, ++xP ) |
1059 |
*gP = PNM_GET1( *xP ); |
1060 |
if ( pgm_writepgmrow( file, grayrow, cols, (gray) maxval, forceplain ) < 0 ) |
1061 |
{ |
1062 |
pgm_freerow( grayrow ); |
1063 |
return -1; |
1064 |
} |
1065 |
pgm_freerow( grayrow ); |
1066 |
break; |
1067 |
|
1068 |
case PBM_TYPE: |
1069 |
bitrow = pbm_allocrow( cols ); |
1070 |
if ( bitrow == (bit*) 0 ) |
1071 |
return -1; |
1072 |
for ( col = 0, bP = bitrow, xP = xelrow; col < cols; ++col, ++bP, ++xP ) |
1073 |
*bP = PNM_GET1( *xP ) == 0 ? PBM_BLACK : PBM_WHITE; |
1074 |
pbm_writepbmrow( file, bitrow, cols, forceplain ); |
1075 |
pbm_freerow( bitrow ); |
1076 |
break; |
1077 |
|
1078 |
default: |
1079 |
(void) fprintf( stderr, "%s: can't happen\n", progname ); |
1080 |
return -1; |
1081 |
} |
1082 |
return 0; |
1083 |
} |
1084 |
|
1085 |
#if __STDC__ |
1086 |
int |
1087 |
pnm_writepnm( FILE* file, xel** xels, int cols, int rows, xelval maxval, int format, int forceplain ) |
1088 |
#else /*__STDC__*/ |
1089 |
int |
1090 |
pnm_writepnm( file, xels, cols, rows, maxval, format, forceplain ) |
1091 |
FILE* file; |
1092 |
xel** xels; |
1093 |
xelval maxval; |
1094 |
int cols, rows, format; |
1095 |
int forceplain; |
1096 |
#endif /*__STDC__*/ |
1097 |
{ |
1098 |
int row; |
1099 |
|
1100 |
if ( pnm_writepnminit( file, cols, rows, maxval, format, forceplain ) < 0 ) |
1101 |
return -1; |
1102 |
|
1103 |
for ( row = 0; row < rows; ++row ) |
1104 |
if ( pnm_writepnmrow( file, xels[row], cols, maxval, format, forceplain ) < 0 ) |
1105 |
return -1; |
1106 |
return 0; |
1107 |
} |
1108 |
|
1109 |
|
1110 |
/* Colormap stuff. */ |
1111 |
|
1112 |
#define HASH_SIZE 20023 |
1113 |
|
1114 |
#define ppm_hashpixel(p) ( ( ( (long) PPM_GETR(p) * 33023 + (long) PPM_GETG(p) * 30013 + (long) PPM_GETB(p) * 27011 ) & 0x7fffffff ) % HASH_SIZE ) |
1115 |
|
1116 |
colorhist_vector |
1117 |
ppm_computecolorhist( pixels, cols, rows, maxcolors, colorsP ) |
1118 |
pixel** pixels; |
1119 |
int cols, rows, maxcolors; |
1120 |
int* colorsP; |
1121 |
{ |
1122 |
colorhash_table cht; |
1123 |
colorhist_vector chv; |
1124 |
|
1125 |
cht = ppm_computecolorhash( pixels, cols, rows, maxcolors, colorsP ); |
1126 |
if ( cht == (colorhash_table) 0 ) |
1127 |
return (colorhist_vector) 0; |
1128 |
chv = ppm_colorhashtocolorhist( cht, maxcolors ); |
1129 |
ppm_freecolorhash( cht ); |
1130 |
return chv; |
1131 |
} |
1132 |
|
1133 |
void |
1134 |
ppm_addtocolorhist( chv, colorsP, maxcolors, colorP, value, position ) |
1135 |
colorhist_vector chv; |
1136 |
pixel* colorP; |
1137 |
int* colorsP; |
1138 |
int maxcolors, value, position; |
1139 |
{ |
1140 |
int i, j; |
1141 |
|
1142 |
/* Search colorhist for the color. */ |
1143 |
for ( i = 0; i < *colorsP; ++i ) |
1144 |
if ( PPM_EQUAL( chv[i].color, *colorP ) ) |
1145 |
{ |
1146 |
/* Found it - move to new slot. */ |
1147 |
if ( position > i ) |
1148 |
{ |
1149 |
for ( j = i; j < position; ++j ) |
1150 |
chv[j] = chv[j + 1]; |
1151 |
} |
1152 |
else if ( position < i ) |
1153 |
{ |
1154 |
for ( j = i; j > position; --j ) |
1155 |
chv[j] = chv[j - 1]; |
1156 |
} |
1157 |
chv[position].color = *colorP; |
1158 |
chv[position].value = value; |
1159 |
return; |
1160 |
} |
1161 |
if ( *colorsP < maxcolors ) |
1162 |
{ |
1163 |
/* Didn't find it, but there's room to add it; so do so. */ |
1164 |
for ( i = *colorsP; i > position; --i ) |
1165 |
chv[i] = chv[i - 1]; |
1166 |
chv[position].color = *colorP; |
1167 |
chv[position].value = value; |
1168 |
++(*colorsP); |
1169 |
} |
1170 |
} |
1171 |
|
1172 |
colorhash_table |
1173 |
ppm_computecolorhash( pixels, cols, rows, maxcolors, colorsP ) |
1174 |
pixel** pixels; |
1175 |
int cols, rows, maxcolors; |
1176 |
int* colorsP; |
1177 |
{ |
1178 |
colorhash_table cht; |
1179 |
register pixel* pP; |
1180 |
colorhist_list chl; |
1181 |
int col, row, hash; |
1182 |
|
1183 |
cht = ppm_alloccolorhash( ); |
1184 |
if ( cht == (colorhash_table) 0 ) |
1185 |
return (colorhash_table) 0; |
1186 |
*colorsP = 0; |
1187 |
|
1188 |
/* Go through the entire image, building a hash table of colors. */ |
1189 |
for ( row = 0; row < rows; ++row ) |
1190 |
for ( col = 0, pP = pixels[row]; col < cols; ++col, ++pP ) |
1191 |
{ |
1192 |
hash = ppm_hashpixel( *pP ); |
1193 |
for ( chl = cht[hash]; chl != (colorhist_list) 0; chl = chl->next ) |
1194 |
if ( PPM_EQUAL( chl->ch.color, *pP ) ) |
1195 |
break; |
1196 |
if ( chl != (colorhist_list) 0 ) |
1197 |
++(chl->ch.value); |
1198 |
else |
1199 |
{ |
1200 |
if ( ++(*colorsP) > maxcolors ) |
1201 |
{ |
1202 |
ppm_freecolorhash( cht ); |
1203 |
return (colorhash_table) 0; |
1204 |
} |
1205 |
chl = (colorhist_list) malloc( sizeof(struct colorhist_list_item) ); |
1206 |
if ( chl == 0 ) |
1207 |
{ |
1208 |
(void) fprintf( |
1209 |
stderr, "%s: out of memory computing hash table\n", |
1210 |
progname ); |
1211 |
ppm_freecolorhash( cht ); |
1212 |
return (colorhash_table) 0; |
1213 |
} |
1214 |
chl->ch.color = *pP; |
1215 |
chl->ch.value = 1; |
1216 |
chl->next = cht[hash]; |
1217 |
cht[hash] = chl; |
1218 |
} |
1219 |
} |
1220 |
|
1221 |
return cht; |
1222 |
} |
1223 |
|
1224 |
colorhash_table |
1225 |
ppm_alloccolorhash( ) |
1226 |
{ |
1227 |
colorhash_table cht; |
1228 |
int i; |
1229 |
|
1230 |
cht = (colorhash_table) malloc( HASH_SIZE * sizeof(colorhist_list) ); |
1231 |
if ( cht == 0 ) |
1232 |
{ |
1233 |
(void) fprintf( |
1234 |
stderr, "%s: out of memory allocating hash table\n", progname ); |
1235 |
return (colorhash_table) 0; |
1236 |
} |
1237 |
|
1238 |
for ( i = 0; i < HASH_SIZE; ++i ) |
1239 |
cht[i] = (colorhist_list) 0; |
1240 |
|
1241 |
return cht; |
1242 |
} |
1243 |
|
1244 |
int |
1245 |
ppm_addtocolorhash( cht, colorP, value ) |
1246 |
colorhash_table cht; |
1247 |
pixel* colorP; |
1248 |
int value; |
1249 |
{ |
1250 |
register int hash; |
1251 |
register colorhist_list chl; |
1252 |
|
1253 |
chl = (colorhist_list) malloc( sizeof(struct colorhist_list_item) ); |
1254 |
if ( chl == 0 ) |
1255 |
return -1; |
1256 |
hash = ppm_hashpixel( *colorP ); |
1257 |
chl->ch.color = *colorP; |
1258 |
chl->ch.value = value; |
1259 |
chl->next = cht[hash]; |
1260 |
cht[hash] = chl; |
1261 |
return 0; |
1262 |
} |
1263 |
|
1264 |
colorhist_vector |
1265 |
ppm_colorhashtocolorhist( cht, maxcolors ) |
1266 |
colorhash_table cht; |
1267 |
int maxcolors; |
1268 |
{ |
1269 |
colorhist_vector chv; |
1270 |
colorhist_list chl; |
1271 |
int i, j; |
1272 |
|
1273 |
/* Now collate the hash table into a simple colorhist array. */ |
1274 |
chv = (colorhist_vector) malloc( maxcolors * sizeof(struct colorhist_item) ); |
1275 |
/* (Leave room for expansion by caller.) */ |
1276 |
if ( chv == (colorhist_vector) 0 ) |
1277 |
{ |
1278 |
(void) fprintf( |
1279 |
stderr, "%s: out of memory generating histogram\n", progname ); |
1280 |
return (colorhist_vector) 0; |
1281 |
} |
1282 |
|
1283 |
/* Loop through the hash table. */ |
1284 |
j = 0; |
1285 |
for ( i = 0; i < HASH_SIZE; ++i ) |
1286 |
for ( chl = cht[i]; chl != (colorhist_list) 0; chl = chl->next ) |
1287 |
{ |
1288 |
/* Add the new entry. */ |
1289 |
chv[j] = chl->ch; |
1290 |
++j; |
1291 |
} |
1292 |
|
1293 |
/* All done. */ |
1294 |
return chv; |
1295 |
} |
1296 |
|
1297 |
colorhash_table |
1298 |
ppm_colorhisttocolorhash( chv, colors ) |
1299 |
colorhist_vector chv; |
1300 |
int colors; |
1301 |
{ |
1302 |
colorhash_table cht; |
1303 |
int i, hash; |
1304 |
pixel color; |
1305 |
colorhist_list chl; |
1306 |
|
1307 |
cht = ppm_alloccolorhash( ); |
1308 |
if ( cht == (colorhash_table) 0 ) |
1309 |
return (colorhash_table) 0; |
1310 |
|
1311 |
for ( i = 0; i < colors; ++i ) |
1312 |
{ |
1313 |
color = chv[i].color; |
1314 |
hash = ppm_hashpixel( color ); |
1315 |
for ( chl = cht[hash]; chl != (colorhist_list) 0; chl = chl->next ) |
1316 |
if ( PPM_EQUAL( chl->ch.color, color ) ) |
1317 |
{ |
1318 |
(void) fprintf( |
1319 |
stderr, "%s: same color found twice - %d %d %d\n", progname, |
1320 |
PPM_GETR(color), PPM_GETG(color), PPM_GETB(color) ); |
1321 |
ppm_freecolorhash( cht ); |
1322 |
return (colorhash_table) 0; |
1323 |
} |
1324 |
chl = (colorhist_list) malloc( sizeof(struct colorhist_list_item) ); |
1325 |
if ( chl == (colorhist_list) 0 ) |
1326 |
{ |
1327 |
(void) fprintf( stderr, "%s: out of memory\n", progname ); |
1328 |
ppm_freecolorhash( cht ); |
1329 |
return (colorhash_table) 0; |
1330 |
} |
1331 |
chl->ch.color = color; |
1332 |
chl->ch.value = i; |
1333 |
chl->next = cht[hash]; |
1334 |
cht[hash] = chl; |
1335 |
} |
1336 |
|
1337 |
return cht; |
1338 |
} |
1339 |
|
1340 |
int |
1341 |
ppm_lookupcolor( cht, colorP ) |
1342 |
colorhash_table cht; |
1343 |
pixel* colorP; |
1344 |
{ |
1345 |
int hash; |
1346 |
colorhist_list chl; |
1347 |
|
1348 |
hash = ppm_hashpixel( *colorP ); |
1349 |
for ( chl = cht[hash]; chl != (colorhist_list) 0; chl = chl->next ) |
1350 |
if ( PPM_EQUAL( chl->ch.color, *colorP ) ) |
1351 |
return chl->ch.value; |
1352 |
|
1353 |
return -1; |
1354 |
} |
1355 |
|
1356 |
void |
1357 |
ppm_freecolorhist( chv ) |
1358 |
colorhist_vector chv; |
1359 |
{ |
1360 |
free( (char*) chv ); |
1361 |
} |
1362 |
|
1363 |
void |
1364 |
ppm_freecolorhash( cht ) |
1365 |
colorhash_table cht; |
1366 |
{ |
1367 |
int i; |
1368 |
colorhist_list chl, chlnext; |
1369 |
|
1370 |
for ( i = 0; i < HASH_SIZE; ++i ) |
1371 |
for ( chl = cht[i]; chl != (colorhist_list) 0; chl = chlnext ) |
1372 |
{ |
1373 |
chlnext = chl->next; |
1374 |
free( (char*) chl ); |
1375 |
} |
1376 |
free( (char*) cht ); |
1377 |
} |
1378 |
|
1379 |
|
1380 |
|
1381 |
|
1382 |
/* added from libpnm3.c: */ |
1383 |
|
1384 |
/* libpnm3.c - pnm utility library part 3 |
1385 |
** |
1386 |
** Copyright (C) 1989, 1991 by Jef Poskanzer. |
1387 |
** |
1388 |
** Permission to use, copy, modify, and distribute this software and its |
1389 |
** documentation for any purpose and without fee is hereby granted, provided |
1390 |
** that the above copyright notice appear in all copies and that both that |
1391 |
** copyright notice and this permission notice appear in supporting |
1392 |
** documentation. This software is provided "as is" without express or |
1393 |
** implied warranty. |
1394 |
*/ |
1395 |
|
1396 |
#if __STDC__ |
1397 |
xel |
1398 |
pnm_backgroundxel( xel** xels, int cols, int rows, xelval maxval, int format ) |
1399 |
#else /*__STDC__*/ |
1400 |
xel |
1401 |
pnm_backgroundxel( xels, cols, rows, maxval, format ) |
1402 |
xel** xels; |
1403 |
int cols, rows, format; |
1404 |
xelval maxval; |
1405 |
#endif /*__STDC__*/ |
1406 |
{ |
1407 |
xel bgxel, ul, ur, ll, lr; |
1408 |
|
1409 |
/* Guess a good background value. */ |
1410 |
ul = xels[0][0]; |
1411 |
ur = xels[0][cols-1]; |
1412 |
ll = xels[rows-1][0]; |
1413 |
lr = xels[rows-1][cols-1]; |
1414 |
|
1415 |
/* First check for three corners equal. */ |
1416 |
if ( PNM_EQUAL( ul, ur ) && PNM_EQUAL( ur, ll ) ) |
1417 |
bgxel = ul; |
1418 |
else if ( PNM_EQUAL( ul, ur ) && PNM_EQUAL( ur, lr ) ) |
1419 |
bgxel = ul; |
1420 |
else if ( PNM_EQUAL( ul, ll ) && PNM_EQUAL( ll, lr ) ) |
1421 |
bgxel = ul; |
1422 |
else if ( PNM_EQUAL( ur, ll ) && PNM_EQUAL( ll, lr ) ) |
1423 |
bgxel = ur; |
1424 |
/* Nope, check for two corners equal. */ |
1425 |
else if ( PNM_EQUAL( ul, ur ) || PNM_EQUAL( ul, ll ) || |
1426 |
PNM_EQUAL( ul, lr ) ) |
1427 |
bgxel = ul; |
1428 |
else if ( PNM_EQUAL( ur, ll ) || PNM_EQUAL( ur, lr ) ) |
1429 |
bgxel = ur; |
1430 |
else if ( PNM_EQUAL( ll, lr ) ) |
1431 |
bgxel = ll; |
1432 |
else |
1433 |
{ |
1434 |
/* Nope, we have to average the four corners. This breaks the |
1435 |
** rules of pnm, but oh well. Let's try to do it portably. */ |
1436 |
switch ( PNM_FORMAT_TYPE(format) ) |
1437 |
{ |
1438 |
case PPM_TYPE: |
1439 |
PPM_ASSIGN( bgxel, |
1440 |
PPM_GETR(ul) + PPM_GETR(ur) + PPM_GETR(ll) + PPM_GETR(lr) / 4, |
1441 |
PPM_GETG(ul) + PPM_GETG(ur) + PPM_GETG(ll) + PPM_GETG(lr) / 4, |
1442 |
PPM_GETB(ul) + PPM_GETB(ur) + PPM_GETB(ll) + PPM_GETB(lr) / 4 ); |
1443 |
break; |
1444 |
|
1445 |
case PGM_TYPE: |
1446 |
{ |
1447 |
gray gul, gur, gll, glr; |
1448 |
gul = (gray) PNM_GET1( ul ); |
1449 |
gur = (gray) PNM_GET1( ur ); |
1450 |
gll = (gray) PNM_GET1( ll ); |
1451 |
glr = (gray) PNM_GET1( lr ); |
1452 |
PNM_ASSIGN1( bgxel, ( ( gul + gur + gll + glr ) / 4 ) ); |
1453 |
break; |
1454 |
} |
1455 |
|
1456 |
case PBM_TYPE: |
1457 |
pm_error( |
1458 |
"pnm_backgroundxel: four bits no two of which equal each other??" ); |
1459 |
|
1460 |
default: |
1461 |
pm_error( "can't happen" ); |
1462 |
} |
1463 |
} |
1464 |
|
1465 |
return bgxel; |
1466 |
} |
1467 |
|
1468 |
#if __STDC__ |
1469 |
xel |
1470 |
pnm_backgroundxelrow( xel* xelrow, int cols, xelval maxval, int format ) |
1471 |
#else /*__STDC__*/ |
1472 |
xel |
1473 |
pnm_backgroundxelrow( xelrow, cols, maxval, format ) |
1474 |
xel* xelrow; |
1475 |
int cols, format; |
1476 |
xelval maxval; |
1477 |
#endif /*__STDC__*/ |
1478 |
{ |
1479 |
xel bgxel, l, r; |
1480 |
|
1481 |
/* Guess a good background value. */ |
1482 |
l = xelrow[0]; |
1483 |
r = xelrow[cols-1]; |
1484 |
|
1485 |
/* First check for both corners equal. */ |
1486 |
if ( PNM_EQUAL( l, r ) ) |
1487 |
bgxel = l; |
1488 |
else |
1489 |
{ |
1490 |
/* Nope, we have to average the two corners. This breaks the |
1491 |
** rules of pnm, but oh well. Let's try to do it portably. */ |
1492 |
switch ( PNM_FORMAT_TYPE(format) ) |
1493 |
{ |
1494 |
case PPM_TYPE: |
1495 |
PPM_ASSIGN( bgxel, PPM_GETR(l) + PPM_GETR(r) / 2, |
1496 |
PPM_GETG(l) + PPM_GETG(r) / 2, PPM_GETB(l) + PPM_GETB(r) / 2 ); |
1497 |
break; |
1498 |
|
1499 |
case PGM_TYPE: |
1500 |
{ |
1501 |
gray gl, gr; |
1502 |
gl = (gray) PNM_GET1( l ); |
1503 |
gr = (gray) PNM_GET1( r ); |
1504 |
PNM_ASSIGN1( bgxel, ( ( gl + gr ) / 2 ) ); |
1505 |
break; |
1506 |
} |
1507 |
|
1508 |
case PBM_TYPE: |
1509 |
{ |
1510 |
int col, blacks; |
1511 |
|
1512 |
/* One black, one white. Gotta count. */ |
1513 |
for ( col = 0, blacks = 0; col < cols; ++col ) |
1514 |
{ |
1515 |
if ( PNM_GET1( xelrow[col] ) == 0 ) |
1516 |
++blacks; |
1517 |
} |
1518 |
if ( blacks >= cols / 2 ) |
1519 |
PNM_ASSIGN1( bgxel, 0 ); |
1520 |
else |
1521 |
PNM_ASSIGN1( bgxel, pnm_pbmmaxval ); |
1522 |
break; |
1523 |
} |
1524 |
|
1525 |
default: |
1526 |
pm_error( "can't happen" ); |
1527 |
} |
1528 |
} |
1529 |
|
1530 |
return bgxel; |
1531 |
} |
1532 |
|
1533 |
#if __STDC__ |
1534 |
xel |
1535 |
pnm_whitexel( xelval maxval, int format ) |
1536 |
#else /*__STDC__*/ |
1537 |
xel |
1538 |
pnm_whitexel( maxval, format ) |
1539 |
xelval maxval; |
1540 |
int format; |
1541 |
#endif /*__STDC__*/ |
1542 |
{ |
1543 |
xel x; |
1544 |
|
1545 |
switch ( PNM_FORMAT_TYPE(format) ) |
1546 |
{ |
1547 |
case PPM_TYPE: |
1548 |
PPM_ASSIGN( x, maxval, maxval, maxval ); |
1549 |
break; |
1550 |
|
1551 |
case PGM_TYPE: |
1552 |
PNM_ASSIGN1( x, maxval ); |
1553 |
break; |
1554 |
|
1555 |
case PBM_TYPE: |
1556 |
PNM_ASSIGN1( x, pnm_pbmmaxval ); |
1557 |
break; |
1558 |
|
1559 |
default: |
1560 |
pm_error( "can't happen" ); |
1561 |
} |
1562 |
|
1563 |
return x; |
1564 |
} |
1565 |
|
1566 |
#if __STDC__ |
1567 |
xel |
1568 |
pnm_blackxel( xelval maxval, int format ) |
1569 |
#else /*__STDC__*/ |
1570 |
xel |
1571 |
pnm_blackxel( maxval, format ) |
1572 |
xelval maxval; |
1573 |
int format; |
1574 |
#endif /*__STDC__*/ |
1575 |
{ |
1576 |
xel x; |
1577 |
|
1578 |
switch ( PNM_FORMAT_TYPE(format) ) |
1579 |
{ |
1580 |
case PPM_TYPE: |
1581 |
PPM_ASSIGN( x, 0, 0, 0 ); |
1582 |
break; |
1583 |
|
1584 |
case PGM_TYPE: |
1585 |
PNM_ASSIGN1( x, (xelval) 0 ); |
1586 |
break; |
1587 |
|
1588 |
case PBM_TYPE: |
1589 |
PNM_ASSIGN1( x, (xelval) 0 ); |
1590 |
break; |
1591 |
|
1592 |
default: |
1593 |
pm_error( "can't happen" ); |
1594 |
} |
1595 |
|
1596 |
return x; |
1597 |
} |
1598 |
|
1599 |
#if __STDC__ |
1600 |
void |
1601 |
pnm_invertxel( xel* xP, xelval maxval, int format ) |
1602 |
#else /*__STDC__*/ |
1603 |
void |
1604 |
pnm_invertxel( xP, maxval, format ) |
1605 |
xel* xP; |
1606 |
xelval maxval; |
1607 |
int format; |
1608 |
#endif /*__STDC__*/ |
1609 |
{ |
1610 |
switch ( PNM_FORMAT_TYPE(format) ) |
1611 |
{ |
1612 |
case PPM_TYPE: |
1613 |
PPM_ASSIGN( |
1614 |
*xP, maxval - PPM_GETR( *xP ), |
1615 |
maxval - PPM_GETG( *xP ), maxval - PPM_GETB( *xP ) ); |
1616 |
break; |
1617 |
|
1618 |
case PGM_TYPE: |
1619 |
PNM_ASSIGN1( *xP, (gray) maxval - (gray) PNM_GET1( *xP ) ); |
1620 |
break; |
1621 |
|
1622 |
case PBM_TYPE: |
1623 |
PNM_ASSIGN1( *xP, ( PNM_GET1( *xP ) == 0 ) ? pnm_pbmmaxval : 0 ); |
1624 |
break; |
1625 |
|
1626 |
default: |
1627 |
pm_error( "can't happen" ); |
1628 |
} |
1629 |
} |
1630 |
|
1631 |
#if __STDC__ |
1632 |
void |
1633 |
pnm_promoteformat( xel** xels, int cols, int rows, xelval maxval, int format, xelval newmaxval, int newformat ) |
1634 |
#else /*__STDC__*/ |
1635 |
void |
1636 |
pnm_promoteformat( xels, cols, rows, maxval, format, newmaxval, newformat ) |
1637 |
xel** xels; |
1638 |
xelval maxval, newmaxval; |
1639 |
int cols, rows, format, newformat; |
1640 |
#endif /*__STDC__*/ |
1641 |
{ |
1642 |
int row; |
1643 |
|
1644 |
for ( row = 0; row < rows; ++row ) |
1645 |
pnm_promoteformatrow( |
1646 |
xels[row], cols, maxval, format, newmaxval, newformat ); |
1647 |
} |
1648 |
|
1649 |
#if __STDC__ |
1650 |
void |
1651 |
pnm_promoteformatrow( xel* xelrow, int cols, xelval maxval, int format, xelval newmaxval, int newformat ) |
1652 |
#else /*__STDC__*/ |
1653 |
void |
1654 |
pnm_promoteformatrow( xelrow, cols, maxval, format, newmaxval, newformat ) |
1655 |
xel* xelrow; |
1656 |
xelval maxval, newmaxval; |
1657 |
int cols, format, newformat; |
1658 |
#endif /*__STDC__*/ |
1659 |
{ |
1660 |
register int col; |
1661 |
register xel* xP; |
1662 |
|
1663 |
if ( ( PNM_FORMAT_TYPE(format) == PPM_TYPE && |
1664 |
( PNM_FORMAT_TYPE(newformat) == PGM_TYPE || |
1665 |
PNM_FORMAT_TYPE(newformat) == PBM_TYPE ) ) || |
1666 |
( PNM_FORMAT_TYPE(format) == PGM_TYPE && |
1667 |
PNM_FORMAT_TYPE(newformat) == PBM_TYPE ) ) |
1668 |
pm_error( "pnm_promoteformatrow: can't promote downwards!" ); |
1669 |
|
1670 |
/* Are we promoting to the same type? */ |
1671 |
if ( PNM_FORMAT_TYPE(format) == PNM_FORMAT_TYPE(newformat) ) |
1672 |
{ |
1673 |
if ( PNM_FORMAT_TYPE(format) == PBM_TYPE ) |
1674 |
return; |
1675 |
if ( newmaxval < maxval ) |
1676 |
pm_error( |
1677 |
"pnm_promoteformatrow: can't decrease maxval - try using pnmdepth" ); |
1678 |
if ( newmaxval == maxval ) |
1679 |
return; |
1680 |
/* Increase maxval. */ |
1681 |
switch ( PNM_FORMAT_TYPE(format) ) |
1682 |
{ |
1683 |
case PGM_TYPE: |
1684 |
for ( col = 0, xP = xelrow; col < cols; ++col, ++xP ) |
1685 |
PNM_ASSIGN1( |
1686 |
*xP, (int) PNM_GET1(*xP) * newmaxval / maxval ); |
1687 |
break; |
1688 |
|
1689 |
case PPM_TYPE: |
1690 |
for ( col = 0, xP = xelrow; col < cols; ++col, ++xP ) |
1691 |
PPM_DEPTH( *xP, *xP, maxval, newmaxval ); |
1692 |
break; |
1693 |
|
1694 |
default: |
1695 |
pm_error( "shouldn't happen" ); |
1696 |
} |
1697 |
return; |
1698 |
} |
1699 |
|
1700 |
/* We must be promoting to a higher type. */ |
1701 |
switch ( PNM_FORMAT_TYPE(format) ) |
1702 |
{ |
1703 |
case PBM_TYPE: |
1704 |
switch ( PNM_FORMAT_TYPE(newformat) ) |
1705 |
{ |
1706 |
case PGM_TYPE: |
1707 |
for ( col = 0, xP = xelrow; col < cols; ++col, ++xP ) |
1708 |
if ( PNM_GET1(*xP) == 0 ) |
1709 |
PNM_ASSIGN1( *xP, 0 ); |
1710 |
else |
1711 |
PNM_ASSIGN1( *xP, newmaxval ); |
1712 |
break; |
1713 |
|
1714 |
case PPM_TYPE: |
1715 |
for ( col = 0, xP = xelrow; col < cols; ++col, ++xP ) |
1716 |
if ( PNM_GET1(*xP) == 0 ) |
1717 |
PPM_ASSIGN( *xP, 0, 0, 0 ); |
1718 |
else |
1719 |
PPM_ASSIGN( *xP, newmaxval, newmaxval, newmaxval ); |
1720 |
break; |
1721 |
|
1722 |
default: |
1723 |
pm_error( "can't happen" ); |
1724 |
} |
1725 |
break; |
1726 |
|
1727 |
case PGM_TYPE: |
1728 |
switch ( PNM_FORMAT_TYPE(newformat) ) |
1729 |
{ |
1730 |
case PPM_TYPE: |
1731 |
if ( newmaxval < maxval ) |
1732 |
pm_error( |
1733 |
"pnm_promoteformatrow: can't decrease maxval - try using pnmdepth" ); |
1734 |
if ( newmaxval == maxval ) |
1735 |
{ |
1736 |
for ( col = 0, xP = xelrow; col < cols; ++col, ++xP ) |
1737 |
PPM_ASSIGN( |
1738 |
*xP, PNM_GET1(*xP), PNM_GET1(*xP), PNM_GET1(*xP) ); |
1739 |
} |
1740 |
else |
1741 |
{ /* Increase maxval. */ |
1742 |
for ( col = 0, xP = xelrow; col < cols; ++col, ++xP ) |
1743 |
PPM_ASSIGN( |
1744 |
*xP, (int) PNM_GET1(*xP) * newmaxval / maxval, |
1745 |
(int) PNM_GET1(*xP) * newmaxval / maxval, |
1746 |
(int) PNM_GET1(*xP) * newmaxval / maxval ); |
1747 |
} |
1748 |
break; |
1749 |
|
1750 |
default: |
1751 |
pm_error( "can't happen" ); |
1752 |
} |
1753 |
break; |
1754 |
|
1755 |
default: |
1756 |
pm_error( "can't happen" ); |
1757 |
} |
1758 |
} |