1 /*
2 * xvpbm.c - load routine for 'pm' format pictures
3 *
4 * LoadPBM(fname, pinfo) - loads a PBM, PGM, or PPM file
5 * WritePBM(fp,pic,ptype,w,h,r,g,b,numcols,style,raw,cmt,comment)
6 */
7
8 #include "copyright.h"
9
10 #include "xv.h"
11
12
13
14 /*
15 * comments on error handling:
16 * a truncated file is not considered a Major Error. The file is loaded, the
17 * rest of the pic is filled with 0's.
18 *
19 * a file with garbage characters in it is an unloadable file. All allocated
20 * stuff is tossed, and LoadPBM returns non-zero
21 *
22 * not being able to malloc is a Fatal Error. The program is aborted.
23 */
24
25
26 typedef unsigned short ush;
27 typedef unsigned char uch;
28
29 #define alpha_composite(composite, fg, alpha, bg) { \
30 ush temp = ((ush)(fg)*(ush)(alpha) + \
31 (ush)(bg)*(ush)(255 - (ush)(alpha)) + (ush)128); \
32 (composite) = (uch)((temp + (temp >> 8)) >> 8); \
33 }
34
35 #define TRUNCSTR "File appears to be truncated."
36
37 static int garbage;
38 static long numgot, filesize;
39
40 static int loadpbm PARM((FILE *, PICINFO *, int));
41 static int loadpgm PARM((FILE *, PICINFO *, int, int));
42 static int loadppm PARM((FILE *, PICINFO *, int, int));
43 static int loadpam PARM((FILE *, PICINFO *, int, int));
44 static int getint PARM((FILE *, PICINFO *));
45 static int getbit PARM((FILE *, PICINFO *));
46 static int getshort PARM((FILE *));
47 static int pbmError PARM((const char *, const char *));
48
49 static const char *bname;
50
51
52 #ifdef HAVE_MGCSFX
53 /*
54 * When file read or file write is fail, probably it's caused by
55 * reading from pipe which has no data yet, or writing to pipe
56 * which is not ready yet.
57 * Then we can use system call select() on descriptor of pipe and wait.
58 * If you want, change 'undef' to 'define' in the following line.
59 * This feature is performance-killer.
60 */
61 #undef FIX_PIPE_ERROR
62
63 #ifdef __osf__
64 # ifdef __alpha
65 # define FIX_PIPE_ERROR
66 # endif
67 #endif
68
69 #endif /* HAVE_MGCSFX */
70
71
72 #ifdef FIX_PIPE_ERROR
73
74 int pipefdr;
75
76 struct timeval timeout;
77 int width;
78 fd_set fds;
79
ready_read()80 static void ready_read()
81 {
82 if(pipefdr < 0) return; /* if file descriptor is not pipe, OK */
83 WaitCursor();
84
85 reselect:
86 /* setting of timeout */
87 timeout.tv_sec = 1; /* 1 sec */
88 timeout.tv_usec = 0; /* 0 usec */
89
90 FD_ZERO(&fds); /* clear bits */
91 FD_SET(pipefdr, &fds); /* set bit of fd in fds */
92
93 /* number of file descriptor to want check (0 $B!A(B width-1) */
94 width = pipefdr + 1;
95
96 /* select returns number of file descriptors */
97 if (select(width, &fds, NULL, NULL, &timeout) < 0){
98 if(DEBUG){
99 fprintf(stderr, "No file descriptors can't selected, waiting...\n");
100 }
101 goto reselect;
102 }
103
104 if (FD_ISSET(pipefdr, &fds)){
105 /* Now, descriptor of pipe is ready to read */
106 return;
107 }else{
108 if(DEBUG){
109 fprintf(stderr, "Can't read from pipe yet, waiting...\n");
110 }
111 goto reselect;
112 }
113
114 }
115 #endif /* FIX_PIPE_ERROR */
116
117 /*******************************************/
118 #ifdef HAVE_MGCSFX
LoadPBM(fname,pinfo,fd)119 int LoadPBM(fname, pinfo, fd)
120 char *fname;
121 PICINFO *pinfo;
122 int fd;
123 #else
124 int LoadPBM(fname, pinfo)
125 char *fname;
126 PICINFO *pinfo;
127 #endif /* HAVE_MGCSFX */
128 /*******************************************/
129 {
130 /* returns '1' on success */
131
132 FILE *fp;
133 int c, c1;
134 int maxv, rv;
135
136 #ifdef FIX_PIPE_ERROR
137 pipefdr = fd;
138 #endif
139
140 garbage = maxv = rv = 0;
141 bname = BaseName(fname);
142
143 pinfo->pic = (byte *) NULL;
144 pinfo->comment = (char *) NULL;
145
146
147 #ifdef HAVE_MGCSFX
148 if(fd < 0){
149 /* open the file */
150 fp = xv_fopen(fname,"r");
151 if (!fp) return (pbmError(bname, "can't open file"));
152
153 /* compute file length */
154 fseek(fp, 0L, 2);
155 filesize = ftell(fp);
156 fseek(fp, 0L, 0);
157 }else{
158 fp = fdopen(fd, "r");
159 if (!fp) return (pbmError(bname, "can't open file"));
160 filesize = 0; /* dummy */
161 }
162 #else
163 /* open the file */
164 fp = xv_fopen(fname,"r");
165 if (!fp) return (pbmError(bname, "can't open file"));
166
167 /* compute file length */
168 fseek(fp, 0L, 2);
169 filesize = ftell(fp);
170 fseek(fp, 0L, 0);
171 #endif /* HAVE_MGCSFX */
172
173
174 /* read the first two bytes of the file to determine which format
175 this file is. "P1" = ascii bitmap, "P2" = ascii greymap,
176 "P3" = ascii pixmap, "P4" = raw bitmap, "P5" = raw greymap,
177 "P6" = raw pixmap */
178
179 c = getc(fp); c1 = getc(fp);
180 if (c!='P' || c1<'1' || (c1>'6' && c1!='8')) /* GRR alpha */
181 return(pbmError(bname, "unknown format"));
182
183 /* read in header information */
184 pinfo->w = getint(fp, pinfo); pinfo->h = getint(fp, pinfo);
185 pinfo->normw = pinfo->w; pinfo->normh = pinfo->h;
186
187 /* if we're not reading a bitmap, read the 'max value' */
188 if ( !(c1=='1' || c1=='4')) {
189 maxv = getint(fp, pinfo);
190 if (maxv < 1) garbage=1; /* to avoid 'div by zero' probs */
191 }
192
193
194 if (garbage) {
195 fclose(fp);
196 if (pinfo->comment) free(pinfo->comment);
197 pinfo->comment = (char *) NULL;
198 return (pbmError(bname, "Garbage characters in header."));
199 }
200
201
202 if (c1=='1' || c1=='2' || c1=='3') pinfo->frmType = F_PBMASCII;
203 else pinfo->frmType = F_PBMRAW;
204
205 /* note: pic, type, r,g,b, frmInfo, shortFrm, and colorType fields of
206 picinfo struct are filled in in the format-specific loaders */
207
208 /* call the appropriate subroutine to handle format-specific stuff */
209 if (c1=='1' || c1=='4') rv = loadpbm(fp, pinfo, c1=='4' ? 1 : 0);
210 else if (c1=='2' || c1=='5') rv = loadpgm(fp, pinfo, c1=='5' ? 1 : 0, maxv);
211 else if (c1=='3' || c1=='6') rv = loadppm(fp, pinfo, c1=='6' ? 1 : 0, maxv);
212 else if (c1=='8') rv = loadpam(fp, pinfo, 1 , maxv);
213
214 fclose(fp);
215
216 if (!rv) {
217 if (pinfo->pic) free(pinfo->pic);
218 if (pinfo->comment) free(pinfo->comment);
219 pinfo->pic = (byte *) NULL;
220 pinfo->comment = (char *) NULL;
221 }
222
223 return rv;
224 }
225
226
227
228 /*******************************************/
loadpbm(fp,pinfo,raw)229 static int loadpbm(fp, pinfo, raw)
230 FILE *fp;
231 PICINFO *pinfo;
232 int raw;
233 {
234 byte *pic8;
235 byte *pix;
236 int i,j,bit,w,h,npixels;
237
238 w = pinfo->w;
239 h = pinfo->h;
240
241 npixels = w * h;
242 if (w <= 0 || h <= 0 || npixels/w != h)
243 return pbmError(bname, "image dimensions too large");
244
245 pic8 = (byte *) calloc((size_t) npixels, (size_t) 1);
246 if (!pic8) FatalError("couldn't malloc 'pic8' for PBM");
247
248 pinfo->pic = pic8;
249 pinfo->type = PIC8;
250 sprintf(pinfo->fullInfo, "PBM, %s format. (%ld bytes)",
251 (raw) ? "raw" : "ascii", filesize);
252 sprintf(pinfo->shrtInfo, "%dx%d PBM.", w, h);
253 pinfo->colType = F_BWDITHER;
254
255
256 /* B/W bitmaps have a two entry colormap */
257 pinfo->r[0] = pinfo->g[0] = pinfo->b[0] = 255; /* entry #0 = white */
258 pinfo->r[1] = pinfo->g[1] = pinfo->b[1] = 0; /* entry #1 = black */
259
260
261 if (!raw) {
262 numgot = 0;
263 for (i=0, pix=pic8; i<h; i++) {
264 if ((i&0x3f)==0) WaitCursor();
265 for (j=0; j<w; j++, pix++) *pix = getbit(fp, pinfo);
266 }
267
268 if (numgot != npixels) pbmError(bname, TRUNCSTR);
269 if (garbage) {
270 return(pbmError(bname, "Garbage characters in image data."));
271 }
272 }
273
274
275 else { /* read raw bits */
276 int trunc = 0, k = 0;
277
278 for (i=0, pix=pic8; i<h; i++) {
279 if ((i&15)==0) WaitCursor();
280 for (j=0,bit=0; j<w; j++, pix++, bit++) {
281
282 bit &= 7;
283 if (!bit) {
284 k = getc(fp);
285 if (k==EOF) { trunc=1; k=0; }
286 }
287
288 *pix = (k&0x80) ? 1 : 0;
289 k = k << 1;
290 }
291 }
292
293 if (trunc) pbmError(bname, TRUNCSTR);
294 }
295
296 return 1;
297 }
298
299
300 /*******************************************/
loadpgm(fp,pinfo,raw,maxv)301 static int loadpgm(fp, pinfo, raw, maxv)
302 FILE *fp;
303 PICINFO *pinfo;
304 int raw, maxv;
305 {
306 byte *pix, *pic8;
307 int i,j,bitshift,w,h,npixels, holdmaxv;
308
309
310 w = pinfo->w;
311 h = pinfo->h;
312
313 npixels = w * h;
314 if (w <= 0 || h <= 0 || npixels/w != h)
315 return pbmError(bname, "image dimensions too large");
316
317 pic8 = (byte *) calloc((size_t) npixels, (size_t) 1);
318 if (!pic8) FatalError("couldn't malloc 'pic8' for PGM");
319
320
321 pinfo->pic = pic8;
322 pinfo->type = PIC8;
323 sprintf(pinfo->fullInfo, "PGM, %s format. (%ld bytes)",
324 (raw) ? "raw" : "ascii", filesize);
325 sprintf(pinfo->shrtInfo, "%dx%d PGM.", pinfo->w, pinfo->h);
326 pinfo->colType = F_GREYSCALE;
327
328
329 /* if maxv>255, keep dropping bits until it's reasonable */
330 holdmaxv = maxv;
331 bitshift = 0;
332 while (maxv>255) { maxv = maxv>>1; bitshift++; }
333
334 /* fill in a greyscale colormap where maxv maps to 255 */
335 for (i=0; i<=maxv; i++)
336 pinfo->r[i] = pinfo->g[i] = pinfo->b[i] = (i*255)/maxv;
337
338
339 numgot = 0;
340
341 if (!raw) {
342 for (i=0, pix=pic8; i<h; i++) {
343 if ((i&0x3f)==0) WaitCursor();
344 for (j=0; j<w; j++, pix++)
345 *pix = (byte) (getint(fp, pinfo) >> bitshift);
346 }
347 }
348 else { /* raw */
349 if (holdmaxv>255) {
350 for (i=0, pix=pic8; i<h; i++) {
351 if ((i&0x3f)==0) WaitCursor();
352 for (j=0; j<w; j++, pix++)
353 *pix = (byte) (getshort(fp) >> bitshift);
354 }
355 }
356 else {
357 #ifdef FIX_PIPE_ERROR
358 reread:
359 numgot += fread(pic8 + numgot, (size_t) 1, (size_t) w*h - numgot, fp); /* read raw data */
360 if(errno == EINTR){
361 if(DEBUG){
362 fprintf(stderr,
363 "Can't read all data from pipe, call select and waiting...\n");
364 }
365 ready_read();
366 goto reread;
367 }
368 #else
369 numgot = fread(pic8, (size_t)1, (size_t)npixels, fp); /* read raw data */
370 #endif
371 }
372 }
373
374 if (numgot != npixels) pbmError(bname, TRUNCSTR); /* warning only */
375
376 if (garbage) {
377 return (pbmError(bname, "Garbage characters in image data."));
378 }
379
380 return 1;
381 }
382
383
384 /*******************************************/
loadppm(fp,pinfo,raw,maxv)385 static int loadppm(fp, pinfo, raw, maxv)
386 FILE *fp;
387 PICINFO *pinfo;
388 int raw, maxv;
389 {
390 byte *pix, *pic24, scale[256];
391 int i,j,bitshift, w, h, npixels, bufsize, holdmaxv;
392
393 w = pinfo->w;
394 h = pinfo->h;
395
396 npixels = w * h;
397 bufsize = 3*npixels;
398 if (w <= 0 || h <= 0 || npixels/w != h || bufsize/3 != npixels)
399 return pbmError(bname, "image dimensions too large");
400
401 /* allocate 24-bit image */
402 pic24 = (byte *) calloc((size_t) bufsize, (size_t) 1);
403 if (!pic24) FatalError("couldn't malloc 'pic24' for PPM");
404
405 pinfo->pic = pic24;
406 pinfo->type = PIC24;
407 sprintf(pinfo->fullInfo, "PPM, %s format. (%ld bytes)",
408 (raw) ? "raw" : "ascii", filesize);
409 sprintf(pinfo->shrtInfo, "%dx%d PPM.", w, h);
410 pinfo->colType = F_FULLCOLOR;
411
412
413 /* if maxv>255, keep dropping bits until it's reasonable */
414 holdmaxv = maxv;
415 bitshift = 0;
416 while (maxv>255) { maxv = maxv>>1; bitshift++; }
417
418
419 numgot = 0;
420
421 if (!raw) {
422 for (i=0, pix=pic24; i<h; i++) {
423 if ((i&0x3f)==0) WaitCursor();
424 for (j=0; j<w*3; j++, pix++)
425 *pix = (byte) (getint(fp, pinfo) >> bitshift);
426 }
427 }
428 else { /* raw */
429 if (holdmaxv>255) {
430 for (i=0, pix=pic24; i<h; i++) {
431 if ((i&0x3f)==0) WaitCursor();
432 for (j=0; j<w*3; j++,pix++)
433 *pix = (byte) (getshort(fp) >> bitshift);
434 }
435 }
436 else {
437 #ifdef FIX_PIPE_ERROR
438 reread:
439 numgot += fread(pic24 + numgot, (size_t) 1, (size_t) w*h*3 - numgot, fp); /* read data */
440 if(errno == EINTR){
441 if(DEBUG){
442 fprintf(stderr,
443 "Can't read all data from pipe, call select and waiting...\n");
444 }
445 ready_read();
446 goto reread;
447 }
448 #else
449 numgot = fread(pic24, (size_t) 1, (size_t) bufsize, fp); /* read data */
450 #endif
451 }
452 }
453
454 if (numgot != bufsize) pbmError(bname, TRUNCSTR);
455
456 if (garbage)
457 return(pbmError(bname, "Garbage characters in image data."));
458
459
460 /* have to scale up all RGB values (Conv24to8 expects RGB values to
461 range from 0-255) */
462
463 if (maxv<255) {
464 for (i=0; i<=maxv; i++) scale[i] = (i * 255) / maxv;
465
466 for (i=0, pix=pic24; i<h; i++) {
467 if ((i&0x3f)==0) WaitCursor();
468 for (j=0; j<w*3; j++, pix++) *pix = scale[*pix];
469 }
470 }
471
472 return 1;
473 }
474
475
476 /*******************************************/
loadpam(fp,pinfo,raw,maxv)477 static int loadpam(fp, pinfo, raw, maxv) /* unofficial RGBA extension */
478 FILE *fp;
479 PICINFO *pinfo;
480 int raw, maxv;
481 {
482 byte *p, *pix, *pic24, *linebuf, scale[256], bgR, bgG, bgB, r, g, b, a;
483 int i, j, bitshift, w, h, npixels, bufsize, linebufsize, holdmaxv;
484
485 w = pinfo->w;
486 h = pinfo->h;
487
488 npixels = w * h;
489 bufsize = 3*npixels;
490 linebufsize = 4*w;
491 if (w <= 0 || h <= 0 || npixels/w != h || bufsize/3 != npixels ||
492 linebufsize/4 != w)
493 return pbmError(bname, "image dimensions too large");
494
495 /* allocate 24-bit image */
496 pic24 = (byte *) calloc((size_t) bufsize, (size_t) 1);
497 if (!pic24) FatalError("couldn't malloc 'pic24' for PAM");
498
499 /* allocate line buffer for pre-composited RGBA data */
500 linebuf = (byte *) malloc((size_t) linebufsize);
501 if (!linebuf) {
502 free(pic24);
503 FatalError("couldn't malloc 'linebuf' for PAM");
504 }
505
506 pinfo->pic = pic24;
507 pinfo->type = PIC24;
508 sprintf(pinfo->fullInfo, "PAM, %s format. (%ld bytes)",
509 (raw) ? "raw" : "ascii", filesize);
510 sprintf(pinfo->shrtInfo, "%dx%d PAM.", w, h);
511 pinfo->colType = F_FULLCOLOR;
512
513
514 /* if maxv>255, keep dropping bits until it's reasonable */
515 holdmaxv = maxv;
516 bitshift = 0;
517 while (maxv>255) { maxv = maxv>>1; bitshift++; }
518
519
520 numgot = 0;
521
522 if (!raw) { /* GRR: not alpha-ready */
523 return pbmError(bname, "can't handle non-raw PAM image");
524 /*
525 for (i=0, pix=pic24; i<h; i++) {
526 if ((i&0x3f)==0) WaitCursor();
527 for (j=0; j<w*3; j++, pix++)
528 *pix = (byte) (getint(fp, pinfo) >> bitshift);
529 }
530 */
531 }
532 else { /* raw */
533 if (holdmaxv>255) { /* GRR: not alpha-ready */
534 return pbmError(bname, "can't handle PAM image with maxval > 255");
535 /*
536 for (i=0, pix=pic24; i<h; i++) {
537 if ((i&0x3f)==0) WaitCursor();
538 for (j=0; j<w*3; j++,pix++)
539 *pix = (byte) (getshort(fp) >> bitshift);
540 }
541 */
542 }
543 else {
544 if (have_imagebg) { /* GRR: alpha-ready */
545 bgR = (imagebgR >> 8);
546 bgG = (imagebgG >> 8);
547 bgB = (imagebgB >> 8);
548 } else {
549 bgR = bgG = bgB = 0;
550 }
551 for (i=0, pix=pic24; i<h; i++) {
552 numgot += fread(linebuf, (size_t) 1, (size_t) linebufsize, fp); /* read data */
553 if ((i&0x3f)==0) WaitCursor();
554 for (j=0, p=linebuf; j<w; j++) {
555 r = *p++;
556 g = *p++;
557 b = *p++;
558 a = *p++;
559 alpha_composite(*pix++, r, a, bgR)
560 alpha_composite(*pix++, g, a, bgG)
561 alpha_composite(*pix++, b, a, bgB)
562 }
563 }
564 }
565 }
566
567 free(linebuf);
568
569 /* in principle this could overflow, but not critical */
570 if (numgot != w*h*4) pbmError(bname, TRUNCSTR);
571
572 if (garbage)
573 return(pbmError(bname, "Garbage characters in image data."));
574
575
576 /* have to scale up all RGB values (Conv24to8 expects RGB values to
577 range from 0-255) */
578
579 if (maxv<255) {
580 for (i=0; i<=maxv; i++) scale[i] = (i * 255) / maxv;
581
582 for (i=0, pix=pic24; i<h; i++) {
583 if ((i&0x3f)==0) WaitCursor();
584 for (j=0; j<w*3; j++, pix++) *pix = scale[*pix];
585 }
586 }
587
588 return 1;
589 }
590
591
592
593 /*******************************************/
getint(fp,pinfo)594 static int getint(fp, pinfo)
595 FILE *fp;
596 PICINFO *pinfo;
597 {
598 int c, i, firstchar;
599
600 /* note: if it sees a '#' character, all characters from there to end of
601 line are appended to the comment string */
602
603 /* skip forward to start of next number */
604 c = getc(fp);
605 while (1) {
606 /* eat comments */
607 if (c=='#') { /* if we're at a comment, read to end of line */
608 char cmt[256], *sp, *tmpptr;
609
610 sp = cmt; firstchar = 1;
611 while (1) {
612 c=getc(fp);
613 if (firstchar && c == ' ') firstchar = 0; /* lop off 1 sp after # */
614 else {
615 if (c == '\n' || c == EOF) break;
616 if ((sp-cmt)<250) *sp++ = c;
617 }
618 }
619 *sp++ = '\n';
620 *sp = '\0';
621
622 if (strlen(cmt) > (size_t) 0) { /* add to pinfo->comment */
623 if (!pinfo->comment) {
624 pinfo->comment = (char *) malloc(strlen(cmt)+1);
625 if (!pinfo->comment) FatalError("malloc failure in xvpbm.c getint");
626 pinfo->comment[0] = '\0';
627 }
628 else {
629 tmpptr = (char *) realloc(pinfo->comment,
630 strlen(pinfo->comment) + strlen(cmt) + 1);
631 if (!tmpptr) FatalError("realloc failure in xvpbm.c getint");
632 pinfo->comment = tmpptr;
633 }
634 strcat(pinfo->comment, cmt);
635 }
636 }
637
638 if (c==EOF) return 0;
639 if (c>='0' && c<='9') break; /* we've found what we were looking for */
640
641 /* see if we are getting garbage (non-whitespace) */
642 if (c!=' ' && c!='\t' && c!='\r' && c!='\n' && c!=',') garbage=1;
643
644 c = getc(fp);
645 }
646
647
648 /* we're at the start of a number, continue until we hit a non-number */
649 i = 0;
650 while (1) {
651 i = (i*10) + (c - '0');
652 c = getc(fp);
653 if (c==EOF) return i;
654 if (c<'0' || c>'9') break;
655 }
656
657 numgot++;
658 return i;
659 }
660
661
662
663 /*******************************************/
getshort(fp)664 static int getshort(fp)
665 FILE *fp;
666 {
667 /* used in RAW mode to read 16-bit values */
668
669 int c1, c2;
670
671 c1 = getc(fp);
672 if (c1 == EOF) return 0;
673 c2 = getc(fp);
674 if (c2 == EOF) return 0;
675
676 numgot++;
677
678 /* Sometime after 1995, NetPBM's ppm(5) man page was changed to say, "Each
679 * sample is represented in pure binary by either 1 or 2 bytes. If the
680 * Maxval is less than 256, it is 1 byte. Otherwise, it is 2 bytes. The
681 * most significant byte is first." This change is incompatible with
682 * images created for viewing with all previous versions of XV, however,
683 * so both approaches are left available as a compile-time option. (Could
684 * make it runtime-selectable, too, but unclear whether anybody cares.) */
685 #ifdef ASSUME_RAW_PPM_LSB_FIRST /* legacy approach */
686 return (c2 << 8) | c1;
687 #else /* MSB first */
688 return (c1 << 8) | c2;
689 #endif
690 }
691
692
693
694 /*******************************************/
getbit(fp,pinfo)695 static int getbit(fp, pinfo)
696 FILE *fp;
697 PICINFO *pinfo;
698 {
699 int c;
700
701 /* skip forward to start of next number */
702 c = getc(fp);
703 while (1) {
704 /* eat comments */
705 if (c=='#') { /* if we're at a comment, read to end of line */
706 char cmt[256], *sp, *tmpptr;
707
708 sp = cmt;
709 while (1) {
710 c=getc(fp);
711 if (c == '\n' || c == EOF) break;
712
713 if ((sp-cmt)<250) *sp++ = c;
714 }
715 *sp++ = '\n';
716 *sp = '\0';
717
718 if (strlen(cmt) > (size_t) 0) { /* add to pinfo->comment */
719 if (!pinfo->comment) {
720 pinfo->comment = (char *) malloc(strlen(cmt)+1);
721 if (!pinfo->comment) FatalError("malloc failure in xvpbm.c getint");
722 pinfo->comment[0] = '\0';
723 }
724 else {
725 tmpptr = (char *) realloc(pinfo->comment,
726 strlen(pinfo->comment) + strlen(cmt) + 1);
727 if (!tmpptr) FatalError("realloc failure in xvpbm.c getint");
728 pinfo->comment = tmpptr;
729 }
730 strcat(pinfo->comment, cmt);
731 }
732 }
733 if (c==EOF) return 0;
734 if (c=='0' || c=='1') break; /* we've found what we were looking for */
735
736 /* see if we are getting garbage (non-whitespace) */
737 if (c!=' ' && c!='\t' && c!='\r' && c!='\n' && c!=',') garbage=1;
738
739 c = getc(fp);
740 }
741
742
743 numgot++;
744 return(c-'0');
745 }
746
747
748 /*******************************************/
pbmError(fname,st)749 static int pbmError(fname, st)
750 const char *fname, *st;
751 {
752 SetISTR(ISTR_WARNING,"%s: %s", fname, st);
753 return 0;
754 }
755
756
757
758
759
760 /*******************************************/
WritePBM(fp,pic,ptype,w,h,rmap,gmap,bmap,numcols,colorstyle,raw,comment)761 int WritePBM(fp,pic,ptype,w,h,rmap,gmap,bmap,numcols,colorstyle,raw,comment)
762 FILE *fp;
763 byte *pic;
764 int ptype, w,h;
765 byte *rmap, *gmap, *bmap;
766 int numcols, colorstyle, raw;
767 char *comment;
768 {
769 /* writes a PBM/PGM/PPM file to the already open stream
770 if (raw), writes as RAW bytes, otherwise writes as ASCII
771 'colorstyle' single-handedly determines the type of file written
772 if colorstyle==0, (Full Color) a PPM file is written
773 if colorstyle==1, (Greyscale) a PGM file is written
774 if colorstyle==2, (B/W stipple) a PBM file is written */
775
776 int magic;
777 byte *pix;
778 int i,j,len;
779
780 /* calc the appropriate magic number for this file type */
781 magic = 0;
782 if (colorstyle==0) magic = 3;
783 else if (colorstyle==1) magic = 2;
784 else if (colorstyle==2) magic = 1;
785
786 if (raw && magic) magic+=3;
787
788
789 /* write the header info */
790 fprintf(fp,"P%d\n",magic);
791 fprintf(fp,"# CREATOR: XV %s\n", REVDATE);
792
793 if (comment) { /* write comment lines */
794 char *sp;
795
796 sp = comment;
797 while (*sp) {
798 fprintf(fp, "# ");
799 while (*sp && *sp != '\n') fputc(*sp++, fp);
800 if (*sp == '\n') sp++;
801 fputc('\n', fp);
802 }
803 }
804
805
806 fprintf(fp,"%d %d\n",w,h);
807 if (colorstyle!=2) fprintf(fp,"255\n");
808
809 if (ferror(fp)) return -1;
810
811 /* write the image data */
812
813 if (colorstyle==0) { /* 24bit RGB, 3 bytes per pixel */
814 for (i=0, pix=pic, len=0; i<h; i++) {
815 if ((i&63)==0) WaitCursor();
816 for (j=0; j<w; j++) {
817 if (raw) {
818 if (ptype==PIC8) {
819 putc(rmap[*pix],fp); putc(gmap[*pix],fp); putc(bmap[*pix],fp);
820 }
821 else { /* PIC24 */
822 putc(pix[0],fp); putc(pix[1],fp); putc(pix[2],fp);
823 }
824 }
825 else {
826 if (ptype==PIC8)
827 fprintf(fp,"%3d %3d %3d ",rmap[*pix], gmap[*pix], bmap[*pix]);
828 else
829 fprintf(fp,"%3d %3d %3d ",pix[0], pix[1], pix[2]);
830
831 len+=12;
832 if (len>58) { fprintf(fp,"\n"); len=0; }
833 }
834
835 pix += (ptype==PIC24) ? 3 : 1;
836 }
837 }
838 }
839
840
841 else if (colorstyle==1) { /* 8-bit greyscale */
842 byte rgb[256];
843 if (ptype==PIC8)
844 for (i=0; i<numcols; i++) rgb[i] = MONO(rmap[i],gmap[i],bmap[i]);
845
846 for (i=0, pix=pic, len=0; i<w*h; i++) {
847 if ((i&0x7fff)==0) WaitCursor();
848
849 if (raw) putc((ptype==PIC8) ? rgb[*pix] : MONO(pix[0],pix[1],pix[2]),fp);
850
851 else {
852 if (ptype==PIC8) fprintf(fp,"%3d ",rgb[*pix]);
853 else fprintf(fp,"%3d ",MONO(pix[0],pix[1],pix[2]));
854 len += 4;
855 if (len>66) { fprintf(fp,"\n"); len=0; }
856 }
857
858 pix += (ptype==PIC24) ? 3 : 1;
859 }
860 }
861
862 else if (colorstyle==2) { /* 1-bit B/W stipple */
863 int bit,k,flipbw;
864 const char *str0, *str1;
865
866 /* shouldn't happen */
867 if (ptype == PIC24) FatalError("PIC24 and B/W Stipple in WritePBM()\n");
868
869 /* if '0' is black, set flipbw */
870 flipbw = (MONO(rmap[0],gmap[0],bmap[0]) < MONO(rmap[1],gmap[1],bmap[1]));
871
872 str0 = (flipbw) ? "1 " : "0 ";
873 str1 = (flipbw) ? "0 " : "1 ";
874
875 for (i=0, pix=pic, len=0; i<h; i++) {
876 if ((i&15)==0) WaitCursor();
877 for (j=0, bit=0, k=0; j<w; j++, pix++) {
878 if (raw) {
879 k = (k << 1) | *pix;
880 bit++;
881 if (bit==8) {
882 if (flipbw) k = ~k;
883 fputc(k,fp);
884 bit = k = 0;
885 }
886 }
887 else {
888 if (*pix) fprintf(fp,str1);
889 else fprintf(fp,str0);
890 len+=2;
891 if (len>68) { fprintf(fp,"\n"); len=0; }
892 }
893 } /* j */
894 if (raw && bit) {
895 k = k << (8-bit);
896 if (flipbw) k = ~k;
897 fputc(k,fp);
898 }
899 }
900 }
901
902 if (ferror(fp)) return -1;
903
904 return 0;
905 }
906