/* STARTHEADER * * File : raw.c * * Author : Paul Obermeier (paul@poSoft.de) * * Date : Wed Feb 21 12:45:08 CET 2001 * * Copyright : (C) 2001-2004 Paul Obermeier * * Description : * * A photo image handler for raw data interpreted as image files. * * The following image types are currently supported: * * Grayscale image: 1 channel of 32-bit floating point values. * 1 channel of 16-bit unsigned integer values. * 1 channel of 8-bit unsigned integer values. * True-color image: 3 channels of 32-bit floating point values. * 3 channels of 16-bit unsigned integer values. * 3 channels of 8-bit unsigned integer values. * * List of currently supported features: * * Type | Read | Write | * | -file | -data | -file | -data | * ---------------------------------------- * Gray | Yes | Yes | Yes | Yes | * RGB | Yes | Yes | Yes | Yes | * * There are 2 supported file formats: * One with the pure raw data only, the other with a 7 line ASCII header of the * following form: * * Magic=RAW\n File format identifier. Fixed value. * Width=128\n Image width in pixels. * Height=128\n Image height in pixels. * NumChan=1\n Possible values: 1 or 3. * ByteOrder=Intel\n Possible values: "Intel" or "Motorola". * ScanOrder=TopDown\n Possible values: "TopDown" or "BottomUp". * PixelType=byte\n Possible values: "float", "short" or "byte". * * The following format options are available: * * For raw images with header: * Read RAW image: "raw -useheader true -verbose -gamma * -min -max " * Write RAW image: "raw -useheader true -verbose -nchan * -scanorder " * * For raw images without header: * Read RAW image: "raw -useheader false -verbose -nchan * -scanorder -byteorder * -width -height -gamma * -pixeltype -min -max * -uuencode " * Write RAW image: "raw -useheader false -verbose -nchan * -scanorder " * * -verbose : If set to true, additional information about the file * format is printed to stdout. Default is false. * -useheader : If set to true, use file header information for reading * and writing. Default is true. * -nchan : Specify the number of channels of the input image. * Only valid, if reading image data without header. * Default is 1. * -width : Specify the width of the input image. Only valid, if * reading image data without header. Default is 128. * -height : Specify the height of the input image. Only valid, if * reading image data without header. Default is 128. * -byteorder : Specify the byteorder of the input image. Only valid, if * reading image data without header. * Possible values: "Intel" or "Motorola". * Default is assuming the same byteorder as that of the * host computer. * -scanorder : Specify the scanline order of the input image. Only * valid, if reading image data without header. * Possible values: "TopDown" or "BottomUp". * Default is "TopDown". * -pixeltype : Specify the type of the pixel values. * Only valid, if reading image data without header. * Possible values: "float", "short" or "byte". * Default is "byte". * -gamma : Specify a gamma correction to be applied when mapping * the input data to 8-bit image values. * Default is 1.0. * -nomap : If set to true, no mapping of input values is done. * Use this option, if your image already contains RGB * values in the range of 0 ..255. * When using the nomap mode, no information about the * minimum and maximum pixel values is gathered during * reading and therefore no verbose output is printed. * On the other hand reading the image is faster. * Default is false. * -uuencode : If set to false, do not assume, that the image data stored in a * variable is uuencoded. Default is true, i.e. the image data is * assumed to be uuencoded. * -min : Specify the minimum pixel value to be used for mapping * the input data to 8-bit image values. * Default is the minimum value found in the image data. * -max : Specify the maximum pixel value to be used for mapping * the input data to 8-bit image values. * Default is the maximum value found in the image data. * * Notes: * Currently RAW files are only written in "byte" pixel format. * * ENDHEADER * * $Id: raw.c,v 1.1.1.1 2016/01/25 21:20:47 joye Exp $ * */ #include #include /* * Generic initialization code, parameterized via CPACKAGE and PACKAGE. */ #include "init.c" /* #define DEBUG_LOCAL */ /* Maximum length of a header line. */ #define HEADLEN 100 /* Header fields. */ #define strMagic "Magic=%s\n" #define strWidth "Width=%d\n" #define strHeight "Height=%d\n" #define strNumChan "NumChan=%d\n" #define strByteOrder "ByteOrder=%s\n" #define strScanOrder "ScanOrder=%s\n" #define strPixelType "PixelType=%s\n" /* Header fields possible values. */ #define strIntel "Intel" #define strMotorola "Motorola" #define strTopDown "TopDown" #define strBottomUp "BottomUp" #define strFloat "float" #define strUShort "short" #define strUByte "byte" #define strUnknown "Unknown" #define BOTTOM_UP 0 #define TOP_DOWN 1 #define INTEL 0 #define MOTOROLA 1 #define TYPE_FLOAT 0 #define TYPE_USHORT 1 #define TYPE_UBYTE 2 #define MAXCHANS 4 /* Some general defines and typedefs. */ #define TRUE 1 #define FALSE 0 #define MIN(a,b) ((a)<(b)? (a): (b)) #define MAX(a,b) ((a)>(b)? (a): (b)) typedef unsigned char Boln; /* Boolean value: TRUE or FALSE */ typedef unsigned char UByte; /* Unsigned 8 bit integer */ typedef char Byte; /* Signed 8 bit integer */ typedef unsigned short UShort; /* Unsigned 16 bit integer */ typedef short Short; /* Signed 16 bit integer */ typedef int UInt; /* Unsigned 32 bit integer */ typedef int Int; /* Signed 32 bit integer */ typedef float Float; /* IEEE 32 bit floating point */ typedef double Double; /* IEEE 64 bit floating point */ /* RAW file header structure */ typedef struct { char id[3]; Int nChans; Int width; Int height; Int scanOrder; Int byteOrder; Int pixelType; } RAWHEADER; /* RAW file format options structure for use with ParseFormatOpts */ typedef struct { Int width; Int height; Int nchan; Int scanOrder; Int byteOrder; Int pixelType; Float minVal; Float maxVal; Float gamma; Boln nomap; Boln verbose; Boln uuencode; Boln useHeader; } FMTOPT; /* Structure to hold information about the Targa file being processed. */ typedef struct { RAWHEADER th; UByte *pixbuf; Float *floatBuf; UShort *ushortBuf; UByte *ubyteBuf; } RAWFILE; #define MINGAMMA 0.01 #define MAXGAMMA 100.0 #define GTABSIZE 257 /* Given a pixel value in Float format, "valIn", and a gamma-correction * lookup table, "tab", macro "gcorrectFloat" returns the gamma-corrected * pixel value in "valOut". */ #define gcorrectFloat(valIn,tab,valOut) \ { \ Int gc_i; \ Float gc_t; \ gc_t = (valIn) * (GTABSIZE - 2); \ gc_i = gc_t; \ gc_t -= gc_i; \ (valOut) = (tab)[gc_i] * (1.0-gc_t) + (tab)[gc_i+1] * gc_t; \ } static Boln gtableFloat (Float gamma, Float table[]) { Int i; if (gamma < MINGAMMA || gamma > MAXGAMMA) { printf ("Invalid gamma value %f\n", gamma); return FALSE; } for (i = 0; i < GTABSIZE - 1; ++i) { table[i] = pow ((Float) i / (Float) (GTABSIZE - 2), 1.0 / gamma); } table[GTABSIZE - 1] = 1.0; return TRUE; } /* If no gamma correction is needed (i.e. gamma == 1.0), specify NULL for * parameter gtable. */ static void FloatGammaUByte (Int n, const Float floatIn[], const Float gtable[], UByte ubOut[]) { const Float *src, *stop; Float ftmp; Int itmp; UByte *ubdest; src = floatIn; stop = floatIn + n; ubdest = ubOut; /* Handle a gamma value of 1.0 (gtable == NULL) as a special case. Quite nice speed improvement for the maybe most used case. */ if (gtable) { while (src < stop) { ftmp = MAX (0.0, MIN (*src, 1.0)); gcorrectFloat (ftmp, gtable, ftmp); itmp = (Int)(ftmp * 255.0 + 0.5); *ubdest = MAX (0, MIN (itmp, 255)); ++ubdest; ++src; } } else { while (src < stop) { itmp = (Int)(*src * 255.0 + 0.5); *ubdest = MAX (0, MIN (itmp, 255)); ++ubdest; ++src; } } return; } /* If no gamma correction is needed (i.e. gamma == 1.0), specify NULL for * parameter gtable. */ static void UShortGammaUByte (Int n, const UShort shortIn[], const Float gtable[], UByte ubOut[]) { const UShort *src, *stop; Float ftmp; Int itmp; UByte *ubdest; src = shortIn; stop = shortIn + n; ubdest = ubOut; /* Handle a gamma value of 1.0 (gtable == NULL) as a special case. Quite nice speed improvement for the maybe most used case. */ if (gtable) { while (src < stop) { ftmp = *src / 65535.0; ftmp = MAX (0.0, MIN (ftmp, 1.0)); gcorrectFloat (ftmp, gtable, ftmp); itmp = (Int)(ftmp * 255.0 + 0.5); *ubdest = MAX (0, MIN (itmp, 255)); ++ubdest; ++src; } } else { while (src < stop) { itmp = (Int)(*src / 256); *ubdest = MAX (0, MIN (itmp, 255)); ++ubdest; ++src; } } return; } /* This function determines at runtime, whether we are on an Intel system. */ static int isIntel (void) { unsigned long val = 513; /* On Intel (little-endian) systems this value is equal to "\01\02\00\00". On big-endian systems this value equals "\00\00\02\01" */ return memcmp(&val, "\01\02", 2) == 0; } static void rawClose (RAWFILE *tf, Boln fastMode) { if (!fastMode) { if (tf->pixbuf) ckfree ((char *)tf->pixbuf); } if (tf->floatBuf) ckfree ((char *)tf->floatBuf); if (tf->ushortBuf) ckfree ((char *)tf->ushortBuf); if (tf->ubyteBuf) ckfree ((char *)tf->ubyteBuf); return; } static Boln readFloatRow (tkimg_MFile *handle, Float *pixels, Int nFloats, char *buf, Boln swapBytes) { int i; Float *mPtr = pixels; char *bufPtr = buf; #ifdef DEBUG_LOCAL printf ("Reading %d floats\n", nFloats); fflush (stdout); #endif if (4 * nFloats != tkimg_Read (handle, buf, 4 * nFloats)) return FALSE; if (swapBytes) { for (i=0; iwidth, th->height); OUT; sprintf (str, "\tNo. of channels : %d\n", th->nChans); OUT; sprintf (str, "\tPixel type : %s\n", (th->pixelType == TYPE_FLOAT? strFloat: (th->pixelType == TYPE_USHORT? strUShort: (th->pixelType == TYPE_UBYTE? strUByte: strUnknown)))); OUT; sprintf (str, "\tVertical encoding: %s\n", th->scanOrder == TOP_DOWN? strTopDown: strBottomUp); OUT; sprintf (str, "\tGamma correction : %f\n", opts->gamma); OUT; sprintf (str, "\tMinimum map value: %f\n", opts->minVal); OUT; sprintf (str, "\tMaximum map value: %f\n", opts->maxVal); OUT; sprintf (str, "\tHost byte order : %s\n", isIntel ()? strIntel: strMotorola); OUT; sprintf (str, "\tFile byte order : %s\n", th->byteOrder == INTEL? strIntel: strMotorola); OUT; Tcl_Flush (outChan); } #undef OUT static Boln readHeaderLine (Tcl_Interp *interp, tkimg_MFile *handle, char *buf) { char c, *bufPtr, *bufEndPtr; Boln failure; bufPtr = buf; bufEndPtr = buf + HEADLEN; failure = TRUE; #ifdef DEBUG_LOCAL printf ("readHeaderLine\n"); fflush (stdout); #endif while (tkimg_Read (handle, &c, 1) == 1 && bufPtr < bufEndPtr) { if (c == '\n') { *bufPtr = '\0'; failure = FALSE; break; } *bufPtr = c; bufPtr++; } if (failure) { Tcl_AppendResult (interp, "RAW handler: Error reading header line (", buf, ")\n", NULL); return FALSE; } return TRUE; } static Boln readHeader (Tcl_Interp *interp, tkimg_MFile *handle, RAWHEADER *th) { char buf[HEADLEN]; char tmpStr[HEADLEN]; if (!readHeaderLine (interp, handle, buf) || (1 != sscanf (buf, strMagic, th->id))) { Tcl_AppendResult (interp, "Unable to parse header field Magic\n", NULL); return FALSE; } if (strcmp (th->id, "RAW") != 0) { Tcl_AppendResult (interp, "Invalid value for header field Magic:", "Must be \"RAW\"\n", NULL); return FALSE; } if (!readHeaderLine (interp, handle, buf) || (1 != sscanf (buf, strWidth, &th->width))) { Tcl_AppendResult (interp, "Unable to parse header field Width\n", NULL); return FALSE; } if (th->width < 1) { Tcl_AppendResult (interp, "Invalid value for header field Width:", "Must be greater than zero\n", NULL); return FALSE; } if (!readHeaderLine (interp, handle, buf) || (1 != sscanf (buf, strHeight, &th->height))) { Tcl_AppendResult (interp, "Unable to parse header field Height\n", NULL); return FALSE; } if (th->height < 1) { Tcl_AppendResult (interp, "Invalid value for header field Height:", "Must be greater than zero\n", NULL); return FALSE; } if (!readHeaderLine (interp, handle, buf) || (1 != sscanf (buf, strNumChan, &th->nChans))) { Tcl_AppendResult (interp, "Unable to parse header field NumChan\n", NULL); return FALSE; } if (th->nChans != 1 && th->nChans != 3) { Tcl_AppendResult (interp, "Invalid value for header field NumChan:", "Must be 1 or 3\n", NULL); return FALSE; } if (!readHeaderLine (interp, handle, buf) || (1 != sscanf (buf, strByteOrder, tmpStr))) { Tcl_AppendResult (interp, "Unable to parse header field ByteOrder\n", NULL); return FALSE; } if (strcmp (tmpStr, strIntel) == 0) { th->byteOrder = INTEL; } else if (strcmp (tmpStr, strMotorola) == 0) { th->byteOrder = MOTOROLA; } else { Tcl_AppendResult (interp, "Invalid value for header field ByteOrder:", "Must be ", strIntel, " or ", strMotorola, "\n", NULL); return FALSE; } if (!readHeaderLine (interp, handle, buf) || (1 != sscanf (buf, strScanOrder, tmpStr))) { Tcl_AppendResult (interp, "Unable to parse header field ScanOrder\n", NULL); return FALSE; } if (strcmp (tmpStr, strTopDown) == 0) { th->scanOrder = TOP_DOWN; } else if (strcmp (tmpStr, strBottomUp) == 0) { th->scanOrder = BOTTOM_UP; } else { Tcl_AppendResult (interp, "Invalid value for header field ScanOrder:", "Must be ", strTopDown, " or ", strBottomUp, "\n", NULL); return FALSE; } if (!readHeaderLine (interp, handle, buf) || (1 != sscanf (buf, strPixelType, tmpStr))) { Tcl_AppendResult (interp, "Unable to parse header field PixelType\n", NULL); return FALSE; } if (strcmp (tmpStr, strFloat) == 0) { th->pixelType = TYPE_FLOAT; } else if (strcmp (tmpStr, strUShort) == 0) { th->pixelType = TYPE_USHORT; } else if (strcmp (tmpStr, strUByte) == 0) { th->pixelType = TYPE_UBYTE; } else { Tcl_AppendResult (interp, "Invalid value for header field PixelType:", "Must be ", strFloat, ",", strUShort, " or ", strUByte, "\n", NULL); return FALSE; } return TRUE; } static Boln writeHeader (tkimg_MFile *handle, RAWHEADER *th) { char buf[1024]; sprintf (buf, strMagic, "RAW"); tkimg_Write (handle, buf, strlen (buf)); sprintf (buf, strWidth, th->width); tkimg_Write (handle, buf, strlen (buf)); sprintf (buf, strHeight, th->height); tkimg_Write (handle, buf, strlen (buf)); sprintf (buf, strNumChan, th->nChans); tkimg_Write (handle, buf, strlen (buf)); sprintf (buf, strByteOrder, isIntel()? strIntel: strMotorola); tkimg_Write (handle, buf, strlen (buf)); sprintf (buf, strScanOrder, th->scanOrder == TOP_DOWN? strTopDown: strBottomUp); tkimg_Write (handle, buf, strlen (buf)); sprintf (buf, strPixelType, (th->pixelType == TYPE_FLOAT? strFloat: (th->pixelType == TYPE_USHORT? strUShort: (th->pixelType == TYPE_UBYTE? strUByte: strUnknown)))); tkimg_Write (handle, buf, strlen (buf)); return TRUE; } static void initHeader (RAWHEADER *th) { th->id[0] = 'R'; th->id[1] = 'A'; th->id[2] = 'W'; th->nChans = 1; th->width = 128; th->height = 128; th->scanOrder = TOP_DOWN; th->byteOrder = INTEL; th->pixelType = TYPE_UBYTE; return; } static Boln readFloatFile (tkimg_MFile *handle, Float *buf, Int width, Int height, Int nchan, Boln swapBytes, Boln verbose, Boln findMinMax, Float minVals[], Float maxVals[]) { Int x, y, c; Float *bufPtr = buf; char *line; #ifdef DEBUG_LOCAL printf ("readFloatFile: Width=%d Height=%d nchan=%d swapBytes=%s\n", width, height, nchan, swapBytes? "yes": "no"); fflush (stdout); #endif for (c=0; c maxVals[c]) maxVals[c] = *bufPtr; if (*bufPtr < minVals[c]) minVals[c] = *bufPtr; bufPtr++; } } } else { bufPtr += nchan * width; } } if (verbose && findMinMax) { printf ("\tMinimum pixel values :"); for (c=0; c maxVals[c]) maxVals[c] = *bufPtr; if (*bufPtr < minVals[c]) minVals[c] = *bufPtr; bufPtr++; } } } else { bufPtr += nchan * width; } } if (verbose && findMinMax) { printf ("\tMinimum pixel values :"); for (c=0; c maxVals[c]) maxVals[c] = *bufPtr; if (*bufPtr < minVals[c]) minVals[c] = *bufPtr; bufPtr++; } } } else { bufPtr += nchan * width; } } if (verbose && findMinMax) { printf ("\tMinimum pixel values :"); for (c=0; c 1.0) *bufPtr = 1.0; bufPtr++; } } } return TRUE; } static Boln remapUShortValues (UShort *buf, Int width, Int height, Int nchan, Float minVals[], Float maxVals[]) { Int x, y, c; UShort *bufPtr = buf; Float m[MAXCHANS], t[MAXCHANS]; for (c=0; c= objc) { Tcl_AppendResult (interp, "No value for option \"", Tcl_GetStringFromObj (objv[--i], (int *) NULL), "\"", (char *) NULL); return TCL_ERROR; } switch(index) { case 0: verboseStr = Tcl_GetStringFromObj(objv[i], (int *) NULL); break; case 1: widthStr = Tcl_GetStringFromObj(objv[i], (int *) NULL); break; case 2: heightStr = Tcl_GetStringFromObj(objv[i], (int *) NULL); break; case 3: nchanStr = Tcl_GetStringFromObj(objv[i], (int *) NULL); break; case 4: byteOrderStr = Tcl_GetStringFromObj(objv[i], (int *) NULL); break; case 5: scanorderStr = Tcl_GetStringFromObj(objv[i], (int *) NULL); break; case 6: pixelTypeStr = Tcl_GetStringFromObj(objv[i], (int *) NULL); break; case 7: minStr = Tcl_GetStringFromObj(objv[i], (int *) NULL); break; case 8: maxStr = Tcl_GetStringFromObj(objv[i], (int *) NULL); break; case 9: gammaStr = Tcl_GetStringFromObj(objv[i], (int *) NULL); break; case 10: useheaderStr = Tcl_GetStringFromObj(objv[i], (int *) NULL); break; case 11: nomapStr = Tcl_GetStringFromObj(objv[i], (int *) NULL); break; case 12: uuencodeStr = Tcl_GetStringFromObj(objv[i], (int *) NULL); break; } } } /* OPA TODO: Check for valid integer and float strings. */ opts->width = atoi (widthStr); opts->height = atoi (heightStr); opts->nchan = atoi (nchanStr); opts->minVal = atof (minStr); opts->maxVal = atof (maxStr); opts->gamma = atof (gammaStr); length = strlen (byteOrderStr); if (!strncmp (byteOrderStr, strIntel, length)) { opts->byteOrder = INTEL; } else if (!strncmp (byteOrderStr, strMotorola, length)) { opts->byteOrder = MOTOROLA; } else { Tcl_AppendResult (interp, "Invalid byteorder mode \"", byteOrderStr, "\": Should be ", strIntel, " or ", strMotorola, (char *) NULL); return TCL_ERROR; } length = strlen (verboseStr); if (!strncmp (verboseStr, "1", length) || \ !strncmp (verboseStr, "true", length) || \ !strncmp (verboseStr, "on", length)) { opts->verbose = 1; } else if (!strncmp (verboseStr, "0", length) || \ !strncmp (verboseStr, "false", length) || \ !strncmp (verboseStr, "off", length)) { opts->verbose = 0; } else { Tcl_AppendResult (interp, "invalid verbose mode \"", verboseStr, "\": should be 1 or 0, on or off, true or false", (char *) NULL); return TCL_ERROR; } length = strlen (useheaderStr); if (!strncmp (useheaderStr, "1", length) || \ !strncmp (useheaderStr, "true", length) || \ !strncmp (useheaderStr, "on", length)) { opts->useHeader = 1; } else if (!strncmp (useheaderStr, "0", length) || \ !strncmp (useheaderStr, "false", length) || \ !strncmp (useheaderStr, "off", length)) { opts->useHeader = 0; } else { Tcl_AppendResult (interp, "invalid useheader mode \"", useheaderStr, "\": should be 1 or 0, on or off, true or false", (char *) NULL); return TCL_ERROR; } length = strlen (nomapStr); if (!strncmp (nomapStr, "1", length) || \ !strncmp (nomapStr, "true", length) || \ !strncmp (nomapStr, "on", length)) { opts->nomap = 1; } else if (!strncmp (nomapStr, "0", length) || \ !strncmp (nomapStr, "false", length) || \ !strncmp (nomapStr, "off", length)) { opts->nomap = 0; } else { Tcl_AppendResult (interp, "invalid nomap mode \"", nomapStr, "\": should be 1 or 0, on or off, true or false", (char *) NULL); return TCL_ERROR; } length = strlen (scanorderStr); if (!strncmp (scanorderStr, strTopDown, length)) { opts->scanOrder = TOP_DOWN; } else if (!strncmp (scanorderStr, strBottomUp, length)) { opts->scanOrder = BOTTOM_UP; } else { Tcl_AppendResult (interp, "invalid scanline order \"", scanorderStr, "\": should be TopDown or BottomUp", (char *) NULL); return TCL_ERROR; } length = strlen (pixelTypeStr); if (!strncmp (pixelTypeStr, strFloat, length)) { opts->pixelType = TYPE_FLOAT; } else if (!strncmp (pixelTypeStr, strUShort, length)) { opts->pixelType = TYPE_USHORT; } else if (!strncmp (pixelTypeStr, strUByte, length)) { opts->pixelType = TYPE_UBYTE; } else { Tcl_AppendResult (interp, "invalid pixel type \"", pixelTypeStr, "\": should be float, short or byte", (char *) NULL); return TCL_ERROR; } length = strlen (uuencodeStr); if (!strncmp (uuencodeStr, "1", length) || \ !strncmp (uuencodeStr, "true", length) || \ !strncmp (uuencodeStr, "on", length)) { opts->uuencode = 1; } else if (!strncmp (uuencodeStr, "0", length) || \ !strncmp (uuencodeStr, "false", length) || \ !strncmp (uuencodeStr, "off", length)) { opts->uuencode = 0; } else { Tcl_AppendResult (interp, "invalid uuencode mode \"", uuencodeStr, "\": should be 1 or 0, on or off, true or false", (char *) NULL); return TCL_ERROR; } return TCL_OK; } static int ChnMatch( Tcl_Channel chan, const char *filename, Tcl_Obj *format, int *widthPtr, int *heightPtr, Tcl_Interp *interp ) { tkimg_MFile handle; handle.data = (char *) chan; handle.state = IMG_CHAN; return CommonMatch (interp, &handle, format, widthPtr, heightPtr, NULL); } static int ObjMatch( Tcl_Obj *data, Tcl_Obj *format, int *widthPtr, int *heightPtr, Tcl_Interp *interp ) { tkimg_MFile handle; FMTOPT opts; if (ParseFormatOpts (interp, format, &opts) != TCL_OK) { return TCL_ERROR; } if (!opts.uuencode) { handle.data = (char *) tkimg_GetByteArrayFromObj(data, &handle.length); handle.state = IMG_STRING; } else { tkimg_ReadInit(data, 'M', &handle); } return CommonMatch (interp, &handle, format, widthPtr, heightPtr, NULL); } static int CommonMatch (interp, handle, format, widthPtr, heightPtr, rawHeaderPtr) Tcl_Interp *interp; tkimg_MFile *handle; Tcl_Obj *format; int *widthPtr; int *heightPtr; RAWHEADER *rawHeaderPtr; { RAWHEADER th; FMTOPT opts; initHeader (&th); if (ParseFormatOpts (interp, format, &opts) != TCL_OK) { return TCL_ERROR; } if (opts.useHeader) { if (!readHeader (interp, handle, &th)) return 0; } else { th.width = opts.width; th.height = opts.height; th.nChans = opts.nchan; th.pixelType = opts.pixelType; th.scanOrder = opts.scanOrder; th.byteOrder = opts.byteOrder; } *widthPtr = th.width; *heightPtr = th.height; if (rawHeaderPtr) { *rawHeaderPtr = th; } return 1; } static int ChnRead (interp, chan, filename, format, imageHandle, destX, destY, width, height, srcX, srcY) Tcl_Interp *interp; /* Interpreter to use for reporting errors. */ Tcl_Channel chan; /* The image channel, open for reading. */ const char *filename; /* The name of the image file. */ Tcl_Obj *format; /* User-specified format object, or NULL. */ Tk_PhotoHandle imageHandle; /* The photo image to write into. */ int destX, destY; /* Coordinates of top-left pixel in * photo image to be written to. */ int width, height; /* Dimensions of block of photo image to * be written to. */ int srcX, srcY; /* Coordinates of top-left pixel to be used * in image being read. */ { tkimg_MFile handle; handle.data = (char *) chan; handle.state = IMG_CHAN; return CommonRead (interp, &handle, filename, format, imageHandle, destX, destY, width, height, srcX, srcY); } static int ObjRead (interp, data, format, imageHandle, destX, destY, width, height, srcX, srcY) Tcl_Interp *interp; Tcl_Obj *data; Tcl_Obj *format; Tk_PhotoHandle imageHandle; int destX, destY; int width, height; int srcX, srcY; { tkimg_MFile handle; FMTOPT opts; if (ParseFormatOpts (interp, format, &opts) != TCL_OK) { return TCL_ERROR; } if (!opts.uuencode) { handle.data = (char *) tkimg_GetByteArrayFromObj(data, &handle.length); handle.state = IMG_STRING; } else { tkimg_ReadInit(data, 'M', &handle); } return CommonRead (interp, &handle, "InlineData", format, imageHandle, destX, destY, width, height, srcX, srcY); } static int CommonRead (interp, handle, filename, format, imageHandle, destX, destY, width, height, srcX, srcY) Tcl_Interp *interp; /* Interpreter to use for reporting errors. */ tkimg_MFile *handle; /* The image file, open for reading. */ const char *filename; /* The name of the image file. */ Tcl_Obj *format; /* User-specified format object, or NULL. */ Tk_PhotoHandle imageHandle; /* The photo image to write into. */ int destX, destY; /* Coordinates of top-left pixel in * photo image to be written to. */ int width, height; /* Dimensions of block of photo image to * be written to. */ int srcX, srcY; /* Coordinates of top-left pixel to be used * in image being read. */ { Tk_PhotoImageBlock block; Int x, y, c; Int fileWidth = 0, fileHeight = 0; Float minVals[MAXCHANS], maxVals[MAXCHANS]; int stopY, outY, outWidth, outHeight; RAWFILE tf; FMTOPT opts; Boln swapBytes; Boln fastMode; Int byteOrder; Int scanOrder; Int pixelType; Int matte = 0; UByte *pixbufPtr; Float *floatBufPtr; UShort *ushortBufPtr; UByte *ubyteBufPtr; Float gtable[GTABSIZE]; int result = TCL_OK; memset (&tf, 0, sizeof (RAWFILE)); initHeader (&tf.th); CommonMatch (interp, handle, format, &fileWidth, &fileHeight, &tf.th); if (ParseFormatOpts (interp, format, &opts) != TCL_OK) { return TCL_ERROR; } if (opts.verbose) printImgInfo (&tf.th, &opts, filename, "Reading image:"); if ((srcX + width) > fileWidth) { outWidth = fileWidth - srcX; } else { outWidth = width; } if ((srcY + height) > fileHeight) { outHeight = fileHeight - srcY; } else { outHeight = height; } if ((outWidth <= 0) || (outHeight <= 0) || (srcX >= fileWidth) || (srcY >= fileHeight)) { return TCL_OK; } byteOrder = opts.useHeader? tf.th.byteOrder: opts.byteOrder; scanOrder = opts.useHeader? tf.th.scanOrder: opts.scanOrder; pixelType = opts.useHeader? tf.th.pixelType: opts.pixelType; swapBytes = (( isIntel () && (byteOrder != INTEL)) || (!isIntel () && (byteOrder == INTEL))); fastMode = (opts.nomap && pixelType == TYPE_UBYTE && scanOrder == TOP_DOWN && fileWidth == width && fileHeight == height); if (!fastMode) { gtableFloat (opts.gamma, gtable); } switch (pixelType) { case TYPE_FLOAT: { tf.floatBuf = (Float *)ckalloc (fileWidth*fileHeight*tf.th.nChans*sizeof (Float)); readFloatFile (handle, tf.floatBuf, fileWidth, fileHeight, tf.th.nChans, swapBytes, opts.verbose, !opts.nomap, minVals, maxVals); break; } case TYPE_USHORT: { tf.ushortBuf = (UShort *)ckalloc (fileWidth*fileHeight*tf.th.nChans*sizeof (UShort)); readUShortFile (handle, tf.ushortBuf, fileWidth, fileHeight, tf.th.nChans, swapBytes, opts.verbose, !opts.nomap, minVals, maxVals); break; } case TYPE_UBYTE: { tf.ubyteBuf = (UByte *)ckalloc (fileWidth*fileHeight*tf.th.nChans*sizeof (UByte)); readUByteFile (handle, tf.ubyteBuf, fileWidth, fileHeight, tf.th.nChans, opts.verbose, !opts.nomap, minVals, maxVals); break; } } if (opts.nomap) { for (c=0; c 1? 1: 0); block.offset[2] = (tf.th.nChans > 1? 2: 0); block.offset[3] = (tf.th.nChans == 4 && matte? 3: 0); block.pixelPtr = tf.pixbuf + srcX * tf.th.nChans; stopY = srcY + outHeight; outY = destY; if (fastMode) { if (tkimg_PhotoPutBlock(interp, imageHandle, &block, destX, outY, width, height, block.offset[3]? TK_PHOTO_COMPOSITE_SET: TK_PHOTO_COMPOSITE_OVERLAY) == TCL_ERROR) { result = TCL_ERROR; } } else { for (y=0; y= srcY) { if (tkimg_PhotoPutBlock(interp, imageHandle, &block, destX, outY, width, 1, block.offset[3]? TK_PHOTO_COMPOSITE_SET: TK_PHOTO_COMPOSITE_OVERLAY) == TCL_ERROR) { result = TCL_ERROR; break; } outY++; } } } rawClose (&tf, fastMode); return result; } static int ChnWrite (interp, filename, format, blockPtr) Tcl_Interp *interp; const char *filename; Tcl_Obj *format; Tk_PhotoImageBlock *blockPtr; { Tcl_Channel chan; tkimg_MFile handle; int result; chan = tkimg_OpenFileChannel (interp, filename, 0644); if (!chan) { return TCL_ERROR; } handle.data = (char *) chan; handle.state = IMG_CHAN; result = CommonWrite (interp, filename, format, &handle, blockPtr); if (Tcl_Close(interp, chan) == TCL_ERROR) { return TCL_ERROR; } return result; } static int StringWrite( Tcl_Interp *interp, Tcl_Obj *format, Tk_PhotoImageBlock *blockPtr ) { tkimg_MFile handle; int result; Tcl_DString data; Tcl_DStringInit(&data); tkimg_WriteInit (&data, &handle); result = CommonWrite (interp, "InlineData", format, &handle, blockPtr); tkimg_Putc(IMG_DONE, &handle); if (result == TCL_OK) { Tcl_DStringResult(interp, &data); } else { Tcl_DStringFree(&data); } return result; } static int CommonWrite (interp, filename, format, handle, blockPtr) Tcl_Interp *interp; const char *filename; Tcl_Obj *format; tkimg_MFile *handle; Tk_PhotoImageBlock *blockPtr; { Int x, y; Int redOffset, greenOffset, blueOffset, alphaOffset; UByte *pixelPtr, *rowPixPtr; RAWFILE tf; FMTOPT opts; UByte *ubyteBufPtr; Int bytesPerLine; memset (&tf, 0, sizeof (RAWFILE)); if (ParseFormatOpts (interp, format, &opts) != TCL_OK) { return TCL_ERROR; } redOffset = 0; greenOffset = blockPtr->offset[1] - blockPtr->offset[0]; blueOffset = blockPtr->offset[2] - blockPtr->offset[0]; alphaOffset = blockPtr->offset[0]; if (alphaOffset < blockPtr->offset[2]) { alphaOffset = blockPtr->offset[2]; } if (++alphaOffset < blockPtr->pixelSize) { alphaOffset -= blockPtr->offset[0]; } else { alphaOffset = 0; } initHeader (&tf.th); tf.th.width = blockPtr->width; tf.th.height = blockPtr->height; tf.th.nChans = opts.nchan; tf.th.scanOrder = opts.scanOrder; tf.th.pixelType = TYPE_UBYTE; writeHeader (handle, &tf.th); bytesPerLine = blockPtr->width * tf.th.nChans * sizeof (UByte); tf.ubyteBuf = (UByte *)ckalloc (bytesPerLine); rowPixPtr = blockPtr->pixelPtr + blockPtr->offset[0]; for (y = 0; y < blockPtr->height; y++) { ubyteBufPtr = tf.ubyteBuf; pixelPtr = rowPixPtr; if (tf.th.nChans == 1) { for (x=0; xwidth; x++) { *ubyteBufPtr = pixelPtr[redOffset]; ubyteBufPtr++; pixelPtr += blockPtr->pixelSize; } } else { for (x=0; xwidth; x++) { *(ubyteBufPtr++) = pixelPtr[redOffset]; *(ubyteBufPtr++) = pixelPtr[greenOffset]; *(ubyteBufPtr++) = pixelPtr[blueOffset]; if (tf.th.nChans == 4) { /* Have a matte channel and write it. */ *(ubyteBufPtr++) = pixelPtr[alphaOffset]; } pixelPtr += blockPtr->pixelSize; } } if (tkimg_Write (handle, (char *)tf.ubyteBuf, bytesPerLine) != bytesPerLine) { rawClose (&tf, FALSE); return TCL_ERROR; } rowPixPtr += blockPtr->pitch; } if (opts.verbose) printImgInfo (&tf.th, &opts, filename, "Saving image:"); rawClose (&tf, FALSE); return TCL_OK; }