/* * tkImgPS.c -- * * A photo image file handler for postscript files. * */ /* Author : Jan Nijtmans */ /* Date : 7/24/97 */ #include #include #include "imgInt.h" /* * The format record for the PS file format: */ static int ChanMatchPS _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Channel chan, CONST char *fileName, Tcl_Obj *format, int *widthPtr, int *heightPtr)); static int ObjMatchPS _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *dataObj, Tcl_Obj *format, int *widthPtr, int *heightPtr)); static int ChanMatchPDF _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Channel chan, CONST char *fileName, Tcl_Obj *format, int *widthPtr, int *heightPtr)); static int ObjMatchPDF _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *dataObj, Tcl_Obj *format, int *widthPtr, int *heightPtr)); static int ChanReadPS _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Channel chan, CONST char *fileName, Tcl_Obj *format, Tk_PhotoHandle imageHandle, int destX, int destY, int width, int height, int srcX, int srcY)); static int ObjReadPS _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *dataObj, Tcl_Obj *format, Tk_PhotoHandle imageHandle, int destX, int destY, int width, int height, int srcX, int srcY)); static int ChanReadPDF _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Channel chan, CONST char *fileName, Tcl_Obj *format, Tk_PhotoHandle imageHandle, int destX, int destY, int width, int height, int srcX, int srcY)); static int ObjReadPDF _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *dataObj, Tcl_Obj *format, Tk_PhotoHandle imageHandle, int destX, int destY, int width, int height, int srcX, int srcY)); static int ChanWritePS _ANSI_ARGS_((Tcl_Interp *interp, CONST char *filename, Tcl_Obj *format, Tk_PhotoImageBlock *blockPtr)); static int StringWritePS _ANSI_ARGS_((Tcl_Interp *interp, Tcl_DString *dataPtr, Tcl_Obj *format, Tk_PhotoImageBlock *blockPtr)); Tk_PhotoImageFormat imgFmtPS = { "postscript", /* name */ (Tk_ImageFileMatchProc *) ChanMatchPS, /* fileMatchProc */ (Tk_ImageStringMatchProc *) ObjMatchPS, /* stringMatchProc */ (Tk_ImageFileReadProc *) ChanReadPS, /* fileReadProc */ (Tk_ImageStringReadProc *) ObjReadPS, /* stringReadProc */ (Tk_ImageFileWriteProc *) ChanWritePS, /* fileWriteProc */ (Tk_ImageStringWriteProc *) StringWritePS, /* stringWriteProc */ }; Tk_PhotoImageFormat imgFmtPDF = { "pdf", /* name */ (Tk_ImageFileMatchProc *) ChanMatchPDF, /* fileMatchProc */ (Tk_ImageStringMatchProc *) ObjMatchPDF, /* stringMatchProc */ (Tk_ImageFileReadProc *) ChanReadPDF, /* fileReadProc */ (Tk_ImageStringReadProc *) ObjReadPDF, /* stringReadProc */ (Tk_ImageFileWriteProc *) ChanWritePS, /* fileWriteProc */ (Tk_ImageStringWriteProc *) StringWritePS, /* stringWriteProc */ }; /* * Prototypes for local procedures defined in this file: */ static int CommonMatchPS _ANSI_ARGS_((MFile *handle, Tcl_Obj *format, int *widthPtr, int *heightPtr)); static int CommonMatchPDF _ANSI_ARGS_((MFile *handle, Tcl_Obj *format, int *widthPtr, int *heightPtr)); static int CommonReadPS _ANSI_ARGS_((Tcl_Interp *interp, MFile *handle, Tcl_Obj *format, Tk_PhotoHandle imageHandle, int destX, int destY, int width, int height, int srcX, int srcY)); static int CommonWritePS _ANSI_ARGS_((Tcl_Interp *interp, MFile *handle, Tcl_Obj *format, Tk_PhotoImageBlock *blockPtr)); static int parseFormat _ANSI_ARGS_((Tcl_Obj *format, int *zoomx, int *zoomy)); static int parseFormat(format, zoomx, zoomy) Tcl_Obj *format; int *zoomx; int *zoomy; { int objc, i, length, index = 0; Tcl_Obj **objv = NULL; char *p; double zx = 1.0, zy = 1.0; if (!format) { *zoomx = (int) (72 * zx + 0.5); *zoomy = (int) (72 * zy + 0.5); } if (ImgListObjGetElements((Tcl_Interp*) NULL, format, &objc, &objv) != TCL_OK) { return -1; } for (i=1; i objc) { zy = zx; } else { p = Tcl_GetStringFromObj(objv[i+1], &length); if (p[0] != '-') { if (Tcl_GetDoubleFromObj((Tcl_Interp *) NULL, objv[++i], &zy) != TCL_OK) { index = -1; break; } } else { zy = zx; } } } else { index = -1; break; } } else { if (Tcl_GetIntFromObj((Tcl_Interp *) NULL, objv[++i], &index) != TCL_OK) { index = -1; break; } } } if (!index) { *zoomx = (int) (72 * zx + 0.5); *zoomy = (int) (72 * zy + 0.5); } return index; } static int ChanMatchPS(interp, chan, fileName, format, widthPtr, heightPtr) Tcl_Interp *interp; Tcl_Channel chan; CONST char *fileName; Tcl_Obj *format; int *widthPtr, *heightPtr; { MFile handle; ImgFixChanMatchProc(&interp, &chan, &fileName, &format, &widthPtr, &heightPtr); handle.data = (char *) chan; handle.state = IMG_CHAN; return CommonMatchPS(&handle, format, widthPtr, heightPtr); } static int ObjMatchPS(interp, data, format, widthPtr, heightPtr) Tcl_Interp *interp; Tcl_Obj *data; Tcl_Obj *format; int *widthPtr, *heightPtr; { MFile handle; ImgFixObjMatchProc(&interp, &data, &format, &widthPtr, &heightPtr); handle.data = ImgGetStringFromObj(data, &handle.length); handle.state = IMG_STRING; return CommonMatchPS(&handle, format, widthPtr, heightPtr); } static int CommonMatchPS(handle, format, widthPtr, heightPtr) MFile *handle; Tcl_Obj *format; int *widthPtr, *heightPtr; { unsigned char buf[41]; if ((ImgRead(handle, (char *) buf, 11) != 11) || (strncmp("%!PS-Adobe-", (char *) buf, 11) != 0)) { return 0; } while (ImgRead(handle,(char *) buf, 1) == 1) { if (buf[0] == '%' && (ImgRead(handle, (char *) buf, 2) == 2) && (!memcmp(buf, "%B", 2) && (ImgRead(handle, (char *) buf, 11) == 11) && (!memcmp(buf, "oundingBox:", 11)) && (ImgRead(handle, (char *) buf, 40) == 40))) { int w, h, zoomx, zoomy; char *p = buf; buf[41] = 0; w = - (int) strtoul(p, &p, 0); h = - (int) strtoul(p, &p, 0); w += strtoul(p, &p, 0); h += strtoul(p, &p, 0); if (parseFormat(format, &zoomx, &zoomy) >= 0) { w = (w * zoomx + 36) / 72; h = (h * zoomy + 36) / 72; } if ((w <= 0) || (h <= 0)) return 0; *widthPtr = w; *heightPtr = h; return 1; } } return 0; } static int ChanReadPS(interp, chan, fileName, format, imageHandle, destX, destY, width, height, srcX, srcY) Tcl_Interp *interp; Tcl_Channel chan; CONST char *fileName; Tcl_Obj *format; Tk_PhotoHandle imageHandle; int destX, destY; int width, height; int srcX, srcY; { MFile handle; handle.data = (char *) chan; handle.state = IMG_CHAN; return CommonReadPS(interp, &handle, format, imageHandle, destX, destY, width, height, srcX, srcY); } static int ObjReadPS(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; { MFile handle; ImgReadInit(data,'%',&handle); return CommonReadPS(interp, &handle, format, imageHandle, destX, destY, width, height, srcX, srcY); } typedef struct myblock { Tk_PhotoImageBlock ck; int dummy; /* extra space for offset[3], in case it is not included already in Tk_PhotoImageBlock */ } myblock; #define block bl.ck static int CommonReadPS(interp, handle, format, imageHandle, destX, destY, width, height, srcX, srcY) Tcl_Interp *interp; MFile *handle; Tcl_Obj *format; Tk_PhotoHandle imageHandle; int destX, destY; int width, height; int srcX, srcY; { #ifndef MAC_TCL const char *argv[10]; int len, i, j, fileWidth, fileHeight, maxintensity, index; char *p, type; unsigned char buffer[1025], *line = NULL, *line3 = NULL; char zoom[64], papersize[64]; Tcl_Channel chan; Tcl_DString dstring; myblock bl; int zoomx, zoomy; index = parseFormat(format, &zoomx, &zoomy); if (index < 0) { Tcl_AppendResult(interp, "invalid format: \"", ImgGetStringFromObj(format, NULL), "\"", (char *) NULL); return TCL_ERROR; } sprintf(zoom, "-r%dx%d", zoomx, zoomy); len = ImgRead(handle, buffer, 1024); buffer[1024] = 0; p = strstr(buffer,"%%BoundingBox:"); fileHeight = height + srcY; if (p) { /* postscript */ p += 14; srcX += (strtoul(p, &p, 0) * zoomx + 36) / 72; fileHeight += (strtoul(p, &p, 0) * zoomy + 36) / 72; strtoul(p, &p, 0); srcY -= (strtoul(p, &p, 0) * zoomy + 36) / 72; } else { /* pdf */ /* * Extract the pixel position of the upper left corner * of the image from the file. How to do that???? * For now I just assume A4-size with 72 pixels/inch. */ srcX += (0 * zoomx + 36) / 72; srcY -= (792 * zoomy + 36) /72; } sprintf(papersize, "-g%dx%d", srcX+width, fileHeight); argv[0] = "gs"; argv[1] = "-sDEVICE=ppmraw"; argv[2] = zoom; argv[3] = papersize; argv[4] = "-q"; argv[5] = "-dNOPAUSE"; argv[6] = "-sOutputFile=-"; argv[7] = "-"; chan = Tcl_OpenCommandChannel(interp, 8, argv, TCL_STDIN|TCL_STDOUT|TCL_STDERR|TCL_ENFORCE_MODE); if (!chan) { return TCL_ERROR; } if (Tcl_SetChannelOption(interp, chan, "-translation", "binary") != TCL_OK) { return TCL_ERROR; } while (len > 0) { Tcl_Write(chan, (char *) buffer, 1024); len = ImgRead(handle, buffer, 1024); } Tcl_Write(chan,"\nquit\n", 6); Tcl_Flush(chan); Tcl_DStringInit(&dstring); len = Tcl_Gets(chan, &dstring); p = Tcl_DStringValue(&dstring); type = p[1]; if ((p[0] != 'P') || (type < '4') || (type > '6')) { Tcl_AppendResult(interp, "gs error: \"", p, "\"",(char *) NULL); return TCL_ERROR; } do { Tcl_DStringSetLength(&dstring, 0); Tcl_Gets(chan, &dstring); p = Tcl_DStringValue(&dstring); } while (p[0] == '#'); fileWidth = strtoul(p, &p, 0); srcY += (fileHeight = strtoul(p, &p, 0)); if ((srcX + width) > fileWidth) { width = fileWidth - srcX; } if ((srcY + height) > fileHeight) { height = fileHeight - srcY; } if ((width <= 0) || (height <= 0)) { Tcl_Close(interp, chan); Tcl_DStringFree(&dstring); return TCL_OK; } Tk_PhotoExpand(imageHandle, destX + width, destY + height); maxintensity = strtoul(p, &p, 0); if ((type != '4') && !maxintensity) { Tcl_DStringSetLength(&dstring, 0); Tcl_Gets(chan, &dstring); p = Tcl_DStringValue(&dstring); maxintensity = strtoul(p, &p, 0); } Tcl_DStringFree(&dstring); line3 = (unsigned char *) ckalloc(3 * fileWidth); block.pixelSize = 1; block.pitch = block.width = width; block.height = 1; block.offset[0] = 0; block.offset[1] = 0; block.offset[2] = 0; block.offset[3] = 0; switch(type) { case '4': i = (fileWidth+7)/8; line = (unsigned char *) ckalloc(i); while (srcY-- > 0) { Tcl_Read(chan,(char *) line, i); } block.pixelPtr = line3; while (height--) { Tcl_Read(chan, (char *) line, i); for (j = 0; j < width; j++) { line3[j] = ((line[(j+srcX)/8]>>(7-(j+srcX)%8) & 1)) ? 0 : 255; } Tk_PhotoPutBlock(imageHandle, &block, destX, destY++, width, 1, TK_PHOTO_COMPOSITE_SET); } break; case '5': line = (unsigned char *) ckalloc(fileWidth); while (srcY-- > 0) { Tcl_Read(chan, (char *) line, fileWidth); } block.pixelPtr = line + srcX; while (height--) { unsigned char *c = block.pixelPtr; Tcl_Read(chan, (char *) line, fileWidth); if (maxintensity != 255) { for (j = width; j > 0; j--) { *c = (((int)*c) * maxintensity) / 255; c++; } } Tk_PhotoPutBlock(imageHandle, &block, destX, destY++, width, 1, TK_PHOTO_COMPOSITE_SET); } break; case '6': i = 3 * fileWidth; line = NULL; while (srcY-- > 0) { Tcl_Read(chan, (char *) line3, i); } block.pixelPtr = line3 + (3 * srcX); block.pixelSize = 3; block.offset[1] = 1; block.offset[2] = 2; while (height--) { unsigned char *c = block.pixelPtr; Tcl_Read(chan, (char *) line3, i); if (maxintensity != 255) { for (j = (3 * width - 1); j >= 0; j--) { *c = (((int)*c) * maxintensity) / 255; c++; } } Tk_PhotoPutBlock(imageHandle, &block, destX, destY++, width, 1, TK_PHOTO_COMPOSITE_SET); } break; } if (line) { ckfree((char *) line); } ckfree((char *) line3); Tcl_Close(interp, chan); Tcl_ResetResult(interp); return TCL_OK; #else Tcl_AppendResult(interp, "Cannot read postscript file: not implemented", (char *) NULL); return TCL_ERROR; #endif } static int ChanReadPDF(interp, chan, fileName, format, imageHandle, destX, destY, width, height, srcX, srcY) Tcl_Interp *interp; Tcl_Channel chan; CONST char *fileName; Tcl_Obj *format; Tk_PhotoHandle imageHandle; int destX, destY; int width, height; int srcX, srcY; { return ChanReadPS(interp, chan, fileName, format, imageHandle, destX, destY, width, height, srcX, srcY); } static int ObjReadPDF(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; { return ObjReadPS(interp, data, format, imageHandle, destX, destY, width, height, srcX, srcY); } static int ChanWritePS(interp, filename, format, blockPtr) Tcl_Interp *interp; CONST char *filename; Tcl_Obj *format; Tk_PhotoImageBlock *blockPtr; { Tcl_Channel chan; MFile handle; int result; chan = ImgOpenFileChannel(interp, filename, 0644); if (!chan) { return TCL_ERROR; } handle.data = (char *) chan; handle.state = IMG_CHAN; result = CommonWritePS(interp, &handle, format, blockPtr); if (Tcl_Close(interp, chan) == TCL_ERROR) { return TCL_ERROR; } return result; } static int StringWritePS(interp, dataPtr, format, blockPtr) Tcl_Interp *interp; Tcl_DString *dataPtr; Tcl_Obj *format; Tk_PhotoImageBlock *blockPtr; { MFile handle; int result; Tcl_DString data; ImgFixStringWriteProc(&data, &interp, &dataPtr, &format, &blockPtr); ImgWriteInit(dataPtr, &handle); result = CommonWritePS(interp, &handle, format, blockPtr); ImgPutc(IMG_DONE, &handle); if ((result == TCL_OK) && (dataPtr == &data)) { Tcl_DStringResult(interp, dataPtr); } return result; } static int CommonWritePS(interp, handle, format, blockPtr) Tcl_Interp *interp; MFile *handle; Tcl_Obj *format; Tk_PhotoImageBlock *blockPtr; { return TCL_OK; } static int ChanMatchPDF(interp, chan, fileName, format, widthPtr, heightPtr) Tcl_Interp *interp; Tcl_Channel chan; CONST char *fileName; Tcl_Obj *format; int *widthPtr, *heightPtr; { MFile handle; ImgFixChanMatchProc(&interp, &chan, &fileName, &format, &widthPtr, &heightPtr); handle.data = (char *) chan; handle.state = IMG_CHAN; return CommonMatchPDF(&handle, format, widthPtr, heightPtr); } static int ObjMatchPDF(interp, data, format, widthPtr, heightPtr) Tcl_Interp *interp; Tcl_Obj *data; Tcl_Obj *format; int *widthPtr, *heightPtr; { MFile handle; ImgFixObjMatchProc(&interp, &data, &format, &widthPtr, &heightPtr); if (!ImgReadInit(data, '%', &handle)) { return 0; } return CommonMatchPDF(&handle, format, widthPtr, heightPtr); } static int CommonMatchPDF(handle, format, widthPtr, heightPtr) MFile *handle; Tcl_Obj *format; int *widthPtr, *heightPtr; { unsigned char buf[41]; int zoomx, zoomy, w, h; if ((ImgRead(handle, (char *) buf, 5) != 5) || (strncmp("%PDF-", (char *) buf, 5) != 0)) { return 0; } /* Here w and h should be set to the bounding box of the pdf * data. But I don't know how to extract that from the file. * For now I just assume A4-size with 72 pixels/inch. If anyone * has a better idea, please mail to . */ w = 612/10; h = 792/10; if (parseFormat(format, &zoomx, &zoomy) >= 0) { w = (w * zoomx + 36) / 72; h = (h * zoomy + 36) / 72; } if ((w <= 0) || (h <= 0)) return 0; *widthPtr = w; *heightPtr = h; return 1; }