/*1* tkCanvBmap.c --2*3* This file implements bitmap items for canvas widgets.4*5* Copyright (c) 1992-1994 The Regents of the University of California.6* Copyright (c) 1994-1995 Sun Microsystems, Inc.7*8* See the file "license.terms" for information on usage and redistribution9* of this file, and for a DISCLAIMER OF ALL WARRANTIES.10*11* SCCS: @(#) tkCanvBmap.c 1.29 96/02/17 16:59:1012*/1314#include "tkInt.h"15#include "tkCanvas.h"1617/*18* The structure below defines the record for each bitmap item.19*/2021typedef struct BitmapItem {22Tk_Item header; /* Generic stuff that's the same for all23* types. MUST BE FIRST IN STRUCTURE. */24double x, y; /* Coordinates of positioning point for25* bitmap. */26Tk_Anchor anchor; /* Where to anchor bitmap relative to27* (x,y). */28Pixmap bitmap; /* Bitmap to display in window. */29XColor *fgColor; /* Foreground color to use for bitmap. */30XColor *bgColor; /* Background color to use for bitmap. */31GC gc; /* Graphics context to use for drawing32* bitmap on screen. */33} BitmapItem;3435/*36* Information used for parsing configuration specs:37*/3839static Tk_CustomOption tagsOption = {Tk_CanvasTagsParseProc,40Tk_CanvasTagsPrintProc, (ClientData) NULL41};4243static Tk_ConfigSpec configSpecs[] = {44{TK_CONFIG_ANCHOR, "-anchor", (char *) NULL, (char *) NULL,45"center", Tk_Offset(BitmapItem, anchor), TK_CONFIG_DONT_SET_DEFAULT},46{TK_CONFIG_COLOR, "-background", (char *) NULL, (char *) NULL,47(char *) NULL, Tk_Offset(BitmapItem, bgColor), TK_CONFIG_NULL_OK},48{TK_CONFIG_BITMAP, "-bitmap", (char *) NULL, (char *) NULL,49(char *) NULL, Tk_Offset(BitmapItem, bitmap), TK_CONFIG_NULL_OK},50{TK_CONFIG_COLOR, "-foreground", (char *) NULL, (char *) NULL,51"black", Tk_Offset(BitmapItem, fgColor), 0},52{TK_CONFIG_CUSTOM, "-tags", (char *) NULL, (char *) NULL,53(char *) NULL, 0, TK_CONFIG_NULL_OK, &tagsOption},54{TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,55(char *) NULL, 0, 0}56};5758/*59* Prototypes for procedures defined in this file:60*/6162static int BitmapCoords _ANSI_ARGS_((Tcl_Interp *interp,63Tk_Canvas canvas, Tk_Item *itemPtr, int argc,64char **argv));65static int BitmapToArea _ANSI_ARGS_((Tk_Canvas canvas,66Tk_Item *itemPtr, double *rectPtr));67static double BitmapToPoint _ANSI_ARGS_((Tk_Canvas canvas,68Tk_Item *itemPtr, double *coordPtr));69static int BitmapToPostscript _ANSI_ARGS_((Tcl_Interp *interp,70Tk_Canvas canvas, Tk_Item *itemPtr, int prepass));71static void ComputeBitmapBbox _ANSI_ARGS_((Tk_Canvas canvas,72BitmapItem *bmapPtr));73static int ConfigureBitmap _ANSI_ARGS_((Tcl_Interp *interp,74Tk_Canvas canvas, Tk_Item *itemPtr, int argc,75char **argv, int flags));76static int CreateBitmap _ANSI_ARGS_((Tcl_Interp *interp,77Tk_Canvas canvas, struct Tk_Item *itemPtr,78int argc, char **argv));79static void DeleteBitmap _ANSI_ARGS_((Tk_Canvas canvas,80Tk_Item *itemPtr, Display *display));81static void DisplayBitmap _ANSI_ARGS_((Tk_Canvas canvas,82Tk_Item *itemPtr, Display *display, Drawable dst,83int x, int y, int width, int height));84static void ScaleBitmap _ANSI_ARGS_((Tk_Canvas canvas,85Tk_Item *itemPtr, double originX, double originY,86double scaleX, double scaleY));87static void TranslateBitmap _ANSI_ARGS_((Tk_Canvas canvas,88Tk_Item *itemPtr, double deltaX, double deltaY));8990/*91* The structures below defines the bitmap item type in terms of92* procedures that can be invoked by generic item code.93*/9495Tk_ItemType tkBitmapType = {96"bitmap", /* name */97sizeof(BitmapItem), /* itemSize */98CreateBitmap, /* createProc */99configSpecs, /* configSpecs */100ConfigureBitmap, /* configureProc */101BitmapCoords, /* coordProc */102DeleteBitmap, /* deleteProc */103DisplayBitmap, /* displayProc */1040, /* alwaysRedraw */105BitmapToPoint, /* pointProc */106BitmapToArea, /* areaProc */107BitmapToPostscript, /* postscriptProc */108ScaleBitmap, /* scaleProc */109TranslateBitmap, /* translateProc */110(Tk_ItemIndexProc *) NULL, /* indexProc */111(Tk_ItemCursorProc *) NULL, /* icursorProc */112(Tk_ItemSelectionProc *) NULL, /* selectionProc */113(Tk_ItemInsertProc *) NULL, /* insertProc */114(Tk_ItemDCharsProc *) NULL, /* dTextProc */115(Tk_ItemType *) NULL /* nextPtr */116};117118/*119*--------------------------------------------------------------120*121* CreateBitmap --122*123* This procedure is invoked to create a new bitmap124* item in a canvas.125*126* Results:127* A standard Tcl return value. If an error occurred in128* creating the item, then an error message is left in129* interp->result; in this case itemPtr is left uninitialized,130* so it can be safely freed by the caller.131*132* Side effects:133* A new bitmap item is created.134*135*--------------------------------------------------------------136*/137138static int139CreateBitmap(interp, canvas, itemPtr, argc, argv)140Tcl_Interp *interp; /* Interpreter for error reporting. */141Tk_Canvas canvas; /* Canvas to hold new item. */142Tk_Item *itemPtr; /* Record to hold new item; header143* has been initialized by caller. */144int argc; /* Number of arguments in argv. */145char **argv; /* Arguments describing rectangle. */146{147BitmapItem *bmapPtr = (BitmapItem *) itemPtr;148149if (argc < 2) {150Tcl_AppendResult(interp, "wrong # args: should be \"",151Tk_PathName(Tk_CanvasTkwin(canvas)), " create ",152itemPtr->typePtr->name, " x y ?options?\"",153(char *) NULL);154return TCL_ERROR;155}156157/*158* Initialize item's record.159*/160161bmapPtr->anchor = TK_ANCHOR_CENTER;162bmapPtr->bitmap = None;163bmapPtr->fgColor = NULL;164bmapPtr->bgColor = NULL;165bmapPtr->gc = None;166167/*168* Process the arguments to fill in the item record.169*/170171if ((Tk_CanvasGetCoord(interp, canvas, argv[0], &bmapPtr->x) != TCL_OK)172|| (Tk_CanvasGetCoord(interp, canvas, argv[1], &bmapPtr->y)173!= TCL_OK)) {174return TCL_ERROR;175}176177if (ConfigureBitmap(interp, canvas, itemPtr, argc-2, argv+2, 0) != TCL_OK) {178DeleteBitmap(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas)));179return TCL_ERROR;180}181return TCL_OK;182}183184/*185*--------------------------------------------------------------186*187* BitmapCoords --188*189* This procedure is invoked to process the "coords" widget190* command on bitmap items. See the user documentation for191* details on what it does.192*193* Results:194* Returns TCL_OK or TCL_ERROR, and sets interp->result.195*196* Side effects:197* The coordinates for the given item may be changed.198*199*--------------------------------------------------------------200*/201202static int203BitmapCoords(interp, canvas, itemPtr, argc, argv)204Tcl_Interp *interp; /* Used for error reporting. */205Tk_Canvas canvas; /* Canvas containing item. */206Tk_Item *itemPtr; /* Item whose coordinates are to be207* read or modified. */208int argc; /* Number of coordinates supplied in209* argv. */210char **argv; /* Array of coordinates: x1, y1,211* x2, y2, ... */212{213BitmapItem *bmapPtr = (BitmapItem *) itemPtr;214char x[TCL_DOUBLE_SPACE], y[TCL_DOUBLE_SPACE];215216if (argc == 0) {217Tcl_PrintDouble(interp, bmapPtr->x, x);218Tcl_PrintDouble(interp, bmapPtr->y, y);219Tcl_AppendResult(interp, x, " ", y, (char *) NULL);220} else if (argc == 2) {221if ((Tk_CanvasGetCoord(interp, canvas, argv[0], &bmapPtr->x) != TCL_OK)222|| (Tk_CanvasGetCoord(interp, canvas, argv[1], &bmapPtr->y)223!= TCL_OK)) {224return TCL_ERROR;225}226ComputeBitmapBbox(canvas, bmapPtr);227} else {228sprintf(interp->result,229"wrong # coordinates: expected 0 or 2, got %d", argc);230return TCL_ERROR;231}232return TCL_OK;233}234235/*236*--------------------------------------------------------------237*238* ConfigureBitmap --239*240* This procedure is invoked to configure various aspects241* of a bitmap item, such as its anchor position.242*243* Results:244* A standard Tcl result code. If an error occurs, then245* an error message is left in interp->result.246*247* Side effects:248* Configuration information may be set for itemPtr.249*250*--------------------------------------------------------------251*/252253static int254ConfigureBitmap(interp, canvas, itemPtr, argc, argv, flags)255Tcl_Interp *interp; /* Used for error reporting. */256Tk_Canvas canvas; /* Canvas containing itemPtr. */257Tk_Item *itemPtr; /* Bitmap item to reconfigure. */258int argc; /* Number of elements in argv. */259char **argv; /* Arguments describing things to configure. */260int flags; /* Flags to pass to Tk_ConfigureWidget. */261{262BitmapItem *bmapPtr = (BitmapItem *) itemPtr;263XGCValues gcValues;264GC newGC;265Tk_Window tkwin;266unsigned long mask;267268tkwin = Tk_CanvasTkwin(canvas);269if (Tk_ConfigureWidget(interp, tkwin, configSpecs, argc, argv,270(char *) bmapPtr, flags) != TCL_OK) {271return TCL_ERROR;272}273274/*275* A few of the options require additional processing, such as those276* that determine the graphics context.277*/278279gcValues.foreground = bmapPtr->fgColor->pixel;280mask = GCForeground;281if (bmapPtr->bgColor != NULL) {282gcValues.background = bmapPtr->bgColor->pixel;283mask |= GCBackground;284} else {285gcValues.clip_mask = bmapPtr->bitmap;286mask |= GCClipMask;287}288newGC = Tk_GetGC(tkwin, mask, &gcValues);289if (bmapPtr->gc != None) {290Tk_FreeGC(Tk_Display(tkwin), bmapPtr->gc);291}292bmapPtr->gc = newGC;293294ComputeBitmapBbox(canvas, bmapPtr);295296return TCL_OK;297}298299/*300*--------------------------------------------------------------301*302* DeleteBitmap --303*304* This procedure is called to clean up the data structure305* associated with a bitmap item.306*307* Results:308* None.309*310* Side effects:311* Resources associated with itemPtr are released.312*313*--------------------------------------------------------------314*/315316static void317DeleteBitmap(canvas, itemPtr, display)318Tk_Canvas canvas; /* Info about overall canvas widget. */319Tk_Item *itemPtr; /* Item that is being deleted. */320Display *display; /* Display containing window for321* canvas. */322{323BitmapItem *bmapPtr = (BitmapItem *) itemPtr;324325if (bmapPtr->bitmap != None) {326Tk_FreeBitmap(display, bmapPtr->bitmap);327}328if (bmapPtr->fgColor != NULL) {329Tk_FreeColor(bmapPtr->fgColor);330}331if (bmapPtr->bgColor != NULL) {332Tk_FreeColor(bmapPtr->bgColor);333}334if (bmapPtr->gc != NULL) {335Tk_FreeGC(display, bmapPtr->gc);336}337}338339/*340*--------------------------------------------------------------341*342* ComputeBitmapBbox --343*344* This procedure is invoked to compute the bounding box of345* all the pixels that may be drawn as part of a bitmap item.346* This procedure is where the child bitmap's placement is347* computed.348*349* Results:350* None.351*352* Side effects:353* The fields x1, y1, x2, and y2 are updated in the header354* for itemPtr.355*356*--------------------------------------------------------------357*/358359/* ARGSUSED */360static void361ComputeBitmapBbox(canvas, bmapPtr)362Tk_Canvas canvas; /* Canvas that contains item. */363BitmapItem *bmapPtr; /* Item whose bbox is to be364* recomputed. */365{366int width, height;367int x, y;368369x = bmapPtr->x + ((bmapPtr->x >= 0) ? 0.5 : - 0.5);370y = bmapPtr->y + ((bmapPtr->y >= 0) ? 0.5 : - 0.5);371372if (bmapPtr->bitmap == None) {373bmapPtr->header.x1 = bmapPtr->header.x2 = x;374bmapPtr->header.y1 = bmapPtr->header.y2 = y;375return;376}377378/*379* Compute location and size of bitmap, using anchor information.380*/381382Tk_SizeOfBitmap(Tk_Display(Tk_CanvasTkwin(canvas)), bmapPtr->bitmap,383&width, &height);384switch (bmapPtr->anchor) {385case TK_ANCHOR_N:386x -= width/2;387break;388case TK_ANCHOR_NE:389x -= width;390break;391case TK_ANCHOR_E:392x -= width;393y -= height/2;394break;395case TK_ANCHOR_SE:396x -= width;397y -= height;398break;399case TK_ANCHOR_S:400x -= width/2;401y -= height;402break;403case TK_ANCHOR_SW:404y -= height;405break;406case TK_ANCHOR_W:407y -= height/2;408break;409case TK_ANCHOR_NW:410break;411case TK_ANCHOR_CENTER:412x -= width/2;413y -= height/2;414break;415}416417/*418* Store the information in the item header.419*/420421bmapPtr->header.x1 = x;422bmapPtr->header.y1 = y;423bmapPtr->header.x2 = x + width;424bmapPtr->header.y2 = y + height;425}426427/*428*--------------------------------------------------------------429*430* DisplayBitmap --431*432* This procedure is invoked to draw a bitmap item in a given433* drawable.434*435* Results:436* None.437*438* Side effects:439* ItemPtr is drawn in drawable using the transformation440* information in canvas.441*442*--------------------------------------------------------------443*/444445static void446DisplayBitmap(canvas, itemPtr, display, drawable, x, y, width, height)447Tk_Canvas canvas; /* Canvas that contains item. */448Tk_Item *itemPtr; /* Item to be displayed. */449Display *display; /* Display on which to draw item. */450Drawable drawable; /* Pixmap or window in which to draw451* item. */452int x, y, width, height; /* Describes region of canvas that453* must be redisplayed (not used). */454{455BitmapItem *bmapPtr = (BitmapItem *) itemPtr;456int bmapX, bmapY, bmapWidth, bmapHeight;457short drawableX, drawableY;458459/*460* If the area being displayed doesn't cover the whole bitmap,461* then only redisplay the part of the bitmap that needs462* redisplay.463*/464465if (bmapPtr->bitmap != None) {466if (x > bmapPtr->header.x1) {467bmapX = x - bmapPtr->header.x1;468bmapWidth = bmapPtr->header.x2 - x;469} else {470bmapX = 0;471if ((x+width) < bmapPtr->header.x2) {472bmapWidth = x + width - bmapPtr->header.x1;473} else {474bmapWidth = bmapPtr->header.x2 - bmapPtr->header.x1;475}476}477if (y > bmapPtr->header.y1) {478bmapY = y - bmapPtr->header.y1;479bmapHeight = bmapPtr->header.y2 - y;480} else {481bmapY = 0;482if ((y+height) < bmapPtr->header.y2) {483bmapHeight = y + height - bmapPtr->header.y1;484} else {485bmapHeight = bmapPtr->header.y2 - bmapPtr->header.y1;486}487}488Tk_CanvasDrawableCoords(canvas,489(double) (bmapPtr->header.x1 + bmapX),490(double) (bmapPtr->header.y1 + bmapY),491&drawableX, &drawableY);492493/*494* Must modify the mask origin within the graphics context495* to line up with the bitmap's origin (in order to make496* bitmaps with "-background {}" work right).497*/498499XSetClipOrigin(display, bmapPtr->gc, drawableX - bmapX,500drawableY - bmapY);501XCopyPlane(display, bmapPtr->bitmap, drawable,502bmapPtr->gc, bmapX, bmapY, (unsigned int) bmapWidth,503(unsigned int) bmapHeight, drawableX, drawableY, 1);504}505}506507/*508*--------------------------------------------------------------509*510* BitmapToPoint --511*512* Computes the distance from a given point to a given513* rectangle, in canvas units.514*515* Results:516* The return value is 0 if the point whose x and y coordinates517* are coordPtr[0] and coordPtr[1] is inside the bitmap. If the518* point isn't inside the bitmap then the return value is the519* distance from the point to the bitmap.520*521* Side effects:522* None.523*524*--------------------------------------------------------------525*/526527/* ARGSUSED */528static double529BitmapToPoint(canvas, itemPtr, coordPtr)530Tk_Canvas canvas; /* Canvas containing item. */531Tk_Item *itemPtr; /* Item to check against point. */532double *coordPtr; /* Pointer to x and y coordinates. */533{534BitmapItem *bmapPtr = (BitmapItem *) itemPtr;535double x1, x2, y1, y2, xDiff, yDiff;536537x1 = bmapPtr->header.x1;538y1 = bmapPtr->header.y1;539x2 = bmapPtr->header.x2;540y2 = bmapPtr->header.y2;541542/*543* Point is outside rectangle.544*/545546if (coordPtr[0] < x1) {547xDiff = x1 - coordPtr[0];548} else if (coordPtr[0] > x2) {549xDiff = coordPtr[0] - x2;550} else {551xDiff = 0;552}553554if (coordPtr[1] < y1) {555yDiff = y1 - coordPtr[1];556} else if (coordPtr[1] > y2) {557yDiff = coordPtr[1] - y2;558} else {559yDiff = 0;560}561562return hypot(xDiff, yDiff);563}564565/*566*--------------------------------------------------------------567*568* BitmapToArea --569*570* This procedure is called to determine whether an item571* lies entirely inside, entirely outside, or overlapping572* a given rectangle.573*574* Results:575* -1 is returned if the item is entirely outside the area576* given by rectPtr, 0 if it overlaps, and 1 if it is entirely577* inside the given area.578*579* Side effects:580* None.581*582*--------------------------------------------------------------583*/584585/* ARGSUSED */586static int587BitmapToArea(canvas, itemPtr, rectPtr)588Tk_Canvas canvas; /* Canvas containing item. */589Tk_Item *itemPtr; /* Item to check against rectangle. */590double *rectPtr; /* Pointer to array of four coordinates591* (x1, y1, x2, y2) describing rectangular592* area. */593{594BitmapItem *bmapPtr = (BitmapItem *) itemPtr;595596if ((rectPtr[2] <= bmapPtr->header.x1)597|| (rectPtr[0] >= bmapPtr->header.x2)598|| (rectPtr[3] <= bmapPtr->header.y1)599|| (rectPtr[1] >= bmapPtr->header.y2)) {600return -1;601}602if ((rectPtr[0] <= bmapPtr->header.x1)603&& (rectPtr[1] <= bmapPtr->header.y1)604&& (rectPtr[2] >= bmapPtr->header.x2)605&& (rectPtr[3] >= bmapPtr->header.y2)) {606return 1;607}608return 0;609}610611/*612*--------------------------------------------------------------613*614* ScaleBitmap --615*616* This procedure is invoked to rescale a bitmap item in a617* canvas. It is one of the standard item procedures for618* bitmap items, and is invoked by the generic canvas code.619*620* Results:621* None.622*623* Side effects:624* The item referred to by itemPtr is rescaled so that the625* following transformation is applied to all point coordinates:626* x' = originX + scaleX*(x-originX)627* y' = originY + scaleY*(y-originY)628*629*--------------------------------------------------------------630*/631632static void633ScaleBitmap(canvas, itemPtr, originX, originY, scaleX, scaleY)634Tk_Canvas canvas; /* Canvas containing rectangle. */635Tk_Item *itemPtr; /* Rectangle to be scaled. */636double originX, originY; /* Origin about which to scale item. */637double scaleX; /* Amount to scale in X direction. */638double scaleY; /* Amount to scale in Y direction. */639{640BitmapItem *bmapPtr = (BitmapItem *) itemPtr;641642bmapPtr->x = originX + scaleX*(bmapPtr->x - originX);643bmapPtr->y = originY + scaleY*(bmapPtr->y - originY);644ComputeBitmapBbox(canvas, bmapPtr);645}646647/*648*--------------------------------------------------------------649*650* TranslateBitmap --651*652* This procedure is called to move an item by a given amount.653*654* Results:655* None.656*657* Side effects:658* The position of the item is offset by (xDelta, yDelta), and659* the bounding box is updated in the generic part of the item660* structure.661*662*--------------------------------------------------------------663*/664665static void666TranslateBitmap(canvas, itemPtr, deltaX, deltaY)667Tk_Canvas canvas; /* Canvas containing item. */668Tk_Item *itemPtr; /* Item that is being moved. */669double deltaX, deltaY; /* Amount by which item is to be670* moved. */671{672BitmapItem *bmapPtr = (BitmapItem *) itemPtr;673674bmapPtr->x += deltaX;675bmapPtr->y += deltaY;676ComputeBitmapBbox(canvas, bmapPtr);677}678679/*680*--------------------------------------------------------------681*682* BitmapToPostscript --683*684* This procedure is called to generate Postscript for685* bitmap items.686*687* Results:688* The return value is a standard Tcl result. If an error689* occurs in generating Postscript then an error message is690* left in interp->result, replacing whatever used to be there.691* If no error occurs, then Postscript for the item is appended692* to the result.693*694* Side effects:695* None.696*697*--------------------------------------------------------------698*/699700static int701BitmapToPostscript(interp, canvas, itemPtr, prepass)702Tcl_Interp *interp; /* Leave Postscript or error message703* here. */704Tk_Canvas canvas; /* Information about overall canvas. */705Tk_Item *itemPtr; /* Item for which Postscript is706* wanted. */707int prepass; /* 1 means this is a prepass to708* collect font information; 0 means709* final Postscript is being created. */710{711BitmapItem *bmapPtr = (BitmapItem *) itemPtr;712double x, y;713int width, height, rowsAtOnce, rowsThisTime;714int curRow;715char buffer[200];716717if (bmapPtr->bitmap == None) {718return TCL_OK;719}720721/*722* Compute the coordinates of the lower-left corner of the bitmap,723* taking into account the anchor position for the bitmp.724*/725726x = bmapPtr->x;727y = Tk_CanvasPsY(canvas, bmapPtr->y);728Tk_SizeOfBitmap(Tk_Display(Tk_CanvasTkwin(canvas)), bmapPtr->bitmap,729&width, &height);730switch (bmapPtr->anchor) {731case TK_ANCHOR_NW: y -= height; break;732case TK_ANCHOR_N: x -= width/2.0; y -= height; break;733case TK_ANCHOR_NE: x -= width; y -= height; break;734case TK_ANCHOR_E: x -= width; y -= height/2.0; break;735case TK_ANCHOR_SE: x -= width; break;736case TK_ANCHOR_S: x -= width/2.0; break;737case TK_ANCHOR_SW: break;738case TK_ANCHOR_W: y -= height/2.0; break;739case TK_ANCHOR_CENTER: x -= width/2.0; y -= height/2.0; break;740}741742/*743* Color the background, if there is one.744*/745746if (bmapPtr->bgColor != NULL) {747sprintf(buffer,748"%.15g %.15g moveto %d 0 rlineto 0 %d rlineto %d %s\n",749x, y, width, height, -width,"0 rlineto closepath");750Tcl_AppendResult(interp, buffer, (char *) NULL);751if (Tk_CanvasPsColor(interp, canvas, bmapPtr->bgColor) != TCL_OK) {752return TCL_ERROR;753}754Tcl_AppendResult(interp, "fill\n", (char *) NULL);755}756757/*758* Draw the bitmap, if there is a foreground color. If the bitmap759* is very large, then chop it up into multiple bitmaps, each760* consisting of one or more rows. This is needed because Postscript761* can't handle single strings longer than 64 KBytes long.762*/763764if (bmapPtr->fgColor != NULL) {765if (Tk_CanvasPsColor(interp, canvas, bmapPtr->fgColor) != TCL_OK) {766return TCL_ERROR;767}768if (width > 60000) {769Tcl_ResetResult(interp);770Tcl_AppendResult(interp, "can't generate Postscript",771" for bitmaps more than 60000 pixels wide",772(char *) NULL);773return TCL_ERROR;774}775rowsAtOnce = 60000/width;776if (rowsAtOnce < 1) {777rowsAtOnce = 1;778}779sprintf(buffer, "%.15g %.15g translate\n", x, y+height);780Tcl_AppendResult(interp, buffer, (char *) NULL);781for (curRow = 0; curRow < height; curRow += rowsAtOnce) {782rowsThisTime = rowsAtOnce;783if (rowsThisTime > (height - curRow)) {784rowsThisTime = height - curRow;785}786sprintf(buffer, "0 -%.15g translate\n%d %d true matrix {\n",787(double) rowsThisTime, width, rowsThisTime);788Tcl_AppendResult(interp, buffer, (char *) NULL);789if (Tk_CanvasPsBitmap(interp, canvas, bmapPtr->bitmap,7900, curRow, width, rowsThisTime) != TCL_OK) {791return TCL_ERROR;792}793Tcl_AppendResult(interp, "\n} imagemask\n", (char *) NULL);794}795}796return TCL_OK;797}798799800