tkImgPPM.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:22k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /*
  2.  * tkImgPPM.c --
  3.  *
  4.  * A photo image file handler for PPM (Portable PixMap) files.
  5.  *
  6.  * Copyright (c) 1994 The Australian National University.
  7.  * Copyright (c) 1994-1997 Sun Microsystems, Inc.
  8.  *
  9.  * See the file "license.terms" for information on usage and redistribution
  10.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  11.  *
  12.  * Author: Paul Mackerras (paulus@cs.anu.edu.au),
  13.  *    Department of Computer Science,
  14.  *    Australian National University.
  15.  *
  16.  * RCS: @(#) $Id: tkImgPPM.c,v 1.10.2.3 2007/11/26 20:53:57 kennykb Exp $
  17.  */
  18. #include "tkInt.h"
  19. #include "tkPort.h"
  20. /*
  21.  * The maximum amount of memory to allocate for data read from the
  22.  * file.  If we need more than this, we do it in pieces.
  23.  */
  24. #define MAX_MEMORY 10000 /* don't allocate > 10KB */
  25. /*
  26.  * Define PGM and PPM, i.e. gray images and color images.
  27.  */
  28. #define PGM 1
  29. #define PPM 2
  30. /*
  31.  * The format record for the PPM file format:
  32.  */
  33. static int FileMatchPPM _ANSI_ARGS_((Tcl_Channel chan,
  34.     CONST char *fileName, Tcl_Obj *format,
  35.     int *widthPtr, int *heightPtr,
  36.     Tcl_Interp *interp));
  37. static int FileReadPPM  _ANSI_ARGS_((Tcl_Interp *interp,
  38.     Tcl_Channel chan, CONST char *fileName,
  39.     Tcl_Obj *format, Tk_PhotoHandle imageHandle,
  40.     int destX, int destY, int width, int height,
  41.     int srcX, int srcY));
  42. static int FileWritePPM _ANSI_ARGS_((Tcl_Interp *interp,
  43.     CONST char *fileName, Tcl_Obj *format,
  44.     Tk_PhotoImageBlock *blockPtr));
  45. static int StringWritePPM _ANSI_ARGS_((Tcl_Interp *interp,
  46.     Tcl_Obj *format, Tk_PhotoImageBlock *blockPtr));
  47. static int StringMatchPPM _ANSI_ARGS_((Tcl_Obj *dataObj,
  48.     Tcl_Obj *format, int *widthPtr, int *heightPtr,
  49.     Tcl_Interp *interp));
  50. static int StringReadPPM _ANSI_ARGS_((Tcl_Interp *interp,
  51.     Tcl_Obj *dataObj, Tcl_Obj *format,
  52.     Tk_PhotoHandle imageHandle, int destX, int destY,
  53.     int width, int height, int srcX, int srcY));
  54. Tk_PhotoImageFormat tkImgFmtPPM = {
  55.     "ppm", /* name */
  56.     FileMatchPPM, /* fileMatchProc */
  57.     StringMatchPPM, /* stringMatchProc */
  58.     FileReadPPM, /* fileReadProc */
  59.     StringReadPPM, /* stringReadProc */
  60.     FileWritePPM, /* fileWriteProc */
  61.     StringWritePPM, /* stringWriteProc */
  62. };
  63. /*
  64.  * Prototypes for local procedures defined in this file:
  65.  */
  66. static int ReadPPMFileHeader _ANSI_ARGS_((Tcl_Channel chan,
  67.     int *widthPtr, int *heightPtr,
  68.     int *maxIntensityPtr));
  69. static int ReadPPMStringHeader _ANSI_ARGS_((Tcl_Obj *dataObj,
  70.     int *widthPtr, int *heightPtr,
  71.     int *maxIntensityPtr,
  72.     unsigned char **dataBufferPtr, int *dataSizePtr));
  73. /*
  74.  *----------------------------------------------------------------------
  75.  *
  76.  * FileMatchPPM --
  77.  *
  78.  * This procedure is invoked by the photo image type to see if
  79.  * a file contains image data in PPM format.
  80.  *
  81.  * Results:
  82.  * The return value is >0 if the first characters in file "f" look
  83.  * like PPM data, and 0 otherwise.
  84.  *
  85.  * Side effects:
  86.  * The access position in f may change.
  87.  *
  88.  *----------------------------------------------------------------------
  89.  */
  90. static int
  91. FileMatchPPM(chan, fileName, format, widthPtr, heightPtr, interp)
  92.     Tcl_Channel chan; /* The image file, open for reading. */
  93.     CONST char *fileName; /* The name of the image file. */
  94.     Tcl_Obj *format; /* User-specified format string, or NULL. */
  95.     int *widthPtr, *heightPtr; /* The dimensions of the image are
  96.  * returned here if the file is a valid
  97.  * raw PPM file. */
  98.     Tcl_Interp *interp;
  99. {
  100.     int dummy;
  101.     return ReadPPMFileHeader(chan, widthPtr, heightPtr, &dummy);
  102. }
  103. /*
  104.  *----------------------------------------------------------------------
  105.  *
  106.  * FileReadPPM --
  107.  *
  108.  * This procedure is called by the photo image type to read
  109.  * PPM format data from a file and write it into a given
  110.  * photo image.
  111.  *
  112.  * Results:
  113.  * A standard TCL completion code.  If TCL_ERROR is returned
  114.  * then an error message is left in the interp's result.
  115.  *
  116.  * Side effects:
  117.  * The access position in file f is changed, and new data is
  118.  * added to the image given by imageHandle.
  119.  *
  120.  *----------------------------------------------------------------------
  121.  */
  122. static int
  123. FileReadPPM(interp, chan, fileName, format, imageHandle, destX, destY,
  124. width, height, srcX, srcY)
  125.     Tcl_Interp *interp; /* Interpreter to use for reporting errors. */
  126.     Tcl_Channel chan; /* The image file, open for reading. */
  127.     CONST char *fileName; /* The name of the image file. */
  128.     Tcl_Obj *format; /* User-specified format string, or NULL. */
  129.     Tk_PhotoHandle imageHandle; /* The photo image to write into. */
  130.     int destX, destY; /* Coordinates of top-left pixel in
  131.  * photo image to be written to. */
  132.     int width, height; /* Dimensions of block of photo image to
  133.  * be written to. */
  134.     int srcX, srcY; /* Coordinates of top-left pixel to be used
  135.  * in image being read. */
  136. {
  137.     int fileWidth, fileHeight, maxIntensity;
  138.     int nLines, nBytes, h, type, count;
  139.     unsigned char *pixelPtr;
  140.     Tk_PhotoImageBlock block;
  141.     type = ReadPPMFileHeader(chan, &fileWidth, &fileHeight, &maxIntensity);
  142.     if (type == 0) {
  143. Tcl_AppendResult(interp, "couldn't read raw PPM header from file "",
  144. fileName, """, NULL);
  145. return TCL_ERROR;
  146.     }
  147.     if ((fileWidth <= 0) || (fileHeight <= 0)) {
  148. Tcl_AppendResult(interp, "PPM image file "", fileName,
  149. "" has dimension(s) <= 0", NULL);
  150. return TCL_ERROR;
  151.     }
  152.     if ((maxIntensity <= 0) || (maxIntensity >= 256)) {
  153. char buffer[TCL_INTEGER_SPACE];
  154. sprintf(buffer, "%d", maxIntensity);
  155. Tcl_AppendResult(interp, "PPM image file "", fileName,
  156. "" has bad maximum intensity value ", buffer, NULL);
  157. return TCL_ERROR;
  158.     }
  159.     if ((srcX + width) > fileWidth) {
  160. width = fileWidth - srcX;
  161.     }
  162.     if ((srcY + height) > fileHeight) {
  163. height = fileHeight - srcY;
  164.     }
  165.     if ((width <= 0) || (height <= 0)
  166. || (srcX >= fileWidth) || (srcY >= fileHeight)) {
  167. return TCL_OK;
  168.     }
  169.     if (type == PGM) {
  170.         block.pixelSize = 1;
  171.         block.offset[0] = 0;
  172. block.offset[1] = 0;
  173. block.offset[2] = 0;
  174.     }
  175.     else {
  176.         block.pixelSize = 3;
  177.         block.offset[0] = 0;
  178. block.offset[1] = 1;
  179. block.offset[2] = 2;
  180.     }
  181.     block.offset[3] = 0;
  182.     block.width = width;
  183.     block.pitch = block.pixelSize * fileWidth;
  184.     Tk_PhotoExpand(imageHandle, destX + width, destY + height);
  185.     if (srcY > 0) {
  186. Tcl_Seek(chan, (Tcl_WideInt)(srcY * block.pitch), SEEK_CUR);
  187.     }
  188.     nLines = (MAX_MEMORY + block.pitch - 1) / block.pitch;
  189.     if (nLines > height) {
  190. nLines = height;
  191.     }
  192.     if (nLines <= 0) {
  193. nLines = 1;
  194.     }
  195.     nBytes = nLines * block.pitch;
  196.     pixelPtr = (unsigned char *) ckalloc((unsigned) nBytes);
  197.     block.pixelPtr = pixelPtr + srcX * block.pixelSize;
  198.     for (h = height; h > 0; h -= nLines) {
  199. if (nLines > h) {
  200.     nLines = h;
  201.     nBytes = nLines * block.pitch;
  202. }
  203. count = Tcl_Read(chan, (char *) pixelPtr, nBytes);
  204. if (count != nBytes) {
  205.     Tcl_AppendResult(interp, "error reading PPM image file "",
  206.     fileName, "": ",
  207.     Tcl_Eof(chan) ? "not enough data" : Tcl_PosixError(interp),
  208.     NULL);
  209.     ckfree((char *) pixelPtr);
  210.     return TCL_ERROR;
  211. }
  212. if (maxIntensity != 255) {
  213.     unsigned char *p;
  214.     for (p = pixelPtr; count > 0; count--, p++) {
  215. *p = (((int) *p) * 255)/maxIntensity;
  216.     }
  217. }
  218. block.height = nLines;
  219. Tk_PhotoPutBlock(imageHandle, &block, destX, destY, width, nLines,
  220. TK_PHOTO_COMPOSITE_SET);
  221. destY += nLines;
  222.     }
  223.     ckfree((char *) pixelPtr);
  224.     return TCL_OK;
  225. }
  226. /*
  227.  *----------------------------------------------------------------------
  228.  *
  229.  * FileWritePPM --
  230.  *
  231.  * This procedure is invoked to write image data to a file in PPM
  232.  * format.
  233.  *
  234.  * Results:
  235.  * A standard TCL completion code.  If TCL_ERROR is returned
  236.  * then an error message is left in the interp's result.
  237.  *
  238.  * Side effects:
  239.  * Data is written to the file given by "fileName".
  240.  *
  241.  *----------------------------------------------------------------------
  242.  */
  243. static int
  244. FileWritePPM(interp, fileName, format, blockPtr)
  245.     Tcl_Interp *interp;
  246.     CONST char *fileName;
  247.     Tcl_Obj *format;
  248.     Tk_PhotoImageBlock *blockPtr;
  249. {
  250.     Tcl_Channel chan;
  251.     int w, h;
  252.     int greenOffset, blueOffset, nBytes;
  253.     unsigned char *pixelPtr, *pixLinePtr;
  254.     char header[16 + TCL_INTEGER_SPACE * 2];
  255.     chan = Tcl_OpenFileChannel(interp, fileName, "w", 0666);
  256.     if (chan == NULL) {
  257. return TCL_ERROR;
  258.     }
  259.     if (Tcl_SetChannelOption(interp, chan, "-translation", "binary")
  260.     != TCL_OK) {
  261. Tcl_Close(NULL, chan);
  262. return TCL_ERROR;
  263.     }
  264.     if (Tcl_SetChannelOption(interp, chan, "-encoding", "binary")
  265.     != TCL_OK) {
  266. Tcl_Close(NULL, chan);
  267. return TCL_ERROR;
  268.     }
  269.     sprintf(header, "P6n%d %dn255n", blockPtr->width, blockPtr->height);
  270.     Tcl_Write(chan, header, -1);
  271.     pixLinePtr = blockPtr->pixelPtr + blockPtr->offset[0];
  272.     greenOffset = blockPtr->offset[1] - blockPtr->offset[0];
  273.     blueOffset = blockPtr->offset[2] - blockPtr->offset[0];
  274.     if ((greenOffset == 1) && (blueOffset == 2) && (blockPtr->pixelSize == 3)
  275.     && (blockPtr->pitch == (blockPtr->width * 3))) {
  276. nBytes = blockPtr->height * blockPtr->pitch;
  277. if (Tcl_Write(chan, (char *) pixLinePtr, nBytes) != nBytes) {
  278.     goto writeerror;
  279. }
  280.     } else {
  281. for (h = blockPtr->height; h > 0; h--) {
  282.     pixelPtr = pixLinePtr;
  283.     for (w = blockPtr->width; w > 0; w--) {
  284. if ((Tcl_Write(chan, (char *) &pixelPtr[0], 1) == -1)
  285. || (Tcl_Write(chan, (char *) &pixelPtr[greenOffset], 1) == -1)
  286. || (Tcl_Write(chan, (char *) &pixelPtr[blueOffset], 1) == -1)) {
  287.     goto writeerror;
  288. }
  289. pixelPtr += blockPtr->pixelSize;
  290.     }
  291.     pixLinePtr += blockPtr->pitch;
  292. }
  293.     }
  294.     if (Tcl_Close(NULL, chan) == 0) {
  295. return TCL_OK;
  296.     }
  297.     chan = NULL;
  298.  writeerror:
  299.     Tcl_AppendResult(interp, "error writing "", fileName, "": ",
  300.     Tcl_PosixError(interp), NULL);
  301.     if (chan != NULL) {
  302. Tcl_Close(NULL, chan);
  303.     }
  304.     return TCL_ERROR;
  305. }
  306. /*
  307.  *----------------------------------------------------------------------
  308.  *
  309.  * StringWritePPM --
  310.  *
  311.  * This procedure is invoked to write image data to a string in PPM
  312.  * format.
  313.  *
  314.  * Results:
  315.  * A standard TCL completion code.  If TCL_ERROR is returned
  316.  * then an error message is left in the interp's result.
  317.  *
  318.  * Side effects:
  319.  * None.
  320.  *
  321.  *----------------------------------------------------------------------
  322.  */
  323. static int
  324. StringWritePPM(interp, format, blockPtr)
  325.     Tcl_Interp *interp;
  326.     Tcl_Obj *format;
  327.     Tk_PhotoImageBlock *blockPtr;
  328. {
  329.     int w, h, size, greenOffset, blueOffset;
  330.     unsigned char *pixLinePtr, *byteArray;
  331.     char header[16 + TCL_INTEGER_SPACE * 2];
  332.     Tcl_Obj *byteArrayObj;
  333.     sprintf(header, "P6n%d %dn255n", blockPtr->width, blockPtr->height);
  334.     /*
  335.      * Construct a byte array of the right size with the header and
  336.      * get a pointer to the data part of it.
  337.      */
  338.     size = strlen(header);
  339.     byteArrayObj = Tcl_NewByteArrayObj((unsigned char *)header, size);
  340.     byteArray = Tcl_SetByteArrayLength(byteArrayObj,
  341.     size + 3*blockPtr->width*blockPtr->height);
  342.     byteArray += size;
  343.     pixLinePtr = blockPtr->pixelPtr + blockPtr->offset[0];
  344.     greenOffset = blockPtr->offset[1] - blockPtr->offset[0];
  345.     blueOffset = blockPtr->offset[2] - blockPtr->offset[0];
  346.     /*
  347.      * Check if we can do the data move in single action.
  348.      */
  349.     if ((greenOffset == 1) && (blueOffset == 2) && (blockPtr->pixelSize == 3)
  350.     && (blockPtr->pitch == (blockPtr->width * 3))) {
  351. memcpy(byteArray, pixLinePtr,
  352. (unsigned)blockPtr->height * blockPtr->pitch);
  353.     } else {
  354. for (h = blockPtr->height; h > 0; h--) {
  355.     unsigned char *pixelPtr = pixLinePtr;
  356.     for (w = blockPtr->width; w > 0; w--) {
  357. *byteArray++ = pixelPtr[0];
  358. *byteArray++ = pixelPtr[greenOffset];
  359. *byteArray++ = pixelPtr[blueOffset];
  360. pixelPtr += blockPtr->pixelSize;
  361.     }
  362.     pixLinePtr += blockPtr->pitch;
  363. }
  364.     }
  365.     /*
  366.      * Return the object in the interpreter result.
  367.      */
  368.     Tcl_SetObjResult(interp, byteArrayObj);
  369.     return TCL_OK;
  370. }
  371. /*
  372.  *----------------------------------------------------------------------
  373.  *
  374.  * StringMatchPPM --
  375.  *
  376.  * This procedure is invoked by the photo image type to see if
  377.  * a string contains image data in PPM format.
  378.  *
  379.  * Results:
  380.  * The return value is >0 if the first characters in file "f" look
  381.  * like PPM data, and 0 otherwise.
  382.  *
  383.  * Side effects:
  384.  * The access position in f may change.
  385.  *
  386.  *----------------------------------------------------------------------
  387.  */
  388. static int
  389. StringMatchPPM(dataObj, format, widthPtr, heightPtr, interp)
  390.     Tcl_Obj *dataObj; /* The image data. */
  391.     Tcl_Obj *format; /* User-specified format string, or NULL. */
  392.     int *widthPtr, *heightPtr; /* The dimensions of the image are
  393.  * returned here if the file is a valid
  394.  * raw PPM file. */
  395.     Tcl_Interp *interp; /* unused */
  396. {
  397.     int dummy;
  398.     return ReadPPMStringHeader(dataObj, widthPtr, heightPtr,
  399.     &dummy, NULL, NULL);
  400. }
  401. /*
  402.  *----------------------------------------------------------------------
  403.  *
  404.  * StringReadPPM --
  405.  *
  406.  * This procedure is called by the photo image type to read
  407.  * PPM format data from a string and write it into a given
  408.  * photo image.
  409.  *
  410.  * Results:
  411.  * A standard TCL completion code.  If TCL_ERROR is returned
  412.  * then an error message is left in the interp's result.
  413.  *
  414.  * Side effects:
  415.  * New data is added to the image given by imageHandle.
  416.  *
  417.  *----------------------------------------------------------------------
  418.  */
  419. static int
  420. StringReadPPM(interp, dataObj, format, imageHandle, destX, destY,
  421. width, height, srcX, srcY)
  422.     Tcl_Interp *interp; /* Interpreter to use for reporting errors. */
  423.     Tcl_Obj *dataObj; /* The image data. */
  424.     Tcl_Obj *format; /* User-specified format string, or NULL. */
  425.     Tk_PhotoHandle imageHandle; /* The photo image to write into. */
  426.     int destX, destY; /* Coordinates of top-left pixel in
  427.  * photo image to be written to. */
  428.     int width, height; /* Dimensions of block of photo image to
  429.  * be written to. */
  430.     int srcX, srcY; /* Coordinates of top-left pixel to be used
  431.  * in image being read. */
  432. {
  433.     int fileWidth, fileHeight, maxIntensity;
  434.     int nLines, nBytes, h, type, count, dataSize;
  435.     unsigned char *pixelPtr, *dataBuffer;
  436.     Tk_PhotoImageBlock block;
  437.     type = ReadPPMStringHeader(dataObj, &fileWidth, &fileHeight,
  438.     &maxIntensity, &dataBuffer, &dataSize);
  439.     if (type == 0) {
  440. Tcl_AppendResult(interp, "couldn't read raw PPM header from string",
  441. NULL);
  442. return TCL_ERROR;
  443.     }
  444.     if ((fileWidth <= 0) || (fileHeight <= 0)) {
  445. Tcl_AppendResult(interp, "PPM image data has dimension(s) <= 0",
  446. NULL);
  447. return TCL_ERROR;
  448.     }
  449.     if ((maxIntensity <= 0) || (maxIntensity >= 256)) {
  450. char buffer[TCL_INTEGER_SPACE];
  451. sprintf(buffer, "%d", maxIntensity);
  452. Tcl_AppendResult(interp,
  453. "PPM image data has bad maximum intensity value ", buffer,
  454. NULL);
  455. return TCL_ERROR;
  456.     }
  457.     if ((srcX + width) > fileWidth) {
  458. width = fileWidth - srcX;
  459.     }
  460.     if ((srcY + height) > fileHeight) {
  461. height = fileHeight - srcY;
  462.     }
  463.     if ((width <= 0) || (height <= 0)
  464. || (srcX >= fileWidth) || (srcY >= fileHeight)) {
  465. return TCL_OK;
  466.     }
  467.     if (type == PGM) {
  468.         block.pixelSize = 1;
  469.         block.offset[0] = 0;
  470. block.offset[1] = 0;
  471. block.offset[2] = 0;
  472.     } else {
  473.         block.pixelSize = 3;
  474.         block.offset[0] = 0;
  475. block.offset[1] = 1;
  476. block.offset[2] = 2;
  477.     }
  478.     block.offset[3] = 0;
  479.     block.width = width;
  480.     block.pitch = block.pixelSize * fileWidth;
  481.     if (srcY > 0) {
  482. dataBuffer += srcY * block.pitch;
  483. dataSize -= srcY * block.pitch;
  484.     }
  485.     if (maxIntensity == 255) {
  486. /*
  487.  * We have all the data in memory, so write everything in one
  488.  * go.
  489.  */
  490. if (block.pitch*height > dataSize) {
  491.     Tcl_AppendResult(interp, "truncated PPM data", NULL);
  492.     return TCL_ERROR;
  493. }
  494. block.pixelPtr = dataBuffer + srcX * block.pixelSize;
  495. block.height = height;
  496. Tk_PhotoPutBlock(imageHandle, &block, destX, destY, width, height,
  497. TK_PHOTO_COMPOSITE_SET);
  498. return TCL_OK;
  499.     }
  500.     Tk_PhotoExpand(imageHandle, destX + width, destY + height);
  501.     nLines = (MAX_MEMORY + block.pitch - 1) / block.pitch;
  502.     if (nLines > height) {
  503. nLines = height;
  504.     }
  505.     if (nLines <= 0) {
  506. nLines = 1;
  507.     }
  508.     nBytes = nLines * block.pitch;
  509.     pixelPtr = (unsigned char *) ckalloc((unsigned) nBytes);
  510.     block.pixelPtr = pixelPtr + srcX * block.pixelSize;
  511.     for (h = height; h > 0; h -= nLines) {
  512. unsigned char *p;
  513. if (nLines > h) {
  514.     nLines = h;
  515.     nBytes = nLines * block.pitch;
  516. }
  517. if (dataSize < nBytes) {
  518.     ckfree((char *) pixelPtr);
  519.     Tcl_AppendResult(interp, "truncated PPM data", NULL);
  520.     return TCL_ERROR;
  521. }
  522. for (p=pixelPtr,count=nBytes ; count>0 ; count--,p++,dataBuffer++) {
  523.     *p = (((int) *dataBuffer) * 255)/maxIntensity;
  524. }
  525. dataSize -= nBytes;
  526. block.height = nLines;
  527. Tk_PhotoPutBlock(imageHandle, &block, destX, destY, width, nLines,
  528. TK_PHOTO_COMPOSITE_SET);
  529. destY += nLines;
  530.     }
  531.     ckfree((char *) pixelPtr);
  532.     return TCL_OK;
  533. }
  534. /*
  535.  *----------------------------------------------------------------------
  536.  *
  537.  * ReadPPMFileHeader --
  538.  *
  539.  * This procedure reads the PPM header from the beginning of a
  540.  * PPM file and returns information from the header.
  541.  *
  542.  * Results:
  543.  * The return value is PGM if file "f" appears to start with
  544.  * a valid PGM header, PPM if "f" appears to start with a valid
  545.  *      PPM header, and 0 otherwise.  If the header is valid,
  546.  * then *widthPtr and *heightPtr are modified to hold the
  547.  * dimensions of the image and *maxIntensityPtr is modified to
  548.  * hold the value of a "fully on" intensity value.
  549.  *
  550.  * Side effects:
  551.  * The access position in f advances.
  552.  *
  553.  *----------------------------------------------------------------------
  554.  */
  555. static int
  556. ReadPPMFileHeader(chan, widthPtr, heightPtr, maxIntensityPtr)
  557.     Tcl_Channel chan; /* Image file to read the header from */
  558.     int *widthPtr, *heightPtr; /* The dimensions of the image are
  559.  * returned here. */
  560.     int *maxIntensityPtr; /* The maximum intensity value for
  561.  * the image is stored here. */
  562. {
  563. #define BUFFER_SIZE 1000
  564.     char buffer[BUFFER_SIZE];
  565.     int i, numFields;
  566.     int type = 0;
  567.     char c;
  568.     /*
  569.      * Read 4 space-separated fields from the file, ignoring
  570.      * comments (any line that starts with "#").
  571.      */
  572.     if (Tcl_Read(chan, &c, 1) != 1) {
  573. return 0;
  574.     }
  575.     i = 0;
  576.     for (numFields = 0; numFields < 4; numFields++) {
  577. /*
  578.  * Skip comments and white space.
  579.  */
  580. while (1) {
  581.     while (isspace(UCHAR(c))) {
  582. if (Tcl_Read(chan, &c, 1) != 1) {
  583.     return 0;
  584. }
  585.     }
  586.     if (c != '#') {
  587. break;
  588.     }
  589.     do {
  590. if (Tcl_Read(chan, &c, 1) != 1) {
  591.     return 0;
  592. }
  593.     } while (c != 'n');
  594. }
  595. /*
  596.  * Read a field (everything up to the next white space).
  597.  */
  598. while (!isspace(UCHAR(c))) {
  599.     if (i < (BUFFER_SIZE-2)) {
  600. buffer[i] = c;
  601. i++;
  602.     }
  603.     if (Tcl_Read(chan, &c, 1) != 1) {
  604. goto done;
  605.     }
  606. }
  607. if (i < (BUFFER_SIZE-1)) {
  608.     buffer[i] = ' ';
  609.     i++;
  610. }
  611.     }
  612.     done:
  613.     buffer[i] = 0;
  614.     /*
  615.      * Parse the fields, which are: id, width, height, maxIntensity.
  616.      */
  617.     if (strncmp(buffer, "P6 ", 3) == 0) {
  618. type = PPM;
  619.     } else if (strncmp(buffer, "P5 ", 3) == 0) {
  620. type = PGM;
  621.     } else {
  622. return 0;
  623.     }
  624.     if (sscanf(buffer+3, "%d %d %d", widthPtr, heightPtr, maxIntensityPtr)
  625.     != 3) {
  626. return 0;
  627.     }
  628.     return type;
  629. }
  630. /*
  631.  *----------------------------------------------------------------------
  632.  *
  633.  * ReadPPMStringHeader --
  634.  *
  635.  * This procedure reads the PPM header from the beginning of a
  636.  * PPM-format string and returns information from the header.
  637.  *
  638.  * Results:
  639.  * The return value is PGM if the string appears to start with
  640.  * a valid PGM header, PPM if the string appears to start with
  641.  *      a valid PPM header, and 0 otherwise.  If the header is valid,
  642.  * then *widthPtr and *heightPtr are modified to hold the
  643.  * dimensions of the image and *maxIntensityPtr is modified to
  644.  * hold the value of a "fully on" intensity value.
  645.  *
  646.  * Side effects:
  647.  * None
  648.  *
  649.  *----------------------------------------------------------------------
  650.  */
  651. static int
  652. ReadPPMStringHeader(dataPtr, widthPtr, heightPtr, maxIntensityPtr,
  653. dataBufferPtr, dataSizePtr)
  654.     Tcl_Obj *dataPtr; /* Object to read the header from. */
  655.     int *widthPtr, *heightPtr; /* The dimensions of the image are
  656.  * returned here. */
  657.     int *maxIntensityPtr; /* The maximum intensity value for
  658.  * the image is stored here. */
  659.     unsigned char **dataBufferPtr;
  660.     int *dataSizePtr;
  661. {
  662. #define BUFFER_SIZE 1000
  663.     char buffer[BUFFER_SIZE];
  664.     int i, numFields, dataSize;
  665.     int type = 0;
  666.     char c;
  667.     unsigned char *dataBuffer;
  668.     dataBuffer = Tcl_GetByteArrayFromObj(dataPtr, &dataSize);
  669.     /*
  670.      * Read 4 space-separated fields from the string, ignoring
  671.      * comments (any line that starts with "#").
  672.      */
  673.     if (dataSize-- < 1) {
  674. return 0;
  675.     }
  676.     c = (char) (*dataBuffer++);
  677.     i = 0;
  678.     for (numFields = 0; numFields < 4; numFields++) {
  679. /*
  680.  * Skip comments and white space.
  681.  */
  682. while (1) {
  683.     while (isspace(UCHAR(c))) {
  684. if (dataSize-- < 1) {
  685.     return 0;
  686. }
  687. c = (char) (*dataBuffer++);
  688.     }
  689.     if (c != '#') {
  690. break;
  691.     }
  692.     do {
  693. if (dataSize-- < 1) {
  694.     return 0;
  695. }
  696. c = (char) (*dataBuffer++);
  697.     } while (c != 'n');
  698. }
  699. /*
  700.  * Read a field (everything up to the next white space).
  701.  */
  702. while (!isspace(UCHAR(c))) {
  703.     if (i < (BUFFER_SIZE-2)) {
  704. buffer[i] = c;
  705. i++;
  706.     }
  707.     if (dataSize-- < 1) {
  708. goto done;
  709.     }
  710.     c = (char) (*dataBuffer++);
  711. }
  712. if (i < (BUFFER_SIZE-1)) {
  713.     buffer[i] = ' ';
  714.     i++;
  715. }
  716.     }
  717.     done:
  718.     buffer[i] = 0;
  719.     /*
  720.      * Parse the fields, which are: id, width, height, maxIntensity.
  721.      */
  722.     if (strncmp(buffer, "P6 ", 3) == 0) {
  723. type = PPM;
  724.     } else if (strncmp(buffer, "P5 ", 3) == 0) {
  725. type = PGM;
  726.     } else {
  727. return 0;
  728.     }
  729.     if (sscanf(buffer+3, "%d %d %d", widthPtr, heightPtr, maxIntensityPtr)
  730.     != 3) {
  731. return 0;
  732.     }
  733.     if (dataBufferPtr != NULL) {
  734. *dataBufferPtr = dataBuffer;
  735. *dataSizePtr = dataSize;
  736.     }
  737.     return type;
  738. }