diff -cr oommf11b2/ext/if/if.cc oommf/ext/if/if.cc *** oommf11b2/ext/if/if.cc Thu Nov 20 17:41:28 2003 --- oommf/ext/if/if.cc Sat Mar 20 00:24:17 2004 *************** *** 9,20 **** * * NOTICE: Please see the file ../../LICENSE * ! * Last modified on: $Date: 2003/11/20 22:41:28 $ ! * Last modified by: $Author: dgp $ */ #include #include #define USE_OLD_IMAGE #define USE_COMPOSITELESS_PHOTO_PUT_BLOCK --- 9,22 ---- * * NOTICE: Please see the file ../../LICENSE * ! * Last modified on: $Date: 2004/03/20 05:24:17 $ ! * Last modified by: $Author: donahue $ */ #include #include + #include + #include #define USE_OLD_IMAGE #define USE_COMPOSITELESS_PHOTO_PUT_BLOCK *************** *** 23,28 **** --- 25,32 ---- /* End includes */ // Optional directive to pimake + //////////////////////////////////////////////////////////////////////// + // MsBitmap and related classes struct RGBQuad { BYTE Red; BYTE Green; *************** *** 31,37 **** int MSFill32(Tcl_Channel chan); // Fills structure from chan /// of MS RGBQuad's, returning the number of bytes read (4), /// or 0 on error. ! inline int MSFill24(const char* carr); // Analogous to above, /// but takes input from a 3-byte long buffer. }; --- 35,41 ---- int MSFill32(Tcl_Channel chan); // Fills structure from chan /// of MS RGBQuad's, returning the number of bytes read (4), /// or 0 on error. ! inline int MSFill24(const unsigned char* carr); // Analogous to above, /// but takes input from a 3-byte long buffer. }; *************** *** 45,51 **** return count; } ! int RGBQuad::MSFill24(const char* carr) { // Note: MS RGBQuad's are ordered "Blue Green Red Reserved" Blue=carr[0]; Green=carr[1]; Red=carr[2]; Reserved=0; --- 49,55 ---- return count; } ! int RGBQuad::MSFill24(const unsigned char* carr) { // Note: MS RGBQuad's are ordered "Blue Green Red Reserved" Blue=carr[0]; Green=carr[1]; Red=carr[2]; Reserved=0; *************** *** 53,59 **** } class MSBitmap; // Forward declaration for typedef ! typedef int (MSBitmap::*BmpConvert)(const char* read_buf, RGBQuad* &pix, UINT4 startcol, UINT4 stopcol); --- 57,63 ---- } class MSBitmap; // Forward declaration for typedef ! typedef int (MSBitmap::*BmpConvert)(const unsigned char* read_buf, RGBQuad* &pix, UINT4 startcol, UINT4 stopcol); *************** *** 96,108 **** UINT4 PaletteSize; // FillPhoto() bitmap->rgb conversion routines. ! int Bmp1toRgbq(const char* read_buf,RGBQuad* &pix, UINT4 startcol,UINT4 stopcol); // 1 bit/pixel ! int Bmp4toRgbq(const char* read_buf,RGBQuad* &pix, UINT4 startcol,UINT4 stopcol); // 4 bits/pixel ! int Bmp8toRgbq(const char* read_buf,RGBQuad* &pix, UINT4 startcol,UINT4 stopcol); // 8 bits/pixel ! int Bmp24toRgbq(const char* read_buf,RGBQuad* &pix, UINT4 startcol,UINT4 stopcol); // 24 bits/pixel BmpConvert DataConvert; --- 100,112 ---- UINT4 PaletteSize; // FillPhoto() bitmap->rgb conversion routines. ! int Bmp1toRgbq(const unsigned char* read_buf,RGBQuad* &pix, UINT4 startcol,UINT4 stopcol); // 1 bit/pixel ! int Bmp4toRgbq(const unsigned char* read_buf,RGBQuad* &pix, UINT4 startcol,UINT4 stopcol); // 4 bits/pixel ! int Bmp8toRgbq(const unsigned char* read_buf,RGBQuad* &pix, UINT4 startcol,UINT4 stopcol); // 8 bits/pixel ! int Bmp24toRgbq(const unsigned char* read_buf,RGBQuad* &pix, UINT4 startcol,UINT4 stopcol); // 24 bits/pixel BmpConvert DataConvert; *************** *** 251,257 **** } int ! MSBitmap::Bmp1toRgbq(const char* read_buf,RGBQuad* &pix, UINT4 startcol,UINT4 stopcol) { // 1 bit per pixel, with palette UINT4 jstart=8*(startcol/8); --- 255,261 ---- } int ! MSBitmap::Bmp1toRgbq(const unsigned char* read_buf,RGBQuad* &pix, UINT4 startcol,UINT4 stopcol) { // 1 bit per pixel, with palette UINT4 jstart=8*(startcol/8); *************** *** 274,280 **** } int ! MSBitmap::Bmp4toRgbq(const char* read_buf,RGBQuad* &pix, UINT4 startcol,UINT4 stopcol) { // 4 bits per pixel, with palette UINT4 jstart=2*(startcol/2); --- 278,284 ---- } int ! MSBitmap::Bmp4toRgbq(const unsigned char* read_buf,RGBQuad* &pix, UINT4 startcol,UINT4 stopcol) { // 4 bits per pixel, with palette UINT4 jstart=2*(startcol/2); *************** *** 299,318 **** } int ! MSBitmap::Bmp8toRgbq(const char* read_buf,RGBQuad* &pix, UINT4 startcol,UINT4 stopcol) { // 8 bits per pixel, with palette for(UINT4 j=startcol;j=PaletteSize) return 1; pix[j-startcol]=Palette[index]; } return 0; } int ! MSBitmap::Bmp24toRgbq(const char* read_buf,RGBQuad* &pix, UINT4 startcol,UINT4 stopcol) { // True color input file; 24 bits per pixel, no palette const int data_width=3; --- 303,324 ---- } int ! MSBitmap::Bmp8toRgbq(const unsigned char* read_buf,RGBQuad* &pix, UINT4 startcol,UINT4 stopcol) { // 8 bits per pixel, with palette for(UINT4 j=startcol;j=PaletteSize) { ! return 1; ! } pix[j-startcol]=Palette[index]; } return 0; } int ! MSBitmap::Bmp24toRgbq(const unsigned char* read_buf,RGBQuad* &pix, UINT4 startcol,UINT4 stopcol) { // True color input file; 24 bits per pixel, no palette const int data_width=3; *************** *** 390,396 **** } // ! char *read_buf=new char[FileRowSize]; RGBQuad *pix=new RGBQuad[reqwidth]; Tk_PhotoImageBlock pib; --- 396,402 ---- } // ! unsigned char *read_buf=new unsigned char[FileRowSize]; RGBQuad *pix=new RGBQuad[reqwidth]; Tk_PhotoImageBlock pib; *************** *** 412,418 **** Tcl_Seek(chan,OffBits+startrow*FileRowSize,SEEK_SET); for(UINT4 i= UINT4(startrow);i= 8) extern "C" { static Tk_ImageFileMatchProc bmpFileMatchProc; ! static Tk_ImageFileReadProc bmpFileReadProc; static Tk_ImageFileWriteProc bmpFileWriteProc; } --- 560,1069 ---- return Tcl_Close(interp,chan); } + //////////////////////////////////////////////////////////////////////// + // OOMMF If_PPM class + class If_PPM { + private: + UINT4m Width; + UINT4m Height; + UINT4m Maxvalue; + + int ReadNumber(Tcl_Channel chan,int& number); + char* ReadNumber(char* data,int& number); + char* ReadHeader(char* data, + int& imagewidth,int& imageheight,int& maxval); + + public: + If_PPM() : Width(0), Height(0), Maxvalue(0) {} + ~If_PPM() {} + int ReadCheck(Tcl_Channel chan,int& imagewidth,int& imageheight); + /// Returns 1 if the file on chan looks like a PPM P3. + + int FillPhoto(Tcl_Interp* interp,Tcl_Channel chan, + char* fileName,Tk_PhotoHandle imageHandle, + int destX,int destY,int width,int height,int srcX,int srcY); + /// Fills in imageHandle as requested, one row at a time. + + int WritePhoto(Tcl_Interp* interp,const char* filename, + Tk_PhotoImageBlock* blockPtr); + // Write PhotoImageBlock to file "filename" in PPM P3 format. + + // String versions of the above + int ReadCheck(char* data,int& imagewidth,int& imageheight); + int FillPhoto(Tcl_Interp* interp,char* data,Tk_PhotoHandle imageHandle, + int destX,int destY,int width,int height,int srcX,int srcY); + int WritePhoto(Tcl_Interp* interp,Tcl_DString* dataPtr, + Tk_PhotoImageBlock* blockPtr); + + }; + + int If_PPM::ReadNumber(Tcl_Channel chan,int& number) + { // Consumes the next integer on chan, and also the first subsequent + // non-number character, from chan. Converts from text to int, + // storing the result in the export "number". Returns 0 on success, + // otherwise an errorcode>0. + + number = 0; // Safety + + // Pass over whitespace and comments + char ch; + while(1) { + if(Tcl_Read(chan,&ch,sizeof(char))!=1) { + // Premature EOF + return 1; + } + if(!isspace(ch)) { + if(ch!='#') break; // Start of number detected + // Otherwise, comment detected; read to end of line + while(Tcl_Read(chan,&ch,sizeof(char))==1 && ch!='\n') {} + } + } + + // At this point, ch should hold first non-whitespace + // character outside of any comments. + + char buf[65]; // Should be big enough + buf[0]=ch; + int i=1; + while(Tcl_Read(chan,buf+i,sizeof(char))==1 && isdigit(buf[i])) { + i++; + if(i>=sizeof(buf)-1) break; + } + buf[i]='\0'; + + char* cptr; + long int lnum = strtol(buf,&cptr,10); + number = static_cast(lnum); + if(*cptr != '\0') return 2; + return 0; + } + + char* If_PPM::ReadNumber(char* data,int& number) + { // After skipping leading whitespace and comments, + // converts the first integer from text to int, + // storing the result in the export "number". + // On success, the return points to the first + // character past the end of the converted number. + // Returns NULL on failure + + number = 0; // Safety + + // Pass over whitespace and comments + char* cptr = data; + while(cptr!=NULL) { + if(!isspace(*cptr)) { + if(*cptr!='#') break; // Start of number detected + // Otherwise, comment detected; read to end of line + if((cptr = strchr(cptr,'\n'))==NULL) return NULL; + } + ++cptr; + } + + // At this point, cptr should point to the first non-whitespace + // character outside of any comments. + long int lnum = strtol(cptr,&cptr,10); + number = static_cast(lnum); + return cptr; + } + + int If_PPM::ReadCheck + (Tcl_Channel chan,int& imagewidth,int& imageheight) + { // Returns 1 if the file on chan looks like a PPM P3 + + // Read and check signature + char type[2]; + Tcl_Read(chan,type,2*sizeof(char)); + if(type[0]!='P' || type[1]!='3') return 0; + + if(ReadNumber(chan,imagewidth)!=0) return 0; + if(ReadNumber(chan,imageheight)!=0) return 0; + + return 1; + } + + char* If_PPM::ReadHeader + (char* data,int& imagewidth,int& imageheight,int& maxval) + { // Returns NULL if the data doesn't looks like PPM P3 + // data. Otherwise, returns pointer to first byte + // past header. + + // Check signature + if(data[0]!='P' || data[1]!='3') return NULL; + + char* cptr = data + 2; + if((cptr = ReadNumber(cptr,imagewidth))==NULL) return NULL; + if((cptr = ReadNumber(cptr,imageheight))==NULL) return NULL; + if((cptr = ReadNumber(cptr,maxval))==NULL) return NULL; + + return cptr; + } + + int If_PPM::ReadCheck + (char* data,int& imagewidth,int& imageheight) + { // Returns 1 if the data looks like a PPM P3 + int maxval; + if(ReadHeader(data,imagewidth,imageheight,maxval)==NULL) { + return 0; + } + return 1; + } + + int If_PPM::FillPhoto + (Tcl_Interp* interp,Tcl_Channel chan, + char* fileName,Tk_PhotoHandle imageHandle, + int destX,int destY,int width,int height,int srcX,int srcY) + { // Fills in imageHandle as requested, one row at a time. + // Returns TCL_OK on success, TCL_ERROR on failure. + + int imagewidth,imageheight; + if(ReadCheck(chan,imagewidth,imageheight)==0) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp,"Header in file ",fileName, + " not recognized as a PPM P3 header.", + (char *)NULL); + return TCL_ERROR; + } + + int maxvalue; + if(ReadNumber(chan,maxvalue)!=0) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp,"File ",fileName, + " doesn't conform to PPM P3 format (bad maxvalue).", + (char *)NULL); + return TCL_ERROR; + } + + // Safety checks + if(srcX<0) { width += srcX; srcX=0; } + if(srcX+width>imagewidth) { + width = imagewidth-srcX; + } + if(srcY<0) {height += srcY; srcY=0; } + if(srcY+height>imageheight) { + height = imageheight-srcY; + } + if(width<1 || height<1) return TCL_OK; // Nothing to do + + + // Skip through file until we get to (srcX,srcY) + int i,j; + int red,green,blue; + for(i=0;i 8) \ + || ((TK_MAJOR_VERSION == 8) && (TK_MINOR_VERSION >= 3)) + // Jan Nijtmans recommends this safe way to disable alpha processing + pib.offset[3]=pib.offset[0]; + #endif + + // Read and write data + for(i=0;i((red*255 + maxvalue/2)/maxvalue); + pix[3*j+1] + = static_cast((green*255 + maxvalue/2)/maxvalue); + pix[3*j+2] + = static_cast((blue*255 + maxvalue/2)/maxvalue); + } + // Write row + Tk_PhotoPutBlock(imageHandle,&pib,destX,destY+i,width,1); + // Skip through to next row + for(j=width;jimagewidth) { + width = imagewidth-srcX; + } + if(srcY<0) {height += srcY; srcY=0; } + if(srcY+height>imageheight) { + height = imageheight-srcY; + } + if(width<1 || height<1) return TCL_OK; // Nothing to do + + + // Skip through file until we get to (srcX,srcY) + int i,j; + int red,green,blue; + for(i=0;i 8) \ + || ((TK_MAJOR_VERSION == 8) && (TK_MINOR_VERSION >= 3)) + // Jan Nijtmans recommends this safe way to disable alpha processing + pib.offset[3]=pib.offset[0]; + #endif + + // Read and write data + for(i=0;i((red*255 + maxvalue/2)/maxvalue); + pix[3*j+1] + = static_cast((green*255 + maxvalue/2)/maxvalue); + pix[3*j+2] + = static_cast((blue*255 + maxvalue/2)/maxvalue); + } + // Write row + Tk_PhotoPutBlock(imageHandle,&pib,destX,destY+i,width,1); + // Skip through to next row + for(j=width;jwidth; + int height = blockPtr->height; + int maxval = 255; // Assumed + + // Write header + Oc_Snprintf(buf,sizeof(buf),"P3\n%d %d\n%d\n", + width,height,maxval); + if(Tcl_Write(chan,buf,strlen(buf))==-1) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp,"Output error writing" + " PPM P3 file: \"",filename, + "\"",(char *)NULL); + Tcl_Close(interp,chan); + return TCL_ERROR; + } + + // Write data, from top to bottom. + for(int i = 0 ; i < height ; i++) { + int pixoff = i * blockPtr->pitch; + for(int j=0;jpixelSize) { + int red = blockPtr->pixelPtr[pixoff+blockPtr->offset[0]]; + int green = blockPtr->pixelPtr[pixoff+blockPtr->offset[1]]; + int blue = blockPtr->pixelPtr[pixoff+blockPtr->offset[2]]; + int outlen + = Oc_Snprintf(buf,sizeof(buf),"%d %d %d\n",red,green,blue); + if(Tcl_Write(chan,buf,outlen)==-1) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp,"Output error writing" + " PPM P3 file: \"",filename, + "\"",(char *)NULL); + Tcl_Close(interp,chan); + return TCL_ERROR; + } + } + } + + // Close channel and exit + return Tcl_Close(interp,chan); + } + + int If_PPM::WritePhoto + (Tcl_Interp* interp,Tcl_DString* dataPtr, + Tk_PhotoImageBlock* blockPtr) + { // Write PhotoImageBlock to file "fileName" in PPM P3 format. + + // Buffer space + char buf[64*4]; + int outlen; // Length of string in buffer + + // Header info + int width = blockPtr->width; + int height = blockPtr->height; + int maxval = 255; // Assumed + + // Write header + outlen = Oc_Snprintf(buf,sizeof(buf),"P3\n%d %d\n%d\n", + width,height,maxval); + Tcl_DStringInit(dataPtr); + Tcl_DStringAppend(dataPtr,buf,outlen); + + // Write data, from top to bottom. + for(int i = 0 ; i < height ; i++) { + int pixoff = i * blockPtr->pitch; + for(int j=0;jpixelSize) { + int red = blockPtr->pixelPtr[pixoff+blockPtr->offset[0]]; + int green = blockPtr->pixelPtr[pixoff+blockPtr->offset[1]]; + int blue = blockPtr->pixelPtr[pixoff+blockPtr->offset[2]]; + outlen + = Oc_Snprintf(buf,sizeof(buf),"%d %d %d\n",red,green,blue); + Tcl_DStringAppend(dataPtr,buf,outlen); + } + } + + return TCL_OK; + } + // The C interface for extending the photo image formats changed ! // incompatibly between versions 4 and 8 of Tk. May want to code a ! // workaround eventually. For now, the bmp and ppm p3 photo image ! // formats are simply not available in pre-8.0 interpreters. #if (TK_MAJOR_VERSION >= 8) extern "C" { static Tk_ImageFileMatchProc bmpFileMatchProc; ! static Tk_ImageFileReadProc bmpFileReadProc; static Tk_ImageFileWriteProc bmpFileWriteProc; } *************** *** 615,620 **** --- 1116,1216 ---- NULL, // String write routine NULL, // NULL nextPtr to be overwritten by Tk }; + + extern "C" { + static Tk_ImageFileMatchProc ppmFileMatchProc; + static Tk_ImageFileReadProc ppmFileReadProc; + static Tk_ImageFileWriteProc ppmFileWriteProc; + static Tk_ImageStringMatchProc ppmStringMatchProc; + static Tk_ImageStringReadProc ppmStringReadProc; + static Tk_ImageStringWriteProc ppmStringWriteProc; + } + + + static char ppmnamestr[] = "P3"; + + int + ppmFileMatchProc(Tcl_Channel chan, + char* /* filename */, + char* /* formatString */, + int* widthPtr, + int* heightPtr) + { + If_PPM ppm; + return ppm.ReadCheck(chan,*widthPtr,*heightPtr); + } + + int + ppmFileReadProc(Tcl_Interp* interp, + Tcl_Channel chan, + char* filename, + char* /* formatString */, + Tk_PhotoHandle imageHandle, + int destX, int destY, + int width, int height, + int srcX, int srcY) + { + If_PPM ppm; + return ppm.FillPhoto(interp,chan,filename,imageHandle, + destX,destY,width,height,srcX,srcY); + } + + int + ppmFileWriteProc(Tcl_Interp* interp, + char* filename, + char* /* format */, + Tk_PhotoImageBlock* blockPtr) + { + If_PPM ppm; + return ppm.WritePhoto(interp,filename,blockPtr); + } + + int + ppmStringMatchProc(char* data, + char* formatString, + int* widthPtr, + int* heightPtr) + { + If_PPM ppm; + return ppm.ReadCheck(data,*widthPtr,*heightPtr); + } + + int + ppmStringReadProc(Tcl_Interp *interp, + char* data, + char* /* formatString */, + Tk_PhotoHandle imageHandle, + int destX, int destY, + int width, int height, + int srcX, int srcY) + { + If_PPM ppm; + return ppm.FillPhoto(interp,data,imageHandle, + destX,destY,width,height,srcX,srcY); + } + + int + ppmStringWriteProc(Tcl_Interp* interp, + Tcl_DString* dataPtr, + char* /* formatString */, + Tk_PhotoImageBlock* blockPtr) + { + If_PPM ppm; + return ppm.WritePhoto(interp,dataPtr,blockPtr); + } + + + static Tk_PhotoImageFormat ppmformat = + { + ppmnamestr, // Format name + ppmFileMatchProc, // File format identifier routine + ppmStringMatchProc, // String format id routine + ppmFileReadProc, // File read routine + ppmStringReadProc, // String read routine + ppmFileWriteProc, // File write routine + ppmStringWriteProc, // String write routine + NULL, // NULL nextPtr to be overwritten by Tk + }; #endif int *************** *** 635,640 **** --- 1231,1237 ---- // See note above. #if (TK_MAJOR_VERSION >= 8) Tk_CreatePhotoImageFormat(&bmpformat); + Tk_CreatePhotoImageFormat(&ppmformat); #endif if (Tcl_PkgProvide(interp, ab("If"), ab1(IF_VERSION)) != TCL_OK) {