diff options
Diffstat (limited to 'generic/tkCanvPs.c')
-rw-r--r-- | generic/tkCanvPs.c | 466 |
1 files changed, 464 insertions, 2 deletions
diff --git a/generic/tkCanvPs.c b/generic/tkCanvPs.c index c234320..940b754 100644 --- a/generic/tkCanvPs.c +++ b/generic/tkCanvPs.c @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkCanvPs.c,v 1.6 1999/12/14 06:52:26 hobbs Exp $ + * RCS: @(#) $Id: tkCanvPs.c,v 1.7 2000/04/25 01:03:06 hobbs Exp $ */ #include "tkInt.h" @@ -128,7 +128,7 @@ static CONST char * CONST prolog[]= { \n\ % This is a standard prolog for Postscript generated by Tk's canvas\n\ % widget.\n\ -% RCS: @(#) $Id: tkCanvPs.c,v 1.6 1999/12/14 06:52:26 hobbs Exp $\n\ +% RCS: @(#) $Id: tkCanvPs.c,v 1.7 2000/04/25 01:03:06 hobbs Exp $\n\ \n\ % The definitions below just define all of the variables used in\n\ % any of the procedures here. This is needed for obscure reasons\n\ @@ -1681,3 +1681,465 @@ TkPostscriptImage(interp, tkwin, psInfo, ximage, x, y, width, height) ckfree((char *) cdata.colors); return TCL_OK; } + +/* + *-------------------------------------------------------------- + * + * Tk_PostscriptPhoto -- + * + * This procedure is called to output the contents of a + * photo image in Postscript, using a format appropriate for + * the requested postscript color mode (i.e. one byte per pixel + * in gray, and three bytes per pixel in color). + * + * Results: + * Returns a standard Tcl return value. If an error occurs + * then an error message will be left in interp->result. + * If no error occurs, then additional Postscript will be + * appended to the interpreter's result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ +int +Tk_PostscriptPhoto(interp, blockPtr, psInfo, width, height) + Tcl_Interp *interp; + Tk_PhotoImageBlock *blockPtr; + Tk_PostscriptInfo psInfo; + int width, height; +{ + TkPostscriptInfo *psInfoPtr = (TkPostscriptInfo *) psInfo; + int colorLevel = psInfoPtr->colorLevel; + static int codeIncluded = 0; + + unsigned char *pixelPtr; + char buffer[256], cspace[40], decode[40]; + int bpc; + int xx, yy, lineLen; + float red, green, blue; + int alpha; + int bytesPerLine=0, maxWidth=0; + + unsigned char opaque = 255; + unsigned char *alphaPtr; + int alphaOffset, alphaPitch, alphaIncr; + + if (psInfoPtr->prepass) { + codeIncluded = 0; + return TCL_OK; + } + + /* + * Define the "TkPhoto" function, which is a modified version + * of the original "transparentimage" function posted + * by ian@five-d.com (Ian Kemmish) to comp.lang.postscript. + * For a monochrome colorLevel this is a slightly different + * version that uses the imagemask command instead of image. + */ + + if( !codeIncluded && (colorLevel != 0) ) { + /* + * Color and gray-scale code. + */ + + codeIncluded = !0; + Tcl_AppendResult( interp, + "/TkPhoto { \n", + " gsave \n", + " 32 dict begin \n", + " /tinteger exch def \n", + " /transparent 1 string def \n", + " transparent 0 tinteger put \n", + " /olddict exch def \n", + " olddict /DataSource get dup type /filetype ne { \n", + " olddict /DataSource 3 -1 roll \n", + " 0 () /SubFileDecode filter put \n", + " } { \n", + " pop \n", + " } ifelse \n", + " /newdict olddict maxlength dict def \n", + " olddict newdict copy pop \n", + " /w newdict /Width get def \n", + " /crpp newdict /Decode get length 2 idiv def \n", + " /str w string def \n", + " /pix w crpp mul string def \n", + " /substrlen 2 w log 2 log div floor exp cvi def \n", + " /substrs [ \n", + " { \n", + " substrlen string \n", + " 0 1 substrlen 1 sub { \n", + " 1 index exch tinteger put \n", + " } for \n", + " /substrlen substrlen 2 idiv def \n", + " substrlen 0 eq {exit} if \n", + " } loop \n", + " ] def \n", + " /h newdict /Height get def \n", + " 1 w div 1 h div matrix scale \n", + " olddict /ImageMatrix get exch matrix concatmatrix \n", + " matrix invertmatrix concat \n", + " newdict /Height 1 put \n", + " newdict /DataSource pix put \n", + " /mat [w 0 0 h 0 0] def \n", + " newdict /ImageMatrix mat put \n", + " 0 1 h 1 sub { \n", + " mat 5 3 -1 roll neg put \n", + " olddict /DataSource get str readstring pop pop \n", + " /tail str def \n", + " /x 0 def \n", + " olddict /DataSource get pix readstring pop pop \n", + " { \n", + " tail transparent search dup /done exch not def \n", + " {exch pop exch pop} if \n", + " /w1 exch length def \n", + " w1 0 ne { \n", + " newdict /DataSource ", + " pix x crpp mul w1 crpp mul getinterval put \n", + " newdict /Width w1 put \n", + " mat 4 x neg put \n", + " /x x w1 add def \n", + " newdict image \n", + " /tail tail w1 tail length w1 sub getinterval def \n", + " } if \n", + " done {exit} if \n", + " tail substrs { \n", + " anchorsearch {pop} if \n", + " } forall \n", + " /tail exch def \n", + " tail length 0 eq {exit} if \n", + " /x w tail length sub def \n", + " } loop \n", + " } for \n", + " end \n", + " grestore \n", + "} bind def \n\n\n", (char *) NULL); + } else if( !codeIncluded && (colorLevel == 0) ) { + /* + * Monochrome-only code + */ + + codeIncluded = !0; + Tcl_AppendResult( interp, + "/TkPhoto { \n", + " gsave \n", + " 32 dict begin \n", + " /dummyInteger exch def \n", + " /olddict exch def \n", + " olddict /DataSource get dup type /filetype ne { \n", + " olddict /DataSource 3 -1 roll \n", + " 0 () /SubFileDecode filter put \n", + " } { \n", + " pop \n", + " } ifelse \n", + " /newdict olddict maxlength dict def \n", + " olddict newdict copy pop \n", + " /w newdict /Width get def \n", + " /pix w 7 add 8 idiv string def \n", + " /h newdict /Height get def \n", + " 1 w div 1 h div matrix scale \n", + " olddict /ImageMatrix get exch matrix concatmatrix \n", + " matrix invertmatrix concat \n", + " newdict /Height 1 put \n", + " newdict /DataSource pix put \n", + " /mat [w 0 0 h 0 0] def \n", + " newdict /ImageMatrix mat put \n", + " 0 1 h 1 sub { \n", + " mat 5 3 -1 roll neg put \n", + " 0.000 0.000 0.000 setrgbcolor \n", + " olddict /DataSource get pix readstring pop pop \n", + " newdict /DataSource pix put \n", + " newdict imagemask \n", + " 1.000 1.000 1.000 setrgbcolor \n", + " olddict /DataSource get pix readstring pop pop \n", + " newdict /DataSource pix put \n", + " newdict imagemask \n", + " } for \n", + " end \n", + " grestore \n", + "} bind def \n\n\n", (char *) NULL); + } + + /* + * Check that at least one row of the image can be represented + * with a string less than 64 KB long (this is a limit in the + * Postscript interpreter). + */ + + switch (colorLevel) + { + case 0: bytesPerLine = (width + 7) / 8; maxWidth = 240000; break; + case 1: bytesPerLine = width; maxWidth = 60000; break; + case 2: bytesPerLine = 3 * width; maxWidth = 20000; break; + } + if (bytesPerLine > 60000) { + Tcl_ResetResult(interp); + sprintf(buffer, + "Can't generate Postscript for images more than %d pixels wide", + maxWidth); + Tcl_AppendResult(interp, buffer, (char *) NULL); + return TCL_ERROR; + } + + /* + * Set up the postscript code except for the image-data stream. + */ + + switch (colorLevel) { + case 0: + strcpy( cspace, "/DeviceGray"); + strcpy( decode, "[1 0]"); + bpc = 1; + break; + case 1: + strcpy( cspace, "/DeviceGray"); + strcpy( decode, "[0 1]"); + bpc = 8; + break; + default: + strcpy( cspace, "/DeviceRGB"); + strcpy( decode, "[0 1 0 1 0 1]"); + bpc = 8; + break; + } + + + Tcl_AppendResult(interp, + cspace, " setcolorspace\n\n", (char *) NULL); + + sprintf(buffer, + " /Width %d\n /Height %d\n /BitsPerComponent %d\n", + width, height, bpc); + Tcl_AppendResult(interp, + "<<\n /ImageType 1\n", buffer, + " /DataSource currentfile", + " /ASCIIHexDecode filter\n", (char *) NULL); + + + sprintf(buffer, + " /ImageMatrix [1 0 0 -1 0 %d]\n", height); + Tcl_AppendResult(interp, buffer, + " /Decode ", decode, "\n>>\n1 TkPhoto\n", (char *) NULL); + + + /* + * Check the PhotoImageBlock information. + * We assume that: + * if pixelSize is 1,2 or 4, the image is R,G,B,A; + * if pixelSize is 3, the image is R,G,B and offset[3] is bogus. + */ + + if (blockPtr->pixelSize == 3) { + /* + * No alpha information: the whole image is opaque. + */ + + alphaPtr = &opaque; + alphaPitch = alphaIncr = alphaOffset = 0; + } else { + /* + * Set up alpha handling. + */ + + alphaPtr = blockPtr->pixelPtr; + alphaPitch = blockPtr->pitch; + alphaIncr = blockPtr->pixelSize; + alphaOffset = blockPtr->offset[3]; + } + + + for (yy = 0, lineLen=0; yy < height; yy++) { + switch (colorLevel) { + case 0: { + /* + * Generate data for image in monochrome mode. + * No attempt at dithering is made--instead, just + * set a threshold. + * To handle transparecies we need to output two lines: + * one for the black pixels, one for the white ones. + */ + + unsigned char mask=0x80; + unsigned char data=0x00; + for (xx = 0; xx< width; xx ++) { + pixelPtr = blockPtr->pixelPtr + + (yy * blockPtr->pitch) + + (xx *blockPtr->pixelSize); + + red = pixelPtr[blockPtr->offset[0]]; + green = pixelPtr[blockPtr->offset[1]]; + blue = pixelPtr[blockPtr->offset[2]]; + + alpha = *(alphaPtr + (yy * alphaPitch) + + (xx * alphaIncr) + alphaOffset); + + /* + * If pixel is less than threshold, then it is black. + */ + + if ((alpha != 0) && + ( 0.3086 * red + + 0.6094 * green + + 0.082 * blue < 128)) { + data |= mask; + } + mask >>= 1; + if (mask == 0) { + sprintf(buffer, "%02X", data); + Tcl_AppendResult(interp, buffer, (char *) NULL); + lineLen += 2; + if (lineLen >= 60) { + lineLen = 0; + Tcl_AppendResult(interp, "\n", (char *) NULL); + } + mask=0x80; + data=0x00; + } + } + if ((width % 8) != 0) { + sprintf(buffer, "%02X", data); + Tcl_AppendResult(interp, buffer, (char *) NULL); + mask=0x80; + data=0x00; + } + + mask=0x80; + data=0x00; + for (xx = 0; xx< width; xx ++) { + pixelPtr = blockPtr->pixelPtr + + (yy * blockPtr->pitch) + + (xx *blockPtr->pixelSize); + + red = pixelPtr[blockPtr->offset[0]]; + green = pixelPtr[blockPtr->offset[1]]; + blue = pixelPtr[blockPtr->offset[2]]; + + alpha = *(alphaPtr + (yy * alphaPitch) + + (xx * alphaIncr) + alphaOffset); + + /* + * If pixel is greater than threshold, then it is white. + */ + + if ((alpha != 0) && + ( 0.3086 * red + + 0.6094 * green + + 0.082 * blue >= 128)) { + data |= mask; + } + mask >>= 1; + if (mask == 0) { + sprintf(buffer, "%02X", data); + Tcl_AppendResult(interp, buffer, (char *) NULL); + lineLen += 2; + if (lineLen >= 60) { + lineLen = 0; + Tcl_AppendResult(interp, "\n", (char *) NULL); + } + mask=0x80; + data=0x00; + } + } + if ((width % 8) != 0) { + sprintf(buffer, "%02X", data); + Tcl_AppendResult(interp, buffer, (char *) NULL); + mask=0x80; + data=0x00; + } + break; + } + case 1: { + /* + * Generate transparency data. + * We must prevent a transparent value of 0 + * because of a bug in some HP printers. + */ + + for (xx = 0; xx < width; xx ++) { + alpha = *(alphaPtr + (yy * alphaPitch) + + (xx * alphaIncr) + alphaOffset); + sprintf(buffer, "%02X", alpha | 0x01); + Tcl_AppendResult(interp, buffer, (char *) NULL); + lineLen += 2; + if (lineLen >= 60) { + lineLen = 0; + Tcl_AppendResult(interp, "\n", (char *) NULL); + } + } + + + /* + * Generate data in gray mode--in this case, take a + * weighted sum of the red, green, and blue values. + */ + + for (xx = 0; xx < width; xx ++) { + pixelPtr = blockPtr->pixelPtr + + (yy * blockPtr->pitch) + + (xx *blockPtr->pixelSize); + + red = pixelPtr[blockPtr->offset[0]]; + green = pixelPtr[blockPtr->offset[1]]; + blue = pixelPtr[blockPtr->offset[2]]; + + sprintf(buffer, "%02X", (int) floor(0.5 + + ( 0.3086 * red + 0.6094 * green + 0.0820 * blue))); + Tcl_AppendResult(interp, buffer, (char *) NULL); + lineLen += 2; + if (lineLen >= 60) { + lineLen = 0; + Tcl_AppendResult(interp, "\n", (char *) NULL); + } + } + break; + } + default: { + /* + * Generate transparency data. + * We must prevent a transparent value of 0 + * because of a bug in some HP printers. + */ + + for (xx = 0; xx < width; xx ++) { + alpha = *(alphaPtr + (yy * alphaPitch) + + (xx * alphaIncr) + alphaOffset); + sprintf(buffer, "%02X", alpha | 0x01); + Tcl_AppendResult(interp, buffer, (char *) NULL); + lineLen += 2; + if (lineLen >= 60) { + lineLen = 0; + Tcl_AppendResult(interp, "\n", (char *) NULL); + } + } + + + /* + * Finally, color mode. Here, just output the red, green, + * and blue values directly. + */ + + for (xx = 0; xx < width; xx ++) { + pixelPtr = blockPtr->pixelPtr + + (yy * blockPtr->pitch) + + (xx *blockPtr->pixelSize); + + sprintf(buffer, "%02X%02X%02X", + pixelPtr[blockPtr->offset[0]], + pixelPtr[blockPtr->offset[1]], + pixelPtr[blockPtr->offset[2]]); + Tcl_AppendResult(interp, buffer, (char *) NULL); + lineLen += 6; + if (lineLen >= 60) { + lineLen = 0; + Tcl_AppendResult(interp, "\n", (char *) NULL); + } + } + break; + } + } + } + + Tcl_AppendResult(interp, ">\n", (char *) NULL); + return TCL_OK; +} |