1 |
|
---|
2 | /*
|
---|
3 | * bltGrPs.c --
|
---|
4 | *
|
---|
5 | * This module implements the "postscript" operation for BLT
|
---|
6 | * graph widget.
|
---|
7 | *
|
---|
8 | * Copyright 1991-1998 Lucent Technologies, Inc.
|
---|
9 | *
|
---|
10 | * Permission to use, copy, modify, and distribute this software and
|
---|
11 | * its documentation for any purpose and without fee is hereby
|
---|
12 | * granted, provided that the above copyright notice appear in all
|
---|
13 | * copies and that both that the copyright notice and warranty
|
---|
14 | * disclaimer appear in supporting documentation, and that the names
|
---|
15 | * of Lucent Technologies any of their entities not be used in
|
---|
16 | * advertising or publicity pertaining to distribution of the software
|
---|
17 | * without specific, written prior permission.
|
---|
18 | *
|
---|
19 | * Lucent Technologies disclaims all warranties with regard to this
|
---|
20 | * software, including all implied warranties of merchantability and
|
---|
21 | * fitness. In no event shall Lucent Technologies be liable for any
|
---|
22 | * special, indirect or consequential damages or any damages
|
---|
23 | * whatsoever resulting from loss of use, data or profits, whether in
|
---|
24 | * an action of contract, negligence or other tortuous action, arising
|
---|
25 | * out of or in connection with the use or performance of this
|
---|
26 | * software.
|
---|
27 | */
|
---|
28 |
|
---|
29 | /*
|
---|
30 | * -----------------------------------------------------------------
|
---|
31 | *
|
---|
32 | * PostScript routines to print a graph
|
---|
33 | *
|
---|
34 | * -----------------------------------------------------------------
|
---|
35 | */
|
---|
36 | #include "bltGraph.h"
|
---|
37 | #include <X11/Xutil.h>
|
---|
38 | #if defined(__STDC__)
|
---|
39 | #include <stdarg.h>
|
---|
40 | #else
|
---|
41 | #include <varargs.h>
|
---|
42 | #endif
|
---|
43 |
|
---|
44 | #define PS_PREVIEW_EPSI 0
|
---|
45 | #define PS_PREVIEW_WMF 1
|
---|
46 | #define PS_PREVIEW_TIFF 2
|
---|
47 |
|
---|
48 | static Tk_OptionParseProc StringToColorMode;
|
---|
49 | static Tk_OptionPrintProc ColorModeToString;
|
---|
50 | static Tk_CustomOption colorModeOption =
|
---|
51 | {
|
---|
52 | StringToColorMode, ColorModeToString, (ClientData)0,
|
---|
53 | };
|
---|
54 | static Tk_OptionParseProc StringToFormat;
|
---|
55 | static Tk_OptionPrintProc FormatToString;
|
---|
56 | static Tk_CustomOption formatOption =
|
---|
57 | {
|
---|
58 | StringToFormat, FormatToString, (ClientData)0,
|
---|
59 | };
|
---|
60 | extern Tk_CustomOption bltDistanceOption;
|
---|
61 | extern Tk_CustomOption bltPositiveDistanceOption;
|
---|
62 | extern Tk_CustomOption bltPadOption;
|
---|
63 |
|
---|
64 | #define DEF_PS_CENTER "yes"
|
---|
65 | #define DEF_PS_COLOR_MAP (char *)NULL
|
---|
66 | #define DEF_PS_COLOR_MODE "color"
|
---|
67 | #define DEF_PS_DECORATIONS "yes"
|
---|
68 | #define DEF_PS_FONT_MAP (char *)NULL
|
---|
69 | #define DEF_PS_FOOTER "no"
|
---|
70 | #define DEF_PS_HEIGHT "0"
|
---|
71 | #define DEF_PS_LANDSCAPE "no"
|
---|
72 | #define DEF_PS_MAXPECT "no"
|
---|
73 | #define DEF_PS_PADX "1.0i"
|
---|
74 | #define DEF_PS_PADY "1.0i"
|
---|
75 | #define DEF_PS_PAPERHEIGHT "11.0i"
|
---|
76 | #define DEF_PS_PAPERWIDTH "8.5i"
|
---|
77 | #define DEF_PS_PREVIEW "no"
|
---|
78 | #define DEF_PS_PREVIEW_FORMAT "epsi"
|
---|
79 | #define DEF_PS_WIDTH "0"
|
---|
80 |
|
---|
81 | static Tk_ConfigSpec configSpecs[] =
|
---|
82 | {
|
---|
83 | {TK_CONFIG_BOOLEAN, "-center", "center", "Center",
|
---|
84 | DEF_PS_CENTER, Tk_Offset(PostScript, center),
|
---|
85 | TK_CONFIG_DONT_SET_DEFAULT},
|
---|
86 | {TK_CONFIG_STRING, "-colormap", "colorMap", "ColorMap",
|
---|
87 | DEF_PS_COLOR_MAP, Tk_Offset(PostScript, colorVarName),
|
---|
88 | TK_CONFIG_NULL_OK},
|
---|
89 | {TK_CONFIG_CUSTOM, "-colormode", "colorMode", "ColorMode",
|
---|
90 | DEF_PS_COLOR_MODE, Tk_Offset(PostScript, colorMode),
|
---|
91 | TK_CONFIG_DONT_SET_DEFAULT, &colorModeOption},
|
---|
92 | {TK_CONFIG_BOOLEAN, "-decorations", "decorations", "Decorations",
|
---|
93 | DEF_PS_DECORATIONS, Tk_Offset(PostScript, decorations),
|
---|
94 | TK_CONFIG_DONT_SET_DEFAULT},
|
---|
95 | {TK_CONFIG_STRING, "-fontmap", "fontMap", "FontMap",
|
---|
96 | DEF_PS_FONT_MAP, Tk_Offset(PostScript, fontVarName),
|
---|
97 | TK_CONFIG_NULL_OK},
|
---|
98 | {TK_CONFIG_BOOLEAN, "-footer", "footer", "Footer",
|
---|
99 | DEF_PS_FOOTER, Tk_Offset(PostScript, footer),
|
---|
100 | TK_CONFIG_DONT_SET_DEFAULT},
|
---|
101 | {TK_CONFIG_CUSTOM, "-height", "height", "Height",
|
---|
102 | DEF_PS_HEIGHT, Tk_Offset(PostScript, reqHeight),
|
---|
103 | TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption},
|
---|
104 | {TK_CONFIG_BOOLEAN, "-landscape", "landscape", "Landscape",
|
---|
105 | DEF_PS_LANDSCAPE, Tk_Offset(PostScript, landscape),
|
---|
106 | TK_CONFIG_DONT_SET_DEFAULT},
|
---|
107 | {TK_CONFIG_BOOLEAN, "-maxpect", "maxpect", "Maxpect",
|
---|
108 | DEF_PS_MAXPECT, Tk_Offset(PostScript, maxpect),
|
---|
109 | TK_CONFIG_DONT_SET_DEFAULT},
|
---|
110 | {TK_CONFIG_CUSTOM, "-padx", "padX", "PadX",
|
---|
111 | DEF_PS_PADX, Tk_Offset(PostScript, padX), 0, &bltPadOption},
|
---|
112 | {TK_CONFIG_CUSTOM, "-pady", "padY", "PadY",
|
---|
113 | DEF_PS_PADY, Tk_Offset(PostScript, padY), 0, &bltPadOption},
|
---|
114 | {TK_CONFIG_CUSTOM, "-paperheight", "paperHeight", "PaperHeight",
|
---|
115 | DEF_PS_PAPERHEIGHT, Tk_Offset(PostScript, reqPaperHeight),
|
---|
116 | 0, &bltPositiveDistanceOption},
|
---|
117 | {TK_CONFIG_CUSTOM, "-paperwidth", "paperWidth", "PaperWidth",
|
---|
118 | DEF_PS_PAPERWIDTH, Tk_Offset(PostScript, reqPaperWidth),
|
---|
119 | 0, &bltPositiveDistanceOption},
|
---|
120 | {TK_CONFIG_BOOLEAN, "-preview", "preview", "Preview",
|
---|
121 | DEF_PS_PREVIEW, Tk_Offset(PostScript, addPreview),
|
---|
122 | TK_CONFIG_DONT_SET_DEFAULT},
|
---|
123 | {TK_CONFIG_CUSTOM, "-previewformat", "previewFormat", "PreviewFormat",
|
---|
124 | DEF_PS_PREVIEW_FORMAT, Tk_Offset(PostScript, previewFormat),
|
---|
125 | TK_CONFIG_DONT_SET_DEFAULT, &formatOption},
|
---|
126 | {TK_CONFIG_CUSTOM, "-width", "width", "Width",
|
---|
127 | DEF_PS_WIDTH, Tk_Offset(PostScript, reqWidth),
|
---|
128 | TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption},
|
---|
129 | {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0}
|
---|
130 | };
|
---|
131 |
|
---|
132 | extern void Blt_MarkersToPostScript _ANSI_ARGS_((Graph *graphPtr,
|
---|
133 | PsToken psToken, int under));
|
---|
134 | extern void Blt_ElementsToPostScript _ANSI_ARGS_((Graph *graphPtr,
|
---|
135 | PsToken psToken));
|
---|
136 | extern void Blt_ActiveElementsToPostScript _ANSI_ARGS_((Graph *graphPtr,
|
---|
137 | PsToken psToken));
|
---|
138 | extern void Blt_LegendToPostScript _ANSI_ARGS_((Legend *legendPtr,
|
---|
139 | PsToken psToken));
|
---|
140 | extern void Blt_GridToPostScript _ANSI_ARGS_((Graph *graphPtr,
|
---|
141 | PsToken psToken));
|
---|
142 | extern void Blt_AxesToPostScript _ANSI_ARGS_((Graph *graphPtr,
|
---|
143 | PsToken psToken));
|
---|
144 | extern void Blt_AxisLimitsToPostScript _ANSI_ARGS_((Graph *graphPtr,
|
---|
145 | PsToken psToken));
|
---|
146 | /*
|
---|
147 | *----------------------------------------------------------------------
|
---|
148 | *
|
---|
149 | * StringToColorMode --
|
---|
150 | *
|
---|
151 | * Convert the string representation of a PostScript color mode
|
---|
152 | * into the enumerated type representing the color level:
|
---|
153 | *
|
---|
154 | * PS_MODE_COLOR - Full color
|
---|
155 | * PS_MODE_GREYSCALE - Color converted to greyscale
|
---|
156 | * PS_MODE_MONOCHROME - Only black and white
|
---|
157 | *
|
---|
158 | * Results:
|
---|
159 | * A standard Tcl result. The color level is written into the
|
---|
160 | * page layout information structure.
|
---|
161 | *
|
---|
162 | * Side Effects:
|
---|
163 | * Future invocations of the "postscript" option will use this
|
---|
164 | * variable to determine how color information will be displayed
|
---|
165 | * in the PostScript output it produces.
|
---|
166 | *
|
---|
167 | *----------------------------------------------------------------------
|
---|
168 | */
|
---|
169 | /*ARGSUSED*/
|
---|
170 | static int
|
---|
171 | StringToColorMode(clientData, interp, tkwin, string, widgRec, offset)
|
---|
172 | ClientData clientData; /* Not used. */
|
---|
173 | Tcl_Interp *interp; /* Interpreter to send results back to */
|
---|
174 | Tk_Window tkwin; /* Not used. */
|
---|
175 | char *string; /* New value. */
|
---|
176 | char *widgRec; /* Widget record */
|
---|
177 | int offset; /* Offset of field in record */
|
---|
178 | {
|
---|
179 | PsColorMode *modePtr = (PsColorMode *) (widgRec + offset);
|
---|
180 | unsigned int length;
|
---|
181 | char c;
|
---|
182 |
|
---|
183 | c = string[0];
|
---|
184 | length = strlen(string);
|
---|
185 | if ((c == 'c') && (strncmp(string, "color", length) == 0)) {
|
---|
186 | *modePtr = PS_MODE_COLOR;
|
---|
187 | } else if ((c == 'g') && (strncmp(string, "grayscale", length) == 0)) {
|
---|
188 | *modePtr = PS_MODE_GREYSCALE;
|
---|
189 | } else if ((c == 'g') && (strncmp(string, "greyscale", length) == 0)) {
|
---|
190 | *modePtr = PS_MODE_GREYSCALE;
|
---|
191 | } else if ((c == 'm') && (strncmp(string, "monochrome", length) == 0)) {
|
---|
192 | *modePtr = PS_MODE_MONOCHROME;
|
---|
193 | } else {
|
---|
194 | Tcl_AppendResult(interp, "bad color mode \"", string, "\": should be \
|
---|
195 | \"color\", \"greyscale\", or \"monochrome\"", (char *)NULL);
|
---|
196 | return TCL_ERROR;
|
---|
197 | }
|
---|
198 | return TCL_OK;
|
---|
199 | }
|
---|
200 |
|
---|
201 | /*
|
---|
202 | *----------------------------------------------------------------------
|
---|
203 | *
|
---|
204 | * NameOfColorMode --
|
---|
205 | *
|
---|
206 | * Convert the PostScript mode value into the string representing
|
---|
207 | * a valid color mode.
|
---|
208 | *
|
---|
209 | * Results:
|
---|
210 | * The static string representing the color mode is returned.
|
---|
211 | *
|
---|
212 | *----------------------------------------------------------------------
|
---|
213 | */
|
---|
214 | static char *
|
---|
215 | NameOfColorMode(colorMode)
|
---|
216 | PsColorMode colorMode;
|
---|
217 | {
|
---|
218 | switch (colorMode) {
|
---|
219 | case PS_MODE_COLOR:
|
---|
220 | return "color";
|
---|
221 | case PS_MODE_GREYSCALE:
|
---|
222 | return "greyscale";
|
---|
223 | case PS_MODE_MONOCHROME:
|
---|
224 | return "monochrome";
|
---|
225 | default:
|
---|
226 | return "unknown color mode";
|
---|
227 | }
|
---|
228 | }
|
---|
229 |
|
---|
230 | /*
|
---|
231 | *----------------------------------------------------------------------
|
---|
232 | *
|
---|
233 | * ColorModeToString --
|
---|
234 | *
|
---|
235 | * Convert the current color mode into the string representing a
|
---|
236 | * valid color mode.
|
---|
237 | *
|
---|
238 | * Results:
|
---|
239 | * The string representing the color mode is returned.
|
---|
240 | *
|
---|
241 | *----------------------------------------------------------------------
|
---|
242 | */
|
---|
243 | /*ARGSUSED*/
|
---|
244 | static char *
|
---|
245 | ColorModeToString(clientData, tkwin, widgRec, offset, freeProcPtr)
|
---|
246 | ClientData clientData; /* Not used. */
|
---|
247 | Tk_Window tkwin; /* Not used. */
|
---|
248 | char *widgRec; /* Widget record. */
|
---|
249 | int offset; /* field of colorMode in record */
|
---|
250 | Tcl_FreeProc **freeProcPtr; /* Not used. */
|
---|
251 | {
|
---|
252 | PsColorMode mode = *(PsColorMode *) (widgRec + offset);
|
---|
253 |
|
---|
254 | return NameOfColorMode(mode);
|
---|
255 | }
|
---|
256 |
|
---|
257 | /*
|
---|
258 | *----------------------------------------------------------------------
|
---|
259 | *
|
---|
260 | * StringToFormat --
|
---|
261 | *
|
---|
262 | * Convert the string of the PostScript preview format into
|
---|
263 | * an enumerated type representing the desired format. The
|
---|
264 | * available formats are:
|
---|
265 | *
|
---|
266 | * PS_PREVIEW_WMF - Windows Metafile.
|
---|
267 | * PS_PREVIEW_TIFF - TIFF bitmap image.
|
---|
268 | * PS_PREVIEW_EPSI - Device independent ASCII preview
|
---|
269 | *
|
---|
270 | * Results:
|
---|
271 | * A standard Tcl result. The format is written into the
|
---|
272 | * page layout information structure.
|
---|
273 | *
|
---|
274 | * Side Effects:
|
---|
275 | * Future invocations of the "postscript" option will use this
|
---|
276 | * variable to determine how to format a preview image (if one
|
---|
277 | * is selected) when the PostScript output is produced.
|
---|
278 | *
|
---|
279 | *----------------------------------------------------------------------
|
---|
280 | */
|
---|
281 | /*ARGSUSED*/
|
---|
282 | static int
|
---|
283 | StringToFormat(clientData, interp, tkwin, string, widgRec, offset)
|
---|
284 | ClientData clientData; /* Not used. */
|
---|
285 | Tcl_Interp *interp; /* Interpreter to send results back to */
|
---|
286 | Tk_Window tkwin; /* Not used. */
|
---|
287 | char *string; /* New value. */
|
---|
288 | char *widgRec; /* Widget record */
|
---|
289 | int offset; /* Offset of field in record */
|
---|
290 | {
|
---|
291 | int *formatPtr = (int *) (widgRec + offset);
|
---|
292 | unsigned int length;
|
---|
293 | char c;
|
---|
294 |
|
---|
295 | c = string[0];
|
---|
296 | length = strlen(string);
|
---|
297 | if ((c == 'c') && (strncmp(string, "epsi", length) == 0)) {
|
---|
298 | *formatPtr = PS_PREVIEW_EPSI;
|
---|
299 | #ifdef WIN32
|
---|
300 | #ifdef HAVE_TIFF_H
|
---|
301 | } else if ((c == 't') && (strncmp(string, "tiff", length) == 0)) {
|
---|
302 | *formatPtr = PS_PREVIEW_TIFF;
|
---|
303 | #endif /* HAVE_TIFF_H */
|
---|
304 | } else if ((c == 'w') && (strncmp(string, "wmf", length) == 0)) {
|
---|
305 | *formatPtr = PS_PREVIEW_WMF;
|
---|
306 | #endif /* WIN32 */
|
---|
307 | } else {
|
---|
308 | Tcl_AppendResult(interp, "bad format \"", string, "\": should be ",
|
---|
309 | #ifdef WIN32
|
---|
310 | #ifdef HAVE_TIFF_H
|
---|
311 | "\"tiff\" or ",
|
---|
312 | #endif /* HAVE_TIFF_H */
|
---|
313 | "\"wmf\" or ",
|
---|
314 | #endif /* WIN32 */
|
---|
315 | "\"epsi\"", (char *)NULL);
|
---|
316 | return TCL_ERROR;
|
---|
317 | }
|
---|
318 | return TCL_OK;
|
---|
319 | }
|
---|
320 |
|
---|
321 | /*
|
---|
322 | *----------------------------------------------------------------------
|
---|
323 | *
|
---|
324 | * FormatToString --
|
---|
325 | *
|
---|
326 | * Convert the preview format into the string representing its
|
---|
327 | * type.
|
---|
328 | *
|
---|
329 | * Results:
|
---|
330 | * The string representing the preview format is returned.
|
---|
331 | *
|
---|
332 | *----------------------------------------------------------------------
|
---|
333 | */
|
---|
334 | /*ARGSUSED*/
|
---|
335 | static char *
|
---|
336 | FormatToString(clientData, tkwin, widgRec, offset, freeProcPtr)
|
---|
337 | ClientData clientData; /* Not used. */
|
---|
338 | Tk_Window tkwin; /* Not used. */
|
---|
339 | char *widgRec; /* PostScript structure record */
|
---|
340 | int offset; /* field of colorMode in record */
|
---|
341 | Tcl_FreeProc **freeProcPtr; /* Not used. */
|
---|
342 | {
|
---|
343 | int format = *(int *)(widgRec + offset);
|
---|
344 |
|
---|
345 | switch (format) {
|
---|
346 | case PS_PREVIEW_EPSI:
|
---|
347 | return "epsi";
|
---|
348 | case PS_PREVIEW_WMF:
|
---|
349 | return "wmf";
|
---|
350 | case PS_PREVIEW_TIFF:
|
---|
351 | return "tiff";
|
---|
352 | }
|
---|
353 | return "?unknown preview format?";
|
---|
354 | }
|
---|
355 | |
---|
356 |
|
---|
357 | void
|
---|
358 | Blt_DestroyPostScript(graphPtr)
|
---|
359 | Graph *graphPtr;
|
---|
360 | {
|
---|
361 | Tk_FreeOptions(configSpecs, (char *)graphPtr->postscript,
|
---|
362 | graphPtr->display, 0);
|
---|
363 | Blt_Free(graphPtr->postscript);
|
---|
364 | }
|
---|
365 |
|
---|
366 | /*
|
---|
367 | *----------------------------------------------------------------------
|
---|
368 | *
|
---|
369 | * CgetOp --
|
---|
370 | *
|
---|
371 | *----------------------------------------------------------------------
|
---|
372 | */
|
---|
373 | /*ARGSUSED*/
|
---|
374 | static int
|
---|
375 | CgetOp(graphPtr, interp, argc, argv)
|
---|
376 | Graph *graphPtr;
|
---|
377 | Tcl_Interp *interp;
|
---|
378 | int argc;
|
---|
379 | char *argv[];
|
---|
380 | {
|
---|
381 | PostScript *psPtr = (PostScript *)graphPtr->postscript;
|
---|
382 |
|
---|
383 | if (Tk_ConfigureValue(interp, graphPtr->tkwin, configSpecs, (char *)psPtr,
|
---|
384 | argv[3], 0) != TCL_OK) {
|
---|
385 | return TCL_ERROR;
|
---|
386 | }
|
---|
387 | return TCL_OK;
|
---|
388 | }
|
---|
389 |
|
---|
390 | /*
|
---|
391 | * ----------------------------------------------------------------------
|
---|
392 | *
|
---|
393 | * ConfigureOp --
|
---|
394 | *
|
---|
395 | * This procedure is invoked to print the graph in a file.
|
---|
396 | *
|
---|
397 | * Results:
|
---|
398 | * A standard TCL result.
|
---|
399 | *
|
---|
400 | * Side effects:
|
---|
401 | * A new PostScript file is created.
|
---|
402 | *
|
---|
403 | * ----------------------------------------------------------------------
|
---|
404 | */
|
---|
405 | static int
|
---|
406 | ConfigureOp(graphPtr, interp, argc, argv)
|
---|
407 | Graph *graphPtr;
|
---|
408 | Tcl_Interp *interp;
|
---|
409 | int argc; /* Number of options in argv vector */
|
---|
410 | char **argv; /* Option vector */
|
---|
411 | {
|
---|
412 | int flags = TK_CONFIG_ARGV_ONLY;
|
---|
413 | PostScript *psPtr = (PostScript *)graphPtr->postscript;
|
---|
414 |
|
---|
415 | if (argc == 3) {
|
---|
416 | return Tk_ConfigureInfo(interp, graphPtr->tkwin, configSpecs,
|
---|
417 | (char *)psPtr, (char *)NULL, flags);
|
---|
418 | } else if (argc == 4) {
|
---|
419 | return Tk_ConfigureInfo(interp, graphPtr->tkwin, configSpecs,
|
---|
420 | (char *)psPtr, argv[3], flags);
|
---|
421 | }
|
---|
422 | if (Tk_ConfigureWidget(interp, graphPtr->tkwin, configSpecs, argc - 3,
|
---|
423 | argv + 3, (char *)psPtr, flags) != TCL_OK) {
|
---|
424 | return TCL_ERROR;
|
---|
425 | }
|
---|
426 | return TCL_OK;
|
---|
427 | }
|
---|
428 |
|
---|
429 | /*
|
---|
430 | * --------------------------------------------------------------------------
|
---|
431 | *
|
---|
432 | * ComputeBoundingBox --
|
---|
433 | *
|
---|
434 | * Computes the bounding box for the PostScript plot. First get
|
---|
435 | * the size of the plot (by default, it's the size of graph's X
|
---|
436 | * window). If the plot plus the page border is bigger than the
|
---|
437 | * designated paper size, or if the "-maxpect" option is turned
|
---|
438 | * on, scale the plot to the page.
|
---|
439 | *
|
---|
440 | * Note: All coordinates/sizes are in screen coordinates, not
|
---|
441 | * PostScript coordinates. This includes the computed
|
---|
442 | * bounding box and paper size. They will be scaled to
|
---|
443 | * printer points later.
|
---|
444 | *
|
---|
445 | * Results:
|
---|
446 | * Returns the height of the paper in screen coordinates.
|
---|
447 | *
|
---|
448 | * Side Effects:
|
---|
449 | * The graph dimensions (width and height) are changed to the
|
---|
450 | * requested PostScript plot size.
|
---|
451 | *
|
---|
452 | * --------------------------------------------------------------------------
|
---|
453 | */
|
---|
454 | static int
|
---|
455 | ComputeBoundingBox(graphPtr, psPtr)
|
---|
456 | Graph *graphPtr;
|
---|
457 | PostScript *psPtr;
|
---|
458 | {
|
---|
459 | int paperWidth, paperHeight;
|
---|
460 | int x, y, hSize, vSize, hBorder, vBorder;
|
---|
461 | double hScale, vScale, scale;
|
---|
462 |
|
---|
463 | x = psPtr->padLeft;
|
---|
464 | y = psPtr->padTop;
|
---|
465 | hBorder = PADDING(psPtr->padX);
|
---|
466 | vBorder = PADDING(psPtr->padY);
|
---|
467 |
|
---|
468 | if (psPtr->reqWidth > 0) {
|
---|
469 | graphPtr->width = psPtr->reqWidth;
|
---|
470 | }
|
---|
471 | if (psPtr->reqHeight > 0) {
|
---|
472 | graphPtr->height = psPtr->reqHeight;
|
---|
473 | }
|
---|
474 | if (psPtr->landscape) {
|
---|
475 | hSize = graphPtr->height;
|
---|
476 | vSize = graphPtr->width;
|
---|
477 | } else {
|
---|
478 | hSize = graphPtr->width;
|
---|
479 | vSize = graphPtr->height;
|
---|
480 | }
|
---|
481 | /*
|
---|
482 | * If the paper size wasn't specified, set it to the graph size plus
|
---|
483 | * the paper border.
|
---|
484 | */
|
---|
485 | paperWidth = psPtr->reqPaperWidth;
|
---|
486 | paperHeight = psPtr->reqPaperHeight;
|
---|
487 | if (paperWidth < 1) {
|
---|
488 | paperWidth = hSize + hBorder;
|
---|
489 | }
|
---|
490 | if (paperHeight < 1) {
|
---|
491 | paperHeight = vSize + vBorder;
|
---|
492 | }
|
---|
493 | hScale = vScale = 1.0;
|
---|
494 | /*
|
---|
495 | * Scale the plot size (the graph itself doesn't change size) if
|
---|
496 | * it's bigger than the paper or if -maxpect was set.
|
---|
497 | */
|
---|
498 | if ((psPtr->maxpect) || ((hSize + hBorder) > paperWidth)) {
|
---|
499 | hScale = (double)(paperWidth - hBorder) / (double)hSize;
|
---|
500 | }
|
---|
501 | if ((psPtr->maxpect) || ((vSize + vBorder) > paperHeight)) {
|
---|
502 | vScale = (double)(paperHeight - vBorder) / (double)vSize;
|
---|
503 | }
|
---|
504 | scale = MIN(hScale, vScale);
|
---|
505 | if (scale != 1.0) {
|
---|
506 | hSize = (int)((hSize * scale) + 0.5);
|
---|
507 | vSize = (int)((vSize * scale) + 0.5);
|
---|
508 | }
|
---|
509 | psPtr->pageScale = scale;
|
---|
510 | if (psPtr->center) {
|
---|
511 | if (paperWidth > hSize) {
|
---|
512 | x = (paperWidth - hSize) / 2;
|
---|
513 | }
|
---|
514 | if (paperHeight > vSize) {
|
---|
515 | y = (paperHeight - vSize) / 2;
|
---|
516 | }
|
---|
517 | }
|
---|
518 | psPtr->left = x;
|
---|
519 | psPtr->bottom = y;
|
---|
520 | psPtr->right = x + hSize - 1;
|
---|
521 | psPtr->top = y + vSize - 1;
|
---|
522 |
|
---|
523 | graphPtr->flags |= LAYOUT_NEEDED | MAP_WORLD;
|
---|
524 | Blt_LayoutGraph(graphPtr);
|
---|
525 | return paperHeight;
|
---|
526 | }
|
---|
527 |
|
---|
528 | /*
|
---|
529 | * --------------------------------------------------------------------------
|
---|
530 | *
|
---|
531 | * PreviewImage --
|
---|
532 | *
|
---|
533 | * Generates a EPSI thumbnail of the graph. The thumbnail is
|
---|
534 | * restricted to a certain size. This is to keep the size of the
|
---|
535 | * PostScript file small and the processing time low.
|
---|
536 | *
|
---|
537 | * The graph is drawn into a pixmap. We then take a snapshot
|
---|
538 | * of that pixmap, and rescale it to a smaller image. Finally,
|
---|
539 | * the image is dumped to PostScript.
|
---|
540 | *
|
---|
541 | * Results:
|
---|
542 | * None.
|
---|
543 | *
|
---|
544 | * --------------------------------------------------------------------------
|
---|
545 | */
|
---|
546 | static void
|
---|
547 | PreviewImage(graphPtr, psToken)
|
---|
548 | Graph *graphPtr;
|
---|
549 | PsToken psToken;
|
---|
550 | {
|
---|
551 | PostScript *psPtr = (PostScript *)graphPtr->postscript;
|
---|
552 | int noBackingStore = 0;
|
---|
553 | Pixmap drawable;
|
---|
554 | Blt_ColorImage image;
|
---|
555 | int nLines;
|
---|
556 | Tcl_DString dString;
|
---|
557 |
|
---|
558 | /* Create a pixmap and draw the graph into it. */
|
---|
559 |
|
---|
560 | drawable = Tk_GetPixmap(graphPtr->display, Tk_WindowId(graphPtr->tkwin),
|
---|
561 | graphPtr->width, graphPtr->height, Tk_Depth(graphPtr->tkwin));
|
---|
562 | Blt_DrawGraph(graphPtr, drawable, noBackingStore);
|
---|
563 |
|
---|
564 | /* Get a color image from the pixmap */
|
---|
565 | image = Blt_DrawableToColorImage(graphPtr->tkwin, drawable, 0, 0,
|
---|
566 | graphPtr->width, graphPtr->height, 1.0);
|
---|
567 | Tk_FreePixmap(graphPtr->display, drawable);
|
---|
568 | if (image == NULL) {
|
---|
569 | return; /* Can't grab pixmap? */
|
---|
570 | }
|
---|
571 | #ifdef THUMBNAIL_PREVIEW
|
---|
572 | {
|
---|
573 | double scale, xScale, yScale;
|
---|
574 | int width, height;
|
---|
575 | Blt_ColorImage destImage;
|
---|
576 |
|
---|
577 | /* Scale the source image into a size appropriate for a thumbnail. */
|
---|
578 | #define PS_MAX_PREVIEW_WIDTH 300.0
|
---|
579 | #define PS_MAX_PREVIEW_HEIGHT 300.0
|
---|
580 | xScale = PS_MAX_PREVIEW_WIDTH / (double)graphPtr->width;
|
---|
581 | yScale = PS_MAX_PREVIEW_HEIGHT / (double)graphPtr->height;
|
---|
582 | scale = MIN(xScale, yScale);
|
---|
583 |
|
---|
584 | width = (int)(scale * graphPtr->width + 0.5);
|
---|
585 | height = (int)(scale * graphPtr->height + 0.5);
|
---|
586 | destImage = Blt_ResampleColorImage(image, width, height,
|
---|
587 | bltBoxFilterPtr, bltBoxFilterPtr);
|
---|
588 | Blt_FreeColorImage(image);
|
---|
589 | image = destImage;
|
---|
590 | }
|
---|
591 | #endif /* THUMBNAIL_PREVIEW */
|
---|
592 | Blt_ColorImageToGreyscale(image);
|
---|
593 | if (psPtr->landscape) {
|
---|
594 | Blt_ColorImage oldImage;
|
---|
595 |
|
---|
596 | oldImage = image;
|
---|
597 | image = Blt_RotateColorImage(image, 90.0);
|
---|
598 | Blt_FreeColorImage(oldImage);
|
---|
599 | }
|
---|
600 | Tcl_DStringInit(&dString);
|
---|
601 | /* Finally, we can generate PostScript for the image */
|
---|
602 | nLines = Blt_ColorImageToPsData(image, 1, &dString, "%");
|
---|
603 |
|
---|
604 | Blt_AppendToPostScript(psToken, "%%BeginPreview: ", (char *)NULL);
|
---|
605 | Blt_FormatToPostScript(psToken, "%d %d 8 %d\n", Blt_ColorImageWidth(image),
|
---|
606 | Blt_ColorImageHeight(image), nLines);
|
---|
607 | Blt_AppendToPostScript(psToken, Tcl_DStringValue(&dString), (char *)NULL);
|
---|
608 | Blt_AppendToPostScript(psToken, "%%EndPreview\n\n", (char *)NULL);
|
---|
609 | Tcl_DStringFree(&dString);
|
---|
610 | Blt_FreeColorImage(image);
|
---|
611 | }
|
---|
612 |
|
---|
613 | /*
|
---|
614 | * --------------------------------------------------------------------------
|
---|
615 | *
|
---|
616 | * PostScriptPreamble
|
---|
617 | *
|
---|
618 | * The PostScript preamble calculates the needed translation and scaling
|
---|
619 | * to make X11 coordinates compatible with PostScript.
|
---|
620 | *
|
---|
621 | * ---------------------------------------------------------------------
|
---|
622 | */
|
---|
623 |
|
---|
624 | #ifdef TIME_WITH_SYS_TIME
|
---|
625 | #include <sys/time.h>
|
---|
626 | #include <time.h>
|
---|
627 | #else
|
---|
628 | #ifdef HAVE_SYS_TIME_H
|
---|
629 | #include <sys/time.h>
|
---|
630 | #else
|
---|
631 | #include <time.h>
|
---|
632 | #endif /* HAVE_SYS_TIME_H */
|
---|
633 | #endif /* TIME_WITH_SYS_TIME */
|
---|
634 |
|
---|
635 | static int
|
---|
636 | PostScriptPreamble(graphPtr, fileName, psToken)
|
---|
637 | Graph *graphPtr;
|
---|
638 | char *fileName;
|
---|
639 | PsToken psToken;
|
---|
640 | {
|
---|
641 | PostScript *psPtr = (PostScript *)graphPtr->postscript;
|
---|
642 | time_t ticks;
|
---|
643 | char date[200]; /* Hold the date string from ctime() */
|
---|
644 | CONST char *version;
|
---|
645 | double dpiX, dpiY;
|
---|
646 | double xPixelsToPica, yPixelsToPica; /* Scales to convert pixels to pica */
|
---|
647 | Screen *screenPtr;
|
---|
648 | char *nl;
|
---|
649 | int paperHeightPixels;
|
---|
650 |
|
---|
651 | paperHeightPixels = ComputeBoundingBox(graphPtr, psPtr);
|
---|
652 | if (fileName == NULL) {
|
---|
653 | fileName = Tk_PathName(graphPtr->tkwin);
|
---|
654 | }
|
---|
655 | Blt_AppendToPostScript(psToken, "%!PS-Adobe-3.0 EPSF-3.0\n",
|
---|
656 | (char *)NULL);
|
---|
657 |
|
---|
658 | /*
|
---|
659 | * Compute the scale factors to convert PostScript to X11 coordinates.
|
---|
660 | * Round the pixels per inch (dpi) to an integral value before computing
|
---|
661 | * the scale.
|
---|
662 | */
|
---|
663 | #define MM_INCH 25.4
|
---|
664 | #define PICA_INCH 72.0
|
---|
665 | screenPtr = Tk_Screen(graphPtr->tkwin);
|
---|
666 | dpiX = (WidthOfScreen(screenPtr) * MM_INCH) / WidthMMOfScreen(screenPtr);
|
---|
667 | xPixelsToPica = PICA_INCH / dpiX;
|
---|
668 | dpiY = (HeightOfScreen(screenPtr) * MM_INCH) / HeightMMOfScreen(screenPtr);
|
---|
669 | yPixelsToPica = PICA_INCH / dpiY;
|
---|
670 |
|
---|
671 | /*
|
---|
672 | * The "BoundingBox" comment is required for EPS files. The box
|
---|
673 | * coordinates are integers, so we need round away from the
|
---|
674 | * center of the box.
|
---|
675 | */
|
---|
676 | Blt_FormatToPostScript(psToken, "%%%%BoundingBox: %d %d %d %d\n",
|
---|
677 | (int)floor(psPtr->left * xPixelsToPica),
|
---|
678 | (int)floor((paperHeightPixels - psPtr->top) * yPixelsToPica),
|
---|
679 | (int)ceil(psPtr->right * xPixelsToPica),
|
---|
680 | (int)ceil((paperHeightPixels - psPtr->bottom) * yPixelsToPica));
|
---|
681 |
|
---|
682 | Blt_AppendToPostScript(psToken, "%%Pages: 0\n", (char *)NULL);
|
---|
683 |
|
---|
684 | version = Tcl_GetVar(graphPtr->interp, "blt_version", TCL_GLOBAL_ONLY);
|
---|
685 | if (version == NULL) {
|
---|
686 | version = "???";
|
---|
687 | }
|
---|
688 | Blt_FormatToPostScript(psToken, "%%%%Creator: (BLT %s %s)\n", version,
|
---|
689 | Tk_Class(graphPtr->tkwin));
|
---|
690 |
|
---|
691 | ticks = time((time_t *) NULL);
|
---|
692 | strcpy(date, ctime(&ticks));
|
---|
693 | nl = date + strlen(date) - 1;
|
---|
694 | if (*nl == '\n') {
|
---|
695 | *nl = '\0';
|
---|
696 | }
|
---|
697 | Blt_FormatToPostScript(psToken, "%%%%CreationDate: (%s)\n", date);
|
---|
698 | Blt_FormatToPostScript(psToken, "%%%%Title: (%s)\n", fileName);
|
---|
699 | Blt_AppendToPostScript(psToken, "%%DocumentData: Clean7Bit\n",
|
---|
700 | (char *)NULL);
|
---|
701 | if (psPtr->landscape) {
|
---|
702 | Blt_AppendToPostScript(psToken, "%%Orientation: Landscape\n",
|
---|
703 | (char *)NULL);
|
---|
704 | } else {
|
---|
705 | Blt_AppendToPostScript(psToken, "%%Orientation: Portrait\n",
|
---|
706 | (char *)NULL);
|
---|
707 | }
|
---|
708 | Blt_AppendToPostScript(psToken,
|
---|
709 | "%%DocumentNeededResources: font Helvetica Courier\n", (char *)NULL);
|
---|
710 | Blt_AppendToPostScript(psToken, "%%EndComments\n\n", (char *)NULL);
|
---|
711 | if ((psPtr->addPreview) && (psPtr->previewFormat == PS_PREVIEW_EPSI)) {
|
---|
712 | PreviewImage(graphPtr, psToken);
|
---|
713 | }
|
---|
714 | if (Blt_FileToPostScript(psToken, "bltGraph.pro") != TCL_OK) {
|
---|
715 | return TCL_ERROR;
|
---|
716 | }
|
---|
717 | if (psPtr->footer) {
|
---|
718 | char *who;
|
---|
719 |
|
---|
720 | who = getenv("LOGNAME");
|
---|
721 | if (who == NULL) {
|
---|
722 | who = "???";
|
---|
723 | }
|
---|
724 | Blt_AppendToPostScript(psToken,
|
---|
725 | "8 /Helvetica SetFont\n",
|
---|
726 | "10 30 moveto\n",
|
---|
727 | "(Date: ", date, ") show\n",
|
---|
728 | "10 20 moveto\n",
|
---|
729 | "(File: ", fileName, ") show\n",
|
---|
730 | "10 10 moveto\n",
|
---|
731 | "(Created by: ", who, "@", Tcl_GetHostName(), ") show\n",
|
---|
732 | "0 0 moveto\n",
|
---|
733 | (char *)NULL);
|
---|
734 | }
|
---|
735 | /*
|
---|
736 | * Set the conversion from PostScript to X11 coordinates. Scale
|
---|
737 | * pica to pixels and flip the y-axis (the origin is the upperleft
|
---|
738 | * corner).
|
---|
739 | */
|
---|
740 | Blt_AppendToPostScript(psToken,
|
---|
741 | "% Transform coordinate system to use X11 coordinates\n\n",
|
---|
742 | "% 1. Flip y-axis over by reversing the scale,\n",
|
---|
743 | "% 2. Translate the origin to the other side of the page,\n",
|
---|
744 | "% making the origin the upper left corner\n", (char *)NULL);
|
---|
745 | Blt_FormatToPostScript(psToken, "%g -%g scale\n", xPixelsToPica,
|
---|
746 | yPixelsToPica);
|
---|
747 | /* Papersize is in pixels. Translate the new origin *after*
|
---|
748 | * changing the scale. */
|
---|
749 | Blt_FormatToPostScript(psToken, "0 %d translate\n\n",
|
---|
750 | -paperHeightPixels);
|
---|
751 | Blt_AppendToPostScript(psToken, "% User defined page layout\n\n",
|
---|
752 | "% Set color level\n", (char *)NULL);
|
---|
753 | Blt_FormatToPostScript(psToken, "/CL %d def\n\n", psPtr->colorMode);
|
---|
754 | Blt_FormatToPostScript(psToken, "%% Set origin\n%d %d translate\n\n",
|
---|
755 | psPtr->left, psPtr->bottom);
|
---|
756 | if (psPtr->landscape) {
|
---|
757 | Blt_FormatToPostScript(psToken,
|
---|
758 | "%% Landscape orientation\n0 %g translate\n-90 rotate\n",
|
---|
759 | ((double)graphPtr->width * psPtr->pageScale));
|
---|
760 | }
|
---|
761 | if (psPtr->pageScale != 1.0) {
|
---|
762 | Blt_AppendToPostScript(psToken, "\n% Setting graph scale factor\n",
|
---|
763 | (char *)NULL);
|
---|
764 | Blt_FormatToPostScript(psToken, " %g %g scale\n", psPtr->pageScale,
|
---|
765 | psPtr->pageScale);
|
---|
766 | }
|
---|
767 | Blt_AppendToPostScript(psToken, "\n%%EndSetup\n\n", (char *)NULL);
|
---|
768 | return TCL_OK;
|
---|
769 | }
|
---|
770 |
|
---|
771 |
|
---|
772 | static void
|
---|
773 | MarginsToPostScript(graphPtr, psToken)
|
---|
774 | Graph *graphPtr;
|
---|
775 | PsToken psToken;
|
---|
776 | {
|
---|
777 | PostScript *psPtr = (PostScript *)graphPtr->postscript;
|
---|
778 | XRectangle margin[4];
|
---|
779 |
|
---|
780 | margin[0].x = margin[0].y = margin[3].x = margin[1].x = 0;
|
---|
781 | margin[0].width = margin[3].width = graphPtr->width;
|
---|
782 | margin[0].height = graphPtr->top;
|
---|
783 | margin[3].y = graphPtr->bottom;
|
---|
784 | margin[3].height = graphPtr->height - graphPtr->bottom;
|
---|
785 | margin[2].y = margin[1].y = graphPtr->top;
|
---|
786 | margin[1].width = graphPtr->left;
|
---|
787 | margin[2].height = margin[1].height = graphPtr->bottom - graphPtr->top;
|
---|
788 | margin[2].x = graphPtr->right;
|
---|
789 | margin[2].width = graphPtr->width - graphPtr->right;
|
---|
790 |
|
---|
791 | /* Clear the surrounding margins and clip the plotting surface */
|
---|
792 | if (psPtr->decorations) {
|
---|
793 | Blt_BackgroundToPostScript(psToken,
|
---|
794 | Tk_3DBorderColor(graphPtr->border));
|
---|
795 | } else {
|
---|
796 | Blt_ClearBackgroundToPostScript(psToken);
|
---|
797 | }
|
---|
798 | Blt_RectanglesToPostScript(psToken, margin, 4);
|
---|
799 |
|
---|
800 | /* Interior 3D border */
|
---|
801 | if ((psPtr->decorations) && (graphPtr->plotBorderWidth > 0)) {
|
---|
802 | int x, y, width, height;
|
---|
803 |
|
---|
804 | x = graphPtr->left - graphPtr->plotBorderWidth;
|
---|
805 | y = graphPtr->top - graphPtr->plotBorderWidth;
|
---|
806 | width = (graphPtr->right - graphPtr->left) +
|
---|
807 | (2 * graphPtr->plotBorderWidth);
|
---|
808 | height = (graphPtr->bottom - graphPtr->top) +
|
---|
809 | (2 * graphPtr->plotBorderWidth);
|
---|
810 | Blt_Draw3DRectangleToPostScript(psToken, graphPtr->border,
|
---|
811 | (double)x, (double)y, width, height, graphPtr->plotBorderWidth,
|
---|
812 | graphPtr->plotRelief);
|
---|
813 | }
|
---|
814 | if (Blt_LegendSite(graphPtr->legend) & LEGEND_IN_MARGIN) {
|
---|
815 | /*
|
---|
816 | * Print the legend if we're using a site which lies in one
|
---|
817 | * of the margins (left, right, top, or bottom) of the graph.
|
---|
818 | */
|
---|
819 | Blt_LegendToPostScript(graphPtr->legend, psToken);
|
---|
820 | }
|
---|
821 | if (graphPtr->title != NULL) {
|
---|
822 | Blt_TextToPostScript(psToken, graphPtr->title,
|
---|
823 | &graphPtr->titleTextStyle, (double)graphPtr->titleX,
|
---|
824 | (double)graphPtr->titleY);
|
---|
825 | }
|
---|
826 | Blt_AxesToPostScript(graphPtr, psToken);
|
---|
827 | }
|
---|
828 |
|
---|
829 |
|
---|
830 | static int
|
---|
831 | GraphToPostScript(graphPtr, ident, psToken)
|
---|
832 | Graph *graphPtr;
|
---|
833 | char *ident; /* Identifier string (usually the filename) */
|
---|
834 | PsToken psToken;
|
---|
835 | {
|
---|
836 | int x, y, width, height;
|
---|
837 | int result;
|
---|
838 |
|
---|
839 | /*
|
---|
840 | * We need to know how big a graph to print. If the graph hasn't
|
---|
841 | * been drawn yet, the width and height will be 1. Instead use
|
---|
842 | * the requested size of the widget. The user can still override
|
---|
843 | * this with the -width and -height postscript options.
|
---|
844 | */
|
---|
845 | if (graphPtr->height <= 1) {
|
---|
846 | graphPtr->height = Tk_ReqHeight(graphPtr->tkwin);
|
---|
847 | }
|
---|
848 | if (graphPtr->width <= 1) {
|
---|
849 | graphPtr->width = Tk_ReqWidth(graphPtr->tkwin);
|
---|
850 | }
|
---|
851 | result = PostScriptPreamble(graphPtr, ident, psToken);
|
---|
852 | if (result != TCL_OK) {
|
---|
853 | goto error;
|
---|
854 | }
|
---|
855 | /*
|
---|
856 | * Determine rectangle of the plotting area for the graph window
|
---|
857 | */
|
---|
858 | x = graphPtr->left - graphPtr->plotBorderWidth;
|
---|
859 | y = graphPtr->top - graphPtr->plotBorderWidth;
|
---|
860 |
|
---|
861 | width = (graphPtr->right - graphPtr->left + 1) +
|
---|
862 | (2 * graphPtr->plotBorderWidth);
|
---|
863 | height = (graphPtr->bottom - graphPtr->top + 1) +
|
---|
864 | (2 * graphPtr->plotBorderWidth);
|
---|
865 |
|
---|
866 | Blt_FontToPostScript(psToken, graphPtr->titleTextStyle.font);
|
---|
867 | Blt_RegionToPostScript(psToken, (double)x, (double)y, width, height);
|
---|
868 | if (graphPtr->postscript->decorations) {
|
---|
869 | Blt_BackgroundToPostScript(psToken, graphPtr->plotBg);
|
---|
870 | } else {
|
---|
871 | Blt_ClearBackgroundToPostScript(psToken);
|
---|
872 | }
|
---|
873 | Blt_AppendToPostScript(psToken, "Fill\n", (char *)NULL);
|
---|
874 | Blt_AppendToPostScript(psToken, "gsave clip\n\n", (char *)NULL);
|
---|
875 | /* Draw the grid, elements, and markers in the plotting area. */
|
---|
876 | if (!graphPtr->gridPtr->hidden) {
|
---|
877 | Blt_GridToPostScript(graphPtr, psToken);
|
---|
878 | }
|
---|
879 | Blt_MarkersToPostScript(graphPtr, psToken, TRUE);
|
---|
880 | if ((Blt_LegendSite(graphPtr->legend) & LEGEND_IN_PLOT) &&
|
---|
881 | (!Blt_LegendIsRaised(graphPtr->legend))) {
|
---|
882 | /* Print legend underneath elements and markers */
|
---|
883 | Blt_LegendToPostScript(graphPtr->legend, psToken);
|
---|
884 | }
|
---|
885 | Blt_AxisLimitsToPostScript(graphPtr, psToken);
|
---|
886 | Blt_ElementsToPostScript(graphPtr, psToken);
|
---|
887 | if ((Blt_LegendSite(graphPtr->legend) & LEGEND_IN_PLOT) &&
|
---|
888 | (Blt_LegendIsRaised(graphPtr->legend))) {
|
---|
889 | /* Print legend above elements (but not markers) */
|
---|
890 | Blt_LegendToPostScript(graphPtr->legend, psToken);
|
---|
891 | }
|
---|
892 | Blt_MarkersToPostScript(graphPtr, psToken, FALSE);
|
---|
893 | Blt_ActiveElementsToPostScript(graphPtr, psToken);
|
---|
894 | Blt_AppendToPostScript(psToken, "\n",
|
---|
895 | "% Unset clipping\n",
|
---|
896 | "grestore\n\n", (char *)NULL);
|
---|
897 | MarginsToPostScript(graphPtr, psToken);
|
---|
898 | Blt_AppendToPostScript(psToken,
|
---|
899 | "showpage\n",
|
---|
900 | "%Trailer\n",
|
---|
901 | "grestore\n",
|
---|
902 | "end\n",
|
---|
903 | "%EOF\n", (char *)NULL);
|
---|
904 | error:
|
---|
905 | /* Reset height and width of graph window */
|
---|
906 | graphPtr->width = Tk_Width(graphPtr->tkwin);
|
---|
907 | graphPtr->height = Tk_Height(graphPtr->tkwin);
|
---|
908 | graphPtr->flags = MAP_WORLD;
|
---|
909 |
|
---|
910 | /*
|
---|
911 | * Redraw the graph in order to re-calculate the layout as soon as
|
---|
912 | * possible. This is in the case the crosshairs are active.
|
---|
913 | */
|
---|
914 | Blt_EventuallyRedrawGraph(graphPtr);
|
---|
915 | return result;
|
---|
916 | }
|
---|
917 |
|
---|
918 | #ifdef WIN32
|
---|
919 |
|
---|
920 | static void
|
---|
921 | InitAPMHeader(
|
---|
922 | Tk_Window tkwin,
|
---|
923 | int width, int height,
|
---|
924 | APMHEADER *headerPtr)
|
---|
925 | {
|
---|
926 | unsigned int *p;
|
---|
927 | unsigned int sum;
|
---|
928 | Screen *screen;
|
---|
929 | #define MM_INCH 25.4
|
---|
930 | double dpiX, dpiY;
|
---|
931 |
|
---|
932 | headerPtr->key = 0x9ac6cdd7L;
|
---|
933 | headerPtr->hmf = 0;
|
---|
934 | headerPtr->inch = 1440;
|
---|
935 |
|
---|
936 | screen = Tk_Screen(tkwin);
|
---|
937 | dpiX = (WidthOfScreen(screen) * MM_INCH) / WidthMMOfScreen(screen);
|
---|
938 | dpiY = (HeightOfScreen(screen) * MM_INCH) / HeightMMOfScreen(screen);
|
---|
939 |
|
---|
940 | headerPtr->bbox.Left = headerPtr->bbox.Top = 0;
|
---|
941 | headerPtr->bbox.Bottom = (SHORT)((width * 1440) / dpiX);
|
---|
942 | headerPtr->bbox.Right = (SHORT)((height * 1440) / dpiY);
|
---|
943 | headerPtr->reserved = 0;
|
---|
944 | sum = 0;
|
---|
945 | for (p = (unsigned int *)headerPtr;
|
---|
946 | p < (unsigned int *)&(headerPtr->checksum); p++) {
|
---|
947 | sum ^= *p;
|
---|
948 | }
|
---|
949 | headerPtr->checksum = sum;
|
---|
950 | }
|
---|
951 |
|
---|
952 | /*
|
---|
953 | * --------------------------------------------------------------------------
|
---|
954 | *
|
---|
955 | * CreateWindowEPS --
|
---|
956 | *
|
---|
957 | * Generates an EPS file with a Window metafile preview.
|
---|
958 | *
|
---|
959 | * Windows metafiles aren't very robust. Including exactly the
|
---|
960 | * same metafile (one embedded in a DOS EPS, the other as .wmf
|
---|
961 | * file) will play back differently.
|
---|
962 | *
|
---|
963 | * Results:
|
---|
964 | * None.
|
---|
965 | *
|
---|
966 | * --------------------------------------------------------------------------
|
---|
967 | */
|
---|
968 | static int
|
---|
969 | CreateWindowsEPS(
|
---|
970 | Graph *graphPtr,
|
---|
971 | PsToken psToken,
|
---|
972 | FILE *f)
|
---|
973 | {
|
---|
974 | DWORD size;
|
---|
975 | DOSEPSHEADER epsHeader;
|
---|
976 | HANDLE hMem;
|
---|
977 | HDC hRefDC, hDC;
|
---|
978 | HENHMETAFILE hMetaFile;
|
---|
979 | Tcl_DString dString;
|
---|
980 | TkWinDC drawableDC;
|
---|
981 | TkWinDCState state;
|
---|
982 | int result;
|
---|
983 | unsigned char *buffer, *psBuffer;
|
---|
984 |
|
---|
985 | Blt_AppendToPostScript(psToken, "\n", (char *)NULL);
|
---|
986 | psBuffer = Blt_PostScriptFromToken(psToken);
|
---|
987 | /*
|
---|
988 | * Fill out as much information as we can into the DOS EPS header.
|
---|
989 | * We won't know the start of the length of the WMF segment until
|
---|
990 | * we create the metafile.
|
---|
991 | */
|
---|
992 | epsHeader.magic[0] = 0xC5;
|
---|
993 | epsHeader.magic[1] = 0xD0;
|
---|
994 | epsHeader.magic[2] = 0xD3;
|
---|
995 | epsHeader.magic[3] = 0xC6;
|
---|
996 | epsHeader.psStart = sizeof(epsHeader);
|
---|
997 | epsHeader.psLength = strlen(psBuffer) + 1;
|
---|
998 | epsHeader.wmfStart = epsHeader.psStart + epsHeader.psLength;
|
---|
999 | epsHeader.wmfLength = 0L; /* Fill in later. */
|
---|
1000 | epsHeader.tiffStart = 0L;
|
---|
1001 | epsHeader.tiffLength = 0L;
|
---|
1002 | epsHeader.checksum = 0xFFFF;
|
---|
1003 |
|
---|
1004 | result = TCL_ERROR;
|
---|
1005 | hRefDC = TkWinGetDrawableDC(graphPtr->display,
|
---|
1006 | Tk_WindowId(graphPtr->tkwin), &state);
|
---|
1007 |
|
---|
1008 | /* Build a description string. */
|
---|
1009 | Tcl_DStringInit(&dString);
|
---|
1010 | Tcl_DStringAppend(&dString, "BLT Graph ", -1);
|
---|
1011 | Tcl_DStringAppend(&dString, BLT_VERSION, -1);
|
---|
1012 | Tcl_DStringAppend(&dString, "\0", -1);
|
---|
1013 | Tcl_DStringAppend(&dString, Tk_PathName(graphPtr->tkwin), -1);
|
---|
1014 | Tcl_DStringAppend(&dString, "\0", -1);
|
---|
1015 |
|
---|
1016 | hDC = CreateEnhMetaFile(hRefDC, NULL, NULL, Tcl_DStringValue(&dString));
|
---|
1017 | Tcl_DStringFree(&dString);
|
---|
1018 |
|
---|
1019 | if (hDC == NULL) {
|
---|
1020 | Tcl_AppendResult(graphPtr->interp, "can't create metafile: ",
|
---|
1021 | Blt_LastError(), (char *)NULL);
|
---|
1022 | return TCL_ERROR;
|
---|
1023 | }
|
---|
1024 | /* Assemble a Tk drawable that points to the metafile and let the
|
---|
1025 | * graph's drawing routine draw into it. */
|
---|
1026 | drawableDC.hdc = hDC;
|
---|
1027 | drawableDC.type = TWD_WINDC;
|
---|
1028 |
|
---|
1029 | graphPtr->width = Tk_Width(graphPtr->tkwin);
|
---|
1030 | graphPtr->height = Tk_Height(graphPtr->tkwin);
|
---|
1031 | graphPtr->flags |= RESET_WORLD;
|
---|
1032 | Blt_LayoutGraph(graphPtr);
|
---|
1033 | Blt_DrawGraph(graphPtr, (Drawable)&drawableDC, FALSE);
|
---|
1034 | GdiFlush();
|
---|
1035 | hMetaFile = CloseEnhMetaFile(hDC);
|
---|
1036 |
|
---|
1037 | size = GetWinMetaFileBits(hMetaFile, 0, NULL, MM_ANISOTROPIC, hRefDC);
|
---|
1038 | hMem = GlobalAlloc(GHND, size);
|
---|
1039 | if (hMem == NULL) {
|
---|
1040 | Tcl_AppendResult(graphPtr->interp, "can't allocate global memory:",
|
---|
1041 | Blt_LastError(), (char *)NULL);
|
---|
1042 | goto error;
|
---|
1043 | }
|
---|
1044 | buffer = (LPVOID)GlobalLock(hMem);
|
---|
1045 | if (!GetWinMetaFileBits(hMetaFile, size, buffer, MM_ANISOTROPIC, hRefDC)) {
|
---|
1046 | Tcl_AppendResult(graphPtr->interp, "can't get metafile data:",
|
---|
1047 | Blt_LastError(), (char *)NULL);
|
---|
1048 | goto error;
|
---|
1049 | }
|
---|
1050 |
|
---|
1051 | /*
|
---|
1052 | * Fix up the EPS header with the correct metafile length and PS
|
---|
1053 | * offset (now that we what they are).
|
---|
1054 | */
|
---|
1055 | epsHeader.wmfLength = size;
|
---|
1056 | epsHeader.wmfStart = epsHeader.psStart + epsHeader.psLength;
|
---|
1057 |
|
---|
1058 | /* Write out the eps header, */
|
---|
1059 | if (fwrite(&epsHeader, 1, sizeof(epsHeader), f) != sizeof(epsHeader)) {
|
---|
1060 | Tcl_AppendResult(graphPtr->interp, "error writing eps header:",
|
---|
1061 | Blt_LastError(), (char *)NULL);
|
---|
1062 | goto error;
|
---|
1063 | }
|
---|
1064 | /* the PostScript, */
|
---|
1065 | if (fwrite(psBuffer, 1, epsHeader.psLength, f) != epsHeader.psLength) {
|
---|
1066 | Tcl_AppendResult(graphPtr->interp, "error writing PostScript data:",
|
---|
1067 | Blt_LastError(), (char *)NULL);
|
---|
1068 | goto error;
|
---|
1069 | }
|
---|
1070 | /* and finally the metadata itself. */
|
---|
1071 | if (fwrite(buffer, 1, size, f) != size) {
|
---|
1072 | Tcl_AppendResult(graphPtr->interp, "error writing metafile data:",
|
---|
1073 | Blt_LastError(), (char *)NULL);
|
---|
1074 | goto error;
|
---|
1075 | }
|
---|
1076 | result = TCL_OK;
|
---|
1077 |
|
---|
1078 | error:
|
---|
1079 | DeleteEnhMetaFile(hMetaFile);
|
---|
1080 | TkWinReleaseDrawableDC(Tk_WindowId(graphPtr->tkwin), hRefDC, &state);
|
---|
1081 | fclose(f);
|
---|
1082 | if (hMem != NULL) {
|
---|
1083 | GlobalUnlock(hMem);
|
---|
1084 | GlobalFree(hMem);
|
---|
1085 | }
|
---|
1086 | graphPtr->flags = MAP_WORLD;
|
---|
1087 | Blt_EventuallyRedrawGraph(graphPtr);
|
---|
1088 | return result;
|
---|
1089 | }
|
---|
1090 |
|
---|
1091 | #endif /*WIN32*/
|
---|
1092 |
|
---|
1093 | /*
|
---|
1094 | *----------------------------------------------------------------------
|
---|
1095 | *
|
---|
1096 | * OutputOp --
|
---|
1097 | *
|
---|
1098 | * This procedure is invoked to print the graph in a file.
|
---|
1099 | *
|
---|
1100 | * Results:
|
---|
1101 | * Standard TCL result. TCL_OK if plot was successfully printed,
|
---|
1102 | * TCL_ERROR otherwise.
|
---|
1103 | *
|
---|
1104 | * Side effects:
|
---|
1105 | * A new PostScript file is created.
|
---|
1106 | *
|
---|
1107 | *----------------------------------------------------------------------
|
---|
1108 | */
|
---|
1109 | static int
|
---|
1110 | OutputOp(graphPtr, interp, argc, argv)
|
---|
1111 | Graph *graphPtr; /* Graph widget record */
|
---|
1112 | Tcl_Interp *interp;
|
---|
1113 | int argc; /* Number of options in argv vector */
|
---|
1114 | char **argv; /* Option vector */
|
---|
1115 | {
|
---|
1116 | PostScript *psPtr = (PostScript *)graphPtr->postscript;
|
---|
1117 | FILE *f = NULL;
|
---|
1118 | PsToken psToken;
|
---|
1119 | char *fileName; /* Name of file to write PostScript output
|
---|
1120 | * If NULL, output is returned via
|
---|
1121 | * interp->result. */
|
---|
1122 | fileName = NULL;
|
---|
1123 | if (argc > 3) {
|
---|
1124 | if (argv[3][0] != '-') {
|
---|
1125 | fileName = argv[3]; /* First argument is the file name. */
|
---|
1126 | argv++, argc--;
|
---|
1127 | }
|
---|
1128 | if (Tk_ConfigureWidget(interp, graphPtr->tkwin, configSpecs, argc - 3,
|
---|
1129 | argv + 3, (char *)psPtr, TK_CONFIG_ARGV_ONLY) != TCL_OK) {
|
---|
1130 | return TCL_ERROR;
|
---|
1131 | }
|
---|
1132 | if (fileName != NULL) {
|
---|
1133 | #ifdef WIN32
|
---|
1134 | f = fopen(fileName, "wb");
|
---|
1135 | #else
|
---|
1136 | f = fopen(fileName, "w");
|
---|
1137 | #endif
|
---|
1138 | if (f == NULL) {
|
---|
1139 | Tcl_AppendResult(interp, "can't create \"", fileName, "\": ",
|
---|
1140 | Tcl_PosixError(interp), (char *)NULL);
|
---|
1141 | return TCL_ERROR;
|
---|
1142 | }
|
---|
1143 | }
|
---|
1144 | }
|
---|
1145 | psToken = Blt_GetPsToken(graphPtr->interp, graphPtr->tkwin);
|
---|
1146 | psToken->fontVarName = psPtr->fontVarName;
|
---|
1147 | psToken->colorVarName = psPtr->colorVarName;
|
---|
1148 | psToken->colorMode = psPtr->colorMode;
|
---|
1149 |
|
---|
1150 | if (GraphToPostScript(graphPtr, fileName, psToken) != TCL_OK) {
|
---|
1151 | goto error;
|
---|
1152 | }
|
---|
1153 | /*
|
---|
1154 | * If a file name was given, write the results to that file
|
---|
1155 | */
|
---|
1156 | if (f != NULL) {
|
---|
1157 | #ifdef WIN32
|
---|
1158 | if ((psPtr->addPreview) && (psPtr->previewFormat != PS_PREVIEW_EPSI)) {
|
---|
1159 | if (CreateWindowsEPS(graphPtr, psToken, f)) {
|
---|
1160 | return TCL_ERROR;
|
---|
1161 | }
|
---|
1162 | } else {
|
---|
1163 | fputs(Blt_PostScriptFromToken(psToken), f);
|
---|
1164 | if (ferror(f)) {
|
---|
1165 | Tcl_AppendResult(interp, "error writing file \"", fileName,
|
---|
1166 | "\": ", Tcl_PosixError(interp), (char *)NULL);
|
---|
1167 | goto error;
|
---|
1168 | }
|
---|
1169 | }
|
---|
1170 | #else
|
---|
1171 | fputs(Blt_PostScriptFromToken(psToken), f);
|
---|
1172 | if (ferror(f)) {
|
---|
1173 | Tcl_AppendResult(interp, "error writing file \"", fileName, "\": ",
|
---|
1174 | Tcl_PosixError(interp), (char *)NULL);
|
---|
1175 | goto error;
|
---|
1176 | }
|
---|
1177 | #endif /* WIN32 */
|
---|
1178 | fclose(f);
|
---|
1179 | } else {
|
---|
1180 | Tcl_SetResult(interp, Blt_PostScriptFromToken(psToken), TCL_VOLATILE);
|
---|
1181 | }
|
---|
1182 | Blt_ReleasePsToken(psToken);
|
---|
1183 | return TCL_OK;
|
---|
1184 |
|
---|
1185 | error:
|
---|
1186 | if (f != NULL) {
|
---|
1187 | fclose(f);
|
---|
1188 | }
|
---|
1189 | Blt_ReleasePsToken(psToken);
|
---|
1190 | return TCL_ERROR;
|
---|
1191 | }
|
---|
1192 |
|
---|
1193 | /*
|
---|
1194 | *----------------------------------------------------------------------
|
---|
1195 | *
|
---|
1196 | * Blt_CreatePostScript --
|
---|
1197 | *
|
---|
1198 | * Creates a postscript structure.
|
---|
1199 | *
|
---|
1200 | * Results:
|
---|
1201 | * Always TCL_OK.
|
---|
1202 | *
|
---|
1203 | * Side effects:
|
---|
1204 | * A new PostScript structure is created.
|
---|
1205 | *
|
---|
1206 | *----------------------------------------------------------------------
|
---|
1207 | */
|
---|
1208 | int
|
---|
1209 | Blt_CreatePostScript(graphPtr)
|
---|
1210 | Graph *graphPtr;
|
---|
1211 | {
|
---|
1212 | PostScript *psPtr;
|
---|
1213 |
|
---|
1214 | psPtr = Blt_Calloc(1, sizeof(PostScript));
|
---|
1215 | assert(psPtr);
|
---|
1216 | psPtr->colorMode = PS_MODE_COLOR;
|
---|
1217 | psPtr->center = TRUE;
|
---|
1218 | psPtr->decorations = TRUE;
|
---|
1219 | graphPtr->postscript = psPtr;
|
---|
1220 |
|
---|
1221 | if (Blt_ConfigureWidgetComponent(graphPtr->interp, graphPtr->tkwin,
|
---|
1222 | "postscript", "Postscript", configSpecs, 0, (char **)NULL,
|
---|
1223 | (char *)psPtr, 0) != TCL_OK) {
|
---|
1224 | return TCL_ERROR;
|
---|
1225 | }
|
---|
1226 | return TCL_OK;
|
---|
1227 | }
|
---|
1228 |
|
---|
1229 | /*
|
---|
1230 | *--------------------------------------------------------------
|
---|
1231 | *
|
---|
1232 | * Blt_PostScriptOp --
|
---|
1233 | *
|
---|
1234 | * This procedure is invoked to process the Tcl command
|
---|
1235 | * that corresponds to a widget managed by this module.
|
---|
1236 | * See the user documentation for details on what it does.
|
---|
1237 | *
|
---|
1238 | * Results:
|
---|
1239 | * A standard Tcl result.
|
---|
1240 | *
|
---|
1241 | * Side effects:
|
---|
1242 | * See the user documentation.
|
---|
1243 | *
|
---|
1244 | *--------------------------------------------------------------
|
---|
1245 | */
|
---|
1246 | static Blt_OpSpec psOps[] =
|
---|
1247 | {
|
---|
1248 | {"cget", 2, (Blt_Op)CgetOp, 4, 4, "option",},
|
---|
1249 | {"configure", 2, (Blt_Op)ConfigureOp, 3, 0, "?option value?...",},
|
---|
1250 | {"output", 1, (Blt_Op)OutputOp, 3, 0,
|
---|
1251 | "?fileName? ?option value?...",},
|
---|
1252 | };
|
---|
1253 |
|
---|
1254 | static int nPsOps = sizeof(psOps) / sizeof(Blt_OpSpec);
|
---|
1255 |
|
---|
1256 | int
|
---|
1257 | Blt_PostScriptOp(graphPtr, interp, argc, argv)
|
---|
1258 | Graph *graphPtr; /* Graph widget record */
|
---|
1259 | Tcl_Interp *interp;
|
---|
1260 | int argc; /* # arguments */
|
---|
1261 | char **argv; /* Argument list */
|
---|
1262 | {
|
---|
1263 | Blt_Op proc;
|
---|
1264 | int result;
|
---|
1265 |
|
---|
1266 | proc = Blt_GetOp(interp, nPsOps, psOps, BLT_OP_ARG2, argc, argv, 0);
|
---|
1267 | if (proc == NULL) {
|
---|
1268 | return TCL_ERROR;
|
---|
1269 | }
|
---|
1270 | result = (*proc) (graphPtr, interp, argc, argv);
|
---|
1271 | return result;
|
---|
1272 | }
|
---|
1273 |
|
---|