1 /*
2 * This is derived from the file of the same name dated June 5, 1995,
3 * copied from the Army High Performance Computing Research Center's
4 * media-tools.tar.gz package, received from
5 * http://www.arc.umn.edu/gvl-software/media-tools.tar.gz on 2000.04.13.
6 *
7 * This software is copyrighted as noted below. It may be freely copied,
8 * modified, and redistributed, provided that the copyright notice is
9 * preserved on all copies.
10 *
11 * There is no warranty or other guarantee of fitness for this software,
12 * it is provided solely "as is". Bug reports or fixes may be sent
13 * to the author, who may or may not act on them as he desires.
14 *
15 * You may not include this software in a program or other software product
16 * without supplying the source, or without informing the end-user that the
17 * source is available for no extra charge.
18 *
19 * If you modify this software, you should include a notice giving the
20 * name of the person performing the modification, the date of modification,
21 * and the reason for such modification.
22 */
23 /*
24 * rletopnm - A conversion program to convert from Utah's "rle" image format
25 * to pbmplus ppm or pgm image formats.
26 *
27 * Author: Wes Barris (wes@msc.edu)
28 * AHPCRC
29 * Minnesota Supercomputer Center, Inc.
30 * Date: March 30, 1994
31 * Copyright (c) Minnesota Supercomputer Center 1994
32 *
33 * 2000.04.13 adapted for Netpbm by Bryan Henderson. Quieted compiler
34 * warnings. Added --alpha option. Accept input on stdin
35 *
36 */
37
38 #define _DEFAULT_SOURCE 1 /* New name for SVID & BSD source defines */
39 #define _BSD_SOURCE 1 /* Make sure strdup() is in string.h */
40 #define _XOPEN_SOURCE 500 /* Make sure strdup() is in string.h */
41
42 /*-----------------------------------------------------------------------------
43 * System includes.
44 */
45 #include <string.h>
46 #include <stdio.h>
47 #define NO_DECLARE_MALLOC
48 #include <rle.h>
49
50 #include "pm_c_util.h"
51 #include "pnm.h"
52 #include "shhopt.h"
53 #include "mallocvar.h"
54 #include "nstring.h"
55
56 #define HMSG if (headerDump) pm_message
57 #define GRAYSCALE 001 /* 8 bits, no colormap */
58 #define PSEUDOCOLOR 010 /* 8 bits, colormap */
59 #define TRUECOLOR 011 /* 24 bits, colormap */
60 #define DIRECTCOLOR 100 /* 24 bits, no colormap */
61 #define RLE_MAXVAL 255
62 /*
63 * Utah type declarations.
64 */
65 static rle_hdr hdr;
66 static rle_map * colormap;
67
68
69 struct CmdlineInfo {
70 /* All the information the user supplied in the command line,
71 in a form easy for the program to use.
72 */
73 char * inputFilename;
74 unsigned int headerdump;
75 unsigned int verbose;
76 char * alphaout;
77 bool alphaStdout;
78 };
79
80
81
82 /*
83 * Other declarations.
84 */
85 static int visual, maplen;
86 static int width, height;
87
88
89
90 static void
parseCommandLine(int argc,char ** argv,struct CmdlineInfo * const cmdlineP)91 parseCommandLine(int argc, char ** argv,
92 struct CmdlineInfo * const cmdlineP) {
93 /*----------------------------------------------------------------------------
94 Note that many of the strings that this function returns in the
95 *cmdlineP structure are actually in the supplied argv array. And
96 sometimes, one of these strings is actually just a suffix of an entry
97 in argv!
98 -----------------------------------------------------------------------------*/
99 optEntry * option_def; /* malloc'ed */
100 optStruct3 opt;
101 unsigned int option_def_index;
102
103 unsigned int alphaoutSpec;
104
105 MALLOCARRAY(option_def, 100);
106
107 option_def_index = 0; /* incremented by OPTENT3 */
108 OPTENT3('h', "headerdump", OPT_FLAG,
109 NULL, &cmdlineP->headerdump, 0);
110 OPTENT3('v', "verbose", OPT_FLAG,
111 NULL, &cmdlineP->verbose, 0);
112 OPTENT3(0, "alphaout", OPT_STRING,
113 &cmdlineP->alphaout, &alphaoutSpec, 0);
114
115 opt.opt_table = option_def;
116 opt.short_allowed = TRUE; /* We have short (old-fashioned) options */
117 opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */
118
119 pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
120 /* Uses and sets argc, argv, and all of *cmdlineP. */
121
122 if (!alphaoutSpec)
123 cmdlineP->alphaout = NULL;
124
125 if (argc - 1 == 0)
126 cmdlineP->inputFilename = NULL; /* he wants stdin */
127 else if (argc - 1 == 1) {
128 if (streq(argv[1], "-"))
129 cmdlineP->inputFilename = NULL; /* he wants stdin */
130 else
131 cmdlineP->inputFilename = strdup(argv[1]);
132 } else
133 pm_error("Too many arguments. The only argument accepted "
134 "is the input file specification");
135
136 if (cmdlineP->alphaout &&
137 streq(cmdlineP->alphaout, "-"))
138 cmdlineP->alphaStdout = TRUE;
139 else
140 cmdlineP->alphaStdout = FALSE;
141 }
142
143
144
145 static void
reportRleGetSetupError(int const rleGetSetupRc)146 reportRleGetSetupError(int const rleGetSetupRc) {
147
148 switch (rleGetSetupRc) {
149 case -1:
150 pm_error("According to the URT library, the input is not "
151 "an RLE file. rle_get_setup() failed.");
152 break;
153 case -2:
154 pm_error("Unable to get memory for the color map. "
155 "rle_get_setup() failed.");
156 break;
157 case -3:
158 pm_error("Input file is empty. rle_get_setup() failed.");
159 break;
160 case -4:
161 pm_error("End of file in the middle of where the RLE header should "
162 "be. rle_get_setup() failed.");
163 break;
164 default:
165 pm_error("rle_get_setup() failed for an unknown reason");
166 }
167 }
168
169
170
171 static void
readRleHeader(FILE * const ifP,bool const headerDump)172 readRleHeader(FILE * const ifP,
173 bool const headerDump) {
174
175 int rc;
176 int i;
177 hdr.rle_file = ifP;
178 rc = rle_get_setup(&hdr);
179 if (rc != 0)
180 reportRleGetSetupError(rc);
181
182 width = hdr.xmax - hdr.xmin + 1;
183 height = hdr.ymax - hdr.ymin + 1;
184 HMSG("Image size: %dx%d", width, height);
185 if (hdr.ncolors == 1 && hdr.ncmap == 3) {
186 visual = PSEUDOCOLOR;
187 colormap = hdr.cmap;
188 maplen = (1 << hdr.cmaplen);
189 HMSG("Mapped color image with a map of length %d.",
190 maplen);
191 }
192 else if (hdr.ncolors == 3 && hdr.ncmap == 0) {
193 visual = DIRECTCOLOR;
194 HMSG("24 bit color image, no colormap.");
195 }
196 else if (hdr.ncolors == 3 && hdr.ncmap == 3) {
197 visual = TRUECOLOR;
198 colormap = hdr.cmap;
199 maplen = (1 << hdr.cmaplen);
200 HMSG(
201 "24 bit color image with color map of length %d" ,maplen);
202 }
203 else if (hdr.ncolors == 1 && hdr.ncmap == 0) {
204 visual = GRAYSCALE;
205 HMSG("Grayscale image.");
206 }
207 else {
208 fprintf(stderr,
209 "ncolors = %d, ncmap = %d, I don't know how to handle this!",
210 hdr.ncolors, hdr.ncmap);
211 exit(-1);
212 }
213 if (hdr.alpha == 0) {
214 HMSG("No alpha channel.");
215 } else if (hdr.alpha == 1) {
216 HMSG("Alpha channel exists!");
217 } else {
218 fprintf(stderr, "alpha = %d, I don't know how to handle this!\n",
219 hdr.alpha);
220 exit(-1);
221 }
222 switch (hdr.background) {
223 case 0:
224 HMSG("Use all pixels, ignore background color.");
225 break;
226 case 1:
227 HMSG("Use only non-background pixels, ignore background color.");
228 break;
229 case 2:
230 HMSG("Use only non-background pixels, "
231 "clear to background color (default).");
232 break;
233 default:
234 HMSG("Unknown background flag!");
235 break;
236 }
237 if (hdr.background == 2)
238 for (i = 0; i < hdr.ncolors; i++)
239 HMSG(" %d", hdr.bg_color[i]);
240 if (hdr.ncolors == 1 && hdr.ncmap == 3) {
241 HMSG(" (%d %d %d)",
242 hdr.cmap[hdr.bg_color[0]]>>8,
243 hdr.cmap[hdr.bg_color[0]+256]>>8,
244 hdr.cmap[hdr.bg_color[0]+512]>>8);
245 }
246 else if (hdr.ncolors == 3 && hdr.ncmap == 3) {
247 HMSG(" (%d %d %d)",
248 hdr.cmap[hdr.bg_color[0]]>>8,
249 hdr.cmap[hdr.bg_color[1]+256]>>8,
250 hdr.cmap[hdr.bg_color[2]+512]>>8);
251 }
252 if (hdr.comments)
253 for (i = 0; hdr.comments[i] != NULL; i++)
254 HMSG("%s", hdr.comments[i]);
255 }
256
257
258
259 static void
writePpmRaster(FILE * const imageoutFileP,FILE * const alphaFileP)260 writePpmRaster(FILE * const imageoutFileP,
261 FILE * const alphaFileP) {
262
263 rle_pixel ***scanlines, **scanline;
264 pixval r, g, b;
265 pixel *pixelrow;
266 gray *alpharow;
267
268 int scan;
269 int x;
270 /*
271 * Allocate some stuff.
272 */
273 pixelrow = ppm_allocrow(width);
274 alpharow = pgm_allocrow(width);
275
276 MALLOCARRAY(scanlines, height);
277 if (!scanlines)
278 pm_error("Failed to allocate memory for %u scanline pointers", height);
279
280 for (scan = 0; scan < height; ++scan) {
281 int rc;
282 rc = rle_row_alloc(&hdr, &scanlines[scan]);
283 if (rc < 0)
284 pm_error("Failed to allocate memory for a scanline");
285 }
286 /*
287 * Loop through those scan lines.
288 */
289 for (scan = 0; scan < height; ++scan)
290 rle_getrow(&hdr, scanlines[height - scan - 1]);
291 for (scan = 0; scan < height; ++scan) {
292 scanline = scanlines[scan];
293 switch (visual) {
294 case GRAYSCALE: /* 8 bits without colormap */
295 for (x = 0; x < width; x++) {
296 r = scanline[0][x];
297 g = scanline[0][x];
298 b = scanline[0][x];
299 PPM_ASSIGN(pixelrow[x], r, g, b);
300 if (hdr.alpha)
301 alpharow[x] = scanline[-1][x];
302 else
303 alpharow[x] = 0;
304 }
305 break;
306 case TRUECOLOR: /* 24 bits with colormap */
307 for (x = 0; x < width; x++) {
308 r = colormap[scanline[0][x]]>>8;
309 g = colormap[scanline[1][x]+256]>>8;
310 b = colormap[scanline[2][x]+512]>>8;
311 PPM_ASSIGN(pixelrow[x], r, g, b);
312 if (hdr.alpha)
313 alpharow[x] = colormap[scanline[-1][x]];
314 else
315 alpharow[x] = 0;
316 }
317 break;
318 case DIRECTCOLOR: /* 24 bits without colormap */
319 for (x = 0; x < width; x++) {
320 r = scanline[0][x];
321 g = scanline[1][x];
322 b = scanline[2][x];
323 PPM_ASSIGN(pixelrow[x], r, g, b);
324 if (hdr.alpha)
325 alpharow[x] = scanline[-1][x];
326 else
327 alpharow[x] = 0;
328 }
329 break;
330 case PSEUDOCOLOR: /* 8 bits with colormap */
331 for (x = 0; x < width; x++) {
332 r = colormap[scanline[0][x]]>>8;
333 g = colormap[scanline[0][x]+256]>>8;
334 b = colormap[scanline[0][x]+512]>>8;
335 PPM_ASSIGN(pixelrow[x], r, g, b);
336 if (hdr.alpha)
337 alpharow[x] = colormap[scanline[-1][x]];
338 else
339 alpharow[x] = 0;
340 }
341 break;
342 default:
343 break;
344 }
345 /*
346 * Write the scan line.
347 */
348 if (imageoutFileP)
349 ppm_writeppmrow(imageoutFileP, pixelrow, width, RLE_MAXVAL, 0);
350 if (alphaFileP)
351 pgm_writepgmrow(alphaFileP, alpharow, width, RLE_MAXVAL, 0);
352
353 } /* end of for scan = 0 to height */
354
355 /* Free scanline memory. */
356 for (scan = 0; scan < height; ++scan)
357 rle_row_free(&hdr, scanlines[scan]);
358 free (scanlines);
359 ppm_freerow(pixelrow);
360 pgm_freerow(alpharow);
361 }
362
363
364
365 static void
writePgmRaster(FILE * const imageoutFileP,FILE * const alphaFileP)366 writePgmRaster(FILE * const imageoutFileP,
367 FILE * const alphaFileP) {
368 /*----------------------------------------------------------------------------
369 Write the PGM image data
370 -----------------------------------------------------------------------------*/
371 rle_pixel ***scanlines, **scanline;
372 gray * pixelrow;
373 gray * alpharow;
374 int scan;
375 /*
376 * Allocate some stuff.
377 */
378 pixelrow = pgm_allocrow(width);
379 alpharow = pgm_allocrow(width);
380
381 MALLOCARRAY(scanlines, height);
382 if (!scanlines)
383 pm_error("Failed to allocate memory for %u scanline pointers", height);
384
385 for (scan = 0; scan < height; ++scan) {
386 int rc;
387 rc = rle_row_alloc(&hdr, &scanlines[scan]);
388 if (rc < 0)
389 pm_error("Failed to allocate memory for a scanline");
390 }
391 /*
392 * Loop through those scan lines.
393 */
394 for (scan = 0; scan < height; ++scan)
395 rle_getrow(&hdr, scanlines[height - scan - 1]);
396
397 for (scan = 0; scan < height; ++scan) {
398 int x;
399 scanline = scanlines[scan];
400 for (x = 0; x < width; ++x) {
401 pixelrow[x] = scanline[0][x];
402 if (hdr.alpha)
403 alpharow[x] = scanline[1][x];
404 else
405 alpharow[x] = 0;
406 }
407 if (imageoutFileP)
408 pgm_writepgmrow(imageoutFileP, pixelrow, width, RLE_MAXVAL, 0);
409 if (alphaFileP)
410 pgm_writepgmrow(alphaFileP, alpharow, width, RLE_MAXVAL, 0);
411
412 } /* end of for scan = 0 to height */
413
414 /* Free scanline memory. */
415 for (scan = 0; scan < height; ++scan)
416 rle_row_free(&hdr, scanlines[scan]);
417 free(scanlines);
418 pgm_freerow(pixelrow);
419 pgm_freerow(alpharow);
420 }
421
422
423
424 int
main(int argc,char ** argv)425 main(int argc, char ** argv) {
426
427 struct CmdlineInfo cmdline;
428 FILE * ifP;
429 FILE * imageoutFileP;
430 FILE * alphaFileP;
431 char * fname;
432
433 pnm_init( &argc, argv );
434
435 parseCommandLine(argc, argv, &cmdline);
436
437 fname = NULL; /* initial value */
438
439 if (cmdline.inputFilename != NULL )
440 ifP = pm_openr(cmdline.inputFilename);
441 else
442 ifP = stdin;
443
444 if (cmdline.alphaStdout)
445 alphaFileP = stdout;
446 else if (cmdline.alphaout == NULL)
447 alphaFileP = NULL;
448 else {
449 alphaFileP = pm_openw(cmdline.alphaout);
450 }
451
452 if (cmdline.alphaStdout)
453 imageoutFileP = NULL;
454 else
455 imageoutFileP = stdout;
456
457
458 /*
459 * Open the file.
460 */
461 /* Initialize header. */
462 hdr = *rle_hdr_init(NULL);
463 rle_names(&hdr, cmd_name( argv ), fname, 0);
464
465 /*
466 * Read the rle file header.
467 */
468 readRleHeader(ifP, cmdline.headerdump || cmdline.verbose);
469 if (cmdline.headerdump)
470 exit(0);
471
472 /*
473 * Write the alpha file header
474 */
475 if (alphaFileP)
476 pgm_writepgminit(alphaFileP, width, height, RLE_MAXVAL, 0);
477
478 /*
479 * Write the pnm file header.
480 */
481 switch (visual) {
482 case GRAYSCALE: /* 8 bits without colormap -> pgm */
483 if (cmdline.verbose)
484 pm_message("Writing pgm file.");
485 if (imageoutFileP)
486 pgm_writepgminit(imageoutFileP, width, height, RLE_MAXVAL, 0);
487 writePgmRaster(imageoutFileP, alphaFileP);
488 break;
489 default: /* anything else -> ppm */
490 if (cmdline.verbose)
491 pm_message("Writing ppm file.");
492 if (imageoutFileP)
493 ppm_writeppminit(imageoutFileP, width, height, RLE_MAXVAL, 0);
494 writePpmRaster(imageoutFileP, alphaFileP);
495 break;
496 }
497
498 pm_close(ifP);
499 if (imageoutFileP)
500 pm_close(imageoutFileP);
501 if (alphaFileP)
502 pm_close(alphaFileP);
503
504 return 0;
505 }
506