/*
* tkImgPS.c --
*
* A photo image file handler for postscript files.
*
*/
/* Author : Jan Nijtmans */
/* Date : 7/24/97 */
#include <string.h>
#include <stdlib.h>
#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; i++) {
p = Tcl_GetStringFromObj(objv[i], &length);
if ((p[0] == '-') && ((i+1)<objc)) {
if (length < 2) {
index = -1; break;
}
if (!strncmp(p,"-index", length)) {
if (Tcl_GetIntFromObj((Tcl_Interp *) NULL, objv[++i], &index) != TCL_OK) {
index = -1; break;
}
} else if (!strncmp(p, "-zoom", length)) {
if (Tcl_GetDoubleFromObj((Tcl_Interp *) NULL, objv[++i], &zx) != TCL_OK) {
index = -1; break;
}
if (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
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);
}
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);
}
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);
}
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 <j.nijtmans@chello.nl>.
*/
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;
}