tkCanvPs.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:55k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /* 
  2.  * tkCanvPs.c --
  3.  *
  4.  * This module provides Postscript output support for canvases,
  5.  * including the "postscript" widget command plus a few utility
  6.  * procedures used for generating Postscript.
  7.  *
  8.  * Copyright (c) 1991-1994 The Regents of the University of California.
  9.  * Copyright (c) 1994-1997 Sun Microsystems, Inc.
  10.  *
  11.  * See the file "license.terms" for information on usage and redistribution
  12.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  13.  *
  14.  * RCS: @(#) $Id: tkCanvPs.c,v 1.13.2.1 2004/02/23 10:49:29 das Exp $
  15.  */
  16. #include "tkInt.h"
  17. #include "tkCanvas.h"
  18. #include "tkPort.h"
  19. /*
  20.  * See tkCanvas.h for key data structures used to implement canvases.
  21.  */
  22. /*
  23.  * The following definition is used in generating postscript for images
  24.  * and windows.
  25.  */
  26. typedef struct TkColormapData { /* Hold color information for a window */
  27.     int separated; /* Whether to use separate color bands */
  28.     int color; /* Whether window is color or black/white */
  29.     int ncolors; /* Number of color values stored */
  30.     XColor *colors; /* Pixel value -> RGB mappings */
  31.     int red_mask, green_mask, blue_mask; /* Masks and shifts for each */
  32.     int red_shift, green_shift, blue_shift; /* color band */
  33. } TkColormapData;
  34. /*
  35.  * One of the following structures is created to keep track of Postscript
  36.  * output being generated.  It consists mostly of information provided on
  37.  * the widget command line.
  38.  */
  39. typedef struct TkPostscriptInfo {
  40.     int x, y, width, height; /* Area to print, in canvas pixel
  41.  * coordinates. */
  42.     int x2, y2; /* x+width and y+height. */
  43.     char *pageXString; /* String value of "-pagex" option or NULL. */
  44.     char *pageYString; /* String value of "-pagey" option or NULL. */
  45.     double pageX, pageY; /* Postscript coordinates (in points)
  46.  * corresponding to pageXString and
  47.  * pageYString. Don't forget that y-values
  48.  * grow upwards for Postscript! */
  49.     char *pageWidthString; /* Printed width of output. */
  50.     char *pageHeightString; /* Printed height of output. */
  51.     double scale; /* Scale factor for conversion: each pixel
  52.  * maps into this many points. */
  53.     Tk_Anchor pageAnchor; /* How to anchor bbox on Postscript page. */
  54.     int rotate; /* Non-zero means output should be rotated
  55.  * on page (landscape mode). */
  56.     char *fontVar; /* If non-NULL, gives name of global variable
  57.  * containing font mapping information.
  58.  * Malloc'ed. */
  59.     char *colorVar; /* If non-NULL, give name of global variable
  60.  * containing color mapping information.
  61.  * Malloc'ed. */
  62.     char *colorMode; /* Mode for handling colors:  "monochrome",
  63.  * "gray", or "color".  Malloc'ed. */
  64.     int colorLevel; /* Numeric value corresponding to colorMode:
  65.  * 0 for mono, 1 for gray, 2 for color. */
  66.     char *fileName; /* Name of file in which to write Postscript;
  67.  * NULL means return Postscript info as
  68.  * result. Malloc'ed. */
  69.     char *channelName; /* If -channel is specified, the name of
  70.                                  * the channel to use. */
  71.     Tcl_Channel chan; /* Open channel corresponding to fileName. */
  72.     Tcl_HashTable fontTable; /* Hash table containing names of all font
  73.  * families used in output.  The hash table
  74.  * values are not used. */
  75.     int prepass; /* Non-zero means that we're currently in
  76.  * the pre-pass that collects font information,
  77.  * so the Postscript generated isn't
  78.  * relevant. */
  79.     int prolog; /* Non-zero means output should contain
  80.    the file prolog.ps in the header. */
  81. } TkPostscriptInfo;
  82. /*
  83.  * The table below provides a template that's used to process arguments
  84.  * to the canvas "postscript" command and fill in TkPostscriptInfo
  85.  * structures.
  86.  */
  87. static Tk_ConfigSpec configSpecs[] = {
  88.     {TK_CONFIG_STRING, "-colormap", (char *) NULL, (char *) NULL,
  89. "", Tk_Offset(TkPostscriptInfo, colorVar), 0},
  90.     {TK_CONFIG_STRING, "-colormode", (char *) NULL, (char *) NULL,
  91. "", Tk_Offset(TkPostscriptInfo, colorMode), 0},
  92.     {TK_CONFIG_STRING, "-file", (char *) NULL, (char *) NULL,
  93. "", Tk_Offset(TkPostscriptInfo, fileName), 0},
  94.     {TK_CONFIG_STRING, "-channel", (char *) NULL, (char *) NULL,
  95. "", Tk_Offset(TkPostscriptInfo, channelName), 0},
  96.     {TK_CONFIG_STRING, "-fontmap", (char *) NULL, (char *) NULL,
  97. "", Tk_Offset(TkPostscriptInfo, fontVar), 0},
  98.     {TK_CONFIG_PIXELS, "-height", (char *) NULL, (char *) NULL,
  99. "", Tk_Offset(TkPostscriptInfo, height), 0},
  100.     {TK_CONFIG_ANCHOR, "-pageanchor", (char *) NULL, (char *) NULL,
  101. "", Tk_Offset(TkPostscriptInfo, pageAnchor), 0},
  102.     {TK_CONFIG_STRING, "-pageheight", (char *) NULL, (char *) NULL,
  103. "", Tk_Offset(TkPostscriptInfo, pageHeightString), 0},
  104.     {TK_CONFIG_STRING, "-pagewidth", (char *) NULL, (char *) NULL,
  105. "", Tk_Offset(TkPostscriptInfo, pageWidthString), 0},
  106.     {TK_CONFIG_STRING, "-pagex", (char *) NULL, (char *) NULL,
  107. "", Tk_Offset(TkPostscriptInfo, pageXString), 0},
  108.     {TK_CONFIG_STRING, "-pagey", (char *) NULL, (char *) NULL,
  109. "", Tk_Offset(TkPostscriptInfo, pageYString), 0},
  110.     {TK_CONFIG_BOOLEAN, "-prolog", (char *) NULL, (char *) NULL,
  111. "", Tk_Offset(TkPostscriptInfo, prolog), 0},
  112.     {TK_CONFIG_BOOLEAN, "-rotate", (char *) NULL, (char *) NULL,
  113. "", Tk_Offset(TkPostscriptInfo, rotate), 0},
  114.     {TK_CONFIG_PIXELS, "-width", (char *) NULL, (char *) NULL,
  115. "", Tk_Offset(TkPostscriptInfo, width), 0},
  116.     {TK_CONFIG_PIXELS, "-x", (char *) NULL, (char *) NULL,
  117. "", Tk_Offset(TkPostscriptInfo, x), 0},
  118.     {TK_CONFIG_PIXELS, "-y", (char *) NULL, (char *) NULL,
  119. "", Tk_Offset(TkPostscriptInfo, y), 0},
  120.     {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
  121. (char *) NULL, 0, 0}
  122. };
  123. /*
  124.  * Forward declarations for procedures defined later in this file:
  125.  */
  126. static int GetPostscriptPoints _ANSI_ARGS_((Tcl_Interp *interp,
  127.     char *string, double *doublePtr));
  128. /*
  129.  *--------------------------------------------------------------
  130.  *
  131.  * TkCanvPostscriptCmd --
  132.  *
  133.  * This procedure is invoked to process the "postscript" options
  134.  * of the widget command for canvas widgets. See the user
  135.  * documentation for details on what it does.
  136.  *
  137.  * Results:
  138.  * A standard Tcl result.
  139.  *
  140.  * Side effects:
  141.  * See the user documentation.
  142.  *
  143.  *--------------------------------------------------------------
  144.  */
  145.     /* ARGSUSED */
  146. int
  147. TkCanvPostscriptCmd(canvasPtr, interp, argc, argv)
  148.     TkCanvas *canvasPtr; /* Information about canvas widget. */
  149.     Tcl_Interp *interp; /* Current interpreter. */
  150.     int argc; /* Number of arguments. */
  151.     CONST char **argv; /* Argument strings.  Caller has
  152.  * already parsed this command enough
  153.  * to know that argv[1] is
  154.  * "postscript". */
  155. {
  156.     TkPostscriptInfo psInfo;
  157.     Tk_PostscriptInfo oldInfoPtr;
  158.     int result;
  159.     Tk_Item *itemPtr;
  160. #define STRING_LENGTH 400
  161.     char string[STRING_LENGTH+1];
  162.     CONST char *p;
  163.     time_t now;
  164.     size_t length;
  165.     Tk_Window tkwin = canvasPtr->tkwin;
  166.     int deltaX = 0, deltaY = 0; /* Offset of lower-left corner of
  167.  * area to be marked up, measured
  168.  * in canvas units from the positioning
  169.  * point on the page (reflects
  170.  * anchor position).  Initial values
  171.  * needed only to stop compiler
  172.  * warnings. */
  173.     Tcl_HashSearch search;
  174.     Tcl_HashEntry *hPtr;
  175.     Tcl_DString buffer;
  176.     char psenccmd[]="::tk::ensure_psenc_is_loaded";
  177.     /*
  178.      *----------------------------------------------------------------
  179.      * Initialize the data structure describing Postscript generation,
  180.      * then process all the arguments to fill the data structure in.
  181.      *----------------------------------------------------------------
  182.      */
  183.     result = Tcl_EvalEx(interp,psenccmd,-1,TCL_EVAL_GLOBAL);
  184.     if (result != TCL_OK) {
  185.         return result;
  186.     }
  187.     oldInfoPtr = canvasPtr->psInfo;
  188.     canvasPtr->psInfo = (Tk_PostscriptInfo) &psInfo;
  189.     psInfo.x = canvasPtr->xOrigin;
  190.     psInfo.y = canvasPtr->yOrigin;
  191.     psInfo.width = -1;
  192.     psInfo.height = -1;
  193.     psInfo.pageXString = NULL;
  194.     psInfo.pageYString = NULL;
  195.     psInfo.pageX = 72*4.25;
  196.     psInfo.pageY = 72*5.5;
  197.     psInfo.pageWidthString = NULL;
  198.     psInfo.pageHeightString = NULL;
  199.     psInfo.scale = 1.0;
  200.     psInfo.pageAnchor = TK_ANCHOR_CENTER;
  201.     psInfo.rotate = 0;
  202.     psInfo.fontVar = NULL;
  203.     psInfo.colorVar = NULL;
  204.     psInfo.colorMode = NULL;
  205.     psInfo.colorLevel = 0;
  206.     psInfo.fileName = NULL;
  207.     psInfo.channelName = NULL;
  208.     psInfo.chan = NULL;
  209.     psInfo.prepass = 0;
  210.     psInfo.prolog = 1;
  211.     Tcl_InitHashTable(&psInfo.fontTable, TCL_STRING_KEYS);
  212.     result = Tk_ConfigureWidget(interp, tkwin,
  213.     configSpecs, argc-2, argv+2, (char *) &psInfo,
  214.     TK_CONFIG_ARGV_ONLY);
  215.     if (result != TCL_OK) {
  216. goto cleanup;
  217.     }
  218.     if (psInfo.width == -1) {
  219. psInfo.width = Tk_Width(tkwin);
  220.     }
  221.     if (psInfo.height == -1) {
  222. psInfo.height = Tk_Height(tkwin);
  223.     }
  224.     psInfo.x2 = psInfo.x + psInfo.width;
  225.     psInfo.y2 = psInfo.y + psInfo.height;
  226.     if (psInfo.pageXString != NULL) {
  227. if (GetPostscriptPoints(interp, psInfo.pageXString,
  228. &psInfo.pageX) != TCL_OK) {
  229.     goto cleanup;
  230. }
  231.     }
  232.     if (psInfo.pageYString != NULL) {
  233. if (GetPostscriptPoints(interp, psInfo.pageYString,
  234. &psInfo.pageY) != TCL_OK) {
  235.     goto cleanup;
  236. }
  237.     }
  238.     if (psInfo.pageWidthString != NULL) {
  239. if (GetPostscriptPoints(interp, psInfo.pageWidthString,
  240. &psInfo.scale) != TCL_OK) {
  241.     goto cleanup;
  242. }
  243. psInfo.scale /= psInfo.width;
  244.     } else if (psInfo.pageHeightString != NULL) {
  245. if (GetPostscriptPoints(interp, psInfo.pageHeightString,
  246. &psInfo.scale) != TCL_OK) {
  247.     goto cleanup;
  248. }
  249. psInfo.scale /= psInfo.height;
  250.     } else {
  251. psInfo.scale = (72.0/25.4)*WidthMMOfScreen(Tk_Screen(tkwin));
  252. psInfo.scale /= WidthOfScreen(Tk_Screen(tkwin));
  253.     }
  254.     switch (psInfo.pageAnchor) {
  255. case TK_ANCHOR_NW:
  256. case TK_ANCHOR_W:
  257. case TK_ANCHOR_SW:
  258.     deltaX = 0;
  259.     break;
  260. case TK_ANCHOR_N:
  261. case TK_ANCHOR_CENTER:
  262. case TK_ANCHOR_S:
  263.     deltaX = -psInfo.width/2;
  264.     break;
  265. case TK_ANCHOR_NE:
  266. case TK_ANCHOR_E:
  267. case TK_ANCHOR_SE:
  268.     deltaX = -psInfo.width;
  269.     break;
  270.     }
  271.     switch (psInfo.pageAnchor) {
  272. case TK_ANCHOR_NW:
  273. case TK_ANCHOR_N:
  274. case TK_ANCHOR_NE:
  275.     deltaY = - psInfo.height;
  276.     break;
  277. case TK_ANCHOR_W:
  278. case TK_ANCHOR_CENTER:
  279. case TK_ANCHOR_E:
  280.     deltaY = -psInfo.height/2;
  281.     break;
  282. case TK_ANCHOR_SW:
  283. case TK_ANCHOR_S:
  284. case TK_ANCHOR_SE:
  285.     deltaY = 0;
  286.     break;
  287.     }
  288.     if (psInfo.colorMode == NULL) {
  289. psInfo.colorLevel = 2;
  290.     } else {
  291. length = strlen(psInfo.colorMode);
  292. if (strncmp(psInfo.colorMode, "monochrome", length) == 0) {
  293.     psInfo.colorLevel = 0;
  294. } else if (strncmp(psInfo.colorMode, "gray", length) == 0) {
  295.     psInfo.colorLevel = 1;
  296. } else if (strncmp(psInfo.colorMode, "color", length) == 0) {
  297.     psInfo.colorLevel = 2;
  298. } else {
  299.     Tcl_AppendResult(interp, "bad color mode "",
  300.     psInfo.colorMode, "": must be monochrome, ",
  301.     "gray, or color", (char *) NULL);
  302.     goto cleanup;
  303. }
  304.     }
  305.     if (psInfo.fileName != NULL) {
  306.         /*
  307.          * Check that -file and -channel are not both specified.
  308.          */
  309.         if (psInfo.channelName != NULL) {
  310.             Tcl_AppendResult(interp, "can't specify both -file",
  311.                     " and -channel", (char *) NULL);
  312.             result = TCL_ERROR;
  313.             goto cleanup;
  314.         }
  315.         /*
  316.          * Check that we are not in a safe interpreter. If we are, disallow
  317.          * the -file specification.
  318.          */
  319.         if (Tcl_IsSafe(interp)) {
  320.             Tcl_AppendResult(interp, "can't specify -file in a",
  321.                     " safe interpreter", (char *) NULL);
  322.             result = TCL_ERROR;
  323.             goto cleanup;
  324.         }
  325.         
  326. p = Tcl_TranslateFileName(interp, psInfo.fileName, &buffer);
  327. if (p == NULL) {
  328.     goto cleanup;
  329. }
  330. psInfo.chan = Tcl_OpenFileChannel(interp, p, "w", 0666);
  331. Tcl_DStringFree(&buffer);
  332. if (psInfo.chan == NULL) {
  333.     goto cleanup;
  334. }
  335.     }
  336.     if (psInfo.channelName != NULL) {
  337.         int mode;
  338.         
  339.         /*
  340.          * Check that the channel is found in this interpreter and that it
  341.          * is open for writing.
  342.          */
  343.         psInfo.chan = Tcl_GetChannel(interp, psInfo.channelName,
  344.                 &mode);
  345.         if (psInfo.chan == (Tcl_Channel) NULL) {
  346.             result = TCL_ERROR;
  347.             goto cleanup;
  348.         }
  349.         if ((mode & TCL_WRITABLE) == 0) {
  350.             Tcl_AppendResult(interp, "channel "",
  351.                     psInfo.channelName, "" wasn't opened for writing",
  352.                     (char *) NULL);
  353.             result = TCL_ERROR;
  354.             goto cleanup;
  355.         }
  356.     }
  357.     
  358.     /*
  359.      *--------------------------------------------------------
  360.      * Make a pre-pass over all of the items, generating Postscript
  361.      * and then throwing it away.  The purpose of this pass is just
  362.      * to collect information about all the fonts in use, so that
  363.      * we can output font information in the proper form required
  364.      * by the Document Structuring Conventions.
  365.      *--------------------------------------------------------
  366.      */
  367.     psInfo.prepass = 1;
  368.     for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
  369.     itemPtr = itemPtr->nextPtr) {
  370. if ((itemPtr->x1 >= psInfo.x2) || (itemPtr->x2 < psInfo.x)
  371. || (itemPtr->y1 >= psInfo.y2) || (itemPtr->y2 < psInfo.y)) {
  372.     continue;
  373. }
  374. if (itemPtr->typePtr->postscriptProc == NULL) {
  375.     continue;
  376. }
  377. result = (*itemPtr->typePtr->postscriptProc)(interp,
  378. (Tk_Canvas) canvasPtr, itemPtr, 1);
  379. Tcl_ResetResult(interp);
  380. if (result != TCL_OK) {
  381.     /*
  382.      * An error just occurred.  Just skip out of this loop.
  383.      * There's no need to report the error now;  it can be
  384.      * reported later (errors can happen later that don't
  385.      * happen now, so we still have to check for errors later
  386.      * anyway).
  387.      */
  388.     break;
  389. }
  390.     }
  391.     psInfo.prepass = 0;
  392.     /*
  393.      *--------------------------------------------------------
  394.      * Generate the header and prolog for the Postscript.
  395.      *--------------------------------------------------------
  396.      */
  397.     if (psInfo.prolog) {
  398.       Tcl_AppendResult(interp, "%!PS-Adobe-3.0 EPSF-3.0n",
  399.        "%%Creator: Tk Canvas Widgetn", (char *) NULL);
  400. #ifdef HAVE_PW_GECOS
  401.     if (!Tcl_IsSafe(interp)) {
  402. struct passwd *pwPtr = getpwuid(getuid()); /* INTL: Native. */
  403. Tcl_AppendResult(interp, "%%For: ",
  404. (pwPtr != NULL) ? pwPtr->pw_gecos : "Unknown", "n",
  405. (char *) NULL);
  406. endpwent();
  407.     }
  408. #endif /* HAVE_PW_GECOS */
  409.     Tcl_AppendResult(interp, "%%Title: Window ",
  410.     Tk_PathName(tkwin), "n", (char *) NULL);
  411.     time(&now);
  412.     Tcl_AppendResult(interp, "%%CreationDate: ",
  413.     ctime(&now), (char *) NULL); /* INTL: Native. */
  414.     if (!psInfo.rotate) {
  415. sprintf(string, "%d %d %d %d",
  416. (int) (psInfo.pageX + psInfo.scale*deltaX),
  417. (int) (psInfo.pageY + psInfo.scale*deltaY),
  418. (int) (psInfo.pageX + psInfo.scale*(deltaX + psInfo.width)
  419. + 1.0),
  420. (int) (psInfo.pageY + psInfo.scale*(deltaY + psInfo.height)
  421. + 1.0));
  422.     } else {
  423. sprintf(string, "%d %d %d %d",
  424. (int) (psInfo.pageX - psInfo.scale*(deltaY + psInfo.height)),
  425. (int) (psInfo.pageY + psInfo.scale*deltaX),
  426. (int) (psInfo.pageX - psInfo.scale*deltaY + 1.0),
  427. (int) (psInfo.pageY + psInfo.scale*(deltaX + psInfo.width)
  428. + 1.0));
  429.     }
  430.     Tcl_AppendResult(interp, "%%BoundingBox: ", string,
  431.     "n", (char *) NULL);
  432.     Tcl_AppendResult(interp, "%%Pages: 1n", 
  433.     "%%DocumentData: Clean7Bitn", (char *) NULL);
  434.     Tcl_AppendResult(interp, "%%Orientation: ",
  435.     psInfo.rotate ? "Landscapen" : "Portraitn", (char *) NULL);
  436.     p = "%%DocumentNeededResources: font ";
  437.     for (hPtr = Tcl_FirstHashEntry(&psInfo.fontTable, &search);
  438.     hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
  439. Tcl_AppendResult(interp, p,
  440. Tcl_GetHashKey(&psInfo.fontTable, hPtr),
  441. "n", (char *) NULL);
  442. p = "%%+ font ";
  443.     }
  444.     Tcl_AppendResult(interp, "%%EndCommentsnn", (char *) NULL);
  445.     /*
  446.      * Insert the prolog
  447.      */
  448.     Tcl_AppendResult(interp, Tcl_GetVar(interp,"::tk::ps_preamable",
  449.     TCL_GLOBAL_ONLY), (char *) NULL);
  450.     if (psInfo.chan != NULL) {
  451.         Tcl_Write(psInfo.chan, Tcl_GetStringResult(interp), -1);
  452. Tcl_ResetResult(canvasPtr->interp);
  453.     }
  454.     /*
  455.      *-----------------------------------------------------------
  456.      * Document setup:  set the color level and include fonts.
  457.      *-----------------------------------------------------------
  458.      */
  459.     sprintf(string, "/CL %d defn", psInfo.colorLevel);
  460.     Tcl_AppendResult(interp, "%%BeginSetupn", string,
  461.     (char *) NULL);
  462.     for (hPtr = Tcl_FirstHashEntry(&psInfo.fontTable, &search);
  463.     hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
  464. Tcl_AppendResult(interp, "%%IncludeResource: font ",
  465. Tcl_GetHashKey(&psInfo.fontTable, hPtr), "n", (char *) NULL);
  466.     }
  467.     Tcl_AppendResult(interp, "%%EndSetupnn", (char *) NULL);
  468.     /*
  469.      *-----------------------------------------------------------
  470.      * Page setup:  move to page positioning point, rotate if
  471.      * needed, set scale factor, offset for proper anchor position,
  472.      * and set clip region.
  473.      *-----------------------------------------------------------
  474.      */
  475.     Tcl_AppendResult(interp, "%%Page: 1 1n", "saven",
  476.     (char *) NULL);
  477.     sprintf(string, "%.1f %.1f translaten", psInfo.pageX, psInfo.pageY);
  478.     Tcl_AppendResult(interp, string, (char *) NULL);
  479.     if (psInfo.rotate) {
  480. Tcl_AppendResult(interp, "90 rotaten", (char *) NULL);
  481.     }
  482.     sprintf(string, "%.4g %.4g scalen", psInfo.scale, psInfo.scale);
  483.     Tcl_AppendResult(interp, string, (char *) NULL);
  484.     sprintf(string, "%d %d translaten", deltaX - psInfo.x, deltaY);
  485.     Tcl_AppendResult(interp, string, (char *) NULL);
  486.     sprintf(string, "%d %.15g moveto %d %.15g lineto %d %.15g lineto %d %.15g",
  487.     psInfo.x,
  488.     Tk_PostscriptY((double) psInfo.y, (Tk_PostscriptInfo) &psInfo),
  489.     psInfo.x2,
  490.     Tk_PostscriptY((double) psInfo.y, (Tk_PostscriptInfo) &psInfo),
  491.     psInfo.x2, 
  492.     Tk_PostscriptY((double) psInfo.y2, (Tk_PostscriptInfo) &psInfo),
  493.     psInfo.x,
  494.     Tk_PostscriptY((double) psInfo.y2, (Tk_PostscriptInfo) &psInfo));
  495.     Tcl_AppendResult(interp, string,
  496. " lineto closepath clip newpathn", (char *) NULL);
  497.     }
  498.     if (psInfo.chan != NULL) {
  499. Tcl_Write(psInfo.chan, Tcl_GetStringResult(interp), -1);
  500. Tcl_ResetResult(canvasPtr->interp);
  501.     }
  502.     /*
  503.      *---------------------------------------------------------------------
  504.      * Iterate through all the items, having each relevant one draw itself.
  505.      * Quit if any of the items returns an error.
  506.      *---------------------------------------------------------------------
  507.      */
  508.     result = TCL_OK;
  509.     for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
  510.     itemPtr = itemPtr->nextPtr) {
  511. if ((itemPtr->x1 >= psInfo.x2) || (itemPtr->x2 < psInfo.x)
  512. || (itemPtr->y1 >= psInfo.y2) || (itemPtr->y2 < psInfo.y)) {
  513.     continue;
  514. }
  515. if (itemPtr->typePtr->postscriptProc == NULL) {
  516.     continue;
  517. }
  518. if (itemPtr->state == TK_STATE_HIDDEN) {
  519.     continue;
  520. }
  521. Tcl_AppendResult(interp, "gsaven", (char *) NULL);
  522. result = (*itemPtr->typePtr->postscriptProc)(interp,
  523. (Tk_Canvas) canvasPtr, itemPtr, 0);
  524. if (result != TCL_OK) {
  525.     char msg[64 + TCL_INTEGER_SPACE];
  526.     sprintf(msg, "n    (generating Postscript for item %d)",
  527.     itemPtr->id);
  528.     Tcl_AddErrorInfo(interp, msg);
  529.     goto cleanup;
  530. }
  531. Tcl_AppendResult(interp, "grestoren", (char *) NULL);
  532. if (psInfo.chan != NULL) {
  533.     Tcl_Write(psInfo.chan, Tcl_GetStringResult(interp), -1);
  534.     Tcl_ResetResult(interp);
  535. }
  536.     }
  537.     /*
  538.      *---------------------------------------------------------------------
  539.      * Output page-end information, such as commands to print the page
  540.      * and document trailer stuff.
  541.      *---------------------------------------------------------------------
  542.      */
  543.     if (psInfo.prolog) {
  544.       Tcl_AppendResult(interp, "restore showpagenn",
  545.     "%%Trailernendn%%EOFn", (char *) NULL);
  546.     }
  547.     if (psInfo.chan != NULL) {
  548. Tcl_Write(psInfo.chan, Tcl_GetStringResult(interp), -1);
  549. Tcl_ResetResult(canvasPtr->interp);
  550.     }
  551.     /*
  552.      * Clean up psInfo to release malloc'ed stuff.
  553.      */
  554.     cleanup:
  555.     if (psInfo.pageXString != NULL) {
  556. ckfree(psInfo.pageXString);
  557.     }
  558.     if (psInfo.pageYString != NULL) {
  559. ckfree(psInfo.pageYString);
  560.     }
  561.     if (psInfo.pageWidthString != NULL) {
  562. ckfree(psInfo.pageWidthString);
  563.     }
  564.     if (psInfo.pageHeightString != NULL) {
  565. ckfree(psInfo.pageHeightString);
  566.     }
  567.     if (psInfo.fontVar != NULL) {
  568. ckfree(psInfo.fontVar);
  569.     }
  570.     if (psInfo.colorVar != NULL) {
  571. ckfree(psInfo.colorVar);
  572.     }
  573.     if (psInfo.colorMode != NULL) {
  574. ckfree(psInfo.colorMode);
  575.     }
  576.     if (psInfo.fileName != NULL) {
  577. ckfree(psInfo.fileName);
  578.     }
  579.     if ((psInfo.chan != NULL) && (psInfo.channelName == NULL)) {
  580. Tcl_Close(interp, psInfo.chan);
  581.     }
  582.     if (psInfo.channelName != NULL) {
  583.         ckfree(psInfo.channelName);
  584.     }
  585.     Tcl_DeleteHashTable(&psInfo.fontTable);
  586.     canvasPtr->psInfo = (Tk_PostscriptInfo) oldInfoPtr;
  587.     return result;
  588. }
  589. /*
  590.  *--------------------------------------------------------------
  591.  *
  592.  * Tk_PostscriptColor --
  593.  *
  594.  * This procedure is called by individual canvas items when
  595.  * they want to set a color value for output.  Given information
  596.  * about an X color, this procedure will generate Postscript
  597.  * commands to set up an appropriate color in Postscript.
  598.  *
  599.  * Results:
  600.  * Returns a standard Tcl return value.  If an error occurs
  601.  * then an error message will be left in the interp's result.
  602.  * If no error occurs, then additional Postscript will be
  603.  * appended to the interp's result.
  604.  *
  605.  * Side effects:
  606.  * None.
  607.  *
  608.  *--------------------------------------------------------------
  609.  */
  610. int
  611. Tk_PostscriptColor(interp, psInfo, colorPtr)
  612.     Tcl_Interp *interp;
  613.     Tk_PostscriptInfo psInfo; /* Postscript info. */
  614.     XColor *colorPtr; /* Information about color. */
  615. {
  616.     TkPostscriptInfo *psInfoPtr = (TkPostscriptInfo *) psInfo;
  617.     int tmp;
  618.     double red, green, blue;
  619.     char string[200];
  620.     if (psInfoPtr->prepass) {
  621. return TCL_OK;
  622.     }
  623.     /*
  624.      * If there is a color map defined, then look up the color's name
  625.      * in the map and use the Postscript commands found there, if there
  626.      * are any.
  627.      */
  628.     if (psInfoPtr->colorVar != NULL) {
  629. CONST char *cmdString;
  630. cmdString = Tcl_GetVar2(interp, psInfoPtr->colorVar,
  631. Tk_NameOfColor(colorPtr), 0);
  632. if (cmdString != NULL) {
  633.     Tcl_AppendResult(interp, cmdString, "n", (char *) NULL);
  634.     return TCL_OK;
  635. }
  636.     }
  637.     /*
  638.      * No color map entry for this color.  Grab the color's intensities
  639.      * and output Postscript commands for them.  Special note:  X uses
  640.      * a range of 0-65535 for intensities, but most displays only use
  641.      * a range of 0-255, which maps to (0, 256, 512, ... 65280) in the
  642.      * X scale.  This means that there's no way to get perfect white,
  643.      * since the highest intensity is only 65280 out of 65535.  To
  644.      * work around this problem, rescale the X intensity to a 0-255
  645.      * scale and use that as the basis for the Postscript colors.  This
  646.      * scheme still won't work if the display only uses 4 bits per color,
  647.      * but most diplays use at least 8 bits.
  648.      */
  649.     tmp = colorPtr->red;
  650.     red = ((double) (tmp >> 8))/255.0;
  651.     tmp = colorPtr->green;
  652.     green = ((double) (tmp >> 8))/255.0;
  653.     tmp = colorPtr->blue;
  654.     blue = ((double) (tmp >> 8))/255.0;
  655.     sprintf(string, "%.3f %.3f %.3f setrgbcolor AdjustColorn",
  656.     red, green, blue);
  657.     Tcl_AppendResult(interp, string, (char *) NULL);
  658.     return TCL_OK;
  659. }
  660. /*
  661.  *--------------------------------------------------------------
  662.  *
  663.  * Tk_PostscriptFont --
  664.  *
  665.  * This procedure is called by individual canvas items when
  666.  * they want to output text.  Given information about an X
  667.  * font, this procedure will generate Postscript commands
  668.  * to set up an appropriate font in Postscript.
  669.  *
  670.  * Results:
  671.  * Returns a standard Tcl return value.  If an error occurs
  672.  * then an error message will be left in the interp's result.
  673.  * If no error occurs, then additional Postscript will be
  674.  * appended to the interp's result.
  675.  *
  676.  * Side effects:
  677.  * The Postscript font name is entered into psInfoPtr->fontTable
  678.  * if it wasn't already there.
  679.  *
  680.  *--------------------------------------------------------------
  681.  */
  682. int
  683. Tk_PostscriptFont(interp, psInfo, tkfont)
  684.     Tcl_Interp *interp;
  685.     Tk_PostscriptInfo psInfo; /* Postscript Info. */
  686.     Tk_Font tkfont; /* Information about font in which text
  687.  * is to be printed. */
  688. {
  689.     TkPostscriptInfo *psInfoPtr = (TkPostscriptInfo *) psInfo;
  690.     char *end;
  691.     char pointString[TCL_INTEGER_SPACE];
  692.     Tcl_DString ds;
  693.     int i, points;
  694.     /*
  695.      * First, look up the font's name in the font map, if there is one.
  696.      * If there is an entry for this font, it consists of a list
  697.      * containing font name and size.  Use this information.
  698.      */
  699.     Tcl_DStringInit(&ds);
  700.     
  701.     if (psInfoPtr->fontVar != NULL) {
  702. CONST char *list;
  703. int argc;
  704. double size;
  705. CONST char **argv;
  706. CONST char *name;
  707. name = Tk_NameOfFont(tkfont);
  708. list = Tcl_GetVar2(interp, psInfoPtr->fontVar, name, 0);
  709. if (list != NULL) {
  710.     if (Tcl_SplitList(interp, list, &argc, &argv) != TCL_OK) {
  711. badMapEntry:
  712. Tcl_ResetResult(interp);
  713. Tcl_AppendResult(interp, "bad font map entry for "", name,
  714. "": "", list, """, (char *) NULL);
  715. return TCL_ERROR;
  716.     }
  717.     if (argc != 2) {
  718. goto badMapEntry;
  719.     }
  720.     size = strtod(argv[1], &end);
  721.     if ((size <= 0) || (*end != 0)) {
  722. goto badMapEntry;
  723.     }
  724.     Tcl_DStringAppend(&ds, argv[0], -1);
  725.     points = (int) size;
  726.     
  727.     ckfree((char *) argv);
  728.     goto findfont;
  729. }
  730.     } 
  731.     points = Tk_PostscriptFontName(tkfont, &ds);
  732.     findfont:
  733.     sprintf(pointString, "%d", points);
  734.     Tcl_AppendResult(interp, "/", Tcl_DStringValue(&ds), " findfont ",
  735.     pointString, " scalefont ", (char *) NULL);
  736.     if (strncasecmp(Tcl_DStringValue(&ds), "Symbol", 7) != 0) {
  737. Tcl_AppendResult(interp, "ISOEncode ", (char *) NULL);
  738.     }
  739.     Tcl_AppendResult(interp, "setfontn", (char *) NULL);
  740.     Tcl_CreateHashEntry(&psInfoPtr->fontTable, Tcl_DStringValue(&ds), &i);
  741.     Tcl_DStringFree(&ds);
  742.     return TCL_OK;
  743. }
  744. /*
  745.  *--------------------------------------------------------------
  746.  *
  747.  * Tk_PostscriptBitmap --
  748.  *
  749.  * This procedure is called to output the contents of a
  750.  * sub-region of a bitmap in proper image data format for
  751.  * Postscript (i.e. data between angle brackets, one bit
  752.  * per pixel).
  753.  *
  754.  * Results:
  755.  * Returns a standard Tcl return value.  If an error occurs
  756.  * then an error message will be left in the interp's result.
  757.  * If no error occurs, then additional Postscript will be
  758.  * appended to the interp's result.
  759.  *
  760.  * Side effects:
  761.  * None.
  762.  *
  763.  *--------------------------------------------------------------
  764.  */
  765. int
  766. Tk_PostscriptBitmap(interp, tkwin, psInfo, bitmap, startX, startY, width,
  767. height)
  768.     Tcl_Interp *interp;
  769.     Tk_Window tkwin;
  770.     Tk_PostscriptInfo psInfo; /* Postscript info. */
  771.     Pixmap bitmap; /* Bitmap for which to generate
  772.  * Postscript. */
  773.     int startX, startY; /* Coordinates of upper-left corner
  774.  * of rectangular region to output. */
  775.     int width, height; /* Height of rectangular region. */
  776. {
  777.     TkPostscriptInfo *psInfoPtr = (TkPostscriptInfo *) psInfo;
  778.     XImage *imagePtr;
  779.     int charsInLine, x, y, lastX, lastY, value, mask;
  780.     unsigned int totalWidth, totalHeight;
  781.     char string[100];
  782.     Window dummyRoot;
  783.     int dummyX, dummyY;
  784.     unsigned dummyBorderwidth, dummyDepth;
  785.     if (psInfoPtr->prepass) {
  786. return TCL_OK;
  787.     }
  788.     /*
  789.      * The following call should probably be a call to Tk_SizeOfBitmap
  790.      * instead, but it seems that we are occasionally invoked by custom
  791.      * item types that create their own bitmaps without registering them
  792.      * with Tk.  XGetGeometry is a bit slower than Tk_SizeOfBitmap, but
  793.      * it shouldn't matter here.
  794.      */
  795.     XGetGeometry(Tk_Display(tkwin), bitmap, &dummyRoot,
  796.     (int *) &dummyX, (int *) &dummyY, (unsigned int *) &totalWidth,
  797.     (unsigned int *) &totalHeight, &dummyBorderwidth, &dummyDepth);
  798.     imagePtr = XGetImage(Tk_Display(tkwin), bitmap, 0, 0,
  799.     totalWidth, totalHeight, 1, XYPixmap);
  800.     Tcl_AppendResult(interp, "<", (char *) NULL);
  801.     mask = 0x80;
  802.     value = 0;
  803.     charsInLine = 0;
  804.     lastX = startX + width - 1;
  805.     lastY = startY + height - 1;
  806.     for (y = lastY; y >= startY; y--) {
  807. for (x = startX; x <= lastX; x++) {
  808.     if (XGetPixel(imagePtr, x, y)) {
  809. value |= mask;
  810.     }
  811.     mask >>= 1;
  812.     if (mask == 0) {
  813. sprintf(string, "%02x", value);
  814. Tcl_AppendResult(interp, string, (char *) NULL);
  815. mask = 0x80;
  816. value = 0;
  817. charsInLine += 2;
  818. if (charsInLine >= 60) {
  819.     Tcl_AppendResult(interp, "n", (char *) NULL);
  820.     charsInLine = 0;
  821. }
  822.     }
  823. }
  824. if (mask != 0x80) {
  825.     sprintf(string, "%02x", value);
  826.     Tcl_AppendResult(interp, string, (char *) NULL);
  827.     mask = 0x80;
  828.     value = 0;
  829.     charsInLine += 2;
  830. }
  831.     }
  832.     Tcl_AppendResult(interp, ">", (char *) NULL);
  833.     XDestroyImage(imagePtr);
  834.     return TCL_OK;
  835. }
  836. /*
  837.  *--------------------------------------------------------------
  838.  *
  839.  * Tk_PostscriptStipple --
  840.  *
  841.  * This procedure is called by individual canvas items when
  842.  * they have created a path that they'd like to be filled with
  843.  * a stipple pattern.  Given information about an X bitmap,
  844.  * this procedure will generate Postscript commands to fill
  845.  * the current clip region using a stipple pattern defined by the
  846.  * bitmap.
  847.  *
  848.  * Results:
  849.  * Returns a standard Tcl return value.  If an error occurs
  850.  * then an error message will be left in the interp's result.
  851.  * If no error occurs, then additional Postscript will be
  852.  * appended to the interp's result.
  853.  *
  854.  * Side effects:
  855.  * None.
  856.  *
  857.  *--------------------------------------------------------------
  858.  */
  859. int
  860. Tk_PostscriptStipple(interp, tkwin, psInfo, bitmap)
  861.     Tcl_Interp *interp;
  862.     Tk_Window tkwin;
  863.     Tk_PostscriptInfo psInfo; /* Interpreter for returning Postscript
  864.  * or error message. */
  865.     Pixmap bitmap; /* Bitmap to use for stippling. */
  866. {
  867.     TkPostscriptInfo *psInfoPtr = (TkPostscriptInfo *) psInfo;
  868.     int width, height;
  869.     char string[TCL_INTEGER_SPACE * 2];
  870.     Window dummyRoot;
  871.     int dummyX, dummyY;
  872.     unsigned dummyBorderwidth, dummyDepth;
  873.     if (psInfoPtr->prepass) {
  874. return TCL_OK;
  875.     }
  876.     /*
  877.      * The following call should probably be a call to Tk_SizeOfBitmap
  878.      * instead, but it seems that we are occasionally invoked by custom
  879.      * item types that create their own bitmaps without registering them
  880.      * with Tk.  XGetGeometry is a bit slower than Tk_SizeOfBitmap, but
  881.      * it shouldn't matter here.
  882.      */
  883.     XGetGeometry(Tk_Display(tkwin), bitmap, &dummyRoot,
  884.     (int *) &dummyX, (int *) &dummyY, (unsigned *) &width,
  885.     (unsigned *) &height, &dummyBorderwidth, &dummyDepth);
  886.     sprintf(string, "%d %d ", width, height);
  887.     Tcl_AppendResult(interp, string, (char *) NULL);
  888.     if (Tk_PostscriptBitmap(interp, tkwin, psInfo, bitmap, 0, 0,
  889.     width, height) != TCL_OK) {
  890. return TCL_ERROR;
  891.     }
  892.     Tcl_AppendResult(interp, " StippleFilln", (char *) NULL);
  893.     return TCL_OK;
  894. }
  895. /*
  896.  *--------------------------------------------------------------
  897.  *
  898.  * Tk_PostscriptY --
  899.  *
  900.  * Given a y-coordinate in local coordinates, this procedure
  901.  * returns a y-coordinate to use for Postscript output.
  902.  *
  903.  * Results:
  904.  * Returns the Postscript coordinate that corresponds to
  905.  * "y".
  906.  *
  907.  * Side effects:
  908.  * None.
  909.  *
  910.  *--------------------------------------------------------------
  911.  */
  912. double
  913. Tk_PostscriptY(y, psInfo)
  914.     double y; /* Y-coordinate in canvas coords. */
  915.     Tk_PostscriptInfo psInfo; /* Postscript info */
  916. {
  917.     TkPostscriptInfo *psInfoPtr = (TkPostscriptInfo *) psInfo;
  918.     return psInfoPtr->y2 - y;
  919. }
  920. /*
  921.  *--------------------------------------------------------------
  922.  *
  923.  * Tk_PostscriptPath --
  924.  *
  925.  * Given an array of points for a path, generate Postscript
  926.  * commands to create the path.
  927.  *
  928.  * Results:
  929.  * Postscript commands get appended to what's in the interp's result.
  930.  *
  931.  * Side effects:
  932.  * None.
  933.  *
  934.  *--------------------------------------------------------------
  935.  */
  936. void
  937. Tk_PostscriptPath(interp, psInfo, coordPtr, numPoints)
  938.     Tcl_Interp *interp;
  939.     Tk_PostscriptInfo psInfo; /* Canvas on whose behalf Postscript
  940.  * is being generated. */
  941.     double *coordPtr; /* Pointer to first in array of
  942.  * 2*numPoints coordinates giving
  943.  * points for path. */
  944.     int numPoints; /* Number of points at *coordPtr. */
  945. {
  946.     TkPostscriptInfo *psInfoPtr = (TkPostscriptInfo *) psInfo;
  947.     char buffer[200];
  948.     if (psInfoPtr->prepass) {
  949. return;
  950.     }
  951.     sprintf(buffer, "%.15g %.15g moveton", coordPtr[0],
  952.     Tk_PostscriptY(coordPtr[1], psInfo));
  953.     Tcl_AppendResult(interp, buffer, (char *) NULL);
  954.     for (numPoints--, coordPtr += 2; numPoints > 0;
  955.     numPoints--, coordPtr += 2) {
  956. sprintf(buffer, "%.15g %.15g lineton", coordPtr[0],
  957. Tk_PostscriptY(coordPtr[1], psInfo));
  958. Tcl_AppendResult(interp, buffer, (char *) NULL);
  959.     }
  960. }
  961. /*
  962.  *--------------------------------------------------------------
  963.  *
  964.  * GetPostscriptPoints --
  965.  *
  966.  * Given a string, returns the number of Postscript points
  967.  * corresponding to that string.
  968.  *
  969.  * Results:
  970.  * The return value is a standard Tcl return result.  If
  971.  * TCL_OK is returned, then everything went well and the
  972.  * screen distance is stored at *doublePtr;  otherwise
  973.  * TCL_ERROR is returned and an error message is left in
  974.  * the interp's result.
  975.  *
  976.  * Side effects:
  977.  * None.
  978.  *
  979.  *--------------------------------------------------------------
  980.  */
  981. static int
  982. GetPostscriptPoints(interp, string, doublePtr)
  983.     Tcl_Interp *interp; /* Use this for error reporting. */
  984.     char *string; /* String describing a screen distance. */
  985.     double *doublePtr; /* Place to store converted result. */
  986. {
  987.     char *end;
  988.     double d;
  989.     d = strtod(string, &end);
  990.     if (end == string) {
  991. error:
  992. Tcl_AppendResult(interp, "bad distance "", string,
  993. """, (char *) NULL);
  994. return TCL_ERROR;
  995.     }
  996.     while ((*end != '') && isspace(UCHAR(*end))) {
  997. end++;
  998.     }
  999.     switch (*end) {
  1000. case 'c':
  1001.     d *= 72.0/2.54;
  1002.     end++;
  1003.     break;
  1004. case 'i':
  1005.     d *= 72.0;
  1006.     end++;
  1007.     break;
  1008. case 'm':
  1009.     d *= 72.0/25.4;
  1010.     end++;
  1011.     break;
  1012. case 0:
  1013.     break;
  1014. case 'p':
  1015.     end++;
  1016.     break;
  1017. default:
  1018.     goto error;
  1019.     }
  1020.     while ((*end != '') && isspace(UCHAR(*end))) {
  1021. end++;
  1022.     }
  1023.     if (*end != 0) {
  1024. goto error;
  1025.     }
  1026.     *doublePtr = d;
  1027.     return TCL_OK;
  1028. }
  1029. /*
  1030.  *--------------------------------------------------------------
  1031.  *
  1032.  * TkImageGetColor --
  1033.  *
  1034.  * This procedure converts a pixel value to three floating
  1035.  *      point numbers, representing the amount of red, green, and 
  1036.  *      blue in that pixel on the screen.  It makes use of colormap
  1037.  *      data passed as an argument, and should work for all Visual
  1038.  *      types.
  1039.  *
  1040.  * This implementation is bogus on Windows because the colormap
  1041.  * data is never filled in.  Instead all postscript generated
  1042.  * data coming through here is expected to be RGB color data.
  1043.  * To handle lower bit-depth images properly, XQueryColors
  1044.  * must be implemented for Windows.
  1045.  *
  1046.  * Results:
  1047.  * Returns red, green, and blue color values in the range 
  1048.  *      0 to 1.  There are no error returns.
  1049.  *
  1050.  * Side effects:
  1051.  * None.
  1052.  *
  1053.  *--------------------------------------------------------------
  1054.  */
  1055. #ifdef WIN32
  1056. #include <windows.h>
  1057. /*
  1058.  * We could just define these instead of pulling in windows.h.
  1059.  #define GetRValue(rgb) ((BYTE)(rgb))
  1060.  #define GetGValue(rgb) ((BYTE)(((WORD)(rgb)) >> 8))
  1061.  #define GetBValue(rgb) ((BYTE)((rgb)>>16))
  1062. */
  1063. #else
  1064. #define GetRValue(rgb) ((rgb & cdata->red_mask) >> cdata->red_shift)
  1065. #define GetGValue(rgb) ((rgb & cdata->green_mask) >> cdata->green_shift)
  1066. #define GetBValue(rgb) ((rgb & cdata->blue_mask) >> cdata->blue_shift)
  1067. #endif
  1068. #if defined(WIN32) || defined(MAC_OSX_TK)
  1069. static void
  1070. TkImageGetColor(cdata, pixel, red, green, blue)
  1071.     TkColormapData *cdata;              /* Colormap data */
  1072.     unsigned long pixel;                /* Pixel value to look up */
  1073.     double *red, *green, *blue;         /* Color data to return */
  1074. {
  1075.     *red   = (double) GetRValue(pixel) / 255.0;
  1076.     *green = (double) GetGValue(pixel) / 255.0;
  1077.     *blue  = (double) GetBValue(pixel) / 255.0;
  1078. }
  1079. #else
  1080. static void
  1081. TkImageGetColor(cdata, pixel, red, green, blue)
  1082.     TkColormapData *cdata;              /* Colormap data */
  1083.     unsigned long pixel;                /* Pixel value to look up */
  1084.     double *red, *green, *blue;         /* Color data to return */
  1085. {
  1086.     if (cdata->separated) {
  1087. int r = GetRValue(pixel);
  1088. int g = GetGValue(pixel);
  1089. int b = GetBValue(pixel);
  1090. *red   = cdata->colors[r].red / 65535.0;
  1091. *green = cdata->colors[g].green / 65535.0;
  1092. *blue  = cdata->colors[b].blue / 65535.0;
  1093.     } else {
  1094. *red   = cdata->colors[pixel].red / 65535.0;
  1095. *green = cdata->colors[pixel].green / 65535.0;
  1096. *blue  = cdata->colors[pixel].blue / 65535.0;
  1097.     }
  1098. }
  1099. #endif
  1100. /*
  1101.  *--------------------------------------------------------------
  1102.  *
  1103.  * TkPostscriptImage --
  1104.  *
  1105.  * This procedure is called to output the contents of an
  1106.  * image in Postscript, using a format appropriate for the 
  1107.  *      current color mode (i.e. one bit per pixel in monochrome, 
  1108.  *      one byte per pixel in gray, and three bytes per pixel in
  1109.  *      color).
  1110.  *
  1111.  * Results:
  1112.  * Returns a standard Tcl return value.  If an error occurs
  1113.  * then an error message will be left in interp->result.
  1114.  * If no error occurs, then additional Postscript will be
  1115.  * appended to interp->result.
  1116.  *
  1117.  * Side effects:
  1118.  * None.
  1119.  *
  1120.  *--------------------------------------------------------------
  1121.  */
  1122. int
  1123. TkPostscriptImage(interp, tkwin, psInfo, ximage, x, y, width, height)
  1124.     Tcl_Interp *interp;
  1125.     Tk_Window tkwin;
  1126.     Tk_PostscriptInfo psInfo; /* postscript info */
  1127.     XImage *ximage; /* Image to draw */
  1128.     int x, y; /* First pixel to output */
  1129.     int width, height; /* Width and height of area */
  1130. {
  1131.     TkPostscriptInfo *psInfoPtr = (TkPostscriptInfo *) psInfo;
  1132.     char buffer[256];
  1133.     int xx, yy, band, maxRows;
  1134.     double red, green, blue;
  1135.     int bytesPerLine=0, maxWidth=0;
  1136.     int level = psInfoPtr->colorLevel;
  1137.     Colormap cmap;
  1138.     int i, ncolors;
  1139.     Visual *visual;
  1140.     TkColormapData cdata;
  1141.     if (psInfoPtr->prepass) {
  1142. return TCL_OK;
  1143.     }
  1144.     cmap = Tk_Colormap(tkwin);
  1145.     visual = Tk_Visual(tkwin);
  1146.     /*
  1147.      * Obtain information about the colormap, ie the mapping between
  1148.      * pixel values and RGB values.  The code below should work
  1149.      * for all Visual types.
  1150.      */
  1151.     ncolors = visual->map_entries;
  1152.     cdata.colors = (XColor *) ckalloc(sizeof(XColor) * ncolors);
  1153.     cdata.ncolors = ncolors;
  1154.     if (visual->class == DirectColor || visual->class == TrueColor) {
  1155. cdata.separated = 1;
  1156. cdata.red_mask = visual->red_mask;
  1157. cdata.green_mask = visual->green_mask;
  1158. cdata.blue_mask = visual->blue_mask;
  1159. cdata.red_shift = 0;
  1160. cdata.green_shift = 0;
  1161. cdata.blue_shift = 0;
  1162. while ((0x0001 & (cdata.red_mask >> cdata.red_shift)) == 0)
  1163.     cdata.red_shift ++;
  1164. while ((0x0001 & (cdata.green_mask >> cdata.green_shift)) == 0)
  1165.     cdata.green_shift ++;
  1166. while ((0x0001 & (cdata.blue_mask >> cdata.blue_shift)) == 0)
  1167.     cdata.blue_shift ++;
  1168. for (i = 0; i < ncolors; i ++)
  1169.     cdata.colors[i].pixel =
  1170. ((i << cdata.red_shift) & cdata.red_mask) |
  1171. ((i << cdata.green_shift) & cdata.green_mask) |
  1172. ((i << cdata.blue_shift) & cdata.blue_mask);
  1173.     } else {
  1174. cdata.separated=0;
  1175. for (i = 0; i < ncolors; i ++)
  1176.     cdata.colors[i].pixel = i;
  1177.     }
  1178.     if (visual->class == StaticGray || visual->class == GrayScale)
  1179. cdata.color = 0;
  1180.     else
  1181. cdata.color = 1;
  1182.     XQueryColors(Tk_Display(tkwin), cmap, cdata.colors, ncolors);
  1183.     /*
  1184.      * Figure out which color level to use (possibly lower than the 
  1185.      * one specified by the user).  For example, if the user specifies
  1186.      * color with monochrome screen, use gray or monochrome mode instead. 
  1187.      */
  1188.     if (!cdata.color && level == 2) {
  1189. level = 1;
  1190.     }
  1191.     if (!cdata.color && cdata.ncolors == 2) {
  1192. level = 0;
  1193.     }
  1194.     /*
  1195.      * Check that at least one row of the image can be represented
  1196.      * with a string less than 64 KB long (this is a limit in the 
  1197.      * Postscript interpreter).
  1198.      */
  1199.     switch (level) {
  1200. case 0: bytesPerLine = (width + 7) / 8;  maxWidth = 240000;  break;
  1201. case 1: bytesPerLine = width;  maxWidth = 60000;  break;
  1202. case 2: bytesPerLine = 3 * width;  maxWidth = 20000;  break;
  1203.     }
  1204.     if (bytesPerLine > 60000) {
  1205. Tcl_ResetResult(interp);
  1206. sprintf(buffer,
  1207. "Can't generate Postscript for images more than %d pixels wide",
  1208. maxWidth);
  1209. Tcl_AppendResult(interp, buffer, (char *) NULL);
  1210. ckfree((char *) cdata.colors);
  1211. return TCL_ERROR;
  1212.     }
  1213.     maxRows = 60000 / bytesPerLine;
  1214.     for (band = height-1; band >= 0; band -= maxRows) {
  1215. int rows = (band >= maxRows) ? maxRows : band + 1;
  1216. int lineLen = 0;
  1217. switch (level) {
  1218.     case 0:
  1219. sprintf(buffer, "%d %d 1 matrix {n<", width, rows);
  1220. Tcl_AppendResult(interp, buffer, (char *) NULL);
  1221. break;
  1222.     case 1:
  1223. sprintf(buffer, "%d %d 8 matrix {n<", width, rows);
  1224. Tcl_AppendResult(interp, buffer, (char *) NULL);
  1225. break;
  1226.     case 2:
  1227. sprintf(buffer, "%d %d 8 matrix {n<",
  1228. width, rows);
  1229. Tcl_AppendResult(interp, buffer, (char *) NULL);
  1230. break;
  1231. }
  1232. for (yy = band; yy > band - rows; yy--) {
  1233.     switch (level) {
  1234. case 0: {
  1235.     /*
  1236.      * Generate data for image in monochrome mode.
  1237.      * No attempt at dithering is made--instead, just
  1238.      * set a threshold.
  1239.      */
  1240.     unsigned char mask=0x80;
  1241.     unsigned char data=0x00;
  1242.     for (xx = x; xx< x+width; xx++) {
  1243. TkImageGetColor(&cdata, XGetPixel(ximage, xx, yy),
  1244. &red, &green, &blue);
  1245. if (0.30 * red + 0.59 * green + 0.11 * blue > 0.5)
  1246.     data |= mask;
  1247. mask >>= 1;
  1248. if (mask == 0) {
  1249.     sprintf(buffer, "%02X", data);
  1250.     Tcl_AppendResult(interp, buffer, (char *) NULL);
  1251.     lineLen += 2;
  1252.     if (lineLen > 60) {
  1253.         lineLen = 0;
  1254.         Tcl_AppendResult(interp, "n", (char *) NULL);
  1255.     }
  1256.     mask=0x80;
  1257.     data=0x00;
  1258. }
  1259.     }
  1260.     if ((width % 8) != 0) {
  1261.         sprintf(buffer, "%02X", data);
  1262.         Tcl_AppendResult(interp, buffer, (char *) NULL);
  1263.         mask=0x80;
  1264.         data=0x00;
  1265.     }
  1266.     break;
  1267. }
  1268. case 1: {
  1269.     /*
  1270.      * Generate data in gray mode--in this case, take a 
  1271.      * weighted sum of the red, green, and blue values.
  1272.      */
  1273.     for (xx = x; xx < x+width; xx ++) {
  1274. TkImageGetColor(&cdata, XGetPixel(ximage, xx, yy),
  1275. &red, &green, &blue);
  1276. sprintf(buffer, "%02X", (int) floor(0.5 + 255.0 *
  1277. (0.30 * red + 0.59 * green + 0.11 * blue)));
  1278. Tcl_AppendResult(interp, buffer, (char *) NULL);
  1279. lineLen += 2;
  1280. if (lineLen > 60) {
  1281.     lineLen = 0;
  1282.     Tcl_AppendResult(interp, "n", (char *) NULL);
  1283. }
  1284.     }
  1285.     break;
  1286. }
  1287. case 2: {
  1288.     /*
  1289.      * Finally, color mode.  Here, just output the red, green,
  1290.      * and blue values directly.
  1291.      */
  1292.     for (xx = x; xx < x+width; xx++) {
  1293. TkImageGetColor(&cdata, XGetPixel(ximage, xx, yy),
  1294. &red, &green, &blue);
  1295. sprintf(buffer, "%02X%02X%02X",
  1296. (int) floor(0.5 + 255.0 * red),
  1297. (int) floor(0.5 + 255.0 * green),
  1298. (int) floor(0.5 + 255.0 * blue));
  1299. Tcl_AppendResult(interp, buffer, (char *) NULL);
  1300. lineLen += 6;
  1301. if (lineLen > 60) {
  1302.     lineLen = 0;
  1303.     Tcl_AppendResult(interp, "n", (char *) NULL);
  1304. }
  1305.     }
  1306.     break;
  1307. }
  1308.     }
  1309. }
  1310. switch (level) {
  1311.     case 0: sprintf(buffer, ">n} imagen"); break;
  1312.     case 1: sprintf(buffer, ">n} imagen"); break;
  1313.     case 2: sprintf(buffer, ">n} false 3 colorimagen"); break;
  1314. }
  1315. Tcl_AppendResult(interp, buffer, (char *) NULL);
  1316. sprintf(buffer, "0 %d translaten", rows);
  1317. Tcl_AppendResult(interp, buffer, (char *) NULL);
  1318.     }
  1319.     ckfree((char *) cdata.colors);
  1320.     return TCL_OK;
  1321. }
  1322. /*
  1323.  *--------------------------------------------------------------
  1324.  *
  1325.  * Tk_PostscriptPhoto --
  1326.  *
  1327.  * This procedure is called to output the contents of a
  1328.  * photo image in Postscript, using a format appropriate for
  1329.  * the requested postscript color mode (i.e. one byte per pixel
  1330.  * in gray, and three bytes per pixel in color).
  1331.  *
  1332.  * Results:
  1333.  * Returns a standard Tcl return value.  If an error occurs
  1334.  * then an error message will be left in interp->result.
  1335.  * If no error occurs, then additional Postscript will be
  1336.  * appended to the interpreter's result.
  1337.  *
  1338.  * Side effects:
  1339.  * None.
  1340.  *
  1341.  *--------------------------------------------------------------
  1342.  */
  1343. int
  1344. Tk_PostscriptPhoto(interp, blockPtr, psInfo, width, height)
  1345.     Tcl_Interp *interp;
  1346.     Tk_PhotoImageBlock *blockPtr;
  1347.     Tk_PostscriptInfo psInfo;
  1348.     int width, height;
  1349. {
  1350.     TkPostscriptInfo *psInfoPtr = (TkPostscriptInfo *) psInfo;
  1351.     int colorLevel = psInfoPtr->colorLevel;
  1352.     static int codeIncluded = 0;
  1353.     unsigned char *pixelPtr;
  1354.     char buffer[256], cspace[40], decode[40];
  1355.     int bpc;
  1356.     int xx, yy, lineLen;
  1357.     float red, green, blue;
  1358.     int alpha;
  1359.     int bytesPerLine=0, maxWidth=0;
  1360.     unsigned char opaque = 255;
  1361.     unsigned char *alphaPtr;
  1362.     int alphaOffset, alphaPitch, alphaIncr;
  1363.     if (psInfoPtr->prepass) {
  1364. codeIncluded = 0;
  1365. return TCL_OK;
  1366.     }
  1367.     /*
  1368.      * Define the "TkPhoto" function, which is a modified version
  1369.      * of the original "transparentimage" function posted
  1370.      * by ian@five-d.com (Ian Kemmish) to comp.lang.postscript.
  1371.      * For a monochrome colorLevel this is a slightly different
  1372.      * version that uses the imagemask command instead of image.
  1373.      */
  1374.     if( !codeIncluded && (colorLevel != 0) ) {
  1375. /*
  1376.  * Color and gray-scale code.
  1377.  */
  1378. codeIncluded = !0;
  1379. Tcl_AppendResult( interp,
  1380. "/TkPhoto { n",
  1381. "  gsave n",
  1382. "  32 dict begin n",
  1383. "  /tinteger exch def n",
  1384. "  /transparent 1 string def n",
  1385. "  transparent 0 tinteger put n",
  1386. "  /olddict exch def n",
  1387. "  olddict /DataSource get dup type /filetype ne { n",
  1388. "    olddict /DataSource 3 -1 roll n",
  1389. "    0 () /SubFileDecode filter put n",
  1390. "  } { n",
  1391. "    pop n",
  1392. "  } ifelse n",
  1393. "  /newdict olddict maxlength dict def n",
  1394. "  olddict newdict copy pop n",
  1395. "  /w newdict /Width get def n",
  1396. "  /crpp newdict /Decode get length 2 idiv def n",
  1397. "  /str w string def n",
  1398. "  /pix w crpp mul string def n",
  1399. "  /substrlen 2 w log 2 log div floor exp cvi def n",
  1400. "  /substrs [ n",
  1401. "  { n",
  1402. "     substrlen string n",
  1403. "     0 1 substrlen 1 sub { n",
  1404. "       1 index exch tinteger put n",
  1405. "     } for n",
  1406. "     /substrlen substrlen 2 idiv def n",
  1407. "     substrlen 0 eq {exit} if n",
  1408. "  } loop n",
  1409. "  ] def n",
  1410. "  /h newdict /Height get def n",
  1411. "  1 w div 1 h div matrix scale n",
  1412. "  olddict /ImageMatrix get exch matrix concatmatrix n",
  1413. "  matrix invertmatrix concat n",
  1414. "  newdict /Height 1 put n",
  1415. "  newdict /DataSource pix put n",
  1416. "  /mat [w 0 0 h 0 0] def n",
  1417. "  newdict /ImageMatrix mat put n",
  1418. "  0 1 h 1 sub { n",
  1419. "    mat 5 3 -1 roll neg put n",
  1420. "    olddict /DataSource get str readstring pop pop n",
  1421. "    /tail str def n",
  1422. "    /x 0 def n",
  1423. "    olddict /DataSource get pix readstring pop pop n",
  1424. "    { n",
  1425. "      tail transparent search dup /done exch not def n",
  1426. "      {exch pop exch pop} if n",
  1427. "      /w1 exch length def n",
  1428. "      w1 0 ne { n",
  1429. "        newdict /DataSource ",
  1430.           " pix x crpp mul w1 crpp mul getinterval put n",
  1431. "        newdict /Width w1 put n",
  1432. "        mat 4 x neg put n",
  1433. "        /x x w1 add def n",
  1434. "        newdict image n",
  1435. "        /tail tail w1 tail length w1 sub getinterval def n",
  1436. "      } if n",
  1437. "      done {exit} if n",
  1438. "      tail substrs { n",
  1439. "        anchorsearch {pop} if n",
  1440. "      } forall n",
  1441. "      /tail exch def n",
  1442. "      tail length 0 eq {exit} if n",
  1443. "      /x w tail length sub def n",
  1444. "    } loop n",
  1445. "  } for n",
  1446. "  end n",
  1447. "  grestore n",
  1448. "} bind def nnn", (char *) NULL);
  1449.     } else if( !codeIncluded && (colorLevel == 0) ) {
  1450. /*
  1451.  * Monochrome-only code
  1452.  */
  1453. codeIncluded = !0;
  1454. Tcl_AppendResult( interp,
  1455. "/TkPhoto { n",
  1456. "  gsave n",
  1457. "  32 dict begin n",
  1458. "  /dummyInteger exch def n",
  1459. "  /olddict exch def n",
  1460. "  olddict /DataSource get dup type /filetype ne { n",
  1461. "    olddict /DataSource 3 -1 roll n",
  1462. "    0 () /SubFileDecode filter put n",
  1463. "  } { n",
  1464. "    pop n",
  1465. "  } ifelse n",
  1466. "  /newdict olddict maxlength dict def n",
  1467. "  olddict newdict copy pop n",
  1468. "  /w newdict /Width get def n",
  1469. "  /pix w 7 add 8 idiv string def n",
  1470. "  /h newdict /Height get def n",
  1471. "  1 w div 1 h div matrix scale n",
  1472. "  olddict /ImageMatrix get exch matrix concatmatrix n",
  1473. "  matrix invertmatrix concat n",
  1474. "  newdict /Height 1 put n",
  1475. "  newdict /DataSource pix put n",
  1476. "  /mat [w 0 0 h 0 0] def n",
  1477. "  newdict /ImageMatrix mat put n",
  1478. "  0 1 h 1 sub { n",
  1479. "    mat 5 3 -1 roll neg put n",
  1480. "    0.000 0.000 0.000 setrgbcolor n",
  1481. "    olddict /DataSource get pix readstring pop pop n",
  1482. "    newdict /DataSource pix put n",
  1483. "    newdict imagemask n",
  1484. "    1.000 1.000 1.000 setrgbcolor n",
  1485. "    olddict /DataSource get pix readstring pop pop n",
  1486. "    newdict /DataSource pix put n",
  1487. "    newdict imagemask n",
  1488. "  } for n",
  1489. "  end n",
  1490. "  grestore n",
  1491. "} bind def nnn", (char *) NULL);
  1492.     }
  1493.     /*
  1494.      * Check that at least one row of the image can be represented
  1495.      * with a string less than 64 KB long (this is a limit in the
  1496.      * Postscript interpreter).
  1497.      */
  1498.     switch (colorLevel)
  1499. {
  1500.     case 0: bytesPerLine = (width + 7) / 8;  maxWidth = 240000;  break;
  1501.     case 1: bytesPerLine = width;  maxWidth = 60000;  break;
  1502.     case 2: bytesPerLine = 3 * width;  maxWidth = 20000;  break;
  1503. }
  1504.     if (bytesPerLine > 60000) {
  1505. Tcl_ResetResult(interp);
  1506. sprintf(buffer,
  1507. "Can't generate Postscript for images more than %d pixels wide",
  1508. maxWidth);
  1509. Tcl_AppendResult(interp, buffer, (char *) NULL);
  1510. return TCL_ERROR;
  1511.     }
  1512.     /*
  1513.      * Set up the postscript code except for the image-data stream.
  1514.      */
  1515.     switch (colorLevel) {
  1516. case 0: 
  1517.     strcpy( cspace, "/DeviceGray");
  1518.     strcpy( decode, "[1 0]");
  1519.     bpc = 1;
  1520.     break;
  1521. case 1: 
  1522.     strcpy( cspace, "/DeviceGray");
  1523.     strcpy( decode, "[0 1]");
  1524.     bpc = 8;
  1525.     break;
  1526. default:
  1527.     strcpy( cspace, "/DeviceRGB");
  1528.     strcpy( decode, "[0 1 0 1 0 1]");
  1529.     bpc = 8;
  1530.     break;
  1531.     }
  1532.     Tcl_AppendResult(interp,
  1533.     cspace, " setcolorspacenn", (char *) NULL);
  1534.     sprintf(buffer,
  1535.     "  /Width %dn  /Height %dn  /BitsPerComponent %dn",
  1536.     width, height,  bpc);
  1537.     Tcl_AppendResult(interp,
  1538.     "<<n  /ImageType 1n", buffer,
  1539.     "  /DataSource currentfile",
  1540.     "  /ASCIIHexDecode filtern", (char *) NULL);
  1541.     sprintf(buffer,
  1542.     "  /ImageMatrix [1 0 0 -1 0 %d]n", height);
  1543.     Tcl_AppendResult(interp, buffer,
  1544.     "  /Decode ", decode, "n>>n1 TkPhoton", (char *) NULL);
  1545.     /*
  1546.      * Check the PhotoImageBlock information.
  1547.      * We assume that:
  1548.      *     if pixelSize is 1,2 or 4, the image is R,G,B,A;
  1549.      *     if pixelSize is 3, the image is R,G,B and offset[3] is bogus.
  1550.      */
  1551.     if (blockPtr->pixelSize == 3) {
  1552. /*
  1553.  * No alpha information: the whole image is opaque.
  1554.  */
  1555. alphaPtr = &opaque;
  1556. alphaPitch = alphaIncr = alphaOffset = 0;
  1557.     } else {
  1558. /*
  1559.  * Set up alpha handling.
  1560.  */
  1561. alphaPtr = blockPtr->pixelPtr;
  1562. alphaPitch = blockPtr->pitch;
  1563. alphaIncr = blockPtr->pixelSize;
  1564. alphaOffset = blockPtr->offset[3];
  1565.     }
  1566.     for (yy = 0, lineLen=0; yy < height; yy++) {
  1567. switch (colorLevel) {
  1568.     case 0: {
  1569. /*
  1570.  * Generate data for image in monochrome mode.
  1571.  * No attempt at dithering is made--instead, just
  1572.  * set a threshold.
  1573.  * To handle transparecies we need to output two lines:
  1574.  * one for the black pixels, one for the white ones.
  1575.  */
  1576. unsigned char mask=0x80;
  1577. unsigned char data=0x00;
  1578. for (xx = 0; xx< width; xx ++) {
  1579.     pixelPtr = blockPtr->pixelPtr 
  1580. + (yy * blockPtr->pitch) 
  1581. + (xx *blockPtr->pixelSize);
  1582.     red = pixelPtr[blockPtr->offset[0]];
  1583.     green = pixelPtr[blockPtr->offset[1]];
  1584.     blue = pixelPtr[blockPtr->offset[2]];
  1585.     alpha = *(alphaPtr + (yy * alphaPitch)
  1586.     + (xx * alphaIncr) + alphaOffset);
  1587.     /*
  1588.      * If pixel is less than threshold, then it is black.
  1589.      */
  1590.     if ((alpha != 0) && 
  1591.     ( 0.3086 * red 
  1592.     + 0.6094 * green 
  1593.     + 0.082 * blue < 128)) {
  1594. data |= mask;
  1595.     }
  1596.     mask >>= 1;
  1597.     if (mask == 0) {
  1598. sprintf(buffer, "%02X", data);
  1599. Tcl_AppendResult(interp, buffer, (char *) NULL);
  1600. lineLen += 2;
  1601. if (lineLen >= 60) {
  1602.     lineLen = 0;
  1603.     Tcl_AppendResult(interp, "n", (char *) NULL);
  1604. }
  1605. mask=0x80;
  1606. data=0x00;
  1607.     }
  1608. }
  1609. if ((width % 8) != 0) {
  1610.     sprintf(buffer, "%02X", data);
  1611.     Tcl_AppendResult(interp, buffer, (char *) NULL);
  1612.     mask=0x80;
  1613.     data=0x00;
  1614. }
  1615. mask=0x80;
  1616. data=0x00;
  1617. for (xx = 0; xx< width; xx ++) {
  1618.     pixelPtr = blockPtr->pixelPtr 
  1619. + (yy * blockPtr->pitch) 
  1620. + (xx *blockPtr->pixelSize);
  1621.     red = pixelPtr[blockPtr->offset[0]];
  1622.     green = pixelPtr[blockPtr->offset[1]];
  1623.     blue = pixelPtr[blockPtr->offset[2]];
  1624.     alpha = *(alphaPtr + (yy * alphaPitch)
  1625.     + (xx * alphaIncr) + alphaOffset);
  1626.     
  1627.     /*
  1628.      * If pixel is greater than threshold, then it is white.
  1629.      */
  1630.     if ((alpha != 0) && 
  1631.     (  0.3086 * red 
  1632.     + 0.6094 * green 
  1633.     + 0.082 * blue >= 128)) {
  1634. data |= mask;
  1635.     }
  1636.     mask >>= 1;
  1637.     if (mask == 0) {
  1638. sprintf(buffer, "%02X", data);
  1639. Tcl_AppendResult(interp, buffer, (char *) NULL);
  1640. lineLen += 2;
  1641. if (lineLen >= 60) {
  1642.     lineLen = 0;
  1643.     Tcl_AppendResult(interp, "n", (char *) NULL);
  1644. }
  1645. mask=0x80;
  1646. data=0x00;
  1647.     }
  1648. }
  1649. if ((width % 8) != 0) {
  1650.     sprintf(buffer, "%02X", data);
  1651.     Tcl_AppendResult(interp, buffer, (char *) NULL);
  1652.     mask=0x80;
  1653.     data=0x00;
  1654. }
  1655. break;
  1656.     }
  1657.     case 1: {
  1658. /*
  1659.  * Generate transparency data.
  1660.  * We must prevent a transparent value of 0
  1661.  * because of a bug in some HP printers.
  1662.  */
  1663. for (xx = 0; xx < width; xx ++) {
  1664.     alpha = *(alphaPtr + (yy * alphaPitch)
  1665.     + (xx * alphaIncr) + alphaOffset);
  1666.     sprintf(buffer, "%02X", alpha | 0x01);
  1667.     Tcl_AppendResult(interp, buffer, (char *) NULL);
  1668.     lineLen += 2;
  1669.     if (lineLen >= 60) {
  1670. lineLen = 0;
  1671. Tcl_AppendResult(interp, "n", (char *) NULL);
  1672.     }
  1673. }
  1674. /*
  1675.  * Generate data in gray mode--in this case, take a 
  1676.  * weighted sum of the red, green, and blue values.
  1677.  */
  1678. for (xx = 0; xx < width; xx ++) {
  1679.     pixelPtr = blockPtr->pixelPtr 
  1680. + (yy * blockPtr->pitch) 
  1681. + (xx *blockPtr->pixelSize);
  1682.     red = pixelPtr[blockPtr->offset[0]];
  1683.     green = pixelPtr[blockPtr->offset[1]];
  1684.     blue = pixelPtr[blockPtr->offset[2]];
  1685.     sprintf(buffer, "%02X", (int) floor(0.5 +
  1686.     ( 0.3086 * red + 0.6094 * green + 0.0820 * blue)));
  1687.     Tcl_AppendResult(interp, buffer, (char *) NULL);
  1688.     lineLen += 2;
  1689.     if (lineLen >= 60) {
  1690. lineLen = 0;
  1691. Tcl_AppendResult(interp, "n", (char *) NULL);
  1692.     }
  1693. }
  1694. break;
  1695.     }
  1696.     default: {
  1697. /*
  1698.  * Generate transparency data.
  1699.  * We must prevent a transparent value of 0
  1700.  * because of a bug in some HP printers.
  1701.  */
  1702. for (xx = 0; xx < width; xx ++) {
  1703.     alpha = *(alphaPtr + (yy * alphaPitch)
  1704.     + (xx * alphaIncr) + alphaOffset);
  1705.     sprintf(buffer, "%02X", alpha | 0x01);
  1706.     Tcl_AppendResult(interp, buffer, (char *) NULL);
  1707.     lineLen += 2;
  1708.     if (lineLen >= 60) {
  1709. lineLen = 0;
  1710. Tcl_AppendResult(interp, "n", (char *) NULL);
  1711.     }
  1712. }
  1713. /*
  1714.  * Finally, color mode.  Here, just output the red, green,
  1715.  * and blue values directly.
  1716.  */
  1717. for (xx = 0; xx < width; xx ++) {
  1718.     pixelPtr = blockPtr->pixelPtr 
  1719. + (yy * blockPtr->pitch) 
  1720. + (xx *blockPtr->pixelSize);
  1721.     sprintf(buffer, "%02X%02X%02X",
  1722.     pixelPtr[blockPtr->offset[0]],
  1723.     pixelPtr[blockPtr->offset[1]],
  1724.     pixelPtr[blockPtr->offset[2]]);
  1725.     Tcl_AppendResult(interp, buffer, (char *) NULL);
  1726.     lineLen += 6;
  1727.     if (lineLen >= 60) {
  1728. lineLen = 0;
  1729. Tcl_AppendResult(interp, "n", (char *) NULL);
  1730.     }
  1731. }
  1732. break;
  1733.     }
  1734. }
  1735.     }
  1736.     Tcl_AppendResult(interp, ">n", (char *) NULL);
  1737.     return TCL_OK;
  1738. }