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 /* $Id: libpnmrw.c,v 1.22 2005/03/20 20:15:34 demailly Exp $ */
14
15 #include <stdlib.h>
16 #include <string.h>
17
18 #if defined(HAVE_PARAM_H)
19 #include <sys/param.h>
20 #endif
21
22 #if defined(SVR2) || defined(SVR3) || defined(SVR4) || defined(linux)
23 #ifndef SYSV
24 #define SYSV
25 #endif
26 #endif
27 #if ! ( defined(BSD) || defined(SYSV) || defined(MSDOS) )
28 /* CONFIGURE: If your system is >= 4.2BSD, set the BSD option; if you're a
29 ** System V site, set the SYSV option; and if you're IBM-compatible, set
30 ** MSDOS. If your compiler is ANSI C, you're probably better off setting
31 ** SYSV - all it affects is string handling.
32 */
33 #define BSD
34 /* #define SYSV */
35 /* #define MSDOS */
36 #endif
37
38 #include <stdio.h>
39 #include "libpnmrw.h"
40
41 typedef char *String;
42 #include "../messages.h"
43
44 #ifdef SYSV
45 #include <string.h>
46 #else /*SYSV */
47 #include <strings.h>
48 #endif /*SYSV */
49
50 #include <errno.h>
51
52 /* Definitions. */
53
54 extern void *xmalloc(size_t n);
55
56 #define pbm_allocarray( cols, rows ) \
57 ((bit**) pm_allocarray( cols, rows, sizeof(bit) ))
58 #define pbm_allocrow( cols ) ((bit*) pm_allocrow( cols, sizeof(bit) ))
59 #define pbm_freearray( bits, rows ) pm_freearray( (char**) bits, rows )
60 #define pbm_freerow( bitrow ) pm_freerow( (char*) bitrow )
61 #define pgm_allocarray( cols, rows ) \
62 ((gray**) pm_allocarray( cols, rows, sizeof(gray) ))
63 #define pgm_allocrow( cols ) ((gray*) pm_allocrow( cols, sizeof(gray) ))
64 #define pgm_freearray( grays, rows ) pm_freearray( (char**) grays, rows )
65 #define pgm_freerow( grayrow ) pm_freerow( (char*) grayrow )
66 #define ppm_allocarray( cols, rows ) \
67 ((pixel**) pm_allocarray( cols, rows, sizeof(pixel) ))
68 #define ppm_allocrow( cols ) ((pixel*) pm_allocrow( cols, sizeof(pixel) ))
69 #define ppm_freearray( pixels, rows ) pm_freearray( (char**) pixels, rows )
70 #define ppm_freerow( pixelrow ) pm_freerow( (char*) pixelrow )
71
72
73 /* Variables. */
74
75 static char *progname;
76
77
78 /* Variable-sized arrays. */
79
80 char *
pm_allocrow(int cols,int size)81 pm_allocrow(int cols, int size)
82 {
83 register char *itrow;
84
85 itrow = (char *) xmalloc(cols * size);
86 if (itrow == (char *) 0) {
87 fprintf(stderr, msgText[OUT_OF_MEMORY_ALLOCATING_A_ROW], progname);
88 return (char *) 0;
89 }
90 return itrow;
91 }
92
93 void
pm_freerow(char * itrow)94 pm_freerow(char *itrow)
95 {
96 free(itrow);
97 }
98
99 char **
pm_allocarray(int cols,int rows,int size)100 pm_allocarray(int cols, int rows, int size)
101 {
102 char **its;
103 int i;
104
105 its = (char **) xmalloc(rows * sizeof(char *));
106 if (its == (char **) 0) {
107 fprintf(stderr, msgText[OUT_OF_MEMORY_ALLOCATING_AN_ARRAY], progname);
108 return (char **) 0;
109 }
110 its[0] = (char *) xmalloc(rows * cols * size);
111 if (its[0] == (char *) 0) {
112 fprintf(stderr, msgText[OUT_OF_MEMORY_ALLOCATING_AN_ARRAY], progname);
113 free((char *) its);
114 return (char **) 0;
115 }
116 for (i = 1; i < rows; ++i)
117 its[i] = &(its[0][i * cols * size]);
118 return its;
119 }
120
121 void
pm_freearray(char ** its,int rows)122 pm_freearray(char **its, int rows)
123 {
124 free(its[0]);
125 free(its);
126 }
127
128
129 /* File open/close that handles "-" as stdin and checks errors. */
130
131 static void
pm_perror(char * reason)132 pm_perror(char *reason)
133 {
134 #if !defined(__NetBSD__)
135 #if defined(BSD4_4)
136 __const extern char *__const sys_errlist[];
137 #else
138 #ifndef __GLIBC__
139 #ifndef SYS_ERRLIST_DEFINED
140 #ifdef __CYGWIN__
141 # define sys_errlist _sys_errlist
142 #else
143 #ifdef MISSING_STRERROR
144 extern char *sys_errlist[];
145 #endif
146 #endif
147 #endif
148 #endif
149 #endif
150 #endif
151 char *e;
152
153 #ifdef MISSING_STRERROR
154 e = (char *)sys_errlist[errno];
155 #else
156 e = (char *)strerror(errno);
157 #endif
158
159 if (reason != 0 && reason[0] != '\0')
160 fprintf(stderr, "%s: %s - %s\n", progname, reason, e);
161 else
162 fprintf(stderr, "%s: %s\n", progname, e);
163 }
164
165 FILE *
pm_openr(char * name)166 pm_openr(char *name)
167 {
168 FILE *f;
169
170 if (strcmp(name, "-") == 0)
171 f = stdin;
172 else {
173 f = fopen(name, "r");
174 if (f == NULL) {
175 pm_perror(name);
176 return (FILE *) 0;
177 }
178 }
179 return f;
180 }
181
182 FILE *
pm_openw(char * name)183 pm_openw(char *name)
184 {
185 FILE *f;
186
187 f = fopen(name, "w");
188 if (f == NULL) {
189 pm_perror(name);
190 return (FILE *) 0;
191 }
192 return f;
193 }
194
195 int
pm_closer(FILE * f)196 pm_closer(FILE * f)
197 {
198 if (ferror(f)) {
199 fprintf(stderr, msgText[A_FILE_READ_ERROR_OCCURRED_AT_SOME_POINT],
200 progname);
201 return -1;
202 }
203 if (f != stdin)
204 if (fclose(f) != 0) {
205 pm_perror("fclose");
206 return -1;
207 }
208 return 0;
209 }
210
211 int
pm_closew(FILE * f)212 pm_closew(FILE * f)
213 {
214 fflush(f);
215 if (ferror(f)) {
216 fprintf(stderr, msgText[A_FILE_WRITE_ERROR_OCCURRED_AT_SOME_POINT],
217 progname);
218 return -1;
219 }
220 if (f != stdout)
221 if (fclose(f) != 0) {
222 pm_perror("fclose");
223 return -1;
224 }
225 return 0;
226 }
227
228 static int
pbm_getc(FILE * file)229 pbm_getc(FILE * file)
230 {
231 register int ich;
232
233 ich = getc(file);
234 if (ich == EOF) {
235 fprintf(stderr, msgText[READ_ERROR], progname);
236 return EOF;
237 }
238 if (ich == '#') {
239 do {
240 ich = getc(file);
241 if (ich == EOF) {
242 fprintf(stderr, msgText[READ_ERROR], progname);
243 return EOF;
244 }
245 }
246 while (ich != '\n' && ich != '\r');
247 }
248 return ich;
249 }
250
251 static bit
pbm_getbit(FILE * file)252 pbm_getbit(FILE * file)
253 {
254 register int ich;
255
256 do {
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 fprintf(stderr, msgText[JUNK_IN_FILE_WHERE_BITS_SHOULD_BE], progname);
265 return -1;
266 }
267 return (ich == '1') ? 1 : 0;
268 }
269
270 static int
pbm_readmagicnumber(FILE * file)271 pbm_readmagicnumber(FILE * file)
272 {
273 int ich1, ich2;
274
275 ich1 = getc(file);
276 if (ich1 == EOF) {
277 fprintf(stderr, msgText[READ_ERROR_READING_MAGIC_NUMBER], progname);
278 return -1;
279 }
280 ich2 = getc(file);
281 if (ich2 == EOF) {
282 fprintf(stderr, msgText[READ_ERROR_READING_MAGIC_NUMBER], progname);
283 return -1;
284 }
285 return ich1 * 256 + ich2;
286 }
287
288 static int
pbm_getint(FILE * file)289 pbm_getint(FILE * file)
290 {
291 register char ich;
292 register int i;
293
294 do {
295 ich = pbm_getc(file);
296 if (ich == EOF)
297 return -1;
298 }
299 while (ich == ' ' || ich == '\t' || ich == '\n' || ich == '\r');
300
301 if (ich < '0' || ich > '9') {
302 fprintf(stderr, msgText[JUNK_IN_FILE_WHERE_AN_INTEGER_SHOULD_BE],
303 progname);
304 return -1;
305 }
306 i = 0;
307 do {
308 i = i * 10 + ich - '0';
309 ich = pbm_getc(file);
310 if (ich == EOF)
311 return -1;
312 }
313 while (ich >= '0' && ich <= '9');
314
315 return i;
316 }
317
318 static int
pbm_readpbminitrest(FILE * file,int * colsP,int * rowsP)319 pbm_readpbminitrest(FILE * file, int *colsP, int *rowsP)
320 {
321 /* Read size. */
322 *colsP = pbm_getint(file);
323 *rowsP = pbm_getint(file);
324 if (*colsP == -1 || *rowsP == -1)
325 return -1;
326 return 0;
327 }
328
329 static int
pbm_getrawbyte(FILE * file)330 pbm_getrawbyte(FILE * file)
331 {
332 register int iby;
333
334 iby = getc(file);
335 if (iby == EOF) {
336 fprintf(stderr, msgText[READ_ERROR], progname);
337 return -1;
338 }
339 return iby;
340 }
341
342 static int
pbm_readpbmrow(FILE * file,bit * bitrow,int cols,int format)343 pbm_readpbmrow(FILE * file, bit * bitrow, int cols, int format)
344 {
345 register int col, bitshift, b;
346 register int item = 0;
347 register bit *bP;
348
349 switch (format) {
350 case PBM_FORMAT:
351 for (col = 0, bP = bitrow; col < cols; ++col, ++bP) {
352 b = pbm_getbit(file);
353 if (b == -1)
354 return -1;
355 *bP = b;
356 }
357 break;
358
359 case RPBM_FORMAT:
360 bitshift = -1;
361 for (col = 0, bP = bitrow; col < cols; ++col, ++bP) {
362 if (bitshift == -1) {
363 item = pbm_getrawbyte(file);
364 if (item == -1)
365 return -1;
366 bitshift = 7;
367 }
368 *bP = (item >> bitshift) & 1;
369 --bitshift;
370 }
371 break;
372
373 default:
374 fprintf(stderr, msgText[CANT_HAPPEN], progname);
375 return -1;
376 }
377 return 0;
378 }
379
380 static void
pbm_writepbminit(FILE * file,int cols,int rows,int forceplain)381 pbm_writepbminit(FILE * file, int cols, int rows, int forceplain)
382 {
383 if (!forceplain)
384 fprintf(file, "%c%c\n%d %d\n", PBM_MAGIC1, RPBM_MAGIC2, cols, rows);
385 else
386 fprintf(file, "%c%c\n%d %d\n", PBM_MAGIC1, PBM_MAGIC2, cols, rows);
387 }
388
389 static void
pbm_writepbmrowraw(FILE * file,bit * bitrow,int cols)390 pbm_writepbmrowraw(FILE * file, bit * bitrow, int cols)
391 {
392 register int col, bitshift;
393 register unsigned char item;
394 register bit *bP;
395
396 bitshift = 7;
397 item = 0;
398 for (col = 0, bP = bitrow; col < cols; ++col, ++bP) {
399 if (*bP)
400 item += 1 << bitshift;
401 --bitshift;
402 if (bitshift == -1) {
403 putc(item, file);
404 bitshift = 7;
405 item = 0;
406 }
407 }
408 if (bitshift != 7)
409 putc(item, file);
410 }
411
412 static void
pbm_writepbmrowplain(FILE * file,bit * bitrow,int cols)413 pbm_writepbmrowplain(FILE * file, bit * bitrow, int cols)
414 {
415 register int col, charcount;
416 register bit *bP;
417
418 charcount = 0;
419 for (col = 0, bP = bitrow; col < cols; ++col, ++bP) {
420 if (charcount >= 70) {
421 putc('\n', file);
422 charcount = 0;
423 }
424 putc(*bP ? '1' : '0', file);
425 ++charcount;
426 }
427 putc('\n', file);
428 }
429
430 static void
pbm_writepbmrow(FILE * file,bit * bitrow,int cols,int forceplain)431 pbm_writepbmrow(FILE * file, bit * bitrow, int cols, int forceplain)
432 {
433 if (!forceplain)
434 pbm_writepbmrowraw(file, bitrow, cols);
435 else
436 pbm_writepbmrowplain(file, bitrow, cols);
437 }
438
439 static int
pgm_readpgminitrest(FILE * file,int * colsP,int * rowsP,gray * maxvalP)440 pgm_readpgminitrest(FILE * file, int *colsP, int *rowsP, gray * maxvalP)
441 {
442 int maxval;
443
444 /* Read size. */
445 *colsP = pbm_getint(file);
446 *rowsP = pbm_getint(file);
447 if (*colsP == -1 || *rowsP == -1)
448 return -1;
449
450 /* Read maxval. */
451 maxval = pbm_getint(file);
452 if (maxval == -1)
453 return -1;
454 if (maxval > PGM_MAXMAXVAL) {
455 fprintf(stderr, msgText[MAXVAL_IS_TOO_LARGE], progname);
456 return -1;
457 }
458 *maxvalP = maxval;
459 return 0;
460 }
461
462 static int
pgm_readpgmrow(FILE * file,gray * grayrow,int cols,gray maxval,int format)463 pgm_readpgmrow(FILE * file, gray * grayrow, int cols, gray maxval, int format)
464 {
465 register int col, val;
466 register gray *gP;
467
468 switch (format) {
469 case PGM_FORMAT:
470 for (col = 0, gP = grayrow; col < cols; ++col, ++gP) {
471 val = pbm_getint(file);
472 if (val == -1)
473 return -1;
474 *gP = val;
475 }
476 break;
477
478 case RPGM_FORMAT:
479 if (fread(grayrow, 1, cols, file) != cols) {
480 fprintf(stderr, msgText[READ_ERROR], progname);
481 return -1;
482 }
483 break;
484
485 default:
486 fprintf(stderr, msgText[CANT_HAPPEN], progname);
487 return -1;
488 }
489 return 0;
490 }
491
492 static void
pgm_writepgminit(FILE * file,int cols,int rows,gray maxval,int forceplain)493 pgm_writepgminit(FILE * file, int cols, int rows, gray maxval, int forceplain)
494 {
495 if (!forceplain)
496 fprintf(
497 file, "%c%c\n%d %d\n%d\n", PGM_MAGIC1, RPGM_MAGIC2,
498 cols, rows, maxval);
499 else
500 fprintf(
501 file, "%c%c\n%d %d\n%d\n", PGM_MAGIC1, PGM_MAGIC2,
502 cols, rows, maxval);
503 }
504
505 static void
putus(short unsigned int n,FILE * file)506 putus(short unsigned int n, FILE * file)
507 {
508 if (n >= 10)
509 putus(n / 10, file);
510 putc(n % 10 + '0', file);
511 }
512
513 static int
pgm_writepgmrowraw(FILE * file,gray * grayrow,int cols,gray maxval)514 pgm_writepgmrowraw(FILE * file, gray * grayrow, int cols, gray maxval)
515 {
516 if (fwrite(grayrow, 1, cols, file) != cols) {
517 fprintf(stderr, msgText[WRITE_ERROR], progname);
518 return -1;
519 }
520 return 0;
521 }
522
523 static int
pgm_writepgmrowplain(FILE * file,gray * grayrow,int cols,gray maxval)524 pgm_writepgmrowplain(FILE * file, gray * grayrow, int cols, gray maxval)
525 {
526 register int col, charcount;
527 register gray *gP;
528
529 charcount = 0;
530 for (col = 0, gP = grayrow; col < cols; ++col, ++gP) {
531 if (charcount >= 65) {
532 putc('\n', file);
533 charcount = 0;
534 } else if (charcount > 0) {
535 putc(' ', file);
536 ++charcount;
537 }
538 putus((unsigned short) *gP, file);
539 charcount += 3;
540 }
541 if (charcount > 0)
542 putc('\n', file);
543 return 0;
544 }
545
546 static int
pgm_writepgmrow(FILE * file,gray * grayrow,int cols,gray maxval,int forceplain)547 pgm_writepgmrow(FILE * file, gray * grayrow, int cols, gray maxval, int forceplain)
548 {
549 if (!forceplain)
550 return pgm_writepgmrowraw(file, grayrow, cols, maxval);
551 else
552 return pgm_writepgmrowplain(file, grayrow, cols, maxval);
553 }
554
555 static int
ppm_readppminitrest(FILE * file,int * colsP,int * rowsP,pixval * maxvalP)556 ppm_readppminitrest(FILE * file, int *colsP, int *rowsP, pixval * maxvalP)
557 {
558 int maxval;
559
560 /* Read size. */
561 *colsP = pbm_getint(file);
562 *rowsP = pbm_getint(file);
563 if (*colsP == -1 || *rowsP == -1)
564 return -1;
565
566 /* Read maxval. */
567 maxval = pbm_getint(file);
568 if (maxval == -1)
569 return -1;
570 if (maxval > PPM_MAXMAXVAL) {
571 fprintf(stderr, msgText[MAXVAL_IS_TOO_LARGE], progname);
572 return -1;
573 }
574 *maxvalP = maxval;
575 return 0;
576 }
577
578 static int
ppm_readppmrow(FILE * file,pixel * pixelrow,int cols,pixval maxval,int format)579 ppm_readppmrow(FILE * file, pixel * pixelrow, int cols,
580 pixval maxval, int format)
581 {
582 register int col;
583 register pixel *pP;
584 register int r, g, b;
585 gray *grayrow;
586 register gray *gP;
587
588 switch (format) {
589 case PPM_FORMAT:
590 for (col = 0, pP = pixelrow; col < cols; ++col, ++pP) {
591 r = pbm_getint(file);
592 g = pbm_getint(file);
593 b = pbm_getint(file);
594 if (r == -1 || g == -1 || b == -1)
595 return -1;
596 PPM_ASSIGN(*pP, r, g, b);
597 }
598 break;
599
600 case RPPM_FORMAT:
601 grayrow = pgm_allocrow(3 * cols);
602 if (grayrow == (gray *) 0)
603 return -1;
604 if (fread(grayrow, 1, 3 * cols, file) != 3 * cols) {
605 fprintf(stderr, msgText[READ_ERROR], progname);
606 return -1;
607 }
608 for (col = 0, gP = grayrow, pP = pixelrow; col < cols; ++col, ++pP) {
609 r = *gP++;
610 g = *gP++;
611 b = *gP++;
612 PPM_ASSIGN(*pP, r, g, b);
613 }
614 pgm_freerow(grayrow);
615 break;
616
617 default:
618 fprintf(stderr, msgText[CANT_HAPPEN], progname);
619 return -1;
620 }
621 return 0;
622 }
623
624 static void
ppm_writeppminit(FILE * file,int cols,int rows,pixval maxval,int forceplain)625 ppm_writeppminit(FILE * file, int cols, int rows, pixval maxval, int forceplain)
626 {
627 if (!forceplain)
628 fprintf(
629 file, "%c%c\n%d %d\n%d\n", PPM_MAGIC1, RPPM_MAGIC2,
630 cols, rows, maxval);
631 else
632 fprintf(
633 file, "%c%c\n%d %d\n%d\n", PPM_MAGIC1, PPM_MAGIC2,
634 cols, rows, maxval);
635 }
636
637 static int
ppm_writeppmrowraw(FILE * file,pixel * pixelrow,int cols,pixval maxval)638 ppm_writeppmrowraw(FILE * file, pixel * pixelrow, int cols, pixval maxval)
639 {
640 register int col;
641 register pixel *pP;
642 gray *grayrow;
643 register gray *gP;
644
645 grayrow = pgm_allocrow(3 * cols);
646 if (grayrow == (gray *) 0)
647 return -1;
648 for (col = 0, pP = pixelrow, gP = grayrow; col < cols; ++col, ++pP) {
649 *gP++ = PPM_GETR(*pP);
650 *gP++ = PPM_GETG(*pP);
651 *gP++ = PPM_GETB(*pP);
652 }
653 if (fwrite(grayrow, 1, 3 * cols, file) != 3 * cols) {
654 fprintf(stderr, msgText[WRITE_ERROR], progname);
655 return -1;
656 }
657 pgm_freerow(grayrow);
658 return 0;
659 }
660
661 static int
ppm_writeppmrowplain(FILE * file,pixel * pixelrow,int cols,pixval maxval)662 ppm_writeppmrowplain(FILE * file, pixel * pixelrow, int cols, pixval maxval)
663 {
664 register int col, charcount;
665 register pixel *pP;
666 register pixval val;
667
668 charcount = 0;
669 for (col = 0, pP = pixelrow; col < cols; ++col, ++pP) {
670 if (charcount >= 65) {
671 putc('\n', file);
672 charcount = 0;
673 } else if (charcount > 0) {
674 putc(' ', file);
675 putc(' ', file);
676 charcount += 2;
677 }
678 val = PPM_GETR(*pP);
679 putus(val, file);
680 putc(' ', file);
681 val = PPM_GETG(*pP);
682 putus(val, file);
683 putc(' ', file);
684 val = PPM_GETB(*pP);
685 putus(val, file);
686 charcount += 11;
687 }
688 if (charcount > 0)
689 putc('\n', file);
690 return 0;
691 }
692
693 static int
ppm_writeppmrow(FILE * file,pixel * pixelrow,int cols,pixval maxval,int forceplain)694 ppm_writeppmrow(FILE * file, pixel * pixelrow, int cols,
695 pixval maxval, int forceplain)
696 {
697 if (!forceplain)
698 return ppm_writeppmrowraw(file, pixelrow, cols, maxval);
699 else
700 return ppm_writeppmrowplain(file, pixelrow, cols, maxval);
701 }
702
703 void
pnm_init2(char * pn)704 pnm_init2(char *pn)
705 {
706 /* Save program name. */
707 progname = pn;
708 }
709
710 xelval pnm_pbmmaxval = 1;
711
712 int
pnm_readpnminit(FILE * file,int * colsP,int * rowsP,xelval * maxvalP,int * formatP)713 pnm_readpnminit(FILE * file, int *colsP, int *rowsP,
714 xelval * maxvalP, int *formatP)
715 {
716 gray gmaxval;
717
718 /* Check magic number. */
719 *formatP = pbm_readmagicnumber(file);
720 if (*formatP == -1)
721 return -1;
722 switch (PNM_FORMAT_TYPE(*formatP)) {
723 case PPM_TYPE:
724 if (ppm_readppminitrest(file, colsP, rowsP, (pixval *) maxvalP) < 0)
725 return -1;
726 break;
727
728 case PGM_TYPE:
729 if (pgm_readpgminitrest(file, colsP, rowsP, &gmaxval) < 0)
730 return -1;
731 *maxvalP = (xelval) gmaxval;
732 break;
733
734 case PBM_TYPE:
735 if (pbm_readpbminitrest(file, colsP, rowsP) < 0)
736 return -1;
737 *maxvalP = pnm_pbmmaxval;
738 break;
739
740 default:
741 fprintf(
742 stderr, msgText[BAD_MAGIC_NUMBER_NOT_A_PPM_PGM_OR_PBM_FILE],
743 progname);
744 return -1;
745 }
746 return 0;
747 }
748
749 int
pnm_readpnmrow(FILE * file,xel * xelrow,int cols,xelval maxval,int format)750 pnm_readpnmrow(FILE * file, xel * xelrow, int cols, xelval maxval, int format)
751 {
752 register int col;
753 register xel *xP;
754 gray *grayrow;
755 register gray *gP;
756 bit *bitrow;
757 register bit *bP;
758
759 switch (PNM_FORMAT_TYPE(format)) {
760 case PPM_TYPE:
761 if (ppm_readppmrow(file, (pixel *) xelrow, cols,
762 (pixval) maxval, format) < 0)
763 return -1;
764 break;
765
766 case PGM_TYPE:
767 grayrow = pgm_allocrow(cols);
768 if (grayrow == (gray *) 0)
769 return -1;
770 if (pgm_readpgmrow(file, grayrow, cols, (gray) maxval, format) < 0)
771 return -1;
772 for (col = 0, xP = xelrow, gP = grayrow; col < cols; ++col, ++xP, ++gP)
773 PNM_ASSIGN1(*xP, *gP);
774 pgm_freerow(grayrow);
775 break;
776
777 case PBM_TYPE:
778 bitrow = pbm_allocrow(cols);
779 if (bitrow == (bit *) 0)
780 return -1;
781 if (pbm_readpbmrow(file, bitrow, cols, format) < 0) {
782 pbm_freerow(bitrow);
783 return -1;
784 }
785 for (col = 0, xP = xelrow, bP = bitrow; col < cols; ++col, ++xP, ++bP)
786 PNM_ASSIGN1(*xP, *bP == PBM_BLACK ? 0 : pnm_pbmmaxval);
787 pbm_freerow(bitrow);
788 break;
789
790 default:
791 fprintf(stderr, msgText[CANT_HAPPEN], progname);
792 return -1;
793 }
794 return 0;
795 }
796
797 xel **
pnm_readpnm(FILE * file,int * colsP,int * rowsP,xelval * maxvalP,int * formatP)798 pnm_readpnm(FILE * file, int *colsP, int *rowsP, xelval * maxvalP, int *formatP)
799 {
800 xel **xels;
801 int row;
802
803 if (pnm_readpnminit(file, colsP, rowsP, maxvalP, formatP) < 0)
804 return (xel **) 0;
805
806 xels = pnm_allocarray(*colsP, *rowsP);
807 if (xels == (xel **) 0)
808 return (xel **) 0;
809
810 for (row = 0; row < *rowsP; ++row)
811 if (pnm_readpnmrow(file, xels[row], *colsP, *maxvalP, *formatP) < 0) {
812 pnm_freearray(xels, *rowsP);
813 return (xel **) 0;
814 }
815 return xels;
816 }
817
818 int
pnm_writepnminit(FILE * file,int cols,int rows,xelval maxval,int format,int forceplain)819 pnm_writepnminit(FILE * file, int cols, int rows, xelval maxval,
820 int format, int forceplain)
821 {
822 switch (PNM_FORMAT_TYPE(format)) {
823 case PPM_TYPE:
824 ppm_writeppminit(file, cols, rows, (pixval) maxval, forceplain);
825 break;
826
827 case PGM_TYPE:
828 pgm_writepgminit(file, cols, rows, (gray) maxval, forceplain);
829 break;
830
831 case PBM_TYPE:
832 pbm_writepbminit(file, cols, rows, forceplain);
833 break;
834
835 default:
836 fprintf(stderr, msgText[CANT_HAPPEN], progname);
837 return -1;
838 }
839 return 0;
840 }
841
842 int
pnm_writepnmrow(FILE * file,xel * xelrow,int cols,xelval maxval,int format,int forceplain)843 pnm_writepnmrow(FILE * file, xel * xelrow, int cols,
844 xelval maxval, int format, int forceplain)
845 {
846 register int col;
847 register xel *xP;
848 gray *grayrow;
849 register gray *gP;
850 bit *bitrow;
851 register bit *bP;
852
853 switch (PNM_FORMAT_TYPE(format)) {
854 case PPM_TYPE:
855 if (ppm_writeppmrow(file, (pixel *) xelrow, cols,
856 (pixval) maxval, forceplain) < 0)
857 return -1;
858 break;
859
860 case PGM_TYPE:
861 grayrow = pgm_allocrow(cols);
862 if (grayrow == (gray *) 0)
863 return -1;
864 for (col = 0, gP = grayrow, xP = xelrow; col < cols; ++col, ++gP, ++xP)
865 *gP = PNM_GET1(*xP);
866 if (pgm_writepgmrow(file, grayrow, cols,
867 (gray) maxval, forceplain) < 0) {
868 pgm_freerow(grayrow);
869 return -1;
870 }
871 pgm_freerow(grayrow);
872 break;
873
874 case PBM_TYPE:
875 bitrow = pbm_allocrow(cols);
876 if (bitrow == (bit *) 0)
877 return -1;
878 for (col = 0, bP = bitrow, xP = xelrow; col < cols; ++col, ++bP, ++xP)
879 *bP = PNM_GET1(*xP) == 0 ? PBM_BLACK : PBM_WHITE;
880 pbm_writepbmrow(file, bitrow, cols, forceplain);
881 pbm_freerow(bitrow);
882 break;
883
884 default:
885 fprintf(stderr, msgText[CANT_HAPPEN], progname);
886 return -1;
887 }
888 return 0;
889 }
890
891 int
pnm_writepnm(FILE * file,xel ** xels,int cols,int rows,xelval maxval,int format,int forceplain)892 pnm_writepnm(FILE * file, xel ** xels, int cols, int rows,
893 xelval maxval, int format, int forceplain)
894 {
895 int row;
896
897 if (pnm_writepnminit(file, cols, rows, maxval, format, forceplain) < 0)
898 return -1;
899
900 for (row = 0; row < rows; ++row)
901 if (pnm_writepnmrow(file, xels[row], cols,
902 maxval, format, forceplain) < 0)
903 return -1;
904 return 0;
905 }
906
907
908 /* Colormap stuff. */
909
910 #define HASH_SIZE 20023
911
912 #define ppm_hashpixel(p) ((((long) PPM_GETR(p)*33023 + \
913 (long) PPM_GETG(p)*30013 + \
914 (long) PPM_GETB(p)*27011) & 0x7fffffff) % HASH_SIZE)
915
916 colorhist_vector
ppm_computecolorhist(pixel ** pixels,int cols,int rows,int maxcolors,int * colorsP)917 ppm_computecolorhist(pixel ** pixels, int cols, int rows,
918 int maxcolors, int *colorsP)
919 {
920 colorhash_table cht;
921 colorhist_vector chv;
922
923 cht = ppm_computecolorhash(pixels, cols, rows, maxcolors, colorsP);
924 if (cht == (colorhash_table) 0)
925 return (colorhist_vector) 0;
926 chv = ppm_colorhashtocolorhist(cht, maxcolors);
927 ppm_freecolorhash(cht);
928 return chv;
929 }
930
931 void
ppm_addtocolorhist(colorhist_vector chv,int * colorsP,int maxcolors,pixel * colorP,int value,int position)932 ppm_addtocolorhist(colorhist_vector chv, int *colorsP,
933 int maxcolors, pixel * colorP, int value, int position)
934 {
935 int i, j;
936
937 /* Search colorhist for the color. */
938 for (i = 0; i < *colorsP; ++i)
939 if (PPM_EQUAL(chv[i].color, *colorP)) {
940 /* Found it - move to new slot. */
941 if (position > i) {
942 for (j = i; j < position; ++j)
943 chv[j] = chv[j + 1];
944 } else if (position < i) {
945 for (j = i; j > position; --j)
946 chv[j] = chv[j - 1];
947 }
948 chv[position].color = *colorP;
949 chv[position].value = value;
950 return;
951 }
952 if (*colorsP < maxcolors) {
953 /* Didn't find it, but there's room to add it; so do so. */
954 for (i = *colorsP; i > position; --i)
955 chv[i] = chv[i - 1];
956 chv[position].color = *colorP;
957 chv[position].value = value;
958 ++(*colorsP);
959 }
960 }
961
962 colorhash_table
ppm_computecolorhash(pixel ** pixels,int cols,int rows,int maxcolors,int * colorsP)963 ppm_computecolorhash(pixel ** pixels, int cols, int rows,
964 int maxcolors, int *colorsP)
965 {
966 colorhash_table cht;
967 register pixel *pP;
968 colorhist_list chl;
969 int col, row, hash;
970
971 cht = ppm_alloccolorhash();
972 if (cht == (colorhash_table) 0)
973 return (colorhash_table) 0;
974 *colorsP = 0;
975
976 /* Go through the entire image, building a hash table of colors. */
977 for (row = 0; row < rows; ++row)
978 for (col = 0, pP = pixels[row]; col < cols; ++col, ++pP) {
979 hash = ppm_hashpixel(*pP);
980 for (chl = cht[hash]; chl != (colorhist_list) 0; chl = chl->next)
981 if (PPM_EQUAL(chl->ch.color, *pP))
982 break;
983 if (chl != (colorhist_list) 0)
984 ++(chl->ch.value);
985 else {
986 if (++(*colorsP) > maxcolors) {
987 ppm_freecolorhash(cht);
988 return (colorhash_table) 0;
989 }
990 chl = (colorhist_list)
991 xmalloc(sizeof(struct colorhist_list_item));
992 if (chl == 0) {
993 fprintf(stderr,
994 msgText[OUT_OF_MEMORY_COMPUTING_HASH_TABLE],
995 progname);
996 ppm_freecolorhash(cht);
997 return (colorhash_table) 0;
998 }
999 chl->ch.color = *pP;
1000 chl->ch.value = 1;
1001 chl->next = cht[hash];
1002 cht[hash] = chl;
1003 }
1004 }
1005
1006 return cht;
1007 }
1008
1009 colorhash_table
ppm_alloccolorhash(void)1010 ppm_alloccolorhash(void)
1011 {
1012 colorhash_table cht;
1013 int i;
1014
1015 cht = (colorhash_table) xmalloc(HASH_SIZE * sizeof(colorhist_list));
1016 if (cht == 0) {
1017 fprintf(stderr, msgText[OUT_OF_MEMORY_ALLOCATING_HASH_TABLE],
1018 progname);
1019 return (colorhash_table) 0;
1020 }
1021 for (i = 0; i < HASH_SIZE; ++i)
1022 cht[i] = (colorhist_list) 0;
1023
1024 return cht;
1025 }
1026
1027 int
ppm_addtocolorhash(colorhash_table cht,pixel * colorP,int value)1028 ppm_addtocolorhash(colorhash_table cht, pixel * colorP, int value)
1029 {
1030 register int hash;
1031 register colorhist_list chl;
1032
1033 chl = (colorhist_list) xmalloc(sizeof(struct colorhist_list_item));
1034 if (chl == 0)
1035 return -1;
1036 hash = ppm_hashpixel(*colorP);
1037 chl->ch.color = *colorP;
1038 chl->ch.value = value;
1039 chl->next = cht[hash];
1040 cht[hash] = chl;
1041 return 0;
1042 }
1043
1044 colorhist_vector
ppm_colorhashtocolorhist(colorhash_table cht,int maxcolors)1045 ppm_colorhashtocolorhist(colorhash_table cht, int maxcolors)
1046 {
1047 colorhist_vector chv;
1048 colorhist_list chl;
1049 int i, j;
1050
1051 /* Now collate the hash table into a simple colorhist array. */
1052 chv = (colorhist_vector) xmalloc(maxcolors * sizeof(struct colorhist_item));
1053 /* (Leave room for expansion by caller.) */
1054 if (chv == (colorhist_vector) 0) {
1055 fprintf(stderr, msgText[OUT_OF_MEMORY_GENERATING_HISTOGRAM], progname);
1056 return (colorhist_vector) 0;
1057 }
1058 /* Loop through the hash table. */
1059 j = 0;
1060 for (i = 0; i < HASH_SIZE; ++i)
1061 for (chl = cht[i]; chl != (colorhist_list) 0; chl = chl->next) {
1062 /* Add the new entry. */
1063 chv[j] = chl->ch;
1064 ++j;
1065 }
1066
1067 /* All done. */
1068 return chv;
1069 }
1070
1071 colorhash_table
ppm_colorhisttocolorhash(colorhist_vector chv,int colors)1072 ppm_colorhisttocolorhash(colorhist_vector chv, int colors)
1073 {
1074 colorhash_table cht;
1075 int i, hash;
1076 pixel color;
1077 colorhist_list chl;
1078
1079 cht = ppm_alloccolorhash();
1080 if (cht == (colorhash_table) 0)
1081 return (colorhash_table) 0;
1082
1083 for (i = 0; i < colors; ++i) {
1084 color = chv[i].color;
1085 hash = ppm_hashpixel(color);
1086 for (chl = cht[hash]; chl != (colorhist_list) 0; chl = chl->next)
1087 if (PPM_EQUAL(chl->ch.color, color)) {
1088 fprintf(stderr, "%s %s - %d %d %d\n", progname,
1089 msgText[SAME_COLOR_FOUND_TWICE],
1090 PPM_GETR(color), PPM_GETG(color), PPM_GETB(color));
1091 ppm_freecolorhash(cht);
1092 return (colorhash_table) 0;
1093 }
1094 chl = (colorhist_list) xmalloc(sizeof(struct colorhist_list_item));
1095 if (chl == (colorhist_list) 0) {
1096 fprintf(stderr, msgText[COLORHIST_OUT_OF_MEMORY], progname);
1097 ppm_freecolorhash(cht);
1098 return (colorhash_table) 0;
1099 }
1100 chl->ch.color = color;
1101 chl->ch.value = i;
1102 chl->next = cht[hash];
1103 cht[hash] = chl;
1104 }
1105
1106 return cht;
1107 }
1108
1109 int
ppm_lookupcolor(colorhash_table cht,pixel * colorP)1110 ppm_lookupcolor(colorhash_table cht, pixel * colorP)
1111 {
1112 int hash;
1113 colorhist_list chl;
1114
1115 hash = ppm_hashpixel(*colorP);
1116 for (chl = cht[hash]; chl != (colorhist_list) 0; chl = chl->next)
1117 if (PPM_EQUAL(chl->ch.color, *colorP))
1118 return chl->ch.value;
1119
1120 return -1;
1121 }
1122
1123 void
ppm_freecolorhist(colorhist_vector chv)1124 ppm_freecolorhist(colorhist_vector chv)
1125 {
1126 free((char *) chv);
1127 }
1128
1129 void
ppm_freecolorhash(colorhash_table cht)1130 ppm_freecolorhash(colorhash_table cht)
1131 {
1132 int i;
1133 colorhist_list chl, chlnext;
1134
1135 for (i = 0; i < HASH_SIZE; ++i)
1136 for (chl = cht[i]; chl != (colorhist_list) 0; chl = chlnext) {
1137 chlnext = chl->next;
1138 free((char *) chl);
1139 }
1140 free((char *) cht);
1141 }
1142