1 /*
2 * Author: Burkhard Neidecker-Lutz
3 * Digital CEC Karlsruhe
4 * neideck@nestvx.enet.dec.com
5
6 Copyright (c) Digital Equipment Corporation, 1992
7
8 Permission to use, copy, modify, and distribute this software and its
9 documentation for any purpose and without fee is hereby granted,
10 provided that the above copyright notice appear in all copies and that
11 both that copyright notice and this permission notice appear in
12 supporting documentation, and that the name of Digital Equipment
13 Corporation not be used in advertising or publicity pertaining to
14 distribution of the software without specific, written prior
15 permission. Digital Equipment Corporation makes no representations
16 about the suitability of this software for any purpose. It is provided
17 "as is" without express or implied warranty.
18
19 Version: 1.0 30.07.92
20
21 */
22
23 #include <string.h>
24
25 #include "mallocvar.h"
26 #include "pnm.h"
27
28 /* The structure we use to convey all sorts of "magic" data to the DDIF */
29 /* header write procedure. */
30
31 typedef struct {
32 int width;
33 int height;
34 int h_res; /* Resolutions in dpi for bounding box */
35 int v_res;
36 int bits_per_pixel;
37 int bytes_per_line;
38 int spectral; /* 2 == monochrome, 5 == rgb */
39 int components;
40 int bits_per_component;
41 int polarity; /* zeromin == 2 , zeromax == 1 */
42 } imageparams;
43
44
45
46 /* ASN.1 basic encoding rules magic number */
47 #define UNIVERSAL 0
48 #define APPLICATION 1
49 #define CONTEXT 2
50 #define PRIVATE 3
51
52 #define PRIM 0
53 #define CONS 1
54
55 /* "tag": Emit an ASN tag of the specified class and tag number. */
56 /* This is used in conjunction with the */
57 /* wr_xxx routines that follow to construct the various ASN.1 entities. */
58 /* Writing each entity is a two-step process, where first the tag is */
59 /* written and then the length and value. */
60 /* All of these routines take a pointer to a pointer into an output */
61 /* buffer in the first argument and update it accordingly. */
62
tag(unsigned char ** buffer,int cl,int constructed,unsigned int t)63 static void tag(unsigned char ** buffer, int cl, int constructed,
64 unsigned int t)
65 {
66 int tag_first;
67 unsigned int stack[10];
68 int sp;
69 unsigned char *p = *buffer;
70
71 tag_first = (cl << 6) | constructed << 5;
72 if (t < 31) { /* Short tag form */
73 *p++ = tag_first | t;
74 } else { /* Long tag form */
75 *p++ = tag_first | 31;
76 sp = 0;
77 while (t > 0) {
78 stack[sp++] = t & 0x7f;
79 t >>= 7;
80 }
81 while (--sp > 0) { /* Tag values with continuation bits */
82 *p++ = stack[sp] | 0x80;
83 }
84 *p++ = stack[0]; /* Last tag portion without continuation bit */
85 }
86 *buffer = p; /* Update buffer pointer */
87 }
88
89
90
91 /* Emit indefinite length encoding */
92 static void
ind(unsigned char ** buffer)93 ind(unsigned char **buffer)
94 {
95 unsigned char *p = *buffer;
96
97 *p++ = 0x80;
98 *buffer = p;
99 }
100
101
102
103 /* Emit ASN.1 NULL */
104 static void
wr_null(unsigned char ** buffer)105 wr_null(unsigned char **buffer)
106 {
107 unsigned char *p = *buffer;
108
109 *p++ = 0;
110 *buffer = p;
111 }
112
113
114
115 /* Emit ASN.1 length only into buffer, no data */
116 static void
wr_length(unsigned char ** buffer,int amount)117 wr_length(unsigned char ** buffer, int amount)
118 {
119 int length;
120 unsigned int mask;
121 unsigned char *p = *buffer;
122
123 length = 4;
124 mask = 0xff000000;
125
126 if (amount < 128) {
127 *p++ = amount;
128 } else { /* > 127 */
129 while (!(amount & mask)) { /* Search for first non-zero byte */
130 mask >>= 8;
131 --length;
132 }
133
134 *p++ = length | 0x80; /* Number of length bytes */
135
136 while (--length >= 0) { /* Put length bytes */
137 *p++ =(amount >> (8*length)) & 0xff;
138 }
139
140 }
141 *buffer = p;
142 }
143
144
145
146 /* BER encode an integer and write it's length and value */
147 static void
wr_int(unsigned char ** buffer,int val)148 wr_int(unsigned char ** buffer, int val)
149 {
150 int length;
151 int sign;
152 unsigned int mask;
153 unsigned char *p = *buffer;
154
155 if (val == 0) {
156 *p++ = 1; /* length */
157 *p++ = 0; /* value */
158 } else {
159 sign = val < 0 ? 0xff : 0x00; /* Sign bits */
160 length = 4;
161 mask = 0xffu << 24;
162 while ((val & mask) == sign) { /* Find the smallest representation */
163 length--;
164 mask >>= 8;
165 }
166 sign = (0x80 << ((length-1)*8)) & val; /* New sign bit */
167 if (((val < 0) && !sign) || ((val > 0) && sign)) { /* Sign error */
168 length++;
169 }
170 *p++ = length; /* length */
171 while (--length >= 0) {
172 *p++ = (val >> (8*length)) & 0xff;
173 }
174 }
175 *buffer = p;
176 }
177
178
179
180 /* Emit and End Of Coding sequence */
181 static void
eoc(unsigned char ** buffer)182 eoc(unsigned char ** buffer)
183 {
184 unsigned char *p = *buffer;
185
186 *p++ = 0;
187 *p++ = 0;
188 *buffer = p;
189 }
190
191
192
193 /* Emit a simple string */
194 static
wr_string(unsigned char ** const buffer,const char * const val)195 void wr_string(unsigned char ** const buffer, const char * const val)
196 {
197 int length;
198 unsigned char *p = *buffer;
199
200 length = strlen(val);
201 if (length > 127) {
202 fprintf(stderr,"Can't encode length > 127 yet (%d)\n",length);
203 exit(1);
204 }
205 *p++ = length;
206 {
207 const char * valCursor;
208 for (valCursor = val; *valCursor; ++valCursor)
209 *p++ = *valCursor;
210 }
211 *buffer = p;
212 }
213
214
215
216 /* Emit a ISOLATIN-1 string */
217 static void
emit_isolatin1(unsigned char ** const buffer,const char * const val)218 emit_isolatin1(unsigned char ** const buffer, const char * const val)
219 {
220 int length;
221 unsigned char *p = *buffer;
222
223 length = strlen(val) + 1; /* One NULL byte and charset leader */
224 if (length > 127) {
225 fprintf(stderr,"Can't encode length > 127 yet (%d)\n",length);
226 exit(1);
227 }
228 *p++ = length;
229 *p++ = 1; /* ISO LATIN-1 */
230 {
231 const char * valCursor;
232 for (valCursor = val; *valCursor; ++valCursor)
233 *p++ = *valCursor;
234 }
235 *buffer = p;
236 }
237
238
239
240 /* Write the DDIF grammar onto "file" up to the actual starting location */
241 /* of the image data. The "ip" structure needs to be set to the right */
242 /* values. A lot of the values here are hardcoded to be just right for */
243 /* the bit grammars that the PBMPLUS formats want. */
244
245 static int
write_header(FILE * file,imageparams * ip)246 write_header(FILE *file, imageparams *ip)
247 {
248 unsigned char buffer[300]; /* Be careful with the size ! */
249 unsigned char *p = buffer;
250 int headersize;
251 int bounding_x;
252 int bounding_y;
253 int i;
254
255 /* Calculate the bounding box from the resolutions */
256 bounding_x = ((int) (1200 * ((double) (ip->width) / ip->h_res)));
257 bounding_y = ((int) (1200 * ((double) (ip->height) / ip->v_res)));
258
259 /* This is gross. The entire DDIF grammar is constructed by */
260 /* hand. The indentation is meant to indicate DDIF document structure */
261
262 tag(&p,PRIVATE,CONS,16383); ind(&p); /* DDIF Document */
263 tag(&p,CONTEXT,CONS, 0); ind(&p); /* Document Descriptor */
264 tag(&p,CONTEXT,PRIM, 0); wr_int(&p,1); /* Major Version */
265 tag(&p,CONTEXT,PRIM, 1); wr_int(&p,3); /* Minor Version */
266 tag(&p,CONTEXT,PRIM, 2); wr_string(&p,"PBM+"); /* Product Identifier */
267 tag(&p,CONTEXT,CONS, 3); ind(&p); /* Product Name */
268 tag(&p,PRIVATE,PRIM, 9); emit_isolatin1(&p,"PBMPLUS Writer V1.0");
269 eoc(&p);
270 eoc(&p); /* Document Descriptor */
271 tag(&p,CONTEXT,CONS, 1); ind(&p); /* Document Header */
272 tag(&p,CONTEXT,CONS, 3); ind(&p); /* Version */
273 tag(&p,PRIVATE,PRIM, 9); emit_isolatin1(&p,"1.0");
274 eoc(&p);
275 eoc(&p); /* Document Header */
276 tag(&p,CONTEXT,CONS, 2); ind(&p); /* Document Content */
277 tag(&p,APPLICATION,CONS,2); ind(&p); /* Segment Primitive */
278 eoc(&p);
279 tag(&p,APPLICATION,CONS,2); ind(&p); /* Segment */
280 tag(&p,CONTEXT,CONS, 3); ind(&p); /* Segment Specific Attributes */
281 tag(&p,CONTEXT,PRIM, 2); wr_string(&p,"$I"); /* Category */
282 tag(&p,CONTEXT,CONS,22); ind(&p); /* Image Attributes */
283 tag(&p,CONTEXT,CONS, 0); ind(&p); /* Image Presentation Attributes */
284 tag(&p,CONTEXT,PRIM, 1); wr_int(&p,0); /* Pixel Path */
285 tag(&p,CONTEXT,PRIM, 2); wr_int(&p,270); /* Line Progression */
286 tag(&p,CONTEXT,CONS, 3); ind(&p); /* Pixel Aspect Ratio */
287 tag(&p,CONTEXT,PRIM, 0); wr_int(&p,1); /* PP Pixel Dist */
288 tag(&p,CONTEXT,PRIM, 1); wr_int(&p,1); /* LP Pixel Dist */
289 eoc(&p); /* Pixel Aspect Ratio */
290 tag(&p,CONTEXT,PRIM, 4); wr_int(&p,ip->polarity);
291 /* Brightness Polarity */
292 tag(&p,CONTEXT,PRIM, 5); wr_int(&p,1); /* Grid Type */
293 tag(&p,CONTEXT,PRIM, 7); wr_int(&p,ip->spectral); /* Spectral Mapping */
294 tag(&p,CONTEXT,CONS,10); ind(&p); /* Pixel Group Info */
295 tag(&p,CONTEXT,PRIM, 0); wr_int(&p,1); /* Pixel Group Size */
296 tag(&p,CONTEXT,PRIM, 1); wr_int(&p,1); /* Pixel Group Order */
297 eoc(&p); /* Pixel Group Info */
298 eoc(&p); /* Image Presentation Attributes */
299 tag(&p,CONTEXT,CONS, 1); ind(&p); /* Component Space Attributes */
300 tag(&p,CONTEXT,PRIM, 0); wr_int(&p,1); /* Component Space Organization */
301 tag(&p,CONTEXT,PRIM, 1); wr_int(&p,1); /* Planes per Pixel */
302 tag(&p,CONTEXT,PRIM, 2); wr_int(&p,1); /* Plane Significance */
303 tag(&p,CONTEXT,PRIM, 3); wr_int(&p,ip->components);
304 /* Number of Components */
305 tag(&p,CONTEXT,CONS, 4); ind(&p); /* Bits per Component */
306 for (i = 0; i < ip->components; i++) {
307 tag(&p,UNIVERSAL,PRIM,2); wr_int(&p,ip->bits_per_component);
308 }
309 eoc(&p); /* Bits per Component */
310 tag(&p,CONTEXT,CONS, 5); ind(&p); /* Component Quantization Levels */
311 for (i = 0; i < ip->components; i++) {
312 tag(&p,UNIVERSAL,PRIM,2); wr_int(&p,1 << ip->bits_per_component);
313 }
314 eoc(&p); /* Component Quantization Levels */
315 eoc(&p); /* Component Space Attributes */
316 eoc(&p); /* Image Attributes */
317 tag(&p,CONTEXT,CONS,23); ind(&p); /* Frame Parameters */
318 tag(&p,CONTEXT,CONS, 1); ind(&p); /* Bounding Box */
319 tag(&p,CONTEXT,CONS, 0); ind(&p); /* lower-left */
320 tag(&p,CONTEXT,CONS, 0); ind(&p); /* XCoordinate */
321 tag(&p,CONTEXT,PRIM, 0); wr_int(&p,0);
322 eoc(&p); /* XCoordinate */
323 tag(&p,CONTEXT,CONS, 1); ind(&p); /* YCoordinate */
324 tag(&p,CONTEXT,PRIM, 0); wr_int(&p,0);
325 eoc(&p); /* YCoordinate */
326 eoc(&p); /* lower left */
327 tag(&p,CONTEXT,CONS, 1); ind(&p); /* upper right */
328 tag(&p,CONTEXT,CONS, 0); ind(&p); /* XCoordinate */
329 tag(&p,CONTEXT,PRIM, 0); wr_int(&p,bounding_x);
330 eoc(&p); /* XCoordinate */
331 tag(&p,CONTEXT,CONS, 1); ind(&p); /* YCoordinate */
332 tag(&p,CONTEXT,PRIM, 0); wr_int(&p,bounding_y);
333 eoc(&p); /* YCoordinate */
334 eoc(&p); /* upper right */
335 eoc(&p); /* Bounding Box */
336 tag(&p,CONTEXT,CONS, 4); ind(&p); /* Frame Position */
337 tag(&p,CONTEXT,CONS, 0); ind(&p); /* XCoordinate */
338 tag(&p,CONTEXT,PRIM, 0); wr_int(&p,0);
339 eoc(&p); /* XCoordinate */
340 tag(&p,CONTEXT,CONS, 1); ind(&p); /* YCoordinate */
341 tag(&p,CONTEXT,PRIM, 0); wr_int(&p,0);
342 eoc(&p); /* YCoordinate */
343 eoc(&p); /* Frame Position */
344 eoc(&p); /* Frame Parameters */
345 eoc(&p); /* Segment Specific Attributes */
346 eoc(&p); /* Segment */
347 tag(&p,APPLICATION,CONS,17); ind(&p); /* Image Data Descriptor */
348 tag(&p,UNIVERSAL,CONS,16); ind(&p); /* Sequence */
349 tag(&p,CONTEXT,CONS, 0); ind(&p); /* Image Coding Attributes */
350 tag(&p,CONTEXT,PRIM, 1); wr_int(&p,ip->width); /* Pixels per Line */
351 tag(&p,CONTEXT,PRIM, 2); wr_int(&p,ip->height); /* Number of Lines */
352 tag(&p,CONTEXT,PRIM, 3); wr_int(&p,2); /* Compression Type */
353 tag(&p,CONTEXT,PRIM, 5); wr_int(&p,0); /* Data Offset */
354 tag(&p,CONTEXT,PRIM, 6); wr_int(&p,ip->bits_per_pixel); /* Pixel Stride */
355 tag(&p,CONTEXT,PRIM, 7); wr_int(&p,ip->bytes_per_line * 8);
356 /* Scanline Stride */
357 tag(&p,CONTEXT,PRIM, 8); wr_int(&p,1); /* Bit Order */
358 tag(&p,CONTEXT,PRIM, 9); wr_int(&p,ip->bits_per_pixel);
359 /* Planebits per Pixel */
360 tag(&p,CONTEXT,CONS,10); ind(&p); /* Byteorder Info */
361 tag(&p,CONTEXT,PRIM, 0); wr_int(&p,1); /* Byte Unit */
362 tag(&p,CONTEXT,PRIM, 1); wr_int(&p,1); /* Byte Order */
363 eoc(&p); /* Byteorder Info */
364 tag(&p,CONTEXT,PRIM,11); wr_int(&p,3); /* Data Type */
365 eoc(&p); /* Image Coding Attributes */
366 tag(&p,CONTEXT,PRIM, 1); wr_length(&p,ip->bytes_per_line*ip->height);
367 /* Component Plane Data */
368 /* End of DDIF document Indentation */
369 headersize = p - buffer;
370 if (headersize >= 300) {
371 fprintf(stderr,"Overran buffer area %d >= 300\n",headersize);
372 exit(1);
373 }
374
375 return (fwrite(buffer, 1, headersize, file) == headersize);
376 }
377
378
379
380 /* Write all the closing brackets of the DDIF grammar that are missing */
381 /* The strange indentation reflects exactly the same indentation that */
382 /* we left off in the write_header procedure. */
383 static int
write_trailer(FILE * file)384 write_trailer(FILE * file)
385 {
386 unsigned char buffer[30];
387 unsigned char *p = buffer;
388 int trailersize;
389
390 /* Indentation below gives DDIF document structure */
391 eoc(&p); /* Sequence */
392 eoc(&p); /* Image Data Descriptor */
393 tag(&p,APPLICATION,PRIM,1); wr_null(&p); /* End Segment */
394 tag(&p,APPLICATION,PRIM,1); wr_null(&p); /* End Segment */
395 eoc(&p); /* Document Content */
396 eoc(&p); /* DDIF Document */
397 /* End of DDIF document Indentation */
398 trailersize = p - buffer;
399 if (trailersize >= 30) {
400 fprintf(stderr,"Overran buffer area %d >= 30\n",trailersize);
401 exit(1);
402 }
403
404 return(fwrite(buffer, 1, trailersize, file) == trailersize);
405 }
406
407
408
409
410 static void
convertPbmRaster(FILE * const ifP,int const format,unsigned int const cols,unsigned int const rows,FILE * const ofP,unsigned int const bytesPerLine,unsigned char * const data)411 convertPbmRaster(FILE * const ifP,
412 int const format,
413 unsigned int const cols,
414 unsigned int const rows,
415 FILE * const ofP,
416 unsigned int const bytesPerLine,
417 unsigned char * const data) {
418
419 bit * const pixels = pbm_allocrow(cols);
420
421 unsigned int row;
422
423 for (row = 0; row < rows; ++row) {
424 unsigned int col;
425 unsigned int k;
426 unsigned int mask;
427 unsigned char * p;
428 size_t bytesWritten;
429
430 pbm_readpbmrow(ifP, pixels, cols, format);
431
432 mask = 0x00;
433 p = &data[0];
434 for (col = 0, k = 0; col < cols; ++col) {
435 if (pixels[col] == PBM_BLACK)
436 mask |= 1 << k;
437 if (k == 7) {
438 *p++ = mask;
439 mask = 0x00;
440 k = 0;
441 } else
442 ++k;
443 }
444 if (k != 7)
445 /* Flush the rest of the column */
446 *p = mask;
447
448 bytesWritten = fwrite(data, 1, bytesPerLine, ofP);
449 if (bytesWritten != bytesPerLine)
450 pm_error("File write error on Row %u", row);
451 }
452
453 pbm_freerow(pixels);
454 }
455
456
457
458 static void
convertPgmRaster(FILE * const ifP,int const format,xelval const maxval,unsigned int const cols,unsigned int const rows,FILE * const ofP,unsigned int const bytesPerLine,unsigned char * const data)459 convertPgmRaster(FILE * const ifP,
460 int const format,
461 xelval const maxval,
462 unsigned int const cols,
463 unsigned int const rows,
464 FILE * const ofP,
465 unsigned int const bytesPerLine,
466 unsigned char * const data) {
467
468 gray * const pixels = pgm_allocrow(cols);
469
470 unsigned int row;
471
472 for (row = 0; row < rows; ++row) {
473 unsigned char * p;
474 unsigned int col;
475 size_t bytesWritten;
476
477 p = &data[0];
478
479 pgm_readpgmrow(ifP, pixels, cols, maxval, format);
480
481 for (col = 0; col < cols; ++col)
482 *p++ = (unsigned char) pixels[col];
483
484 bytesWritten = fwrite(data, 1, bytesPerLine, ofP);
485 if (bytesWritten != bytesPerLine)
486 pm_error("File write error on Row %u", row);
487 }
488 pgm_freerow(pixels);
489 }
490
491
492
493
494 static void
convertPpmRaster(FILE * const ifP,int const format,xelval const maxval,unsigned int const cols,unsigned int const rows,FILE * const ofP,unsigned int const bytesPerLine,unsigned char * const data)495 convertPpmRaster(FILE * const ifP,
496 int const format,
497 xelval const maxval,
498 unsigned int const cols,
499 unsigned int const rows,
500 FILE * const ofP,
501 unsigned int const bytesPerLine,
502 unsigned char * const data) {
503
504 pixel * const pixels = ppm_allocrow(cols);
505
506 unsigned int row;
507
508 for (row = 0; row < rows; ++row) {
509 unsigned char * p;
510 unsigned int col;
511 size_t bytesWritten;
512
513 p = &data[0];
514
515 ppm_readppmrow(ifP, pixels, cols, maxval, format);
516
517 for (col = 0; col < cols; ++col) {
518 *p++ = PPM_GETR(pixels[col]);
519 *p++ = PPM_GETG(pixels[col]);
520 *p++ = PPM_GETB(pixels[col]);
521 }
522 bytesWritten = fwrite(data, 1, bytesPerLine, ofP);
523 if (bytesWritten != bytesPerLine)
524 pm_error("File write error on Row %u", row);
525 }
526 ppm_freerow(pixels);
527 }
528
529
530
531 static void
convertRaster(FILE * const ifP,int const format,xelval const maxval,unsigned int const cols,unsigned int const rows,FILE * const ofP,unsigned int const bytesPerLine)532 convertRaster(FILE * const ifP,
533 int const format,
534 xelval const maxval,
535 unsigned int const cols,
536 unsigned int const rows,
537 FILE * const ofP,
538 unsigned int const bytesPerLine) {
539
540 unsigned char * data;
541
542 MALLOCARRAY(data, bytesPerLine);
543
544 if (data == NULL)
545 pm_error("Couldn't allocate %u-byte line buffer", bytesPerLine);
546
547 switch (PNM_FORMAT_TYPE(format)) {
548 case PBM_TYPE:
549 convertPbmRaster(ifP, format, cols, rows, ofP, bytesPerLine, data);
550 break;
551 case PGM_TYPE:
552 convertPgmRaster(ifP, format, maxval, cols, rows, ofP, bytesPerLine,
553 data);
554 break;
555 case PPM_TYPE:
556 convertPpmRaster(ifP, format, maxval, cols, rows, ofP, bytesPerLine,
557 data);
558 break;
559 default:
560 pm_error("INTERNAL ERROR: impossible format value");
561 }
562
563 free(data);
564 }
565
566
567
568 int
main(int argc,char * argv[])569 main(int argc, char *argv[]) {
570 FILE *ifd;
571 FILE *ofd;
572 int rows, cols;
573 xelval maxval;
574 int format;
575 const char * const usage = "[-resolution x y] [pnmfile [ddiffile]]";
576 char *outfile;
577 int argn;
578 int hor_resolution = 75;
579 int ver_resolution = 75;
580 imageparams ip;
581
582 pnm_init(&argc, argv);
583
584 for (argn = 1;argn < argc && argv[argn][0] == '-';argn++) {
585 int arglen = strlen(argv[argn]);
586
587 if (!strncmp (argv[argn],"-resolution", arglen)) {
588 if (argn + 2 < argc) {
589 hor_resolution = atoi(argv[argn+1]);
590 ver_resolution = atoi(argv[argn+2]);
591 argn += 2;
592 continue;
593 } else {
594 pm_usage(usage);
595 }
596 } else {
597 pm_usage(usage);
598 }
599 }
600
601 if (hor_resolution <= 0 || ver_resolution <= 0) {
602 fprintf(stderr,"Unreasonable resolution values: %d x %d\n",
603 hor_resolution,ver_resolution);
604 exit(1);
605 }
606
607 if (argn == argc - 2) {
608 ifd = pm_openr(argv[argn]);
609 outfile = argv[argn+1];
610 if (!(ofd = fopen(outfile,"wb"))) {
611 perror(outfile);
612 exit(1);
613 }
614 } else if (argn == argc - 1) {
615 ifd = pm_openr(argv[argn]);
616 ofd = stdout;
617 } else {
618 ifd = stdin;
619 ofd = stdout;
620 }
621
622 pnm_readpnminit(ifd, &cols, &rows, &maxval, &format);
623
624 ip.width = cols;
625 ip.height = rows;
626 ip.h_res = hor_resolution;
627 ip.v_res = ver_resolution;
628
629 switch (PNM_FORMAT_TYPE(format)) {
630 case PBM_TYPE:
631 ip.bits_per_pixel = 1;
632 ip.bytes_per_line = (cols + 7) / 8;
633 ip.spectral = 2;
634 ip.components = 1;
635 ip.bits_per_component = 1;
636 ip.polarity = 1;
637 break;
638 case PGM_TYPE:
639 ip.bytes_per_line = cols;
640 ip.bits_per_pixel = 8;
641 ip.spectral = 2;
642 ip.components = 1;
643 ip.bits_per_component = 8;
644 ip.polarity = 2;
645 break;
646 case PPM_TYPE:
647 ip.bytes_per_line = 3 * cols;
648 ip.bits_per_pixel = 24;
649 ip.spectral = 5;
650 ip.components = 3;
651 ip.bits_per_component = 8;
652 ip.polarity = 2;
653 break;
654 default:
655 fprintf(stderr, "Unrecognized PBMPLUS format %d\n", format);
656 exit(1);
657 }
658
659 if (!write_header(ofd,&ip)) {
660 perror("Writing header");
661 exit(1);
662 }
663
664 convertRaster(ifd, format, maxval, cols, rows, ofd, ip.bytes_per_line);
665
666 pm_close(ifd);
667
668 if (!write_trailer(ofd)) {
669 perror("Writing trailer");
670 exit(1);
671 }
672
673 if (fclose(ofd) == EOF) {
674 perror("Closing output file");
675 exit(1);
676 };
677
678 return(0);
679 }
680