summaryrefslogtreecommitdiff
path: root/blt/src/bltCanvEps.c
diff options
context:
space:
mode:
Diffstat (limited to 'blt/src/bltCanvEps.c')
-rw-r--r--blt/src/bltCanvEps.c1742
1 files changed, 1742 insertions, 0 deletions
diff --git a/blt/src/bltCanvEps.c b/blt/src/bltCanvEps.c
new file mode 100644
index 00000000000..319f1d0b829
--- /dev/null
+++ b/blt/src/bltCanvEps.c
@@ -0,0 +1,1742 @@
+/*
+ * bltCanvEps.c --
+ *
+ * This file implements Encapsulated PostScript items for canvas widgets.
+ *
+ * Copyright 1991-1998 Lucent Technologies, Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that the above copyright notice appear in all
+ * copies and that both that the copyright notice and warranty
+ * disclaimer appear in supporting documentation, and that the names
+ * of Lucent Technologies any of their entities not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission.
+ *
+ * Lucent Technologies disclaims all warranties with regard to this
+ * software, including all implied warranties of merchantability and
+ * fitness. In no event shall Lucent Technologies be liable for any
+ * special, indirect or consequential damages or any damages
+ * whatsoever resulting from loss of use, data or profits, whether in
+ * an action of contract, negligence or other tortuous action, arising
+ * out of or in connection with the use or performance of this
+ * software.
+ *
+ * EPS canvas item created by George Howlett.
+ */
+
+/*
+ * To do:
+ *
+ * 1. Add -rotate option. Allow arbitrary rotation of image and EPS.
+ * 2. Draw color images instead of photos. This will eliminate the need
+ * to create hidden photo images.
+ * 3. Create a spiffy demo that lets you edit your page description.
+ */
+#include "bltInt.h"
+#include "bltPs.h"
+#include "bltImage.h"
+
+#ifdef HAVE_TIFF_H
+#include "tiff.h"
+#endif
+#include <fcntl.h>
+
+#ifdef WIN32
+#include <io.h>
+#define open _open
+#define close _close
+#define write _write
+#define unlink _unlink
+#define lseek _lseek
+#define fdopen _fdopen
+#define fcntl _fcntl
+#define O_RDWR _O_RDWR
+#define O_CREAT _O_CREAT
+#define O_TRUNC _O_TRUNC
+#define O_EXCL _O_EXCL
+#endif
+
+#define DEBUG_READER 0
+#define PS_PREVIEW_EPSI 0
+#define PS_PREVIEW_WMF 1
+#define PS_PREVIEW_TIFF 2
+
+#define xLeft header.x1
+#define xRight header.x2
+#define yTop header.y1
+#define yBottom header.y2
+
+
+#define MAX_EPS_LINE_LENGTH 255 /* Maximum line length for a EPS file */
+
+/*
+ * ParseInfo --
+ *
+ * This structure is used to pass PostScript file information
+ * around to various routines while parsing the EPS file.
+ */
+typedef struct {
+ int maxBytes; /* Maximum length of PostScript code. */
+ int lineNumber; /* Current line number of EPS file */
+ char line[MAX_EPS_LINE_LENGTH + 1];
+ /* Buffer to contain a single line from
+ * the PostScript file. */
+ char hexTable[256]; /* Table for converting ASCII hex digits to
+ * values */
+
+ char *nextPtr; /* Pointer to the next character to process on
+ * the current line. If NULL (or if nextPtr
+ * points a NULL byte), this indicates the
+ * the next line needs to be read. */
+ FILE *f; /* */
+} ParseInfo;
+
+#define DEF_EPS_ANCHOR "nw"
+#define DEF_EPS_OUTLINE_COLOR RGB_BLACK
+#define DEF_EPS_OUTLINE_MONO RGB_BLACK
+#define DEF_EPS_BORDER_WIDTH STD_BORDERWIDTH
+#define DEF_EPS_FILE_NAME (char *)NULL
+#define DEF_EPS_FONT STD_FONT
+#define DEF_EPS_FILL_COLOR STD_COLOR_NORMAL_FG
+#define DEF_EPS_FILL_MONO STD_MONO_NORMAL_FG
+#define DEF_EPS_HEIGHT "0"
+#define DEF_EPS_IMAGE_NAME (char *)NULL
+#define DEF_EPS_JUSTIFY "center"
+#define DEF_EPS_QUICK_RESIZE "no"
+#define DEF_EPS_RELIEF "sunken"
+#define DEF_EPS_SHADOW_COLOR (char *)NULL
+#define DEF_EPS_SHADOW_MONO (char *)NULL
+#define DEF_EPS_SHOW_IMAGE "yes"
+#define DEF_EPS_STIPPLE (char *)NULL
+#define DEF_EPS_TAGS (char *)NULL
+#define DEF_EPS_TITLE (char *)NULL
+#define DEF_EPS_TITLE_ANCHOR "center"
+#define DEF_EPS_TITLE_COLOR RGB_BLACK
+#define DEF_EPS_TITLE_ROTATE "0"
+#define DEF_EPS_WIDTH "0"
+
+/*
+ * Information used for parsing configuration specs:
+ */
+
+static Tk_CustomOption tagsOption;
+
+extern Tk_CustomOption bltDistanceOption;
+extern Tk_CustomOption bltShadowOption;
+
+/*
+ * The structure below defines the record for each EPS item.
+ */
+typedef struct {
+ Tk_Item header; /* Generic stuff that's the same for all
+ * types. MUST BE FIRST IN STRUCTURE. */
+ Tk_Canvas canvas; /* Canvas containing the EPS item. */
+
+ int canvasX, canvasY; /* Translated (by the anchor) canvas
+ * coordinates of the EPS item. */
+
+ int lastWidth, lastHeight; /* Last known dimensions of the EPS item.
+ * This is used to know if the color image
+ * preview needs to be resized. */
+
+ Tcl_Interp *interp;
+
+ FILE *psFile; /* File pointer to Encapsulated
+ * PostScript file. We'll hold this as
+ * long as the EPS item is using this
+ * file. */
+ size_t psStart; /* File offset of PostScript code. */
+ size_t psLength; /* Length of PostScript code. If zero,
+ * indicates to read to EOF. */
+ size_t wmfStart; /* File offset of Windows Metafile preview. */
+ size_t wmfLength; /* Length of WMF portion in bytes. If zero,
+ * indicates there is no WMF preview. */
+ size_t tiffStart; /* File offset of TIFF preview. */
+ size_t tiffLength; /* Length of TIFF portion in bytes. If zero,
+ * indicates there is no TIFF preview. */
+ char *previewName;
+ int previewFormat;
+
+ Tk_Image preview; /* A Tk photo image provided as a
+ * preview of the EPS contents. This
+ * image supersedes any EPS preview
+ * embedded PostScript preview (EPSI). */
+
+ Tk_Image tmpImage; /* Used to display the resized preview image.
+ * Created and deleted internally. */
+
+
+ Pixmap pixmap; /* Pixmap representing scaled preview. This
+ * isn't currently used. For now we're
+ * overwriting the Tk image everytime the
+ * EPS item is resized. In the future
+ * we'll use our own image routines. */
+
+ ColorTable colorTable; /* Pointer to color table */
+
+ Blt_Colorimage colorImage; /* The original photo or PostScript
+ * preview image converted to a color
+ * image. This is kept around for
+ * resampling or resizing the image. */
+
+ unsigned int firstLine, lastLine;
+ /* First and last line numbers of the
+ * PostScript preview. They are used
+ * to skip over the preview when
+ * encapsulating PostScript for the
+ * canvas item. */
+
+ GC fillGC; /* Graphics context to fill background
+ * of image outline if no preview image
+ * was present. */
+
+ int llx, lly, urx, ury; /* Lower left and upper right coordinates
+ * of PostScript bounding box, retrieved
+ * from file's "BoundingBox:" field. */
+
+ char *title; /* Title, retrieved from the file's "Title:"
+ * field, to be displayed over the top of
+ * the EPS preview (malloc-ed). */
+
+ Tcl_DString dString; /* Contains the encapsulate PostScript. */
+
+ /* User configurable fields */
+
+ double x, y; /* Canvas coordinates of the item */
+ Tk_Anchor anchor;
+
+ char *fileName; /* Name of the encapsulated PostScript file.
+ * If NULL, indicates that no EPS file
+ * has be successfully loaded yet. */
+
+ char *reqTitle; /* Title to be displayed in the EPS item.
+ * Supersedes the title found in the EPS
+ * file. If NULL, indicates that the title
+ * found in the EPS file should be used. */
+
+ int width, height; /* Dimensions of EPS item. If set to zero,
+ * the dimension found in the "%%BoundingBox:"
+ * specification from the EPS file are
+ * used. */
+
+ int showImage; /* Indicates if the image or the outline
+ * rectangle should be displayed */
+
+ int quick;
+
+ XColor *fillColor; /* Fill color of the image outline. */
+
+ Tk_3DBorder border; /* Outline color */
+
+ int borderWidth;
+ int relief;
+
+ TextStyle titleStyle; /* Font, color, etc. for title */
+
+ Pixmap stipple; /* Stipple for image fill */
+
+ ClientData tiffPtr;
+#ifdef WIN32
+ HENHMETAFILE *hMetaFile; /* Windows metafile. */
+#endif
+} EpsItem;
+
+static Tk_ConfigSpec configSpecs[] =
+{
+ {TK_CONFIG_ANCHOR, "-anchor", (char *)NULL, (char *)NULL,
+ DEF_EPS_ANCHOR, Tk_Offset(EpsItem, anchor),
+ TK_CONFIG_DONT_SET_DEFAULT},
+ {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *)NULL, (char *)NULL, 0, 0},
+ {TK_CONFIG_CUSTOM, "-borderwidth", "borderWidth", (char *)NULL,
+ DEF_EPS_BORDER_WIDTH, Tk_Offset(EpsItem, borderWidth),
+ TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption},
+ {TK_CONFIG_STRING, "-file", (char *)NULL, (char *)NULL,
+ DEF_EPS_FILE_NAME, Tk_Offset(EpsItem, fileName), TK_CONFIG_NULL_OK},
+ {TK_CONFIG_FONT, "-font", "font", "Font",
+ DEF_EPS_FONT, Tk_Offset(EpsItem, titleStyle.font), 0},
+ {TK_CONFIG_COLOR, "-fill", "fill", (char *)NULL,
+ DEF_EPS_FILL_COLOR, Tk_Offset(EpsItem, fillColor), TK_CONFIG_COLOR_ONLY},
+ {TK_CONFIG_COLOR, "-fill", "fill", (char *)NULL,
+ DEF_EPS_FILL_MONO, Tk_Offset(EpsItem, fillColor), TK_CONFIG_MONO_ONLY},
+ {TK_CONFIG_CUSTOM, "-height", (char *)NULL, (char *)NULL,
+ DEF_EPS_HEIGHT, Tk_Offset(EpsItem, height),
+ TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption},
+ {TK_CONFIG_STRING, "-image", (char *)NULL, (char *)NULL,
+ DEF_EPS_IMAGE_NAME, Tk_Offset(EpsItem, previewName),
+ TK_CONFIG_NULL_OK},
+ {TK_CONFIG_JUSTIFY, "-justify", "justify", "Justify",
+ DEF_EPS_JUSTIFY, Tk_Offset(EpsItem, titleStyle.justify),
+ TK_CONFIG_DONT_SET_DEFAULT},
+ {TK_CONFIG_BORDER, "-outline", "outline", (char *)NULL,
+ DEF_EPS_OUTLINE_COLOR, Tk_Offset(EpsItem, border),
+ TK_CONFIG_COLOR_ONLY | TK_CONFIG_NULL_OK},
+ {TK_CONFIG_BORDER, "-outline", "outline", (char *)NULL,
+ DEF_EPS_OUTLINE_MONO, Tk_Offset(EpsItem, border),
+ TK_CONFIG_MONO_ONLY | TK_CONFIG_NULL_OK},
+ {TK_CONFIG_BOOLEAN, "-quick", "quick", "Quick",
+ DEF_EPS_QUICK_RESIZE, Tk_Offset(EpsItem, quick),
+ TK_CONFIG_DONT_SET_DEFAULT},
+ {TK_CONFIG_RELIEF, "-relief", (char *)NULL, (char *)NULL,
+ DEF_EPS_RELIEF, Tk_Offset(EpsItem, relief),
+ TK_CONFIG_DONT_SET_DEFAULT},
+ {TK_CONFIG_CUSTOM, "-shadow", "shadow", "Shadow",
+ DEF_EPS_SHADOW_COLOR, Tk_Offset(EpsItem, titleStyle.shadow),
+ TK_CONFIG_COLOR_ONLY, &bltShadowOption},
+ {TK_CONFIG_CUSTOM, "-shadow", "shadow", "Shadow",
+ DEF_EPS_SHADOW_MONO, Tk_Offset(EpsItem, titleStyle.shadow),
+ TK_CONFIG_MONO_ONLY, &bltShadowOption},
+ {TK_CONFIG_BOOLEAN, "-showimage", "showImage", "ShowImage",
+ DEF_EPS_SHOW_IMAGE, Tk_Offset(EpsItem, showImage),
+ TK_CONFIG_DONT_SET_DEFAULT},
+ {TK_CONFIG_BITMAP, "-stipple", (char *)NULL, (char *)NULL,
+ DEF_EPS_STIPPLE, Tk_Offset(EpsItem, stipple), TK_CONFIG_NULL_OK},
+ {TK_CONFIG_CUSTOM, "-tags", (char *)NULL, (char *)NULL,
+ DEF_EPS_TAGS, 0, TK_CONFIG_NULL_OK, &tagsOption},
+ {TK_CONFIG_STRING, "-title", (char *)NULL, (char *)NULL,
+ DEF_EPS_TITLE, Tk_Offset(EpsItem, reqTitle), TK_CONFIG_NULL_OK},
+ {TK_CONFIG_ANCHOR, "-titleanchor", (char *)NULL, (char *)NULL,
+ DEF_EPS_TITLE_ANCHOR, Tk_Offset(EpsItem, titleStyle.anchor), 0},
+ {TK_CONFIG_COLOR, "-titlecolor", (char *)NULL, (char *)NULL,
+ DEF_EPS_TITLE_COLOR, Tk_Offset(EpsItem, titleStyle.color),
+ TK_CONFIG_COLOR_ONLY},
+ {TK_CONFIG_DOUBLE, "-titlerotate", "titleRotate", "TitleRotate",
+ DEF_EPS_TITLE_ROTATE, Tk_Offset(EpsItem, titleStyle.theta),
+ TK_CONFIG_DONT_SET_DEFAULT},
+ {TK_CONFIG_CUSTOM, "-width", (char *)NULL, (char *)NULL,
+ DEF_EPS_WIDTH, Tk_Offset(EpsItem, width),
+ TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption},
+ {TK_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL,
+ (char *)NULL, 0, 0}
+};
+
+/*
+ * Prototypes for procedures defined in this file:
+ */
+
+static void ImageChangedProc _ANSI_ARGS_((ClientData clientData, int x, int y,
+ int width, int height, int imgWidth, int imgHeight));
+static int EpsCoords _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas,
+ Tk_Item * itemPtr, int argc, char **argv));
+static int EpsToArea _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item * itemPtr,
+ double *rectPtr));
+static double EpsToPoint _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item * itemPtr,
+ double *coordPtr));
+static void ComputeEpsBbox _ANSI_ARGS_((Tk_Canvas canvas, EpsItem *imgPtr));
+static int ConfigureEps _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas,
+ Tk_Item * itemPtr, int argc, char **argv, int flags));
+static int CreateEps _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas,
+ struct Tk_Item * itemPtr, int argc, char **argv));
+static void DeleteEps _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item * itemPtr,
+ Display *display));
+static void DisplayEps _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item * itemPtr,
+ Display *display, Drawable dst, int x, int y, int width, int height));
+static void ScaleEps _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item * itemPtr,
+ double originX, double originY, double scaleX, double scaleY));
+static void TranslateEps _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item * itemPtr,
+ double deltaX, double deltaY));
+static int EpsToPostScript _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas,
+ Tk_Item * itemPtr, int prepass));
+static int ReadPostScript _ANSI_ARGS_((Tcl_Interp *interp, EpsItem *epsPtr));
+
+
+static char *
+SkipBlanks(piPtr)
+ ParseInfo *piPtr;
+{
+ char *s;
+
+ for (s = piPtr->line; isspace(UCHAR(*s)); s++) {
+ /*empty*/
+ }
+ return s;
+}
+
+static int
+ReadPsLine(piPtr)
+ ParseInfo *piPtr;
+{
+ if (ftell(piPtr->f) < piPtr->maxBytes) {
+ if (fgets(piPtr->line, MAX_EPS_LINE_LENGTH, piPtr->f) != NULL) {
+ piPtr->lineNumber++;
+#if DEBUG_READER0
+ PurifyPrintf("%d: %s\n", piPtr->lineNumber, piPtr->line);
+#endif
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * ReverseBits --
+ *
+ * Convert a byte from a X image into PostScript image order.
+ * This requires not only the nybbles to be reversed but also
+ * their bit values.
+ *
+ * Results:
+ * The converted byte is returned.
+ *
+ *----------------------------------------------------------------------
+ */
+INLINE static unsigned char
+ReverseBits(byte)
+ register unsigned char byte;
+{
+ byte = ((byte >> 1) & 0x55) | ((byte << 1) & 0xaa);
+ byte = ((byte >> 2) & 0x33) | ((byte << 2) & 0xcc);
+ byte = ((byte >> 4) & 0x0f) | ((byte << 4) & 0xf0);
+ return byte;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * GetHexValue --
+ *
+ * Reads the next ASCII hex value from EPS preview image and
+ * converts it.
+ *
+ * Results:
+ * One of three Tcl return values is possible.
+ *
+ * TCL_OK the next byte was successfully parsed.
+ * TCL_ERROR an error occurred processing the next hex value.
+ * TCL_RETURN "%%EndPreview" line was detected.
+ *
+ * The converted hex value is returned via "bytePtr".
+ *
+ *----------------------------------------------------------------------
+ */
+static int
+GetHexValue(piPtr, bytePtr)
+ ParseInfo *piPtr;
+ unsigned char *bytePtr;
+{
+ register char *p;
+ unsigned int byte;
+
+ p = piPtr->nextPtr;
+ if (p == NULL) {
+ nextLine:
+ if (!ReadPsLine(piPtr)) {
+#if DEBUG_READER
+ PurifyPrintf("short file\n");
+#endif
+ return TCL_ERROR; /* Short file */
+ }
+ if (piPtr->line[0] != '%') {
+#if DEBUG_READER
+ PurifyPrintf("line doesn't start with %% (%s)\n", piPtr->line);
+#endif
+ return TCL_ERROR;
+ }
+ if ((piPtr->line[1] == '%') &&
+ (strncmp(piPtr->line + 2, "EndPreview", 10) == 0)) {
+#if DEBUG_READER
+ PurifyPrintf("end of preview (%s)\n", piPtr->line);
+#endif
+ return TCL_RETURN;
+ }
+ p = piPtr->line + 1;
+ }
+ while (isspace((int)*p)) {
+ p++; /* Skip spaces */
+ }
+ if (*p == '\0') {
+ goto nextLine;
+ }
+ if ((!isxdigit((int)p[0])) || (!isxdigit((int)p[1]))) {
+#if DEBUG_READER
+ PurifyPrintf("not a hex digit (%s)\n", piPtr->line);
+#endif
+ return TCL_ERROR;
+ }
+ byte = (piPtr->hexTable[(int)p[0]] << 4) | piPtr->hexTable[(int)p[1]];
+ p += 2;
+ piPtr->nextPtr = p;
+ *bytePtr = byte;
+ return TCL_OK;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * ReadEPSI --
+ *
+ * Reads the EPS preview image from the PostScript file, converting
+ * the image into a Blt_Colorimage. If an error occurs when parsing
+ * the preview, the preview is silently ignored.
+ *
+ * Results:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+static void
+ReadEPSI(epsPtr, piPtr)
+ EpsItem *epsPtr;
+ ParseInfo *piPtr;
+{
+ Blt_Colorimage image;
+ int width, height, bitsPerPixel, nLines;
+ char *dscBeginPreview;
+
+ dscBeginPreview = piPtr->line + 16;
+ if (sscanf(dscBeginPreview, "%d %d %d %d", &width, &height, &bitsPerPixel,
+ &nLines) != 4) {
+#if DEBUG_READER
+ PurifyPrintf("bad %%BeginPreview (%s) format\n", dscBeginPreview);
+#endif
+ return;
+ }
+ if (((bitsPerPixel != 1) && (bitsPerPixel != 8)) || (width < 1) ||
+ (width > SHRT_MAX) || (height < 1) || (height > SHRT_MAX)) {
+#if DEBUG_READER
+ PurifyPrintf("Bad %%BeginPreview (%s) values\n", dscBeginPreview);
+#endif
+ return; /* Bad "%%BeginPreview:" information */
+ }
+ epsPtr->firstLine = piPtr->lineNumber;
+ Blt_InitHexTable(piPtr->hexTable);
+ piPtr->nextPtr = NULL;
+ image = Blt_CreateColorimage(width, height);
+
+ if (bitsPerPixel == 8) {
+ int result;
+ register Pix32 *destPtr;
+ register int x, y;
+ unsigned char byte;
+
+ for (y = height - 1; y >= 0; y--) {
+ destPtr = Blt_ColorimageBits(image) + (y * width);
+ for (x = 0; x < width; x++, destPtr++) {
+ result = GetHexValue(piPtr, &byte);
+ if (result == TCL_ERROR) {
+ goto error;
+ }
+ if (result == TCL_RETURN) {
+ goto done;
+ }
+ destPtr->Red = destPtr->Green = destPtr->Blue = ~byte;
+ destPtr->Alpha = 0xFF;
+ }
+ }
+ } else if (bitsPerPixel == 1) {
+ int result;
+ register Pix32 *destPtr;
+ register int x, y;
+ unsigned char byte;
+ register int bit;
+
+ destPtr = Blt_ColorimageBits(image);
+ for (y = 0; y < height; y++) {
+ bit = 8;
+ for (x = 0; x < width; x++, destPtr++) {
+ if (bit == 8) {
+ result = GetHexValue(piPtr, &byte);
+ if (result == TCL_ERROR) {
+ goto error;
+ }
+ if (result == TCL_RETURN) {
+ goto done;
+ }
+ byte = ReverseBits(byte);
+ bit = 0;
+ }
+ if (((byte >> bit) & 0x01) == 0) {
+ destPtr->value = 0xFFFFFFFF;
+ }
+ bit++;
+ }
+ }
+ } else {
+ fprintf(stderr, "unknown EPSI bitsPerPixel (%d)\n", bitsPerPixel);
+ }
+ done:
+ epsPtr->colorImage = image;
+ epsPtr->lastLine = piPtr->lineNumber + 1;
+ return;
+
+ error:
+ epsPtr->firstLine = epsPtr->lastLine = -1;
+ if (image != NULL) {
+ Blt_FreeColorimage(image);
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * ReadPostScript --
+ *
+ * This routine reads and parses the few fields we need out
+ * of an EPS file.
+ *
+ * The EPS standards are outlined from Appendix H of the
+ * "PostScript Language Reference Manual" pp. 709-736.
+ *
+ * Mandatory fields:
+ *
+ * - Starts with "%!PS*"
+ * - Contains "%%BoundingBox: llx lly urx ury"
+ *
+ * Optional fields for EPS item:
+ * - "%%BeginPreview: w h bpp #lines"
+ * Preview is in hexadecimal. Each line must start with "%"
+ * - "%%EndPreview"
+ * - "%%Title: (string)"
+ *
+ *----------------------------------------------------------------------
+ */
+static int
+ReadPostScript(interp, epsPtr)
+ Tcl_Interp *interp;
+ EpsItem *epsPtr;
+{
+ char *field;
+ char *dscTitle, *dscBoundingBox, *dscEndProlog;
+ char *dscEndSetup, *dscEndComments;
+ ParseInfo pi;
+
+ pi.line[0] = '\0';
+ pi.maxBytes = epsPtr->psLength;
+ pi.lineNumber = 0;
+ pi.f = epsPtr->psFile;
+
+ if (pi.maxBytes == 0) {
+ pi.maxBytes = INT_MAX;
+ }
+ if (epsPtr->psStart >= 0) {
+ if (fseek(epsPtr->psFile, epsPtr->psStart, 0) != 0) {
+ Tcl_AppendResult(interp,
+ "can't seek to start of PostScript code in \"",
+ epsPtr->fileName, "\"", (char *)NULL);
+ return TCL_ERROR;
+ }
+ }
+ if (!ReadPsLine(&pi)) {
+ Tcl_AppendResult(interp, "file \"", epsPtr->fileName, "\" is empty?",
+ (char *)NULL);
+ return TCL_ERROR;
+ }
+ if (strncmp(pi.line, "%!PS", 4) != 0) {
+ Tcl_AppendResult(interp, "file \"", epsPtr->fileName,
+ "\" doesn't start with \"%!PS\"", (char *)NULL);
+ return TCL_ERROR;
+ }
+
+ /*
+ * Initialize field flags to NULL. We want to look only at the
+ * first appearance of these comment fields. The file itself may
+ * have another EPS file embedded into it.
+ */
+ dscBoundingBox = dscTitle = NULL;
+ dscEndComments = dscEndSetup = dscEndProlog = NULL;
+
+ pi.lineNumber = 1;
+ while (ReadPsLine(&pi)) {
+ pi.lineNumber++;
+ if ((pi.line[0] == '%') && (pi.line[1] == '%')) { /* Header comment */
+ field = pi.line + 2;
+ if ((field[0] == 'B') &&
+ (strncmp(field, "BoundingBox:", 12) == 0)) {
+ if (dscBoundingBox == NULL) {
+ int nFields;
+
+ dscBoundingBox = field + 12;
+ nFields = sscanf(dscBoundingBox, "%d %d %d %d",
+ &(epsPtr->llx), &(epsPtr->lly),
+ &(epsPtr->urx), &(epsPtr->ury));
+ if (nFields != 4) {
+ Tcl_AppendResult(interp,
+ "bad \"%%BoundingBox\" values: \"",
+ dscBoundingBox, "\"", (char *)NULL);
+ goto error;
+ }
+ }
+ } else if ((field[0] == 'T') &&
+ (strncmp(field, "Title:", 6) == 0)) {
+ if (dscTitle == NULL) {
+ dscTitle = Blt_Strdup(field + 6);
+ }
+ } else if (field[0] == 'E') {
+ if (strncmp(field, "EndComments", 11) == 0) {
+ dscEndComments = field;
+ break; /* Done */
+ }
+ if (strncmp(field, "EndSetup", 8) == 0) {
+ dscEndSetup = field;
+ break; /* Done */
+ }
+ }
+ } /* %% */
+ }
+ if (dscEndComments != NULL) {
+ /* Check if a "%%BeginPreview" immediately follows */
+ while (ReadPsLine(&pi)) {
+ field = SkipBlanks(&pi);
+ if (field[0] != '\0') {
+ break;
+ }
+ }
+ if (strncmp(pi.line, "%%BeginPreview:", 15) == 0) {
+ ReadEPSI(epsPtr, &pi);
+ }
+ }
+ if ((dscEndSetup == NULL) && (dscEndProlog == NULL)) {
+ /* Try to find the end of the prolog or setup */
+ while (ReadPsLine(&pi)) {
+ if ((pi.line[0] == '%') && (pi.line[1] == '%')) {
+ field = pi.line + 2;
+ if (field[0] == 'E') {
+ if (strncmp(field, "EndProlog", 9) == 0) {
+ dscEndProlog = field;
+ break;
+ }
+ if (strncmp(field, "EndSetup", 8) == 0) {
+ dscEndSetup = field;
+ break; /* Done */
+ }
+ }
+ }
+ }
+ }
+ if (dscBoundingBox == NULL) {
+ Tcl_AppendResult(interp, "no \"%%BoundingBox:\" found in \"",
+ epsPtr->fileName, "\"", (char *)NULL);
+ goto error;
+ }
+ if ((dscEndSetup == NULL) && (dscEndProlog == NULL)) {
+ Tcl_AppendResult(interp,
+ "no \"%%EndProlog\" or \"%%EndSetup\" found in",
+ epsPtr->fileName, "\"", (char *)NULL);
+ goto error;
+ }
+ if (dscTitle != NULL) {
+ epsPtr->title = dscTitle;
+ }
+ /* Finally save the PostScript into a dynamic string. */
+ Tcl_DStringInit(&epsPtr->dString);
+ while (ReadPsLine(&pi)) {
+ Tcl_DStringAppend(&epsPtr->dString, pi.line, -1);
+ Tcl_DStringAppend(&epsPtr->dString, "\n", 1);
+ }
+ return TCL_OK;
+ error:
+ if (dscTitle != NULL) {
+ Blt_Free(dscTitle);
+ }
+ return TCL_ERROR; /* BoundingBox: is required. */
+}
+
+static int
+OpenEpsFile(interp, epsPtr)
+ Tcl_Interp *interp;
+ EpsItem *epsPtr;
+{
+ FILE *f;
+#ifdef WIN32
+ DOSEPSHEADER dosHeader;
+ int nBytes;
+#endif
+
+ f = fopen(epsPtr->fileName, "rb");
+ if (f == NULL) {
+ Tcl_AppendResult(epsPtr->interp, "can't open \"", epsPtr->fileName,
+ "\": ", Tcl_PosixError(epsPtr->interp), (char *)NULL);
+ return TCL_ERROR;
+ }
+ epsPtr->psFile = f;
+ epsPtr->psStart = epsPtr->psLength = 0L;
+ epsPtr->wmfStart = epsPtr->wmfLength = 0L;
+ epsPtr->tiffStart = epsPtr->tiffLength = 0L;
+
+#ifdef WIN32
+ nBytes = fread(&dosHeader, sizeof(DOSEPSHEADER), 1, f);
+ if ((nBytes == sizeof(DOSEPSHEADER)) &&
+ (dosHeader.magic[0] == 0xC5) && (dosHeader.magic[1] == 0xD0) &&
+ (dosHeader.magic[2] == 0xD3) && (dosHeader.magic[3] == 0xC6)) {
+
+ /* DOS EPS file */
+ epsPtr->psStart = dosHeader.psStart;
+ epsPtr->wmfStart = dosHeader.wmfStart;
+ epsPtr->wmfLength = dosHeader.wmfLength;
+ epsPtr->tiffStart = dosHeader.tiffStart;
+ epsPtr->tiffLength = dosHeader.tiffLength;
+ epsPtr->previewFormat = PS_PREVIEW_EPSI;
+#ifdef HAVE_TIFF_H
+ if (epsPtr->tiffLength > 0) {
+ epsPtr->previewFormat = PS_PREVIEW_TIFF;
+ }
+#endif /* HAVE_TIFF_H */
+ if (epsPtr->wmfLength > 0) {
+ epsPtr->previewFormat = PS_PREVIEW_WMF;
+ }
+ }
+ fseek(f, 0, 0);
+#endif /* WIN32 */
+ return ReadPostScript(interp, epsPtr);
+}
+
+static void
+CloseEpsFile(epsPtr)
+ EpsItem *epsPtr;
+{
+ if (epsPtr->psFile != NULL) {
+ fclose(epsPtr->psFile);
+ epsPtr->psFile = NULL;
+ }
+}
+
+static void
+ReadTiffPreview(epsPtr)
+ EpsItem *epsPtr;
+{
+#ifdef HAVE_TIFF_H
+ unsigned int width, height;
+ Blt_Colorimage image;
+ Pix32 *dataPtr;
+ FILE *f;
+ int n;
+
+ TIFFGetField(epsPtr->tiffPtr, TIFFTAG_IMAGEWIDTH, &width);
+ TIFFGetField(epsPtr->tiffPtr, TIFFTAG_IMAGELENGTH, &height);
+ image = Blt_CreateColorimage(width, height);
+ dataPtr = Blt_ColorimageBits(image);
+ if (!TIFFReadRGBAImage(epsPtr->tiffPtr, width, height, dataPtr, 0)) {
+ Blt_FreeColorimage(image);
+ return;
+ }
+ /* Reverse the order of the components for each pixel. */
+ /* ... */
+ epsPtr->colorImage = image;
+#endif
+}
+
+#ifdef notdef
+ReadWMF(f, epsPtr, headerPtr)
+ FILE *f;
+{
+ HANDLE hMem;
+ Tk_Window tkwin;
+
+ if (fseek(f, headerPtr->wmfStart, 0) != 0) {
+ Tcl_AppendResult(interp, "can't seek in \"", epsPtr->fileName,
+ "\"", (char *)NULL);
+ return TCL_ERROR;
+ }
+ hMem = GlobalAlloc(GHND, size);
+ if (hMem == NULL) {
+ Tcl_AppendResult(graphPtr->interp, "can't allocate global memory:",
+ Blt_LastError(), (char *)NULL);
+ return TCL_ERROR;
+ }
+ buffer = (LPVOID)GlobalLock(hMem);
+ /* Read the header and see what kind of meta file it is. */
+ fread(buffer, sizeof(unsigned char), headerPtr->wmfLength, f);
+ mfp.mm = 0;
+ mfp.xExt = epsPtr->width;
+ mfp.yExt = epsPtr->height;
+ mfp.hMF = hMetaFile;
+ tkwin = Tk_CanvasTkwin(epsPtr->canvas);
+ hRefDC = TkWinGetDrawableDC(Tk_Display(tkwin), Tk_WindowId(tkwin), &state);
+ hDC = CreateEnhMetaFile(hRefDC, NULL, NULL, NULL);
+ mfp.hMF = CloseEnhMetaFile(hDC);
+ hMetaFile = SetWinMetaFileBits(size, buffer, MM_ANISOTROPIC, &pict);
+ Tcl_AppendResult(graphPtr->interp, "can't get metafile data:",
+ Blt_LastError(), (char *)NULL);
+ goto error;
+}
+#endif
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * DeleteEps --
+ *
+ * This procedure is called to clean up the data structure
+ * associated with a EPS item.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Resources associated with itemPtr are released.
+ *
+ *----------------------------------------------------------------------
+ */
+/*ARGSUSED*/
+static void
+DeleteEps(canvas, itemPtr, display)
+ Tk_Canvas canvas; /* Info about overall canvas widget. */
+ Tk_Item *itemPtr; /* Item that is being deleted. */
+ Display *display; /* Display containing window for
+ * canvas. */
+{
+ EpsItem *epsPtr = (EpsItem *)itemPtr;
+
+ Tk_FreeOptions(configSpecs, (char *)epsPtr, display, 0);
+ if (epsPtr->colorImage != NULL) {
+ Blt_FreeColorimage(epsPtr->colorImage);
+ }
+ if (epsPtr->preview != NULL) {
+ Tk_FreeImage(epsPtr->preview);
+ }
+ if (epsPtr->previewName != NULL) {
+ Blt_Free(epsPtr->previewName);
+ }
+ if (epsPtr->tmpImage != NULL) {
+ Blt_DestroyTemporaryImage(epsPtr->interp, epsPtr->tmpImage);
+ }
+ if (epsPtr->pixmap != None) {
+#ifdef notyet
+ Blt_FreeColorTable(epsPtr->colorTable);
+#endif
+ Tk_FreePixmap(display, epsPtr->pixmap);
+ }
+ if (epsPtr->stipple != None) {
+ Tk_FreePixmap(display, epsPtr->stipple);
+ }
+ if (epsPtr->fillGC != NULL) {
+ Tk_FreeGC(display, epsPtr->fillGC);
+ }
+ Blt_FreeTextStyle(display, &(epsPtr->titleStyle));
+
+ if (epsPtr->title != NULL) {
+ Blt_Free(epsPtr->title);
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * CreateEps --
+ *
+ * This procedure is invoked to create a new EPS item
+ * in a canvas.
+ *
+ * Results:
+ * A standard Tcl return value. If an error occurred in
+ * creating the item, then an error message is left in
+ * interp->result; in this case itemPtr is left uninitialized,
+ * so it can be safely freed by the caller.
+ *
+ * Side effects:
+ * A new EPS item is created.
+ *
+ *----------------------------------------------------------------------
+ */
+static int
+CreateEps(interp, canvas, itemPtr, argc, argv)
+ Tcl_Interp *interp; /* Interpreter for error reporting. */
+ Tk_Canvas canvas; /* Canvas to hold new item. */
+ Tk_Item *itemPtr; /* Record to hold new item; header
+ * has been initialized by caller. */
+ int argc; /* Number of arguments in argv. */
+ char **argv; /* Arguments describing rectangle. */
+{
+ EpsItem *epsPtr = (EpsItem *)itemPtr;
+ Tk_Window tkwin;
+
+ tkwin = Tk_CanvasTkwin(canvas);
+ if (argc < 2) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ Tk_PathName(tkwin), " create ", itemPtr->typePtr->name,
+ " x1 y1 ?options?\"", (char *)NULL);
+ return TCL_ERROR;
+ }
+ /*
+ * Initialize the item's record by hand (bleah).
+ */
+ epsPtr->anchor = TK_ANCHOR_NW;
+ epsPtr->border = NULL;
+ epsPtr->borderWidth = 2;
+ epsPtr->canvas = canvas;
+ epsPtr->fileName = NULL;
+ epsPtr->psFile = NULL;
+ epsPtr->fillGC = NULL;
+ epsPtr->fillColor = NULL;
+ epsPtr->colorImage = NULL;
+ epsPtr->previewName = NULL;
+ epsPtr->preview = NULL;
+ epsPtr->interp = interp;
+ epsPtr->tmpImage = NULL;
+ epsPtr->pixmap = None;
+ epsPtr->firstLine = epsPtr->lastLine = -1;
+ epsPtr->relief = TK_RELIEF_SUNKEN;
+ epsPtr->reqTitle = NULL;
+ epsPtr->stipple = None;
+ epsPtr->showImage = TRUE;
+ epsPtr->quick = FALSE;
+ epsPtr->title = NULL;
+ epsPtr->lastWidth = epsPtr->lastHeight = 0;
+ epsPtr->width = epsPtr->height = 0;
+ epsPtr->x = epsPtr->y = 0.0;
+ epsPtr->llx = epsPtr->lly = epsPtr->urx = epsPtr->ury = 0;
+ epsPtr->canvasX = epsPtr->canvasY = 0;
+ Tcl_DStringInit(&epsPtr->dString);
+ memset(&(epsPtr->titleStyle), 0, sizeof(TextStyle));
+#define PAD 8
+ epsPtr->titleStyle.padLeft = epsPtr->titleStyle.padRight = PAD;
+ epsPtr->titleStyle.padTop = epsPtr->titleStyle.padBottom = PAD;
+
+ /*
+ * Process the arguments to fill in the item record.
+ */
+
+ if ((Tk_CanvasGetCoord(interp, canvas, argv[0], &(epsPtr->x)) != TCL_OK) ||
+ (Tk_CanvasGetCoord(interp, canvas, argv[1], &(epsPtr->y)) != TCL_OK)) {
+ return TCL_ERROR;
+ }
+ if (ConfigureEps(interp, canvas, itemPtr, argc - 2, argv + 2, 0)
+ != TCL_OK) {
+ DeleteEps(canvas, itemPtr, Tk_Display(tkwin));
+ return TCL_ERROR;
+ }
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * ImageChangedProc
+ *
+ * The image is over-written each time the EPS item is resized.
+ * So we only worry if the image is deleted.
+ *
+ * We always resample from the color image we saved when the
+ * photo image was specified (-image option).
+ *
+ * Results:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+/* ARGSUSED */
+static void
+ImageChangedProc(clientData, x, y, width, height, imageWidth, imageHeight)
+ ClientData clientData;
+ int x, y, width, height; /* Not used. */
+ int imageWidth, imageHeight;/* Not used. */
+{
+ EpsItem *epsPtr = clientData;
+
+ if ((epsPtr->preview == NULL) || (Tk_ImageIsDeleted(epsPtr->preview))) {
+ epsPtr->preview = NULL;
+ if (epsPtr->previewName != NULL) {
+ Blt_Free(epsPtr->previewName);
+ epsPtr->previewName = NULL;
+ }
+ Tk_CanvasEventuallyRedraw(epsPtr->canvas, epsPtr->xLeft, epsPtr->yTop,
+ epsPtr->xRight, epsPtr->yBottom);
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * ConfigureEps --
+ *
+ * This procedure is invoked to configure various aspects
+ * of an EPS item, such as its background color.
+ *
+ * Results:
+ * A standard Tcl result code. If an error occurs, then
+ * an error message is left in interp->result.
+ *
+ * Side effects:
+ * Configuration information may be set for itemPtr.
+ *
+ *----------------------------------------------------------------------
+ */
+static int
+ConfigureEps(interp, canvas, itemPtr, argc, argv, flags)
+ Tcl_Interp *interp; /* Used for error reporting. */
+ Tk_Canvas canvas; /* Canvas containing itemPtr. */
+ Tk_Item *itemPtr; /* EPS item to reconfigure. */
+ int argc; /* Number of elements in argv. */
+ char **argv; /* Arguments describing things to configure. */
+ int flags; /* Flags to pass to Tk_ConfigureWidget. */
+{
+ EpsItem *epsPtr = (EpsItem *)itemPtr;
+ Tk_Window tkwin;
+ XGCValues gcValues;
+ unsigned long gcMask;
+ GC newGC;
+ int width, height;
+
+ tkwin = Tk_CanvasTkwin(canvas);
+ if (Tk_ConfigureWidget(interp, tkwin, configSpecs, argc,
+ argv, (char *)epsPtr, flags) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ /* Determine the size of the EPS item */
+ width = height = 0;
+ /*
+ * Check for a "-image" option specifying an image to be displayed
+ * representing the EPS canvas item.
+ */
+ if (Blt_ConfigModified(configSpecs, "-image", (char *)NULL)) {
+ if (epsPtr->preview != NULL) {
+ Tk_FreeImage(epsPtr->preview); /* Release old Tk image */
+ Blt_FreeColorimage(epsPtr->colorImage);
+ epsPtr->preview = NULL;
+ epsPtr->colorImage = NULL;
+ }
+ if (epsPtr->previewName != NULL) {
+ Tk_PhotoHandle photo; /* Photo handle to Tk image. */
+ /*
+ * Allocate a new image, if one was named.
+ */
+ photo = Blt_FindPhoto(interp, epsPtr->previewName);
+ if (photo == NULL) {
+ Tcl_AppendResult(interp, "image \"", epsPtr->previewName,
+ "\" doesn't exist or is not a photo image",
+ (char *)NULL);
+ return TCL_ERROR;
+ }
+ epsPtr->preview = Tk_GetImage(interp, tkwin, epsPtr->previewName,
+ ImageChangedProc, epsPtr);
+ if (epsPtr->preview == NULL) {
+ Tcl_AppendResult(interp, "can't find an image \"",
+ epsPtr->previewName, "\"", (char *)NULL);
+ Blt_Free(epsPtr->previewName);
+ epsPtr->previewName = NULL;
+ return TCL_ERROR;
+ }
+ epsPtr->colorImage = Blt_PhotoToColorimage(photo);
+ width = Blt_ColorimageWidth(epsPtr->colorImage);
+ height = Blt_ColorimageHeight(epsPtr->colorImage);
+ }
+ }
+ if (Blt_ConfigModified(configSpecs, "-file", (char *)NULL)) {
+ if (epsPtr->psFile != NULL) {
+ CloseEpsFile(epsPtr);
+ }
+ if (epsPtr->pixmap != None) {
+#ifdef notyet
+ Blt_FreeColorTable(epsPtr->colorTable);
+#endif
+ Tk_FreePixmap(Tk_Display(tkwin), epsPtr->pixmap);
+ epsPtr->pixmap = None;
+ }
+ if (epsPtr->colorImage != NULL) {
+ Blt_FreeColorimage(epsPtr->colorImage);
+ epsPtr->colorImage = NULL;
+ }
+ epsPtr->firstLine = epsPtr->lastLine = -1;
+ if (epsPtr->fileName != NULL) {
+ if (OpenEpsFile(interp, epsPtr) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ }
+ }
+ if ((epsPtr->colorImage != NULL) && (epsPtr->tmpImage == NULL)) {
+ epsPtr->tmpImage = Blt_CreateTemporaryImage(interp, tkwin, epsPtr);
+ if (epsPtr->tmpImage == NULL) {
+ return TCL_ERROR;
+ }
+ } else if ((epsPtr->colorImage == NULL) && (epsPtr->tmpImage != NULL)) {
+ Blt_DestroyTemporaryImage(epsPtr->interp, epsPtr->tmpImage);
+ }
+ if (epsPtr->preview != NULL) {
+ Tk_SizeOfImage(epsPtr->preview, &width, &height);
+ }
+ if (epsPtr->width == 0) {
+ if (epsPtr->fileName != NULL) {
+ width = (epsPtr->urx - epsPtr->llx);
+ }
+ epsPtr->width = width;
+ }
+ if (epsPtr->height == 0) {
+ if (epsPtr->fileName != NULL) {
+ height = (epsPtr->ury - epsPtr->lly);
+ }
+ epsPtr->height = height;
+ }
+ Blt_ResetTextStyle(tkwin, &(epsPtr->titleStyle));
+
+ if (Blt_ConfigModified(configSpecs, "-quick", (char *)NULL)) {
+ epsPtr->lastWidth = epsPtr->lastHeight = 0;
+ }
+ /* Fill color GC */
+
+ newGC = NULL;
+ if (epsPtr->fillColor != NULL) {
+ gcMask = GCForeground;
+ gcValues.foreground = epsPtr->fillColor->pixel;
+ if (epsPtr->stipple != None) {
+ gcMask |= (GCStipple | GCFillStyle);
+ gcValues.stipple = epsPtr->stipple;
+ if (epsPtr->border != NULL) {
+ gcValues.foreground = Tk_3DBorderColor(epsPtr->border)->pixel;
+ gcValues.background = epsPtr->fillColor->pixel;
+ gcMask |= GCBackground;
+ gcValues.fill_style = FillOpaqueStippled;
+ } else {
+ gcValues.fill_style = FillStippled;
+ }
+ }
+ newGC = Tk_GetGC(tkwin, gcMask, &gcValues);
+ }
+ if (epsPtr->fillGC != NULL) {
+ Tk_FreeGC(Tk_Display(tkwin), epsPtr->fillGC);
+ }
+ epsPtr->fillGC = newGC;
+ CloseEpsFile(epsPtr);
+ ComputeEpsBbox(canvas, epsPtr);
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * EpsCoords --
+ *
+ * This procedure is invoked to process the "coords" widget
+ * command on EPS items. See the user documentation for
+ * details on what it does.
+ *
+ * Results:
+ * Returns TCL_OK or TCL_ERROR, and sets interp->result.
+ *
+ * Side effects:
+ * The coordinates for the given item may be changed.
+ *
+ *----------------------------------------------------------------------
+ */
+static int
+EpsCoords(interp, canvas, itemPtr, argc, argv)
+ Tcl_Interp *interp; /* Used for error reporting. */
+ Tk_Canvas canvas; /* Canvas containing item. */
+ Tk_Item *itemPtr; /* Item whose coordinates are to be
+ * read or modified. */
+ int argc; /* Number of coordinates supplied in
+ * argv. */
+ char **argv; /* Array of coordinates: x1, y1,
+ * x2, y2, ... */
+{
+ EpsItem *epsPtr = (EpsItem *)itemPtr;
+
+ if ((argc != 0) && (argc != 2)) {
+ Tcl_AppendResult(interp, "wrong # coordinates: expected 0 or 2, got ",
+ Blt_Itoa(argc), (char *)NULL);
+ return TCL_ERROR;
+ }
+ if (argc == 2) {
+ double x, y; /* Don't overwrite old coordinates on errors */
+
+ if ((Tk_CanvasGetCoord(interp, canvas, argv[0], &x) != TCL_OK) ||
+ (Tk_CanvasGetCoord(interp, canvas, argv[1], &y) != TCL_OK)) {
+ return TCL_ERROR;
+ }
+ epsPtr->x = x;
+ epsPtr->y = y;
+ ComputeEpsBbox(canvas, epsPtr);
+ return TCL_OK;
+ }
+ Tcl_AppendElement(interp, Blt_Dtoa(interp, epsPtr->x));
+ Tcl_AppendElement(interp, Blt_Dtoa(interp, epsPtr->y));
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * ComputeEpsBbox --
+ *
+ * This procedure is invoked to compute the bounding box of
+ * all the pixels that may be drawn as part of a EPS item.
+ * This procedure is where the preview image's placement is
+ * computed.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The fields x1, y1, x2, and y2 are updated in the header
+ * for itemPtr.
+ *
+ *----------------------------------------------------------------------
+ */
+ /* ARGSUSED */
+static void
+ComputeEpsBbox(canvas, epsPtr)
+ Tk_Canvas canvas; /* Canvas that contains item. */
+ EpsItem *epsPtr; /* Item whose bbox is to be recomputed. */
+{
+ int x, y;
+
+ x = ROUND(epsPtr->x), y = ROUND(epsPtr->y);
+ Blt_TranslateAnchor(x, y, epsPtr->width, epsPtr->height, epsPtr->anchor,
+ &x, &y);
+ epsPtr->xLeft = epsPtr->canvasX = x;
+ epsPtr->yTop = epsPtr->canvasY = y;
+
+ /*
+ * The right and bottom are (weirdly) exterior to the item. Can't
+ * complain much since it's documented in the Tk_CreateItemType
+ * manual page.
+ *
+ * "These fields give a bounding box for the items using integer
+ * canvas coordinates: the item should not cover any pixels with
+ * x-coordinate lower than x1 or y-coordinate lower than y1, nor
+ * should it cover any pixels with x-coordinate greater than or
+ * equal to x2 or y-coordinate greater than or equal to y2."
+ */
+ epsPtr->xRight = x + epsPtr->width;
+ epsPtr->yBottom = y + epsPtr->height;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * DisplayEps --
+ *
+ * This procedure is invoked to draw the EPS item in a
+ * given drawable. The EPS item may be drawn as either
+ * a solid rectangle or a pixmap of the preview image.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * ItemPtr is drawn in drawable using the transformation
+ * information in canvas.
+ *
+ *----------------------------------------------------------------------
+ */
+static void
+DisplayEps(canvas, itemPtr, display, drawable, x, y, width, height)
+ Tk_Canvas canvas; /* Canvas that contains item. */
+ Tk_Item *itemPtr; /* Item to be displayed. */
+ Display *display; /* Display on which to draw item. */
+ Drawable drawable; /* Pixmap or window in which to draw
+ * item. */
+ int x, y, width, height; /* Describes region of canvas that
+ * must be redisplayed (not used). */
+{
+ Tk_Window tkwin;
+ EpsItem *epsPtr = (EpsItem *)itemPtr;
+ short int drawableX, drawableY;
+ char *title;
+ int twiceBW;
+ int noImage;
+
+ if ((epsPtr->width < 1) || (epsPtr->height < 1)) {
+ return;
+ }
+ tkwin = Tk_CanvasTkwin(canvas);
+ epsPtr->showImage = TRUE;
+ if ((epsPtr->showImage) && (epsPtr->colorImage != NULL) &&
+ ((epsPtr->lastWidth != epsPtr->width) ||
+ (epsPtr->lastHeight != epsPtr->height))) {
+ Blt_Colorimage image;
+
+ if (epsPtr->quick) {
+ image = Blt_ResizeColorimage(epsPtr->colorImage, 0, 0,
+ Blt_ColorimageWidth(epsPtr->colorImage),
+ Blt_ColorimageHeight(epsPtr->colorImage),
+ epsPtr->width, epsPtr->height);
+ } else {
+ image = Blt_ResampleColorimage(epsPtr->colorImage, epsPtr->width,
+ epsPtr->height, bltBoxFilterPtr, bltBoxFilterPtr);
+ }
+ if (epsPtr->tmpImage != NULL) {
+ Tk_PhotoHandle photo;
+ /*
+ * Resize the Tk photo image used to represent the EPS item.
+ * We will over-write the temporary image with a resampled one.
+ */
+ photo = Blt_FindPhoto(epsPtr->interp,
+ Blt_NameOfImage(epsPtr->tmpImage));
+ Blt_ColorimageToPhoto(image, photo);
+ } else {
+#ifdef notyet
+ epsPtr->pixmap = Blt_ColorimageToPixmap(epsPtr->interp, tkwin,
+ image, &(epsPtr->colorTable));
+#endif
+ }
+ epsPtr->lastHeight = epsPtr->height;
+ epsPtr->lastWidth = epsPtr->width;
+ Blt_FreeColorimage(image);
+ }
+ /*
+ * Translate the coordinates to those of the EPS item, then redisplay it.
+ */
+ Tk_CanvasDrawableCoords(canvas, (double)epsPtr->canvasX,
+ (double)epsPtr->canvasY, &drawableX, &drawableY);
+ x = (int)drawableX;
+ y = (int)drawableY;
+
+ twiceBW = epsPtr->borderWidth * 2;
+ title = epsPtr->title;
+
+ if (epsPtr->reqTitle != NULL) {
+ title = epsPtr->reqTitle;
+ }
+ width = epsPtr->width;
+ height = epsPtr->height;
+ noImage = ((!epsPtr->showImage) || ((epsPtr->tmpImage == NULL) &&
+ (epsPtr->pixmap == None)));
+ if (noImage) {
+ if ((twiceBW >= width) || (twiceBW >= height)) {
+ return;
+ }
+ width -= twiceBW;
+ height -= twiceBW;
+ if (epsPtr->fillGC != NULL) {
+ XSetTSOrigin(display, epsPtr->fillGC, x, y);
+ XFillRectangle(display, drawable, epsPtr->fillGC, x, y,
+ epsPtr->width, epsPtr->height);
+ XSetTSOrigin(display, epsPtr->fillGC, 0, 0);
+ }
+ } else {
+ if (epsPtr->pixmap != None) {
+ XCopyArea(Tk_Display(tkwin), epsPtr->pixmap, drawable,
+ epsPtr->fillGC, 0, 0, width, height, x, y);
+ } else {
+ Tk_RedrawImage(epsPtr->tmpImage, 0, 0, width, height, drawable,
+ x, y);
+ }
+ }
+
+ if (title != NULL) {
+ TextLayout *textPtr;
+ int rotWidth, rotHeight;
+
+ /* Translate the title to an anchor position within the EPS item */
+ textPtr = Blt_GetTextLayout(title, &(epsPtr->titleStyle));
+ Blt_GetBoundingBox(textPtr->width, textPtr->height,
+ epsPtr->titleStyle.theta, &rotWidth, &rotHeight, (Point2D *)NULL);
+ if ((rotWidth <= width) && (rotHeight <= height)) {
+ int titleX, titleY;
+
+ Blt_TranslateAnchor(x, y, width, height, epsPtr->titleStyle.anchor,
+ &titleX, &titleY);
+ if (noImage) {
+ titleX += epsPtr->borderWidth;
+ titleY += epsPtr->borderWidth;
+ }
+ Blt_DrawTextLayout(tkwin, drawable, textPtr, &(epsPtr->titleStyle),
+ titleX, titleY);
+ }
+ Blt_Free(textPtr);
+ }
+ if ((noImage) && (epsPtr->border != NULL)) {
+ Tk_Draw3DRectangle(tkwin, drawable, epsPtr->border, x, y,
+ epsPtr->width, epsPtr->height, epsPtr->borderWidth, epsPtr->relief);
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * EpsToPoint --
+ *
+ * Computes the distance from a given point to a given
+ * rectangle, in canvas units.
+ *
+ * Results:
+ * The return value is 0 if the point whose x and y coordinates
+ * are coordPtr[0] and coordPtr[1] is inside the EPS item. If the
+ * point isn't inside the item then the return value is the
+ * distance from the point to the EPS item.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+/*ARGSUSED*/
+static double
+EpsToPoint(canvas, itemPtr, coordArr)
+ Tk_Canvas canvas; /* Canvas containing item. */
+ Tk_Item *itemPtr; /* Item to check against point. */
+ double *coordArr; /* Pointer to x and y coordinates. */
+{
+ EpsItem *epsPtr = (EpsItem *)itemPtr;
+ double dx, dy;
+
+ /*
+ * Point is outside rectangle.
+ */
+ if (coordArr[0] < epsPtr->xLeft) {
+ dx = epsPtr->xLeft - coordArr[0];
+ } else if (coordArr[0] > epsPtr->xRight) {
+ dx = coordArr[0] - epsPtr->xRight;
+ } else {
+ dx = 0;
+ }
+ if (coordArr[1] < epsPtr->yTop) {
+ dy = epsPtr->yTop - coordArr[1];
+ } else if (coordArr[1] > epsPtr->yBottom) {
+ dy = coordArr[1] - epsPtr->yBottom;
+ } else {
+ dy = 0;
+ }
+ return hypot(dx, dy);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * EpsToArea --
+ *
+ * This procedure is called to determine whether an item
+ * lies entirely inside, entirely outside, or overlapping
+ * a given rectangle.
+ *
+ * Results:
+ * -1 is returned if the item is entirely outside the area
+ * given by rectPtr, 0 if it overlaps, and 1 if it is entirely
+ * inside the given area.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+/*ARGSUSED*/
+static int
+EpsToArea(canvas, itemPtr, area)
+ Tk_Canvas canvas; /* Canvas containing item. */
+ Tk_Item *itemPtr; /* Item to check against rectangle. */
+ double area[]; /* Pointer to array of four coordinates
+ * (x1, y1, x2, y2) describing rectangular
+ * area. */
+{
+ EpsItem *epsPtr = (EpsItem *)itemPtr;
+
+ if ((area[2] <= epsPtr->xLeft) || (area[0] >= epsPtr->xRight) ||
+ (area[3] <= epsPtr->yTop) || (area[1] >= epsPtr->yBottom)) {
+ return -1;
+ }
+ if ((area[0] <= epsPtr->xLeft) && (area[1] <= epsPtr->yTop) &&
+ (area[2] >= epsPtr->xRight) && (area[3] >= epsPtr->yBottom)) {
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * ScaleEps --
+ *
+ * This procedure is invoked to rescale an item.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The item referred to by itemPtr is rescaled so that the
+ * following transformation is applied to all point coordinates:
+ * x' = originX + scaleX*(x-originX)
+ * y' = originY + scaleY*(y-originY)
+ *
+ *----------------------------------------------------------------------
+ */
+static void
+ScaleEps(canvas, itemPtr, originX, originY, scaleX, scaleY)
+ Tk_Canvas canvas; /* Canvas containing rectangle. */
+ Tk_Item *itemPtr; /* Rectangle to be scaled. */
+ double originX, originY; /* Origin about which to scale rect. */
+ double scaleX; /* Amount to scale in X direction. */
+ double scaleY; /* Amount to scale in Y direction. */
+{
+ EpsItem *epsPtr = (EpsItem *)itemPtr;
+
+ epsPtr->x = originX + scaleX * (epsPtr->x - originX);
+ epsPtr->y = originY + scaleY * (epsPtr->y - originY);
+ ComputeEpsBbox(canvas, epsPtr);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TranslateEps --
+ *
+ * This procedure is called to move an item by a given amount.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The position of the item is offset by (xDelta, yDelta), and
+ * the bounding box is updated in the generic part of the item
+ * structure.
+ *
+ *----------------------------------------------------------------------
+ */
+static void
+TranslateEps(canvas, itemPtr, deltaX, deltaY)
+ Tk_Canvas canvas; /* Canvas containing item. */
+ Tk_Item *itemPtr; /* Item that is being moved. */
+ double deltaX, deltaY; /* Amount by which item is to be
+ * moved. */
+{
+ EpsItem *epsPtr = (EpsItem *)itemPtr;
+
+ epsPtr->x += deltaX;
+ epsPtr->y += deltaY;
+ ComputeEpsBbox(canvas, epsPtr);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * EpsToPostscript --
+ *
+ * This procedure is called to generate Postscript for EPS
+ * canvas items.
+ *
+ * Results:
+ * The return value is a standard Tcl result. If an error
+ * occurs in generating Postscript then an error message is
+ * left in interp->result, replacing whatever used
+ * to be there. If no error occurs, then Postscript for the
+ * item is appended to the result.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+static int
+EpsToPostScript(interp, canvas, itemPtr, prepass)
+ Tcl_Interp *interp; /* Leave Postscript or error message
+ * here. */
+ Tk_Canvas canvas; /* Information about overall canvas. */
+ Tk_Item *itemPtr; /* Item for which Postscript is
+ * wanted. */
+ int prepass; /* 1 means this is a prepass to
+ * collect font information; 0 means
+ * final Postscript is being created. */
+{
+ EpsItem *epsPtr = (EpsItem *)itemPtr;
+ PsToken psToken;
+ Tk_Window tkwin;
+ double xScale, yScale;
+ int x, y, width, height;
+ unsigned int count; /* Tracks the current line number. */
+ char *buf;
+
+ if (prepass) {
+ return TCL_OK;
+ }
+ tkwin = Tk_CanvasTkwin(epsPtr->canvas);
+ psToken = Blt_GetPsToken(interp, tkwin);
+ x = epsPtr->canvasX;
+ y = (int)Tk_CanvasPsY(canvas, (double)epsPtr->canvasY + epsPtr->height);
+
+ if (epsPtr->fileName == NULL) {
+ /* No PostScript file, generate PostScript of resized image instead. */
+ if (epsPtr->tmpImage != NULL) {
+ Tk_PhotoHandle photo;
+
+ Blt_FormatToPostScript(psToken, "gsave\n");
+ /*
+ * First flip the PostScript y-coordinate axis so that the
+ * origin is the upper-left corner like our color image.
+ */
+ Blt_FormatToPostScript(psToken, " %d %d translate\n",
+ x, y + epsPtr->height);
+ Blt_FormatToPostScript(psToken, " 1 -1 scale\n");
+
+ photo = Blt_FindPhoto(epsPtr->interp,
+ Blt_NameOfImage(epsPtr->tmpImage));
+ Blt_PhotoToPostScript(psToken, photo, 0.0, 0.0);
+ Blt_FormatToPostScript(psToken, "grestore\n");
+
+ Tcl_AppendResult(interp, Blt_PostScriptFromToken(psToken),
+ (char *)NULL);
+ Blt_ReleasePsToken(psToken);
+ }
+ return TCL_OK;
+ }
+ if (epsPtr->psFile == NULL) {
+ Tcl_AppendResult(interp, "can't get handle to EPS file", (char *)NULL);
+ goto error;
+ }
+ /* Copy in the PostScript prolog for EPS encapsulation. */
+
+ if (Blt_FileToPostScript(psToken, "bltCanvEps.pro") != TCL_OK) {
+ goto error;
+ }
+ Blt_AppendToPostScript(psToken, "BeginEPSF\n", (char *)NULL);
+
+ width = epsPtr->width;
+ height = epsPtr->height;
+ xScale = (double)width / (double)(epsPtr->urx - epsPtr->llx);
+ yScale = (double)height / (double)(epsPtr->ury - epsPtr->lly);
+
+ /* Set up scaling and translation transformations for the EPS item */
+
+ Blt_FormatToPostScript(psToken, "%d %d translate\n", x, y);
+ Blt_FormatToPostScript(psToken, "%g %g scale\n", xScale, yScale);
+ Blt_FormatToPostScript(psToken, "%d %d translate\n", -(epsPtr->llx),
+ -(epsPtr->lly));
+ Blt_FormatToPostScript(psToken, "%d %d %d %d SetClipRegion\n",
+ epsPtr->llx, epsPtr->lly, epsPtr->urx, epsPtr->ury);
+ Blt_AppendToPostScript(psToken, "%% including \"", epsPtr->fileName,
+ "\"\n\n", (char *)NULL);
+
+ buf = Blt_ScratchBufferFromToken(psToken);
+ count = 0;
+ Blt_AppendToPostScript(psToken, Tcl_DStringValue(&epsPtr->dString),
+ (char *)NULL);
+ Blt_AppendToPostScript(psToken, "EndEPSF\n", (char *)NULL);
+ Tcl_AppendResult(interp, Blt_PostScriptFromToken(psToken), (char *)NULL);
+ Blt_ReleasePsToken(psToken);
+ return TCL_OK;
+
+ error:
+ Blt_ReleasePsToken(psToken);
+ return TCL_ERROR;
+}
+
+/*
+ * The structures below defines the EPS item type in terms of
+ * procedures that can be invoked by generic item code.
+ */
+static Tk_ItemType epsItemType =
+{
+ "eps", /* name */
+ sizeof(EpsItem), /* itemSize */
+ CreateEps, /* createProc */
+ configSpecs, /* configSpecs */
+ ConfigureEps, /* configureProc */
+ EpsCoords, /* coordProc */
+ DeleteEps, /* deleteProc */
+ DisplayEps, /* displayProc */
+ 0, /* alwaysRedraw */
+ EpsToPoint, /* pointProc */
+ EpsToArea, /* areaProc */
+ EpsToPostScript, /* postscriptProc */
+ ScaleEps, /* scaleProc */
+ TranslateEps, /* translateProc */
+ (Tk_ItemIndexProc *) NULL, /* indexProc */
+ (Tk_ItemCursorProc *) NULL, /* icursorProc */
+ (Tk_ItemSelectionProc *) NULL, /* selectionProc */
+ (Tk_ItemInsertProc *) NULL, /* insertProc */
+ (Tk_ItemDCharsProc *) NULL, /* dTextProc */
+ (Tk_ItemType *) NULL /* nextPtr */
+};
+
+/*ARGSUSED*/
+void
+Blt_InitEpsCanvasItem(interp)
+ Tcl_Interp *interp; /* Not used. */
+{
+ Tk_CreateItemType(&epsItemType);
+ /* Initialize custom canvas option routines. */
+ tagsOption.parseProc = Tk_CanvasTagsParseProc;
+ tagsOption.printProc = Tk_CanvasTagsPrintProc;
+}