/* * This is derived from the file of the same name dated June 5, 1995, * copied from the Army High Performance Computing Research Center's * media-tools.tar.gz package, received from * http://www.arc.umn.edu/gvl-software/media-tools.tar.gz on 2000.04.13. * * This software is copyrighted as noted below. It may be freely copied, * modified, and redistributed, provided that the copyright notice is * preserved on all copies. * * There is no warranty or other guarantee of fitness for this software, * it is provided solely "as is". Bug reports or fixes may be sent * to the author, who may or may not act on them as he desires. * * You may not include this software in a program or other software product * without supplying the source, or without informing the end-user that the * source is available for no extra charge. * * If you modify this software, you should include a notice giving the * name of the person performing the modification, the date of modification, * and the reason for such modification. */ /* * rletopnm - A conversion program to convert from Utah's "rle" image format * to pbmplus ppm or pgm image formats. * * Author: Wes Barris (wes@msc.edu) * AHPCRC * Minnesota Supercomputer Center, Inc. * Date: March 30, 1994 * Copyright (c) Minnesota Supercomputer Center 1994 * * 2000.04.13 adapted for Netpbm by Bryan Henderson. Quieted compiler * warnings. Added --alpha option. Accept input on stdin * */ #define _DEFAULT_SOURCE 1 /* New name for SVID & BSD source defines */ #define _BSD_SOURCE 1 /* Make sure strdup() is in string.h */ #define _XOPEN_SOURCE 500 /* Make sure strdup() is in string.h */ /*----------------------------------------------------------------------------- * System includes. */ #include #include #define NO_DECLARE_MALLOC #include #include "pm_c_util.h" #include "pnm.h" #include "shhopt.h" #include "mallocvar.h" #include "nstring.h" #define HMSG if (headerDump) pm_message #define GRAYSCALE 001 /* 8 bits, no colormap */ #define PSEUDOCOLOR 010 /* 8 bits, colormap */ #define TRUECOLOR 011 /* 24 bits, colormap */ #define DIRECTCOLOR 100 /* 24 bits, no colormap */ #define RLE_MAXVAL 255 /* * Utah type declarations. */ static rle_hdr hdr; static rle_map * colormap; struct CmdlineInfo { /* All the information the user supplied in the command line, in a form easy for the program to use. */ char * inputFilename; unsigned int headerdump; unsigned int verbose; char * alphaout; bool alphaStdout; }; /* * Other declarations. */ static int visual, maplen; static int width, height; static void parseCommandLine(int argc, char ** argv, struct CmdlineInfo * const cmdlineP) { /*---------------------------------------------------------------------------- Note that many of the strings that this function returns in the *cmdlineP structure are actually in the supplied argv array. And sometimes, one of these strings is actually just a suffix of an entry in argv! -----------------------------------------------------------------------------*/ optEntry * option_def; /* malloc'ed */ optStruct3 opt; unsigned int option_def_index; unsigned int alphaoutSpec; MALLOCARRAY(option_def, 100); option_def_index = 0; /* incremented by OPTENT3 */ OPTENT3('h', "headerdump", OPT_FLAG, NULL, &cmdlineP->headerdump, 0); OPTENT3('v', "verbose", OPT_FLAG, NULL, &cmdlineP->verbose, 0); OPTENT3(0, "alphaout", OPT_STRING, &cmdlineP->alphaout, &alphaoutSpec, 0); opt.opt_table = option_def; opt.short_allowed = TRUE; /* We have short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and all of *cmdlineP. */ if (!alphaoutSpec) cmdlineP->alphaout = NULL; if (argc - 1 == 0) cmdlineP->inputFilename = NULL; /* he wants stdin */ else if (argc - 1 == 1) { if (streq(argv[1], "-")) cmdlineP->inputFilename = NULL; /* he wants stdin */ else cmdlineP->inputFilename = strdup(argv[1]); } else pm_error("Too many arguments. The only argument accepted " "is the input file specification"); if (cmdlineP->alphaout && streq(cmdlineP->alphaout, "-")) cmdlineP->alphaStdout = TRUE; else cmdlineP->alphaStdout = FALSE; } static void reportRleGetSetupError(int const rleGetSetupRc) { switch (rleGetSetupRc) { case -1: pm_error("According to the URT library, the input is not " "an RLE file. rle_get_setup() failed."); break; case -2: pm_error("Unable to get memory for the color map. " "rle_get_setup() failed."); break; case -3: pm_error("Input file is empty. rle_get_setup() failed."); break; case -4: pm_error("End of file in the middle of where the RLE header should " "be. rle_get_setup() failed."); break; default: pm_error("rle_get_setup() failed for an unknown reason"); } } static void readRleHeader(FILE * const ifP, bool const headerDump) { int rc; int i; hdr.rle_file = ifP; rc = rle_get_setup(&hdr); if (rc != 0) reportRleGetSetupError(rc); width = hdr.xmax - hdr.xmin + 1; height = hdr.ymax - hdr.ymin + 1; HMSG("Image size: %dx%d", width, height); if (hdr.ncolors == 1 && hdr.ncmap == 3) { visual = PSEUDOCOLOR; colormap = hdr.cmap; maplen = (1 << hdr.cmaplen); HMSG("Mapped color image with a map of length %d.", maplen); } else if (hdr.ncolors == 3 && hdr.ncmap == 0) { visual = DIRECTCOLOR; HMSG("24 bit color image, no colormap."); } else if (hdr.ncolors == 3 && hdr.ncmap == 3) { visual = TRUECOLOR; colormap = hdr.cmap; maplen = (1 << hdr.cmaplen); HMSG( "24 bit color image with color map of length %d" ,maplen); } else if (hdr.ncolors == 1 && hdr.ncmap == 0) { visual = GRAYSCALE; HMSG("Grayscale image."); } else { fprintf(stderr, "ncolors = %d, ncmap = %d, I don't know how to handle this!", hdr.ncolors, hdr.ncmap); exit(-1); } if (hdr.alpha == 0) { HMSG("No alpha channel."); } else if (hdr.alpha == 1) { HMSG("Alpha channel exists!"); } else { fprintf(stderr, "alpha = %d, I don't know how to handle this!\n", hdr.alpha); exit(-1); } switch (hdr.background) { case 0: HMSG("Use all pixels, ignore background color."); break; case 1: HMSG("Use only non-background pixels, ignore background color."); break; case 2: HMSG("Use only non-background pixels, " "clear to background color (default)."); break; default: HMSG("Unknown background flag!"); break; } if (hdr.background == 2) for (i = 0; i < hdr.ncolors; i++) HMSG(" %d", hdr.bg_color[i]); if (hdr.ncolors == 1 && hdr.ncmap == 3) { HMSG(" (%d %d %d)", hdr.cmap[hdr.bg_color[0]]>>8, hdr.cmap[hdr.bg_color[0]+256]>>8, hdr.cmap[hdr.bg_color[0]+512]>>8); } else if (hdr.ncolors == 3 && hdr.ncmap == 3) { HMSG(" (%d %d %d)", hdr.cmap[hdr.bg_color[0]]>>8, hdr.cmap[hdr.bg_color[1]+256]>>8, hdr.cmap[hdr.bg_color[2]+512]>>8); } if (hdr.comments) for (i = 0; hdr.comments[i] != NULL; i++) HMSG("%s", hdr.comments[i]); } static void writePpmRaster(FILE * const imageoutFileP, FILE * const alphaFileP) { rle_pixel ***scanlines, **scanline; pixval r, g, b; pixel *pixelrow; gray *alpharow; int scan; int x; /* * Allocate some stuff. */ pixelrow = ppm_allocrow(width); alpharow = pgm_allocrow(width); MALLOCARRAY(scanlines, height); if (!scanlines) pm_error("Failed to allocate memory for %u scanline pointers", height); for (scan = 0; scan < height; ++scan) { int rc; rc = rle_row_alloc(&hdr, &scanlines[scan]); if (rc < 0) pm_error("Failed to allocate memory for a scanline"); } /* * Loop through those scan lines. */ for (scan = 0; scan < height; ++scan) rle_getrow(&hdr, scanlines[height - scan - 1]); for (scan = 0; scan < height; ++scan) { scanline = scanlines[scan]; switch (visual) { case GRAYSCALE: /* 8 bits without colormap */ for (x = 0; x < width; x++) { r = scanline[0][x]; g = scanline[0][x]; b = scanline[0][x]; PPM_ASSIGN(pixelrow[x], r, g, b); if (hdr.alpha) alpharow[x] = scanline[-1][x]; else alpharow[x] = 0; } break; case TRUECOLOR: /* 24 bits with colormap */ for (x = 0; x < width; x++) { r = colormap[scanline[0][x]]>>8; g = colormap[scanline[1][x]+256]>>8; b = colormap[scanline[2][x]+512]>>8; PPM_ASSIGN(pixelrow[x], r, g, b); if (hdr.alpha) alpharow[x] = colormap[scanline[-1][x]]; else alpharow[x] = 0; } break; case DIRECTCOLOR: /* 24 bits without colormap */ for (x = 0; x < width; x++) { r = scanline[0][x]; g = scanline[1][x]; b = scanline[2][x]; PPM_ASSIGN(pixelrow[x], r, g, b); if (hdr.alpha) alpharow[x] = scanline[-1][x]; else alpharow[x] = 0; } break; case PSEUDOCOLOR: /* 8 bits with colormap */ for (x = 0; x < width; x++) { r = colormap[scanline[0][x]]>>8; g = colormap[scanline[0][x]+256]>>8; b = colormap[scanline[0][x]+512]>>8; PPM_ASSIGN(pixelrow[x], r, g, b); if (hdr.alpha) alpharow[x] = colormap[scanline[-1][x]]; else alpharow[x] = 0; } break; default: break; } /* * Write the scan line. */ if (imageoutFileP) ppm_writeppmrow(imageoutFileP, pixelrow, width, RLE_MAXVAL, 0); if (alphaFileP) pgm_writepgmrow(alphaFileP, alpharow, width, RLE_MAXVAL, 0); } /* end of for scan = 0 to height */ /* Free scanline memory. */ for (scan = 0; scan < height; ++scan) rle_row_free(&hdr, scanlines[scan]); free (scanlines); ppm_freerow(pixelrow); pgm_freerow(alpharow); } static void writePgmRaster(FILE * const imageoutFileP, FILE * const alphaFileP) { /*---------------------------------------------------------------------------- Write the PGM image data -----------------------------------------------------------------------------*/ rle_pixel ***scanlines, **scanline; gray * pixelrow; gray * alpharow; int scan; /* * Allocate some stuff. */ pixelrow = pgm_allocrow(width); alpharow = pgm_allocrow(width); MALLOCARRAY(scanlines, height); if (!scanlines) pm_error("Failed to allocate memory for %u scanline pointers", height); for (scan = 0; scan < height; ++scan) { int rc; rc = rle_row_alloc(&hdr, &scanlines[scan]); if (rc < 0) pm_error("Failed to allocate memory for a scanline"); } /* * Loop through those scan lines. */ for (scan = 0; scan < height; ++scan) rle_getrow(&hdr, scanlines[height - scan - 1]); for (scan = 0; scan < height; ++scan) { int x; scanline = scanlines[scan]; for (x = 0; x < width; ++x) { pixelrow[x] = scanline[0][x]; if (hdr.alpha) alpharow[x] = scanline[1][x]; else alpharow[x] = 0; } if (imageoutFileP) pgm_writepgmrow(imageoutFileP, pixelrow, width, RLE_MAXVAL, 0); if (alphaFileP) pgm_writepgmrow(alphaFileP, alpharow, width, RLE_MAXVAL, 0); } /* end of for scan = 0 to height */ /* Free scanline memory. */ for (scan = 0; scan < height; ++scan) rle_row_free(&hdr, scanlines[scan]); free(scanlines); pgm_freerow(pixelrow); pgm_freerow(alpharow); } int main(int argc, char ** argv) { struct CmdlineInfo cmdline; FILE * ifP; FILE * imageoutFileP; FILE * alphaFileP; char * fname; pnm_init( &argc, argv ); parseCommandLine(argc, argv, &cmdline); fname = NULL; /* initial value */ if (cmdline.inputFilename != NULL ) ifP = pm_openr(cmdline.inputFilename); else ifP = stdin; if (cmdline.alphaStdout) alphaFileP = stdout; else if (cmdline.alphaout == NULL) alphaFileP = NULL; else { alphaFileP = pm_openw(cmdline.alphaout); } if (cmdline.alphaStdout) imageoutFileP = NULL; else imageoutFileP = stdout; /* * Open the file. */ /* Initialize header. */ hdr = *rle_hdr_init(NULL); rle_names(&hdr, cmd_name( argv ), fname, 0); /* * Read the rle file header. */ readRleHeader(ifP, cmdline.headerdump || cmdline.verbose); if (cmdline.headerdump) exit(0); /* * Write the alpha file header */ if (alphaFileP) pgm_writepgminit(alphaFileP, width, height, RLE_MAXVAL, 0); /* * Write the pnm file header. */ switch (visual) { case GRAYSCALE: /* 8 bits without colormap -> pgm */ if (cmdline.verbose) pm_message("Writing pgm file."); if (imageoutFileP) pgm_writepgminit(imageoutFileP, width, height, RLE_MAXVAL, 0); writePgmRaster(imageoutFileP, alphaFileP); break; default: /* anything else -> ppm */ if (cmdline.verbose) pm_message("Writing ppm file."); if (imageoutFileP) ppm_writeppminit(imageoutFileP, width, height, RLE_MAXVAL, 0); writePpmRaster(imageoutFileP, alphaFileP); break; } pm_close(ifP); if (imageoutFileP) pm_close(imageoutFileP); if (alphaFileP) pm_close(alphaFileP); return 0; }