diff options
Diffstat (limited to 'tkimg/dted/dted.c')
-rw-r--r-- | tkimg/dted/dted.c | 1040 |
1 files changed, 1040 insertions, 0 deletions
diff --git a/tkimg/dted/dted.c b/tkimg/dted/dted.c new file mode 100644 index 0000000..efe93ad --- /dev/null +++ b/tkimg/dted/dted.c @@ -0,0 +1,1040 @@ +/* STARTHEADER + * + * File : dted.c + * + * Author : Paul Obermeier (paul@poSoft.de) + * + * Date : Tue Nov 20 21:24:26 CET 2001 + * + * Copyright : (C) 2001-2003 Paul Obermeier + * + * Description : + * + * A photo image handler for DTED elevation data interpreted as image files. + * + * The following image types are supported: + * + * Grayscale image: Load DTED data as grayscale image. + * + * List of currently supported features: + * + * Type | Read | Write | + * | -file | -data | -file | -data | + * ---------------------------------------- + * Gray | Yes | Yes | No | No | + * + * The following format options are available: + * + * Read DTED image: "dted -verbose <bool> -nchan <int> -nomap <bool> + * -gamma <float> -min <float> -max <float>" + * + * -verbose <bool>: If set to true, additional information about the file + * format is printed to stdout. Default is false. + * -nchan <int>: Specify the number of channels of the generated image. + * Default is 1, i.e. generated a grayscale image. + * -gamma <float>: Specify a gamma correction to be applied when mapping + * the input data to 8-bit image values. + * Default is 1.0. + * -nomap <bool>: 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. + * Default is false. + * -min <short>: 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 <short>: 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 only reading DTED files as grayscale images + * is implemented. Color mapped images and writing will be + * implemented when needed. + * Syntax checking of DTED files is rudimentary, too. + * Only file reading tested right now. + * + * ENDHEADER + * + * $Id: dted.c,v 1.1.1.1 2016/01/25 21:20:46 joye Exp $ + * + */ + +#include <stdlib.h> +#include <math.h> + +/* + * Generic initialization code, parameterized via CPACKAGE and PACKAGE. + */ + +#include "init.c" + + +/* #define DEBUG_LOCAL */ + +#define strIntel "Intel" +#define strMotorola "Motorola" + +#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 */ + +#define MAX_SHORT 32767 +#define MIN_SHORT -32768 + +#define ELEV_UNDEFINED -32000 /* All elevations smaller than this value are + considered undefined, and are set to the + minimum value. */ + +/* DTED file header structures */ + +typedef struct { + Byte uhl_tag[3]; /* 'UHL' sentinel tag */ + Byte reserved1[1]; + Byte origin_long[8]; /* Longitude of origin */ + Byte origin_lat[8]; /* Latitude of origin */ + Byte ew_interval[4]; /* East-west data interval (tenths second) */ + Byte ns_interval[4]; /* North-south data interval (tenths second) */ + Byte accuracy[4]; /* Absolute vertical accuracy (meters) */ + Byte security[3]; + Byte reserved2[45]; +} UHL_STRUCT; + +typedef struct { + Byte dsi_tag[3]; /* 'DSI' sentinel tag */ + Byte security_class[1]; /* Security classification */ + Byte security_mark[2]; /* Security control & release mark */ + Byte security_desc[27]; /* Security handling description */ + Byte reserved1[26]; + Byte level[5]; /* DMA series designator for level */ + Byte ref_num[15]; /* Reference number */ + Byte reserved2[8]; + Byte edition[2]; /* Data edition */ + Byte merge_version[1]; /* Match/merge version */ + Byte maintenance_date[4]; /* Maintenance date (YYMM) */ + Byte merge_date[4]; /* Match/Merge date (YYMM) */ + Byte maintenance_desc[4]; /* Maintenance description */ + Byte producer[8]; /* Producer */ + Byte reserved3[16]; + Byte product_num[9]; /* Product specification stock number */ + Byte product_change[2]; /* Product specification change number */ + Byte product_date[4]; /* Product specification date (YYMM) */ + Byte vertical_datum[3]; /* Vertical datum */ + Byte horizontal_datum[5]; /* Horizontal datum */ + Byte collection_sys[10]; /* Digitizing collection system */ + Byte compilation_date[4]; /* Compilation date (YYMM) */ + Byte reserved4[22]; + Byte origin_lat[9]; /* Latitude of data origin */ + Byte origin_long[10]; /* Longitude of data origin */ + Byte sw_corner_lat[7]; /* Latitude of SW corner */ + Byte sw_corner_long[8]; /* Longitude of SW corner */ + Byte nw_corner_lat[7]; /* Latitude of NW corner */ + Byte nw_corner_long[8]; /* Longitude of NW corner */ + Byte ne_corner_lat[7]; /* Latitude of NE corner */ + Byte ne_corner_long[8]; /* Longitude of NE corner */ + Byte se_corner_lat[7]; /* Latitude of SE corner */ + Byte se_corner_long[8]; /* Longitude of SE corner */ + Byte orientation[9]; /* Orientation angle */ + Byte ns_spacing[4]; /* North-south data spacing (tenths sec) */ + Byte ew_spacing[4]; /* East-west data spacing (tenths sec) */ + Byte rows[4]; /* Number of data rows */ + Byte cols[4]; /* Number of data cols */ + Byte cell_coverage[2]; /* Partial cell indicator */ + Byte reserved5[357]; +} DSI_STRUCT; + +typedef struct { + Byte abs_horiz_acc[4]; /* Absolute horizontal accuracy (meters) */ + Byte abs_vert_acc[4]; /* Absolute vertical accuracy (meters) */ + Byte rel_horiz_acc[4]; /* Relative horizontal accuracy (meters) */ + Byte rel_vert_acc[4]; /* Relative vertical accuracy (meters) */ +} ACCURACY_STRUCT; + +typedef struct { + Byte latitude[9]; /* Latitude */ + Byte longitude[10]; /* Longitude */ +} COORD_STRUCT; + +typedef struct { + ACCURACY_STRUCT acc; /* Accuracy of subregion */ + Byte no_coords[2]; /* Number of coordinates (03-14) */ + COORD_STRUCT coords[14]; /* Outline of subregion */ +} SUBREGION_STRUCT; + +typedef struct { + Byte acc_tag[3]; /* 'ACC' sentinel tag */ + ACCURACY_STRUCT global_acc; /* Accuracy of product */ + Byte reserved1[36]; + Byte no_acc_subregions[2]; /* Number of accuracy subregions + (00 = no, 02-09) */ + SUBREGION_STRUCT subregions[9]; /* Accuracy subregions */ + Byte reserved2[87]; +} ACC_STRUCT; + +typedef struct { + UHL_STRUCT uhl; + DSI_STRUCT dsi; + ACC_STRUCT acc; +} DTEDHEADER; + +/* DTED file format options structure for use with ParseFormatOpts */ +typedef struct { + Int nchan; + Short minVal; + Short maxVal; + Float gamma; + Boln nomap; + Boln verbose; +} FMTOPT; + +/* Structure to hold information about the DTED file being processed. */ +typedef struct { + DTEDHEADER th; + UByte *pixbuf; + Short *rawbuf; +} DTEDFILE; + +#define MINGAMMA 0.01 +#define MAXGAMMA 100.0 +#define GTABSIZE 257 + +/* Given a pixel value in Float format, "fin", and a gamma-correction +lookup table, "ftab", macro "gcorrectFloat" returns the gamma-corrected pixel +value in "fout". */ + +#define gcorrectFloat(fin,ftab,fout) \ + { \ + Int gc_i; \ + Float gc_t; \ + gc_t = (fin) * (GTABSIZE - 2); \ + gc_i = gc_t; \ + gc_t -= gc_i; \ + (fout) = (ftab)[gc_i] * (1.0-gc_t) + (ftab)[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); +#ifdef DEBUG_LOCAL + printf ("gammatable[%d] = %f\n", i, table[i]); +#endif + } + table[GTABSIZE - 1] = 1.0; +#ifdef DEBUG_LOCAL + printf ("gammatable[%d] = %f\n", GTABSIZE-1, table[GTABSIZE-1]); +#endif + return TRUE; +} + +static void gammaShortUByte (Int n, const Short s_in[], + const Float gtable[], UByte ub_out[]) +{ + const Short *ssrc, *sstop; + Float ftmp; + Int itmp; + UByte *ubdest; + + ssrc = s_in; + sstop = s_in + n; + ubdest = ub_out; + + /* 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 (ssrc < sstop) { + /* Map short values from the range [MIN_SHORT .. MAX_SHORT] to + the range [0.0 .. 1.0], do gamma correction and then map into + the displayable range [0 .. 255]. */ + ftmp = (Float)(*ssrc * 1.0 / 65535.0 + 0.5); + gcorrectFloat (ftmp, gtable, ftmp); + itmp = (Int)(ftmp * 255.0 + 0.5); + *ubdest = MAX (0, MIN (itmp, 255)); +#ifdef DEBUG_LOCAL + printf ("Gamma %d --> %f --> %d --> %d\n", + *ssrc, ftmp, itmp, *ubdest); +#endif + ++ubdest; + ++ssrc; + } + } else { + while (ssrc < sstop) { + /* Map short values from the range [MIN_SHORT .. MAX_SHORT] to + the displayable range [0 .. 255]. */ + itmp = (Int)(*ssrc * 255.0 / 65535.0 + 128); + *ubdest = MAX (0, MIN (itmp, 255)); +#ifdef DEBUG_LOCAL + printf ("NoGamma %d --> %d --> %d\n", *ssrc, itmp, *ubdest); +#endif + ++ubdest; + ++ssrc; + } + } + 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 dtedClose (DTEDFILE *tf) +{ + if (tf->pixbuf) ckfree ((char *)tf->pixbuf); + if (tf->rawbuf) ckfree ((char *)tf->rawbuf); + return; +} + +/* Read 1 byte, representing an unsigned integer number. */ + +#if 0 /* unused */ +static Boln readUByte (tkimg_MFile *handle, UByte *b) +{ + char buf[1]; + if (1 != tkimg_Read (handle, buf, 1)) + return FALSE; + *b = buf[0]; + return TRUE; +} +#endif /* unused */ + +/* Read 2 bytes, representing a signed 16 bit integer in the form + <LowByte, HighByte>, from a file and convert them into the current + machine's format. */ + +static Boln readShort (tkimg_MFile *handle, Short *s) +{ + char buf[2]; + if (2 != tkimg_Read (handle, buf, 2)) + return FALSE; + *s = (buf[0] & 0xFF) | (buf[1] << 8); + return TRUE; +} + +/* Read 4 bytes, representing a signed 32 bit integer in the form + <LowByte, HighByte>, from a file and convert them into the current + machine's format. */ + +static Boln readInt (tkimg_MFile *handle, Int *i) +{ + char buf[4]; + if (4 != tkimg_Read (handle, buf, 4)) + return FALSE; + *i = ((((Int)buf[0] & 0x000000FFU) << 24) | \ + (((Int)buf[1] & 0x0000FF00U) << 8) | \ + (((Int)buf[2] & 0x00FF0000U) >> 8) | \ + (((Int)buf[3] & 0x0000FF00U) >> 24)); + return TRUE; +} + +/* Write a byte, representing an unsigned integer to a file. */ + +#if 0 /* unused */ +static Boln writeUByte (tkimg_MFile *handle, UByte b) +{ + UByte buf[1]; + buf[0] = b; + if (1 != tkimg_Write (handle, (const char *)buf, 1)) + return FALSE; + return TRUE; +} +#endif /* unused */ + +/* Write a byte, representing a signed integer to a file. */ + +#if 0 /* unused */ +static Boln writeByte (tkimg_MFile *handle, Byte b) +{ + Byte buf[1]; + buf[0] = b; + if (1 != tkimg_Write (handle, buf, 1)) + return FALSE; + return TRUE; +} +#endif /* unused */ + +/* Convert a signed 16 bit integer number into the format + <LowByte, HighByte> (an array of 2 bytes) and write the array to a file. */ + +#if 0 /* unused */ +static Boln writeShort (tkimg_MFile *handle, Short s) +{ + Byte buf[2]; + buf[0] = s; + buf[1] = s >> 8; + if (2 != tkimg_Write (handle, buf, 2)) + return FALSE; + return TRUE; +} +#endif /* unused */ + +/* Convert a unsigned 16 bit integer number into the format + <LowByte, HighByte> (an array of 2 bytes) and write the array to a file. */ + +#if 0 /* unused */ +static Boln writeUShort (tkimg_MFile *handle, UShort s) +{ + Byte buf[2]; + buf[0] = s; + buf[1] = s >> 8; + if (2 != tkimg_Write (handle, buf, 2)) + return FALSE; + return TRUE; +} +#endif /* unused */ + +#define OUT Tcl_WriteChars (outChan, str, -1) +static void printImgInfo (DTEDHEADER *th, FMTOPT *opts, + const char *filename, const char *msg) +{ + Tcl_Channel outChan; + char str[256]; + + outChan = Tcl_GetStdChannel (TCL_STDOUT); + if (!outChan) { + return; + } + sprintf (str, "%s\n", msg); OUT; + sprintf (str, "\tLongitude of origin : %.8s\n", th->uhl.origin_long); OUT; + sprintf (str, "\tLatitude of origin : %.8s\n", th->uhl.origin_lat); OUT; + sprintf (str, "\tEast-West interval : %.4s\n", th->uhl.ew_interval); OUT; + sprintf (str, "\tNorth-South interval : %.4s\n", th->uhl.ns_interval); OUT; + sprintf (str, "\tVertical accuracy : %.4s\n", th->uhl.accuracy); OUT; + sprintf (str, "\tSecurity Code : %.3s\n", th->uhl.security); OUT; + sprintf (str, "\tDTED level : %.5s\n", th->dsi.level); OUT; + sprintf (str, "\tNumber of rows : %.4s\n", th->dsi.rows); OUT; + sprintf (str, "\tNumber of columns : %.4s\n", th->dsi.cols); OUT; + sprintf (str, "\tCell coverage : %.2s\n", th->dsi.cell_coverage); OUT; + sprintf (str, "\tNo. of channels : %d\n", opts->nchan); OUT; + sprintf (str, "\tGamma correction : %f\n", opts->gamma); OUT; + sprintf (str, "\tMinimum map value : %d\n", opts->minVal); OUT; + sprintf (str, "\tMaximum map value : %d\n", opts->maxVal); OUT; + sprintf (str, "\tHost byte order : %s\n", isIntel ()? + strIntel: strMotorola); OUT; + Tcl_Flush (outChan); +} +#undef OUT +static Boln readHeader (tkimg_MFile *handle, DTEDHEADER *th) +{ + if (sizeof (DTEDHEADER) != tkimg_Read (handle, (char *)th, sizeof(DTEDHEADER))) { + return FALSE; + } + if (strncmp ((char *)th->uhl.uhl_tag, "UHL", 3) != 0) { + return FALSE; + } + + /* OPA: More tests to follow. */ + return TRUE; +} + +#if 0 /* unused */ +static Boln writeHeader (tkimg_MFile *handle, DTEDHEADER *th) +{ + return TRUE; +} +#endif /* unused */ + +#if 0 /* unused */ +static void initHeader (DTEDHEADER *th) +{ + th->uhl.uhl_tag[0] = 'U'; + th->uhl.uhl_tag[1] = 'H'; + th->uhl.uhl_tag[2] = 'L'; + /* OPA: More to follow for DTED writing */ + return; +} +#endif /* unused */ + +static Boln readDtedColumn (tkimg_MFile *handle, Short *pixels, Int nRows, + Int nCols, Int curCol, char *buf, Boln hostIsIntel) +{ + Int i, nBytes; + Short *mPtr; + char *bufPtr = buf; + Short meridian, parallel; + Int block_count; + UByte *cp; + Int checksum, checksum1 = 0; + + /* Read data column header. */ + if (!readInt (handle, &block_count) || + !readShort (handle, &meridian) || + !readShort (handle, ¶llel)) { + printf ("Error reading column header\n"); + return FALSE; + } + + /* Calculate checksum, part 1 */ + cp = (UByte *) &block_count; + checksum1 += cp[0] + cp[1] + cp[2] + cp[3]; + cp = (UByte *) &meridian; + checksum1 += cp[0] + cp[1]; + cp = (UByte *) ∥ + checksum1 += cp[0] + cp[1]; + + if (hostIsIntel) { + block_count = block_count & 0x00ffffff; + } else { + block_count = (block_count & 0xffffff00) >> 8; + } + + /* Read the elevation data into the supplied column buffer "buf". */ + nBytes = sizeof (Short) * nRows; + if (nBytes != tkimg_Read (handle, buf, nBytes)) { + printf ("Error reading elevation data\n"); + return FALSE; + } + + /* Copy (and swap bytes, if needed) from the column buffer into the + pixel array (shorts) . */ + if (hostIsIntel) { + for (i=0; i<nRows; i++) { + mPtr = pixels + (i * nCols) + curCol; + ((char *)mPtr)[0] = bufPtr[1]; + ((char *)mPtr)[1] = bufPtr[0]; + bufPtr += sizeof (Short); + } + } else { + for (i=0; i<nRows; i++) { + mPtr = pixels + (i * nCols) + curCol; + ((char *)mPtr)[0] = bufPtr[0]; + ((char *)mPtr)[1] = bufPtr[1]; + bufPtr += sizeof (Short); + } + } + + /* Read the checksum */ + if (!readInt (handle, &checksum)) { + printf ("Error reading checksum\n"); + return FALSE; + } + + /* Calculate checksum, part 2. OPA TODO Incorrect */ + cp = (UByte *) pixels; + for (i=0; i<nRows*2; i++, cp++) { + checksum1 += *cp; + } + + if (checksum != checksum1) { + /* printf ("DTED Checksum Error (%d vs. %d).\n", checksum, checksum1); */ + /* return FALSE; */ + } + return TRUE; +} + +static Boln readDtedFile (tkimg_MFile *handle, Short *buf, Int width, Int height, + Int nchan, Boln hostIsIntel, Boln verbose, + Short minVals[], Short maxVals[]) +{ + Int x, y, c; + Short *bufPtr = buf; + char *colBuf; + +#ifdef DEBUG_LOCAL + printf ("readDtedFile: Width=%d Height=%d nchan=%d hostIsIntel=%s\n", + width, height, nchan, hostIsIntel? "yes": "no"); +#endif + for (c=0; c<nchan; c++) { + minVals[c] = MAX_SHORT; + maxVals[c] = MIN_SHORT; + } + colBuf = ckalloc (sizeof (Short) * nchan * height); + + /* Read the elevation data column by column. */ + for (x=0; x<width; x++) { + if (!readDtedColumn (handle, buf, height, width, + x, colBuf, hostIsIntel)) { + return FALSE; + } + } + + /* Loop through the elevation data and find minimum and maximum values. + Ignore elevation values equal to -32767, because these indicate, no + elevation data available. See also function remapShortValues. + Note: We extend the range of undefined elevations to all values + smaller than ELEV_UNDEFINED, because of DTED files not fully + compliant to the specification. */ + bufPtr = buf; + for (x=0; x<width; x++) { + for (y=0; y<height; y++) { + for (c=0; c<nchan; c++) { + if ( *bufPtr >= ELEV_UNDEFINED ) { + if (*bufPtr > maxVals[c]) maxVals[c] = *bufPtr; + if (*bufPtr < minVals[c]) minVals[c] = *bufPtr; + } + bufPtr++; + } + } + } + if (verbose) { + printf ("\tMinimum pixel values :"); + for (c=0; c<nchan; c++) { + printf (" %d", minVals[c]); + } + printf ("\n"); + printf ("\tMaximum pixel values :"); + for (c=0; c<nchan; c++) { + printf (" %d", maxVals[c]); + } + printf ("\n"); + fflush (stdout); + } + ckfree (colBuf); + return TRUE; +} + +/* Map the original short values into the range [MIN_SHORT .. MAX_SHORT]. + We must take care of values equal to -32767, which indicate that no + elevation data is available. So we map this value to the minimum value. + See also function readDtedFile. */ + +static Boln remapShortValues (Short *buf, Int width, Int height, Int nchan, + Short minVals[], Short maxVals[]) +{ + Int x, y, c; + Int tmpInt; + Short tmpShort; + Short *bufPtr = buf; + Float m[MAXCHANS], t[MAXCHANS]; + + for (c=0; c<nchan; c++) { + m[c] = (Float)(MAX_SHORT - MIN_SHORT) / + (Float)(maxVals[c] - minVals[c]); + t[c] = MIN_SHORT - m[c] * minVals[c]; + } + for (y=0; y<height; y++) { + for (x=0; x<width; x++) { + for (c=0; c<nchan; c++) { + tmpShort = (*bufPtr >= ELEV_UNDEFINED? *bufPtr: minVals[c]); + tmpInt = (Int)(tmpShort * m[c] + t[c] + 0.5); +#ifdef DEBUG_LOCAL + printf ("Remap %d --> %d --> %d --> ", + *bufPtr, tmpShort, tmpInt); +#endif + if (tmpInt < MIN_SHORT) { + *bufPtr = MIN_SHORT; + } else if (tmpInt > MAX_SHORT) { + *bufPtr = MAX_SHORT; + } else { + *bufPtr = tmpInt; + } +#ifdef DEBUG_LOCAL + printf ("%d (%f %f)\n", *bufPtr, m[c], t[c]); +#endif + bufPtr++; + } + } + } + return TRUE; +} + +/* + * Here is the start of the standard functions needed for every image format. + */ + +/* + * Prototypes for local procedures defined in this file: + */ + +static int ParseFormatOpts(Tcl_Interp *interp, Tcl_Obj *format, + FMTOPT *opts); +static int CommonMatch(Tcl_Interp *interp, tkimg_MFile *handle, + Tcl_Obj *format, int *widthPtr, int *heightPtr, + DTEDHEADER *dtedHeaderPtr); +static int CommonRead(Tcl_Interp *interp, tkimg_MFile *handle, + const char *filename, Tcl_Obj *format, + Tk_PhotoHandle imageHandle, int destX, int destY, + int width, int height, int srcX, int srcY); +static int CommonWrite(Tcl_Interp *interp, + const char *filename, Tcl_Obj *format, + tkimg_MFile *handle, Tk_PhotoImageBlock *blockPtr); + +static int ParseFormatOpts (interp, format, opts) + Tcl_Interp *interp; + Tcl_Obj *format; + FMTOPT *opts; +{ + static const char *const dtedOptions[] = { + "-verbose", "-nchan", "-min", "-max", "-gamma", "-nomap", NULL + }; + int objc, length, i, index; + Tcl_Obj **objv; + const char *nchanStr, *verboseStr, *minStr, *maxStr, *gammaStr, *nomapStr; + + /* Initialize format options with default values. */ + verboseStr = "0"; + nchanStr = "1"; + minStr = "0.0"; + maxStr = "0.0"; + gammaStr = "1.0"; + nomapStr = "0"; + + if (tkimg_ListObjGetElements (interp, format, &objc, &objv) != TCL_OK) + return TCL_ERROR; + if (objc) { + for (i=1; i<objc; i++) { + if (Tcl_GetIndexFromObj (interp, objv[i], (CONST84 char *CONST86 *)dtedOptions, + "format option", 0, &index) != TCL_OK) { + return TCL_ERROR; + } + if (++i >= 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: + nchanStr = Tcl_GetStringFromObj(objv[i], (int *) NULL); + break; + case 2: + minStr = Tcl_GetStringFromObj(objv[i], (int *) NULL); + break; + case 3: + maxStr = Tcl_GetStringFromObj(objv[i], (int *) NULL); + break; + case 4: + gammaStr = Tcl_GetStringFromObj(objv[i], (int *) NULL); + break; + case 5: + nomapStr = Tcl_GetStringFromObj(objv[i], (int *) NULL); + break; + } + } + } + + /* OPA TODO: Check for valid integer and float strings. */ + opts->nchan = atoi (nchanStr); + opts->minVal = atoi (minStr); + opts->maxVal = atoi (maxStr); + opts->gamma = atof (gammaStr); + + 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 (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; + } + + 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; + + tkimg_ReadInit(data, 'U', &handle); + return CommonMatch (interp, &handle, format, widthPtr, heightPtr, NULL); +} + +static int CommonMatch (interp, handle, format, + widthPtr, heightPtr, dtedHeaderPtr) + Tcl_Interp *interp; + tkimg_MFile *handle; + Tcl_Obj *format; + int *widthPtr; + int *heightPtr; + DTEDHEADER *dtedHeaderPtr; +{ + DTEDHEADER th; + FMTOPT opts; + Int nRows, nCols; + + if (ParseFormatOpts (interp, format, &opts) != TCL_OK) { + return TCL_ERROR; + } + + if (!readHeader (handle, &th)) { + return 0; + } + sscanf (th.dsi.rows, "%4d", &nRows); + sscanf (th.dsi.cols, "%4d", &nCols); + *widthPtr = nCols; + *heightPtr = nRows; + if (dtedHeaderPtr) + *dtedHeaderPtr = 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; + + tkimg_ReadInit (data, 'U', &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 y, c; + Int fileWidth, fileHeight; + Short minVals[MAXCHANS], maxVals[MAXCHANS]; + int stopY, outY, outWidth, outHeight; + DTEDFILE tf; + FMTOPT opts; + Boln hostIsIntel; + Int matte = 0; + UByte *pixbufPtr; + Short *rawbufPtr; + Float gtable[GTABSIZE]; + + memset (&tf, 0, sizeof (DTEDFILE)); + CommonMatch (interp, handle, format, &fileWidth, &fileHeight, &tf.th); + + if (ParseFormatOpts (interp, format, &opts) != TCL_OK) { + return TCL_ERROR; + } + + gtableFloat (opts.gamma, gtable); + + 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; + } + + hostIsIntel = isIntel (); + + tf.rawbuf = (Short *)ckalloc (fileWidth * fileHeight * + opts.nchan * sizeof (Short)); + readDtedFile (handle, tf.rawbuf, fileWidth, fileHeight, opts.nchan, + hostIsIntel, opts.verbose, minVals, maxVals); + if (opts.nomap) { + for (c=0; c<opts.nchan; c++) { + minVals[c] = 0; + maxVals[c] = 255; + } + } else if (opts.minVal != 0 || opts.maxVal != 0) { + for (c=0; c<opts.nchan; c++) { + minVals[c] = opts.minVal; + maxVals[c] = opts.maxVal; + } + } + remapShortValues (tf.rawbuf, fileWidth, fileHeight, opts.nchan, + minVals, maxVals); + + if (tkimg_PhotoExpand(interp, imageHandle, destX + outWidth, destY + outHeight) == TCL_ERROR) { + dtedClose(&tf); + return TCL_ERROR; + } + + tf.pixbuf = (UByte *) ckalloc (fileWidth * opts.nchan); + + block.pixelSize = opts.nchan; + block.pitch = fileWidth * opts.nchan; + block.width = outWidth; + block.height = 1; + block.offset[0] = 0; + block.offset[1] = (opts.nchan > 1? 1: 0); + block.offset[2] = (opts.nchan > 1? 2: 0); + block.offset[3] = (opts.nchan == 4 && matte? 3: 0); + block.pixelPtr = tf.pixbuf + srcX * opts.nchan; + + stopY = srcY + outHeight; + outY = destY; + + for (y=0; y<stopY; y++) { + pixbufPtr = tf.pixbuf; + rawbufPtr = tf.rawbuf + (fileHeight - 1 - y) * fileWidth * opts.nchan; + gammaShortUByte (fileWidth * opts.nchan, rawbufPtr, + opts.gamma != 1.0? gtable: NULL, pixbufPtr); + rawbufPtr += fileWidth * opts.nchan; + if (y >= srcY) { + if (tkimg_PhotoPutBlock(interp, imageHandle, &block, destX, outY, + width, 1, TK_PHOTO_COMPOSITE_OVERLAY) == TCL_ERROR) { + dtedClose(&tf); + return TCL_ERROR; + } + outY++; + } + } + dtedClose(&tf); + return TCL_OK; +} + +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; +{ + return TCL_OK; +} |