|
Packit |
78deda |
/******************************************************************************
|
|
Packit |
78deda |
palmtopnm
|
|
Packit |
78deda |
*******************************************************************************
|
|
Packit |
78deda |
By Bryan Henderson, San Jose, California, June 2004.
|
|
Packit |
78deda |
|
|
Packit |
78deda |
Inspired by and using methods from Tbmptopnm by Ian Goldberg
|
|
Packit |
78deda |
<iang@cs.berkeley.edu>, and Bill Janssen <bill@janssen.org>.
|
|
Packit |
78deda |
|
|
Packit |
78deda |
Major fixes and new capability added by Paul Bolle <pebolle@tiscali.nl>
|
|
Packit |
78deda |
in late 2004 / early 2005.
|
|
Packit |
78deda |
|
|
Packit |
78deda |
Bryan's work is contributed to the public domain by its author.
|
|
Packit |
78deda |
******************************************************************************/
|
|
Packit |
78deda |
|
|
Packit |
78deda |
#include <string.h>
|
|
Packit |
78deda |
#include <assert.h>
|
|
Packit |
78deda |
|
|
Packit |
78deda |
#include "pm_c_util.h"
|
|
Packit |
78deda |
#include "pnm.h"
|
|
Packit |
78deda |
#include "shhopt.h"
|
|
Packit |
78deda |
#include "mallocvar.h"
|
|
Packit |
78deda |
|
|
Packit |
78deda |
#include "palm.h"
|
|
Packit |
78deda |
#include "palmcolormap.h"
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
enum PalmCompressionType {
|
|
Packit |
78deda |
COMPRESSION_NONE,
|
|
Packit |
78deda |
COMPRESSION_RLE,
|
|
Packit |
78deda |
COMPRESSION_SCANLINE,
|
|
Packit |
78deda |
COMPRESSION_PACKBITS
|
|
Packit |
78deda |
};
|
|
Packit |
78deda |
|
|
Packit |
78deda |
struct PalmHeader {
|
|
Packit |
78deda |
unsigned short cols;
|
|
Packit |
78deda |
unsigned short rows;
|
|
Packit |
78deda |
unsigned short bytesPerRow;
|
|
Packit |
78deda |
unsigned short flags;
|
|
Packit |
78deda |
bool directColor;
|
|
Packit |
78deda |
/* The header indicates a direct color raster, either by flag
|
|
Packit |
78deda |
(the old way) or by pixel format (the new way)
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
bool hasColormap;
|
|
Packit |
78deda |
bool hasTransparency;
|
|
Packit |
78deda |
unsigned char pixelSizeCode;
|
|
Packit |
78deda |
unsigned int pixelSize;
|
|
Packit |
78deda |
unsigned char version;
|
|
Packit |
78deda |
unsigned int transparentIndex;
|
|
Packit |
78deda |
enum PalmCompressionType compressionType;
|
|
Packit |
78deda |
/* version 3 encoding specific */
|
|
Packit |
78deda |
unsigned char size;
|
|
Packit |
78deda |
unsigned char pixelFormat;
|
|
Packit |
78deda |
unsigned short density;
|
|
Packit |
78deda |
unsigned long transparentValue;
|
|
Packit |
78deda |
};
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
struct DirectPixelFormat {
|
|
Packit |
78deda |
unsigned int redbits;
|
|
Packit |
78deda |
unsigned int greenbits;
|
|
Packit |
78deda |
unsigned int bluebits;
|
|
Packit |
78deda |
};
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
struct DirectColorInfo {
|
|
Packit |
78deda |
struct DirectPixelFormat pixelFormat;
|
|
Packit |
78deda |
ColormapEntry transparentColor;
|
|
Packit |
78deda |
};
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
struct CmdlineInfo {
|
|
Packit |
78deda |
/* All the information the user supplied in the command line,
|
|
Packit |
78deda |
in a form easy for the program to use.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
const char * inputFilespec;
|
|
Packit |
78deda |
unsigned int verbose;
|
|
Packit |
78deda |
unsigned int rendition;
|
|
Packit |
78deda |
unsigned int showhist;
|
|
Packit |
78deda |
unsigned int transparent;
|
|
Packit |
78deda |
};
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
parseCommandLine(int argc, const char ** argv,
|
|
Packit |
78deda |
struct CmdlineInfo *cmdlineP) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
Note that the file spec array we return is stored in the storage that
|
|
Packit |
78deda |
was passed to us as the argv array.
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
optEntry * option_def;
|
|
Packit |
78deda |
/* Instructions to pm_optParseOptions3 on how to parse our options.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
optStruct3 opt;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
unsigned int renditionSpec;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
unsigned int option_def_index;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
MALLOCARRAY_NOFAIL(option_def, 100);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
option_def_index = 0; /* incremented by OPTENTRY */
|
|
Packit |
78deda |
OPTENT3(0, "verbose", OPT_FLAG, NULL,
|
|
Packit |
78deda |
&cmdlineP->verbose, 0);
|
|
Packit |
78deda |
OPTENT3(0, "showhist", OPT_FLAG, NULL,
|
|
Packit |
78deda |
&cmdlineP->showhist, 0);
|
|
Packit |
78deda |
OPTENT3(0, "transparent", OPT_FLAG, NULL,
|
|
Packit |
78deda |
&cmdlineP->transparent, 0);
|
|
Packit |
78deda |
OPTENT3(0, "rendition", OPT_UINT, &cmdlineP->rendition,
|
|
Packit |
78deda |
&renditionSpec, 0);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
opt.opt_table = option_def;
|
|
Packit |
78deda |
opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */
|
|
Packit |
78deda |
opt.allowNegNum = FALSE; /* We may have parms that are negative numbers */
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
|
|
Packit |
78deda |
/* Uses and sets argc, argv, and some of *cmdlineP and others. */
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (renditionSpec) {
|
|
Packit |
78deda |
if (cmdlineP->rendition < 1)
|
|
Packit |
78deda |
pm_error("The -rendition value must be at least 1");
|
|
Packit |
78deda |
} else
|
|
Packit |
78deda |
cmdlineP->rendition = 1;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (cmdlineP->transparent && cmdlineP->showhist)
|
|
Packit |
78deda |
pm_error("You can't specify -showhist with -transparent");
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (argc-1 < 1)
|
|
Packit |
78deda |
cmdlineP->inputFilespec = "-";
|
|
Packit |
78deda |
else {
|
|
Packit |
78deda |
cmdlineP->inputFilespec = argv[1];
|
|
Packit |
78deda |
if (argc-1 > 1)
|
|
Packit |
78deda |
pm_error("Too many arguments (%d). The only non-option "
|
|
Packit |
78deda |
"argument is the file name", argc-1);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
free(option_def);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static xelval *
|
|
Packit |
78deda |
createGraymap(unsigned int const ncolors,
|
|
Packit |
78deda |
xelval const maxval) {
|
|
Packit |
78deda |
int i;
|
|
Packit |
78deda |
xelval *map;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
MALLOCARRAY_NOFAIL(map, ncolors);
|
|
Packit |
78deda |
for (i = 0; i < ncolors; ++i) {
|
|
Packit |
78deda |
map[i] = maxval - (i * maxval) / (ncolors - 1);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
return map;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
skipbytes(FILE * const ifP,
|
|
Packit |
78deda |
unsigned int const nbytes) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
unsigned char buf[256];
|
|
Packit |
78deda |
unsigned int n;
|
|
Packit |
78deda |
size_t bytesRead;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
n = nbytes; /* initial value */
|
|
Packit |
78deda |
|
|
Packit |
78deda |
while (n > 0) {
|
|
Packit |
78deda |
if (n > sizeof(buf)) {
|
|
Packit |
78deda |
bytesRead = fread(buf, sizeof(char), sizeof(buf), ifP);
|
|
Packit |
78deda |
if (bytesRead != sizeof(buf))
|
|
Packit |
78deda |
pm_error("Error reading Palm file. Short read.");
|
|
Packit |
78deda |
n -= sizeof(buf);
|
|
Packit |
78deda |
} else {
|
|
Packit |
78deda |
bytesRead = fread(buf, sizeof(char), n, ifP);
|
|
Packit |
78deda |
if (bytesRead != n)
|
|
Packit |
78deda |
pm_error("Error reading Palm file. Short read.");
|
|
Packit |
78deda |
n = 0;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
interpretCompression(unsigned char const compressionValue,
|
|
Packit |
78deda |
enum PalmCompressionType * const compressionTypeP) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
switch (compressionValue) {
|
|
Packit |
78deda |
case PALM_COMPRESSION_RLE:
|
|
Packit |
78deda |
*compressionTypeP = COMPRESSION_RLE;
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
case PALM_COMPRESSION_SCANLINE:
|
|
Packit |
78deda |
*compressionTypeP = COMPRESSION_SCANLINE;
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
case PALM_COMPRESSION_PACKBITS:
|
|
Packit |
78deda |
*compressionTypeP = COMPRESSION_PACKBITS;
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
case PALM_COMPRESSION_NONE:
|
|
Packit |
78deda |
/* according to the spec this is not possible */
|
|
Packit |
78deda |
*compressionTypeP = COMPRESSION_NONE;
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
default:
|
|
Packit |
78deda |
pm_error("The Palm image header has an unrecognized value for "
|
|
Packit |
78deda |
"compression type: 0x%02x", (unsigned)compressionValue);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
readRestOfHeaderVersion3(FILE * const ifP,
|
|
Packit |
78deda |
unsigned int const pixelSize,
|
|
Packit |
78deda |
unsigned char * const sizeP,
|
|
Packit |
78deda |
unsigned char * const pixelFormatP,
|
|
Packit |
78deda |
unsigned char * const compressionTypeP,
|
|
Packit |
78deda |
short * const densityP,
|
|
Packit |
78deda |
unsigned int * const transparentIndexP,
|
|
Packit |
78deda |
long * const transparentValueP,
|
|
Packit |
78deda |
long * const nextBitmapOffsetP,
|
|
Packit |
78deda |
short * const nextDepthOffsetP) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
unsigned char unused;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_readcharu(ifP, sizeP);
|
|
Packit |
78deda |
/* should be 0x18, but I can't see why we should really care */
|
|
Packit |
78deda |
if (*sizeP != 0x18)
|
|
Packit |
78deda |
pm_message("Strange value for Palm bitmap header size: %hu", *sizeP);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_readcharu(ifP, pixelFormatP);
|
|
Packit |
78deda |
if (*pixelFormatP != PALM_FORMAT_INDEXED &&
|
|
Packit |
78deda |
*pixelFormatP != PALM_FORMAT_565)
|
|
Packit |
78deda |
pm_error("Unrecognized pixelformat type: %u", *pixelFormatP);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_readcharu(ifP, &unused);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_readcharu(ifP, compressionTypeP);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_readbigshort(ifP, densityP);
|
|
Packit |
78deda |
/* the specs imply that 0x00 is not valid */
|
|
Packit |
78deda |
if (*densityP != PALM_DENSITY_LOW &&
|
|
Packit |
78deda |
*densityP != PALM_DENSITY_ONEANDAHALF &&
|
|
Packit |
78deda |
*densityP != PALM_DENSITY_DOUBLE &&
|
|
Packit |
78deda |
*densityP != PALM_DENSITY_TRIPLE &&
|
|
Packit |
78deda |
*densityP != PALM_DENSITY_QUADRUPLE)
|
|
Packit |
78deda |
pm_error("Invalid value for -density: %d.", *densityP);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_readbiglong(ifP, transparentValueP);
|
|
Packit |
78deda |
if (pixelSize < 16)
|
|
Packit |
78deda |
*transparentIndexP = *transparentValueP;
|
|
Packit |
78deda |
else
|
|
Packit |
78deda |
*transparentIndexP = 0;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_readbiglong(ifP, nextBitmapOffsetP);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
/* version < 3 specific */
|
|
Packit |
78deda |
*nextDepthOffsetP = 0;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
readRestOfHeaderOld(FILE * const ifP,
|
|
Packit |
78deda |
unsigned char * const sizeP,
|
|
Packit |
78deda |
unsigned char * const pixelFormatP,
|
|
Packit |
78deda |
unsigned char * const compressionTypeP,
|
|
Packit |
78deda |
short * const densityP,
|
|
Packit |
78deda |
unsigned int * const transparentIndexP,
|
|
Packit |
78deda |
long * const transparentValueP,
|
|
Packit |
78deda |
long * const nextBitmapOffsetP,
|
|
Packit |
78deda |
short * const nextDepthOffsetP) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
short pad;
|
|
Packit |
78deda |
unsigned char transparentIndex;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_readbigshort(ifP, nextDepthOffsetP);
|
|
Packit |
78deda |
pm_readcharu(ifP, &transparentIndex);
|
|
Packit |
78deda |
*transparentIndexP = transparentIndex;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_readcharu(ifP,compressionTypeP);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_readbigshort(ifP, &pad;; /* reserved by Palm as of 8/9/00 */
|
|
Packit |
78deda |
|
|
Packit |
78deda |
/* version 3 specific */
|
|
Packit |
78deda |
*sizeP = 0;
|
|
Packit |
78deda |
*pixelFormatP = 0;
|
|
Packit |
78deda |
*densityP = 0;
|
|
Packit |
78deda |
*transparentValueP = 0;
|
|
Packit |
78deda |
*nextBitmapOffsetP = 0;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
interpretHeader(struct PalmHeader * const palmHeaderP,
|
|
Packit |
78deda |
short const cols,
|
|
Packit |
78deda |
short const rows,
|
|
Packit |
78deda |
short const bytesPerRow,
|
|
Packit |
78deda |
short const flags,
|
|
Packit |
78deda |
unsigned char const pixelSizeCode,
|
|
Packit |
78deda |
unsigned int const pixelSize,
|
|
Packit |
78deda |
unsigned char const version,
|
|
Packit |
78deda |
unsigned char const size,
|
|
Packit |
78deda |
unsigned char const pixelFormat,
|
|
Packit |
78deda |
short const density,
|
|
Packit |
78deda |
long const transparentValue,
|
|
Packit |
78deda |
unsigned int const transparentIndex,
|
|
Packit |
78deda |
unsigned char const compressionType) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
palmHeaderP->cols = cols;
|
|
Packit |
78deda |
palmHeaderP->rows = rows;
|
|
Packit |
78deda |
palmHeaderP->bytesPerRow = bytesPerRow;
|
|
Packit |
78deda |
palmHeaderP->flags = flags; /* Just for diagnostics */
|
|
Packit |
78deda |
palmHeaderP->hasColormap = !!(flags & PALM_HAS_COLORMAP_FLAG);
|
|
Packit |
78deda |
palmHeaderP->hasTransparency = !!(flags & PALM_HAS_TRANSPARENCY_FLAG);
|
|
Packit |
78deda |
palmHeaderP->pixelSizeCode = pixelSizeCode;
|
|
Packit |
78deda |
palmHeaderP->pixelSize = pixelSize;
|
|
Packit |
78deda |
palmHeaderP->version = version;
|
|
Packit |
78deda |
palmHeaderP->size = size;
|
|
Packit |
78deda |
palmHeaderP->pixelFormat = pixelFormat;
|
|
Packit |
78deda |
palmHeaderP->density = density;
|
|
Packit |
78deda |
palmHeaderP->transparentValue = transparentValue;
|
|
Packit |
78deda |
palmHeaderP->transparentIndex = transparentIndex;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (palmHeaderP->version == 3 && ((flags & PALM_DIRECT_COLOR_FLAG) &&
|
|
Packit |
78deda |
(pixelFormat != PALM_FORMAT_565)))
|
|
Packit |
78deda |
/* There's no directColorInfoType section in a version 3 Palm Bitmap
|
|
Packit |
78deda |
so we also need PALM_FORMAT_565 for this flag to make sense
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
pm_error("PALM_DIRECT_COLOR_FLAG is set but pixelFormat is not"
|
|
Packit |
78deda |
"PALM_FORMAT_565.");
|
|
Packit |
78deda |
|
|
Packit |
78deda |
palmHeaderP->directColor = ((flags & PALM_DIRECT_COLOR_FLAG) ||
|
|
Packit |
78deda |
palmHeaderP->pixelFormat == PALM_FORMAT_565);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (flags & PALM_IS_COMPRESSED_FLAG)
|
|
Packit |
78deda |
interpretCompression(compressionType,
|
|
Packit |
78deda |
&palmHeaderP->compressionType);
|
|
Packit |
78deda |
else
|
|
Packit |
78deda |
palmHeaderP->compressionType = COMPRESSION_NONE;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
readHeader(FILE * const ifP,
|
|
Packit |
78deda |
unsigned int const requestedRendition,
|
|
Packit |
78deda |
struct PalmHeader * const palmHeaderP) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
Read the Palm Bitmap header from the file 'ifP'. Read past all
|
|
Packit |
78deda |
renditions up to 'requestedRendition' and read the header of that
|
|
Packit |
78deda |
rendition. Return the information contained in the header as *palmHeaderP.
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
bool gotHeader;
|
|
Packit |
78deda |
unsigned int currentRendition;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
gotHeader = FALSE;
|
|
Packit |
78deda |
currentRendition = 1;
|
|
Packit |
78deda |
while (!gotHeader) {
|
|
Packit |
78deda |
short cols, rows, bytesPerRow, flags, nextDepthOffset, density;
|
|
Packit |
78deda |
unsigned char pixelSizeCode, version, compressionType,
|
|
Packit |
78deda |
size, pixelFormat;
|
|
Packit |
78deda |
long transparentValue, nextBitmapOffset;
|
|
Packit |
78deda |
unsigned int pixelSize, transparentIndex;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_readbigshort(ifP, &cols;;
|
|
Packit |
78deda |
pm_readbigshort(ifP, &rows);
|
|
Packit |
78deda |
pm_readbigshort(ifP, &bytesPerRow);
|
|
Packit |
78deda |
pm_readbigshort(ifP, &flags);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_readcharu(ifP, &pixelSizeCode);
|
|
Packit |
78deda |
pixelSize = pixelSizeCode == 0 ? 1 : pixelSizeCode;
|
|
Packit |
78deda |
if (pixelSizeCode != 0x00 &&
|
|
Packit |
78deda |
pixelSizeCode != 0x01 &&
|
|
Packit |
78deda |
pixelSizeCode != 0x02 &&
|
|
Packit |
78deda |
pixelSizeCode != 0x04 &&
|
|
Packit |
78deda |
pixelSizeCode != 0x08 &&
|
|
Packit |
78deda |
pixelSizeCode != 0x10 &&
|
|
Packit |
78deda |
pixelSizeCode != 0xFF)
|
|
Packit |
78deda |
pm_error("Invalid value for bits per pixel: %u.", pixelSizeCode);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if ((bytesPerRow * 8) < (cols * pixelSize))
|
|
Packit |
78deda |
pm_error("%u bytes per row is not valid with %u columns and %u "
|
|
Packit |
78deda |
"bits per pixel.", bytesPerRow, cols, pixelSize);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_readcharu(ifP, &version);
|
|
Packit |
78deda |
if (version > 3)
|
|
Packit |
78deda |
pm_error("Unknown encoding version type: %d", version);
|
|
Packit |
78deda |
else if (version == 3)
|
|
Packit |
78deda |
readRestOfHeaderVersion3(ifP, pixelSize,
|
|
Packit |
78deda |
&size, &pixelFormat, &compressionType,
|
|
Packit |
78deda |
&density, &transparentIndex,
|
|
Packit |
78deda |
&transparentValue, &nextBitmapOffset,
|
|
Packit |
78deda |
&nextDepthOffset);
|
|
Packit |
78deda |
else
|
|
Packit |
78deda |
readRestOfHeaderOld(ifP,
|
|
Packit |
78deda |
&size, &pixelFormat, &compressionType,
|
|
Packit |
78deda |
&density, &transparentIndex,
|
|
Packit |
78deda |
&transparentValue, &nextBitmapOffset,
|
|
Packit |
78deda |
&nextDepthOffset);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (currentRendition < requestedRendition) {
|
|
Packit |
78deda |
if (version < 3 && nextDepthOffset == 0 && pixelSizeCode != 0xFF)
|
|
Packit |
78deda |
pm_error("Not enough renditions in the input Palm Bitmap "
|
|
Packit |
78deda |
"to extract the %dth", requestedRendition);
|
|
Packit |
78deda |
if (version == 3 && nextBitmapOffset == 0)
|
|
Packit |
78deda |
pm_error("Not enough renditions in the input Palm Bitmap "
|
|
Packit |
78deda |
"to extract the %dth", requestedRendition);
|
|
Packit |
78deda |
/* nextDepthOffset is calculated in 4 byte words
|
|
Packit |
78deda |
from the beginning of this bitmap (so it equals its size)
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
if (version < 3 && pixelSizeCode != 0xFF )
|
|
Packit |
78deda |
skipbytes(ifP, (nextDepthOffset*4)-16);
|
|
Packit |
78deda |
else if (version == 3)
|
|
Packit |
78deda |
/* FIXME rewrite skipbytes to accept longs? */
|
|
Packit |
78deda |
skipbytes(ifP, (short) nextBitmapOffset-24);
|
|
Packit |
78deda |
if (pixelSizeCode != 0xFF)
|
|
Packit |
78deda |
++currentRendition;
|
|
Packit |
78deda |
} else if (pixelSizeCode != 0xFF) {
|
|
Packit |
78deda |
gotHeader = TRUE;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
interpretHeader(palmHeaderP,
|
|
Packit |
78deda |
cols, rows, bytesPerRow, flags, pixelSizeCode,
|
|
Packit |
78deda |
pixelSize, version, size, pixelFormat, density,
|
|
Packit |
78deda |
transparentValue, transparentIndex,
|
|
Packit |
78deda |
compressionType);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static const char *
|
|
Packit |
78deda |
yesno(bool const arg) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (arg)
|
|
Packit |
78deda |
return "YES";
|
|
Packit |
78deda |
else
|
|
Packit |
78deda |
return "NO";
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
reportPalmHeader(struct PalmHeader const palmHeader,
|
|
Packit |
78deda |
struct DirectColorInfo const directColorInfo) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
const char *ctype;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
switch (palmHeader.compressionType) {
|
|
Packit |
78deda |
case COMPRESSION_RLE:
|
|
Packit |
78deda |
ctype = "rle (Palm OS 3.5)";
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
case COMPRESSION_SCANLINE:
|
|
Packit |
78deda |
ctype = "scanline (Palm OS 2.0)";
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
case COMPRESSION_PACKBITS:
|
|
Packit |
78deda |
ctype = "packbits (Palm OS 4.0)";
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
case COMPRESSION_NONE:
|
|
Packit |
78deda |
ctype = "none";
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
pm_message("Dimensions: %hu columns x %hu rows",
|
|
Packit |
78deda |
palmHeader.cols, palmHeader.rows);
|
|
Packit |
78deda |
pm_message("Row layout: %hu bytes per row, %hu bits per pixel",
|
|
Packit |
78deda |
palmHeader.bytesPerRow, palmHeader.pixelSize);
|
|
Packit |
78deda |
pm_message("Pixel Size code: %hu", palmHeader.pixelSizeCode);
|
|
Packit |
78deda |
pm_message("Flags: 0x%04hx", palmHeader.flags);
|
|
Packit |
78deda |
pm_message(" Direct Color: %s", yesno(palmHeader.directColor));
|
|
Packit |
78deda |
pm_message(" Colormap: %s", yesno(palmHeader.hasColormap));
|
|
Packit |
78deda |
pm_message(" Transparency: %s", yesno(palmHeader.hasTransparency));
|
|
Packit |
78deda |
pm_message("Version %d", palmHeader.version);
|
|
Packit |
78deda |
if (palmHeader.hasTransparency) {
|
|
Packit |
78deda |
if (palmHeader.directColor) {
|
|
Packit |
78deda |
/* Copied from doTransparent(...) */
|
|
Packit |
78deda |
ColormapEntry const color = directColorInfo.transparentColor;
|
|
Packit |
78deda |
pm_message("Transparent value: #%02x%02x%02x",
|
|
Packit |
78deda |
(unsigned int)((color >> 16) & 0xFF),
|
|
Packit |
78deda |
(unsigned int)((color >> 8) & 0xFF),
|
|
Packit |
78deda |
(unsigned int)((color >> 0) & 0xFF));
|
|
Packit |
78deda |
} else
|
|
Packit |
78deda |
pm_message("Transparent index: %u", palmHeader.transparentIndex);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
pm_message("Compression type: %s", ctype);
|
|
Packit |
78deda |
if (palmHeader.version == 3)
|
|
Packit |
78deda |
pm_message("Density: %d", palmHeader.density);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
determineOutputFormat(struct PalmHeader const palmHeader,
|
|
Packit |
78deda |
int * const formatP,
|
|
Packit |
78deda |
xelval * const maxvalP) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (palmHeader.directColor) {
|
|
Packit |
78deda |
*formatP = PPM_TYPE;
|
|
Packit |
78deda |
*maxvalP = 255;
|
|
Packit |
78deda |
} else if (palmHeader.hasColormap) {
|
|
Packit |
78deda |
*formatP = PPM_TYPE;
|
|
Packit |
78deda |
*maxvalP = 255;
|
|
Packit |
78deda |
} else if (palmHeader.pixelSize == 1) {
|
|
Packit |
78deda |
*formatP = PBM_TYPE;
|
|
Packit |
78deda |
*maxvalP = 1;
|
|
Packit |
78deda |
} else if (palmHeader.pixelSize >= 8) {
|
|
Packit |
78deda |
*formatP = PPM_TYPE;
|
|
Packit |
78deda |
*maxvalP = pm_bitstomaxval(palmHeader.pixelSize);
|
|
Packit |
78deda |
} else {
|
|
Packit |
78deda |
*formatP = PGM_TYPE;
|
|
Packit |
78deda |
*maxvalP = pm_bitstomaxval(palmHeader.pixelSize);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
readRgbFormat(FILE * const ifP,
|
|
Packit |
78deda |
struct DirectPixelFormat * const pixelFormatP) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
unsigned char r, g, b;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_readcharu(ifP, &r);
|
|
Packit |
78deda |
pm_readcharu(ifP, &g);
|
|
Packit |
78deda |
pm_readcharu(ifP, &b);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (r != 5 || g != 6 || b != 5)
|
|
Packit |
78deda |
pm_error("This image has a direct color pixel format of "
|
|
Packit |
78deda |
"%u red, %u green, %u blue bits. This program "
|
|
Packit |
78deda |
"can handle only 5, 6, 5.", r, g, b);
|
|
Packit |
78deda |
else {
|
|
Packit |
78deda |
pixelFormatP->redbits = r;
|
|
Packit |
78deda |
pixelFormatP->greenbits = g;
|
|
Packit |
78deda |
pixelFormatP->bluebits = b;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
readDirectTransparentColor(FILE * const ifP,
|
|
Packit |
78deda |
ColormapEntry * const colorP) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
unsigned char r, g, b;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_readcharu(ifP, &r);
|
|
Packit |
78deda |
pm_readcharu(ifP, &g);
|
|
Packit |
78deda |
pm_readcharu(ifP, &b);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
*colorP = (r << 16) | (g << 8) | (b << 0);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
readDirectInfoType(FILE * const ifP,
|
|
Packit |
78deda |
struct PalmHeader const palmHeader,
|
|
Packit |
78deda |
struct DirectColorInfo * const directInfoTypeP) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
Read the Palm Bitmap Direct Info Type section, if any.
|
|
Packit |
78deda |
|
|
Packit |
78deda |
The Direct Info Type section is a section of a pre-Version 3 direct
|
|
Packit |
78deda |
color Palm Bitmap that tells how to interpret the direct color
|
|
Packit |
78deda |
raster.
|
|
Packit |
78deda |
|
|
Packit |
78deda |
Return an undefined value as *directInfoTypeP if there is no such
|
|
Packit |
78deda |
section in this Palm Bitmap.
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
if ((palmHeader.directColor) && palmHeader.pixelSize != 16)
|
|
Packit |
78deda |
pm_error("The image is of the direct color type, but has %u "
|
|
Packit |
78deda |
"bits per pixel. The only kind of direct color images "
|
|
Packit |
78deda |
"this program understands are 16 bit ones.",
|
|
Packit |
78deda |
palmHeader.pixelSize);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (palmHeader.version == 3) {
|
|
Packit |
78deda |
/* All direct color info is in the header, because it'sversion
|
|
Packit |
78deda |
3 encoding. No Direct Info Type section.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
} else {
|
|
Packit |
78deda |
if (palmHeader.directColor) {
|
|
Packit |
78deda |
unsigned char padding;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
readRgbFormat(ifP, &directInfoTypeP->pixelFormat);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_readcharu(ifP, &padding);
|
|
Packit |
78deda |
pm_readcharu(ifP, &padding);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
readDirectTransparentColor(ifP,
|
|
Packit |
78deda |
&directInfoTypeP->transparentColor);
|
|
Packit |
78deda |
} else {
|
|
Packit |
78deda |
/* Not a direct color image; no Direct Info Type section. */
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
readColormap(FILE * const ifP,
|
|
Packit |
78deda |
struct PalmHeader const palmHeader,
|
|
Packit |
78deda |
Colormap ** const colormapPP) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
Read the colormap, if any from the Palm Bitmap.
|
|
Packit |
78deda |
|
|
Packit |
78deda |
If the image described by 'palmHeader' doesn't have a colormap,
|
|
Packit |
78deda |
return an undefined value as *colormapP.
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
if (palmHeader.hasColormap)
|
|
Packit |
78deda |
*colormapPP = palmcolor_read_colormap(ifP);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
getColorInfo(struct PalmHeader const palmHeader,
|
|
Packit |
78deda |
struct DirectColorInfo const directInfoType,
|
|
Packit |
78deda |
Colormap * const colormapFromImageP,
|
|
Packit |
78deda |
Colormap ** const colormapPP,
|
|
Packit |
78deda |
unsigned int * const ncolorsP,
|
|
Packit |
78deda |
struct DirectColorInfo * const directColorInfoP) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
Gather color encoding information from the various sources.
|
|
Packit |
78deda |
|
|
Packit |
78deda |
Note that 'directInfoType' and 'colormapFromImage' are meaningful only
|
|
Packit |
78deda |
with certain values of 'palmHeader'.
|
|
Packit |
78deda |
|
|
Packit |
78deda |
If it's a version 3 direct color, the pixel format must be "565".
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
if (palmHeader.version == 3 && palmHeader.directColor) {
|
|
Packit |
78deda |
*colormapPP = NULL;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
assert(palmHeader.pixelFormat == PALM_FORMAT_565);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
directColorInfoP->pixelFormat.redbits = 5;
|
|
Packit |
78deda |
directColorInfoP->pixelFormat.greenbits = 6;
|
|
Packit |
78deda |
directColorInfoP->pixelFormat.bluebits = 5;
|
|
Packit |
78deda |
directColorInfoP->transparentColor =
|
|
Packit |
78deda |
/* See convertRowToPnmDirect for this trick
|
|
Packit |
78deda |
|
|
Packit |
78deda |
This will break once maxval isn't always set 255 for
|
|
Packit |
78deda |
directColor
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
((((palmHeader.transparentValue >> 11) & 0x1F) * 255 / 0x1F)
|
|
Packit |
78deda |
<< 16) |
|
|
Packit |
78deda |
((((palmHeader.transparentValue >> 5) & 0x3F) * 255 / 0x3F)
|
|
Packit |
78deda |
<< 8) |
|
|
Packit |
78deda |
((((palmHeader.transparentValue >> 0) & 0x1F) * 255 / 0x1F)
|
|
Packit |
78deda |
<< 0);
|
|
Packit |
78deda |
} else if (palmHeader.directColor) {
|
|
Packit |
78deda |
*colormapPP = NULL;
|
|
Packit |
78deda |
*directColorInfoP = directInfoType;
|
|
Packit |
78deda |
} else if (palmHeader.hasColormap)
|
|
Packit |
78deda |
*colormapPP = colormapFromImageP;
|
|
Packit |
78deda |
else if (palmHeader.pixelSize >= 8) {
|
|
Packit |
78deda |
Colormap * const colormapP =
|
|
Packit |
78deda |
palmcolor_build_default_8bit_colormap();
|
|
Packit |
78deda |
qsort(colormapP->color_entries, colormapP->ncolors,
|
|
Packit |
78deda |
sizeof(ColormapEntry), palmcolor_compare_indices);
|
|
Packit |
78deda |
*colormapPP = colormapP;
|
|
Packit |
78deda |
} else
|
|
Packit |
78deda |
*colormapPP = NULL;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
*ncolorsP = 1 << palmHeader.pixelSize;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
doTransparent(FILE * const ofP,
|
|
Packit |
78deda |
bool const hasTransparency,
|
|
Packit |
78deda |
bool const directColor,
|
|
Packit |
78deda |
unsigned char const transparentIndex,
|
|
Packit |
78deda |
unsigned char const pixelSize,
|
|
Packit |
78deda |
Colormap * const colormapP,
|
|
Packit |
78deda |
struct DirectColorInfo const directColorInfo) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
Generate a PNM comment on *ofP telling what color in the raster is
|
|
Packit |
78deda |
supposed to be transparent.
|
|
Packit |
78deda |
|
|
Packit |
78deda |
Note that PNM itself doesn't have any way to represent transparency.
|
|
Packit |
78deda |
(But this program could be converted to a PAM program and use the
|
|
Packit |
78deda |
RGB_ALPHA and GRAYSCALE_ALPHA tuple types).
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
if (hasTransparency) {
|
|
Packit |
78deda |
if (colormapP) {
|
|
Packit |
78deda |
ColormapEntry const searchTarget = transparentIndex << 24;
|
|
Packit |
78deda |
ColormapEntry * const foundEntryP =
|
|
Packit |
78deda |
bsearch(&searchTarget,
|
|
Packit |
78deda |
colormapP->color_entries,
|
|
Packit |
78deda |
colormapP->ncolors,
|
|
Packit |
78deda |
sizeof(searchTarget),
|
|
Packit |
78deda |
palmcolor_compare_indices);
|
|
Packit |
78deda |
if (!foundEntryP)
|
|
Packit |
78deda |
pm_error("Invalid input; transparent index %u "
|
|
Packit |
78deda |
"is not among the %u colors in the image's colormap",
|
|
Packit |
78deda |
transparentIndex, colormapP->ncolors);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
fprintf(ofP, "#%02x%02x%02x\n",
|
|
Packit |
78deda |
(unsigned int) ((*foundEntryP >> 16) & 0xFF),
|
|
Packit |
78deda |
(unsigned int) ((*foundEntryP >> 8) & 0xFF),
|
|
Packit |
78deda |
(unsigned int) ((*foundEntryP >> 0) & 0xFF));
|
|
Packit |
78deda |
} else if (directColor) {
|
|
Packit |
78deda |
ColormapEntry const color = directColorInfo.transparentColor;
|
|
Packit |
78deda |
fprintf(ofP, "#%02x%02x%02x\n",
|
|
Packit |
78deda |
(unsigned int)((color >> 16) & 0xFF),
|
|
Packit |
78deda |
(unsigned int)((color >> 8) & 0xFF),
|
|
Packit |
78deda |
(unsigned int)((color >> 0) & 0xFF));
|
|
Packit |
78deda |
} else {
|
|
Packit |
78deda |
unsigned int const maxval = pm_bitstomaxval(pixelSize);
|
|
Packit |
78deda |
unsigned int const grayval =
|
|
Packit |
78deda |
((maxval - transparentIndex) * 256) / maxval;
|
|
Packit |
78deda |
fprintf(ofP, "#%02x%02x%02x\n", grayval, grayval, grayval);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
createHistogram(unsigned int const ncolors,
|
|
Packit |
78deda |
unsigned int ** const seenP) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
unsigned int * seen;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
MALLOCARRAY(seen, ncolors);
|
|
Packit |
78deda |
if (!seen)
|
|
Packit |
78deda |
pm_error("Can't allocate array for keeping track of "
|
|
Packit |
78deda |
"how many pixels of each of %u colors are in the image.",
|
|
Packit |
78deda |
ncolors);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
{
|
|
Packit |
78deda |
/* Initialize the counter for each color to zero */
|
|
Packit |
78deda |
unsigned int i;
|
|
Packit |
78deda |
for (i = 0; i < ncolors; ++i)
|
|
Packit |
78deda |
seen[i] = 0;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
*seenP = seen;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
readScanlineRow(FILE * const ifP,
|
|
Packit |
78deda |
unsigned char * const palmrow,
|
|
Packit |
78deda |
unsigned char * const lastrow,
|
|
Packit |
78deda |
unsigned int const bytesPerRow,
|
|
Packit |
78deda |
bool const firstRow) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
unsigned int j;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
for (j = 0; j < bytesPerRow; j += 8) {
|
|
Packit |
78deda |
unsigned char diffmask;
|
|
Packit |
78deda |
/* A mask telling whether each of the 8 raster bytes indexed
|
|
Packit |
78deda |
j through j+7 is the same as in the previous row ('lastrow')
|
|
Packit |
78deda |
or is to be read from the file. Bit 0 of the mask refers
|
|
Packit |
78deda |
to byte j, Bit 1 to byte j + 1, etc.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
unsigned int byteCount;
|
|
Packit |
78deda |
/* How many bytes are covered by 'diffmask'. Normally 8, but
|
|
Packit |
78deda |
at the end of the row, could be less.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
unsigned int k;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_readcharu(ifP, &diffmask);
|
|
Packit |
78deda |
byteCount = MIN(bytesPerRow - j, 8);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
for (k = 0; k < byteCount; ++k) {
|
|
Packit |
78deda |
/* the first row cannot be compressed */
|
|
Packit |
78deda |
if (firstRow || ((diffmask & (1 << (7 - k))) != 0)) {
|
|
Packit |
78deda |
unsigned char inval;
|
|
Packit |
78deda |
pm_readcharu(ifP, &inval);
|
|
Packit |
78deda |
palmrow[j + k] = inval;
|
|
Packit |
78deda |
} else
|
|
Packit |
78deda |
palmrow[j + k] = lastrow[j + k];
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
memcpy(lastrow, palmrow, bytesPerRow);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
readRleRow(FILE * const ifP,
|
|
Packit |
78deda |
unsigned char * const palmrow,
|
|
Packit |
78deda |
unsigned int const bytesPerRow) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
unsigned int j;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
for (j = 0; j < bytesPerRow; ) {
|
|
Packit |
78deda |
unsigned char incount;
|
|
Packit |
78deda |
unsigned char inval;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_readcharu(ifP, &incount);
|
|
Packit |
78deda |
if (incount == 0)
|
|
Packit |
78deda |
pm_error("Invalid (zero) count in RLE compression.");
|
|
Packit |
78deda |
if (j + incount > bytesPerRow)
|
|
Packit |
78deda |
pm_error("Bytes in RLE compressed row exceed bytes per row. "
|
|
Packit |
78deda |
"Bytes per row is %u. A run length of %u bytes "
|
|
Packit |
78deda |
"pushes the bytes in this row up to %u bytes (and then "
|
|
Packit |
78deda |
"we gave up).", bytesPerRow, incount, j + incount);
|
|
Packit |
78deda |
pm_readcharu(ifP, &inval);
|
|
Packit |
78deda |
memset(palmrow + j, inval, incount);
|
|
Packit |
78deda |
j += incount;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
readPackBitsRow16(FILE * const ifP,
|
|
Packit |
78deda |
unsigned char * const palmrow,
|
|
Packit |
78deda |
unsigned int const bytesPerRow) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
/* From the Palm OS Programmer's API Reference:
|
|
Packit |
78deda |
|
|
Packit |
78deda |
Although the [...] spec is byte-oriented, the 16-bit algorithm is
|
|
Packit |
78deda |
identical [to the 8-bit algorithm]: just substitute "word" for "byte".
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
unsigned int j;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
for (j = 0; j < bytesPerRow; ) {
|
|
Packit |
78deda |
char incount;
|
|
Packit |
78deda |
pm_readchar(ifP, &incount);
|
|
Packit |
78deda |
if (incount < 0) {
|
|
Packit |
78deda |
/* How do we handle incount == -128 ? */
|
|
Packit |
78deda |
unsigned int const runlength = (-incount + 1) * 2;
|
|
Packit |
78deda |
unsigned int k;
|
|
Packit |
78deda |
unsigned short inval;
|
|
Packit |
78deda |
pm_readlittleshortu(ifP, &inval);
|
|
Packit |
78deda |
if (j + runlength <= bytesPerRow) {
|
|
Packit |
78deda |
for (k = 0; k < runlength; k += 2)
|
|
Packit |
78deda |
memcpy(palmrow + j + k, &inval, 2);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
j += runlength;
|
|
Packit |
78deda |
} else {
|
|
Packit |
78deda |
/* We just read the stream of shorts as a stream of chars */
|
|
Packit |
78deda |
unsigned int const nonrunlength = (incount + 1) * 2;
|
|
Packit |
78deda |
unsigned int k;
|
|
Packit |
78deda |
for (k = 0; (k < nonrunlength) && (j + k <= bytesPerRow); ++k) {
|
|
Packit |
78deda |
unsigned char inval;
|
|
Packit |
78deda |
pm_readcharu(ifP, &inval);
|
|
Packit |
78deda |
palmrow[j + k] = inval;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
j += nonrunlength;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
if (j > bytesPerRow)
|
|
Packit |
78deda |
pm_error("Bytes in PackBits compressed row exceed bytes per row. "
|
|
Packit |
78deda |
"Bytes per row is %u. "
|
|
Packit |
78deda |
"The bytes in this row were pushed up to %u bytes "
|
|
Packit |
78deda |
"(and then we gave up).", bytesPerRow, j);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
readPackBitsRow(FILE * const ifP,
|
|
Packit |
78deda |
unsigned char * const palmrow,
|
|
Packit |
78deda |
unsigned int const bytesPerRow) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
unsigned int j;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
for (j = 0; j < bytesPerRow; ) {
|
|
Packit |
78deda |
char incount;
|
|
Packit |
78deda |
pm_readchar(ifP, &incount);
|
|
Packit |
78deda |
if (incount < 0) {
|
|
Packit |
78deda |
/* How do we handle incount == -128 ? */
|
|
Packit |
78deda |
unsigned int const runlength = -incount + 1;
|
|
Packit |
78deda |
unsigned char inval;
|
|
Packit |
78deda |
pm_readcharu(ifP, &inval);
|
|
Packit |
78deda |
if (j + runlength <= bytesPerRow)
|
|
Packit |
78deda |
memset(palmrow + j, inval, runlength);
|
|
Packit |
78deda |
j += runlength;
|
|
Packit |
78deda |
} else {
|
|
Packit |
78deda |
unsigned int const nonrunlength = incount + 1;
|
|
Packit |
78deda |
unsigned int k;
|
|
Packit |
78deda |
for (k = 0; k < nonrunlength && j + k <= bytesPerRow; ++k) {
|
|
Packit |
78deda |
unsigned char inval;
|
|
Packit |
78deda |
pm_readcharu(ifP, &inval);
|
|
Packit |
78deda |
palmrow[j + k] = inval;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
j += nonrunlength;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
if (j > bytesPerRow)
|
|
Packit |
78deda |
pm_error("Bytes in PackBits compressed row exceed bytes per row. "
|
|
Packit |
78deda |
"Bytes per row is %u. "
|
|
Packit |
78deda |
"The bytes in this row were pushed up to %u bytes "
|
|
Packit |
78deda |
"(and then we gave up).", bytesPerRow, j);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
readUncompressedRow(FILE * const ifP,
|
|
Packit |
78deda |
unsigned char * const palmrow,
|
|
Packit |
78deda |
unsigned int const bytesPerRow) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
int bytesRead;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
bytesRead = fread(palmrow, 1, bytesPerRow, ifP);
|
|
Packit |
78deda |
if (bytesRead != bytesPerRow)
|
|
Packit |
78deda |
pm_error("Error reading Palm file. Short read.");
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
readDecompressedRow(FILE * const ifP,
|
|
Packit |
78deda |
unsigned char * const palmrow,
|
|
Packit |
78deda |
unsigned char * const lastrow,
|
|
Packit |
78deda |
enum PalmCompressionType const compressionType,
|
|
Packit |
78deda |
unsigned int const bytesPerRow,
|
|
Packit |
78deda |
unsigned int const pixelSize,
|
|
Packit |
78deda |
bool const firstRow) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
Read a row from Palm file 'ifP', in uncompressed form (i.e. decompress if
|
|
Packit |
78deda |
necessary). Assume the row contains 'bytesPerRow' uncompressed bytes,
|
|
Packit |
78deda |
compressed according to 'compressionType'. Return the data at 'palmrow'.
|
|
Packit |
78deda |
|
|
Packit |
78deda |
'firstRow' means decompress it as if it is the first row of the image
|
|
Packit |
78deda |
(some compression schemes transform the first row differently from the
|
|
Packit |
78deda |
rest, because each row depends on the row before it).
|
|
Packit |
78deda |
|
|
Packit |
78deda |
If 'compressionType' is COMPRESSION_SCANLINE, (which means
|
|
Packit |
78deda |
transformation of a row depends on the contents of the row before
|
|
Packit |
78deda |
it), then 'lastRow' is as input the uncompressed contents of the
|
|
Packit |
78deda |
previous row (undefined if 'firstRow' is true). In that case, we
|
|
Packit |
78deda |
modify 'lastrow' to contain a copy of 'palmrow' (so Caller can
|
|
Packit |
78deda |
conveniently use it to read the next row).
|
|
Packit |
78deda |
|
|
Packit |
78deda |
If 'compressionType' is not COMPRESSION_SCANLINE, 'lastrow' is
|
|
Packit |
78deda |
undefined both as input and output.
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
switch (compressionType) {
|
|
Packit |
78deda |
case COMPRESSION_RLE:
|
|
Packit |
78deda |
readRleRow(ifP, palmrow, bytesPerRow);
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
case COMPRESSION_SCANLINE:
|
|
Packit |
78deda |
readScanlineRow(ifP, palmrow, lastrow, bytesPerRow, firstRow);
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
case COMPRESSION_PACKBITS:
|
|
Packit |
78deda |
if (pixelSize != 16)
|
|
Packit |
78deda |
readPackBitsRow(ifP, palmrow, bytesPerRow);
|
|
Packit |
78deda |
else
|
|
Packit |
78deda |
readPackBitsRow16(ifP, palmrow, bytesPerRow);
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
case COMPRESSION_NONE:
|
|
Packit |
78deda |
readUncompressedRow(ifP, palmrow, bytesPerRow);
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
convertRowToPnmDirect(const unsigned char * const palmrow,
|
|
Packit |
78deda |
xel * const xelrow,
|
|
Packit |
78deda |
unsigned int const cols,
|
|
Packit |
78deda |
xelval const maxval,
|
|
Packit |
78deda |
unsigned int * const seen) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
/* There's a problem with this. Take the Palm 16-bit
|
|
Packit |
78deda |
direct color. That's 5 bits for the red, 6 for the
|
|
Packit |
78deda |
green, and 5 for the blue. So what should the MAXVAL
|
|
Packit |
78deda |
be? I decided to use 255 (8 bits) for everything,
|
|
Packit |
78deda |
since that's the theoretical max of the number of bits
|
|
Packit |
78deda |
in any one color, according to Palm. So the Palm color
|
|
Packit |
78deda |
0xFFFF (white) would be red=0x1F, green=0x3F, and
|
|
Packit |
78deda |
blue=0x1F. How do we promote those colors? Simple
|
|
Packit |
78deda |
shift would give us R=248,G=252,B=248; which is
|
|
Packit |
78deda |
slightly green. Hardly seems right.
|
|
Packit |
78deda |
|
|
Packit |
78deda |
So I've perverted the math a bit. Each color value is
|
|
Packit |
78deda |
multiplied by 255, then divided by either 31 (red or
|
|
Packit |
78deda |
blue) or 63 (green). That's the right way to do it
|
|
Packit |
78deda |
anyway.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
|
|
Packit |
78deda |
const unsigned char *inbyte;
|
|
Packit |
78deda |
unsigned int j;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
for (inbyte = palmrow, j = 0; j < cols; ++j) {
|
|
Packit |
78deda |
unsigned int inval;
|
|
Packit |
78deda |
inval = *inbyte++ << 8;
|
|
Packit |
78deda |
inval |= *inbyte++;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (seen)
|
|
Packit |
78deda |
++seen[inval];
|
|
Packit |
78deda |
|
|
Packit |
78deda |
PPM_ASSIGN(xelrow[j],
|
|
Packit |
78deda |
(((inval >> 11) & 0x1F) * maxval) / 0x1F,
|
|
Packit |
78deda |
(((inval >> 5) & 0x3F) * maxval) / 0x3F,
|
|
Packit |
78deda |
(((inval >> 0) & 0x1F) * maxval) / 0x1F
|
|
Packit |
78deda |
);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
convertRowToPnmNotDirect(const unsigned char * const palmrow,
|
|
Packit |
78deda |
xel * const xelrow,
|
|
Packit |
78deda |
unsigned int const cols,
|
|
Packit |
78deda |
Colormap * const colormapP,
|
|
Packit |
78deda |
xelval * const graymap,
|
|
Packit |
78deda |
unsigned int * const seen,
|
|
Packit |
78deda |
unsigned int const pixelSize) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
unsigned int const mask = (1 << pixelSize) - 1;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
const unsigned char * inbyteP;
|
|
Packit |
78deda |
unsigned int inbit;
|
|
Packit |
78deda |
unsigned int j;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
assert(pixelSize <= 8);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
inbit = 8 - pixelSize;
|
|
Packit |
78deda |
inbyteP = &palmrow[0];
|
|
Packit |
78deda |
for (j = 0; j < cols; ++j) {
|
|
Packit |
78deda |
short const color = (*inbyteP & (mask << inbit)) >> inbit;
|
|
Packit |
78deda |
if (seen)
|
|
Packit |
78deda |
++seen[color];
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (colormapP) {
|
|
Packit |
78deda |
ColormapEntry const searchTarget = color << 24;
|
|
Packit |
78deda |
ColormapEntry * const foundEntryP =
|
|
Packit |
78deda |
bsearch(&searchTarget,
|
|
Packit |
78deda |
colormapP->color_entries,
|
|
Packit |
78deda |
colormapP->ncolors,
|
|
Packit |
78deda |
sizeof(searchTarget),
|
|
Packit |
78deda |
palmcolor_compare_indices);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (!foundEntryP)
|
|
Packit |
78deda |
pm_error("Invalid input. A color index in column %u "
|
|
Packit |
78deda |
"is %u, which is not among the %u colors "
|
|
Packit |
78deda |
"in the colormap",
|
|
Packit |
78deda |
j, color, colormapP->ncolors);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
PPM_ASSIGN(xelrow[j],
|
|
Packit |
78deda |
(*foundEntryP >> 16) & 0xFF,
|
|
Packit |
78deda |
(*foundEntryP >> 8) & 0xFF,
|
|
Packit |
78deda |
(*foundEntryP >> 0) & 0xFF);
|
|
Packit |
78deda |
} else
|
|
Packit |
78deda |
PNM_ASSIGN1(xelrow[j], graymap[color]);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (!inbit) {
|
|
Packit |
78deda |
++inbyteP;
|
|
Packit |
78deda |
inbit = 8 - pixelSize;
|
|
Packit |
78deda |
} else
|
|
Packit |
78deda |
inbit -= pixelSize;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
writePnm(FILE * const ofP,
|
|
Packit |
78deda |
struct PalmHeader const palmHeader,
|
|
Packit |
78deda |
FILE * const ifP,
|
|
Packit |
78deda |
Colormap * const colormapP,
|
|
Packit |
78deda |
xelval * const graymap,
|
|
Packit |
78deda |
unsigned int const nColors,
|
|
Packit |
78deda |
int const format,
|
|
Packit |
78deda |
xelval const maxval,
|
|
Packit |
78deda |
unsigned int ** const seenP) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
int const cols = palmHeader.cols;
|
|
Packit |
78deda |
int const rows = palmHeader.rows;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
unsigned char * palmrow;
|
|
Packit |
78deda |
unsigned char * lastrow;
|
|
Packit |
78deda |
xel * xelrow;
|
|
Packit |
78deda |
unsigned int * seen;
|
|
Packit |
78deda |
unsigned int row;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pnm_writepnminit(ofP, cols, rows, maxval, format, 0);
|
|
Packit |
78deda |
xelrow = pnm_allocrow(cols);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
/* Read the picture data, one row at a time */
|
|
Packit |
78deda |
MALLOCARRAY_NOFAIL(palmrow, palmHeader.bytesPerRow);
|
|
Packit |
78deda |
MALLOCARRAY_NOFAIL(lastrow, palmHeader.bytesPerRow);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (seenP) {
|
|
Packit |
78deda |
createHistogram(nColors, &seen);
|
|
Packit |
78deda |
*seenP = seen;
|
|
Packit |
78deda |
} else
|
|
Packit |
78deda |
seen = NULL;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
/* We should actually use compressedDataSizeNN for checking the sanity
|
|
Packit |
78deda |
of the data we're reading ...
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
if (palmHeader.compressionType != COMPRESSION_NONE) {
|
|
Packit |
78deda |
if (palmHeader.version < 3) {
|
|
Packit |
78deda |
short compressedDataSize16;
|
|
Packit |
78deda |
pm_readbigshort(ifP, &compressedDataSize16);
|
|
Packit |
78deda |
} else {
|
|
Packit |
78deda |
long compressedDataSize32;
|
|
Packit |
78deda |
pm_readbiglong(ifP, &compressedDataSize32);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
for (row = 0; row < rows; ++row) {
|
|
Packit |
78deda |
readDecompressedRow(ifP, palmrow, lastrow,
|
|
Packit |
78deda |
palmHeader.compressionType,
|
|
Packit |
78deda |
palmHeader.bytesPerRow,
|
|
Packit |
78deda |
palmHeader.pixelSize,
|
|
Packit |
78deda |
row == 0);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (palmHeader.directColor) {
|
|
Packit |
78deda |
assert(palmHeader.pixelSize == 16);
|
|
Packit |
78deda |
convertRowToPnmDirect(palmrow, xelrow, cols, maxval, seen);
|
|
Packit |
78deda |
} else
|
|
Packit |
78deda |
convertRowToPnmNotDirect(palmrow, xelrow, cols, colormapP, graymap,
|
|
Packit |
78deda |
seen, palmHeader.pixelSize);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pnm_writepnmrow(ofP, xelrow, cols, maxval, format, 0);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
free(lastrow);
|
|
Packit |
78deda |
free(palmrow);
|
|
Packit |
78deda |
pnm_freerow(xelrow);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
showHistogram(unsigned int * const seen,
|
|
Packit |
78deda |
Colormap * const colormapP,
|
|
Packit |
78deda |
const xelval * const graymap,
|
|
Packit |
78deda |
unsigned int const ncolors) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
unsigned int colorIndex;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
for (colorIndex = 0; colorIndex < ncolors; ++colorIndex) {
|
|
Packit |
78deda |
if (!colormapP)
|
|
Packit |
78deda |
pm_message("%.3d -> %.3d: %d",
|
|
Packit |
78deda |
colorIndex, graymap[colorIndex], seen[colorIndex]);
|
|
Packit |
78deda |
else {
|
|
Packit |
78deda |
ColormapEntry const searchTarget = colorIndex << 24;
|
|
Packit |
78deda |
ColormapEntry * const foundEntryP =
|
|
Packit |
78deda |
bsearch(&searchTarget,
|
|
Packit |
78deda |
colormapP->color_entries,
|
|
Packit |
78deda |
colormapP->ncolors,
|
|
Packit |
78deda |
sizeof(searchTarget),
|
|
Packit |
78deda |
palmcolor_compare_indices);
|
|
Packit |
78deda |
if (foundEntryP)
|
|
Packit |
78deda |
pm_message("%.3d -> %ld,%ld,%ld: %d", colorIndex,
|
|
Packit |
78deda |
(*foundEntryP >> 16) & 0xFF,
|
|
Packit |
78deda |
(*foundEntryP >> 8) & 0xFF,
|
|
Packit |
78deda |
(*foundEntryP & 0xFF), seen[colorIndex]);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
int
|
|
Packit |
78deda |
main(int argc, const char **argv) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
struct CmdlineInfo cmdline;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
FILE * ifP;
|
|
Packit |
78deda |
struct PalmHeader palmHeader;
|
|
Packit |
78deda |
struct DirectColorInfo directInfoType;
|
|
Packit |
78deda |
Colormap * colormapFromImageP;
|
|
Packit |
78deda |
Colormap * colormapP;
|
|
Packit |
78deda |
struct DirectColorInfo directColorInfo;
|
|
Packit |
78deda |
int format;
|
|
Packit |
78deda |
xelval maxval;
|
|
Packit |
78deda |
unsigned int nColors;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_proginit(&argc, argv);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
parseCommandLine(argc, argv, &cmdline);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
ifP = pm_openr(cmdline.inputFilespec);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
readHeader(ifP, cmdline.rendition, &palmHeader);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
readDirectInfoType(ifP, palmHeader, &directInfoType);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
readColormap(ifP, palmHeader, &colormapFromImageP);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
determineOutputFormat(palmHeader, &format, &maxval);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
getColorInfo(palmHeader, directInfoType, colormapFromImageP,
|
|
Packit |
78deda |
&colormapP, &nColors, &directColorInfo);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (cmdline.verbose)
|
|
Packit |
78deda |
reportPalmHeader(palmHeader, directColorInfo);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (cmdline.transparent)
|
|
Packit |
78deda |
doTransparent(stdout,
|
|
Packit |
78deda |
palmHeader.hasTransparency, palmHeader.directColor,
|
|
Packit |
78deda |
palmHeader.transparentIndex,
|
|
Packit |
78deda |
palmHeader.pixelSize, colormapP, directColorInfo);
|
|
Packit |
78deda |
else {
|
|
Packit |
78deda |
unsigned int * seen;
|
|
Packit |
78deda |
xelval * graymap;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
graymap = createGraymap(nColors, maxval);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
writePnm(stdout,
|
|
Packit |
78deda |
palmHeader, ifP, colormapP, graymap, nColors, format, maxval,
|
|
Packit |
78deda |
cmdline.showhist ? &seen : NULL);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (cmdline.showhist)
|
|
Packit |
78deda |
showHistogram(seen, colormapP, graymap, nColors);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
free(graymap);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
pm_close(ifP);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
return 0;
|
|
Packit |
78deda |
}
|