1
2 /*
3 * bltPs.c --
4 *
5 * This module implements general PostScript conversion routines.
6 *
7 * Copyright 1991-1998 Lucent Technologies, Inc.
8 *
9 * Permission to use, copy, modify, and distribute this software and
10 * its documentation for any purpose and without fee is hereby
11 * granted, provided that the above copyright notice appear in all
12 * copies and that both that the copyright notice and warranty
13 * disclaimer appear in supporting documentation, and that the names
14 * of Lucent Technologies any of their entities not be used in
15 * advertising or publicity pertaining to distribution of the software
16 * without specific, written prior permission.
17 *
18 * Lucent Technologies disclaims all warranties with regard to this
19 * software, including all implied warranties of merchantability and
20 * fitness. In no event shall Lucent Technologies be liable for any
21 * special, indirect or consequential damages or any damages
22 * whatsoever resulting from loss of use, data or profits, whether in
23 * an action of contract, negligence or other tortuous action, arising
24 * out of or in connection with the use or performance of this
25 * software.
26 */
27
28 #include "bltInt.h"
29 #include "bltPs.h"
30
31 #include <X11/Xutil.h>
32 #include <X11/Xatom.h>
33 #if defined(__STDC__)
34 #include <stdarg.h>
35 #else
36 #include <varargs.h>
37 #endif
38
39 #define PS_MAXPATH 1500 /* Maximum number of components in a PostScript
40 * (level 1) path. */
41
42 PsToken
Blt_GetPsToken(interp,tkwin)43 Blt_GetPsToken(interp, tkwin)
44 Tcl_Interp *interp;
45 Tk_Window tkwin;
46 {
47 struct PsTokenStruct *tokenPtr;
48
49 tokenPtr = Blt_Malloc(sizeof(struct PsTokenStruct));
50 assert(tokenPtr);
51
52 tokenPtr->fontVarName = tokenPtr->colorVarName = NULL;
53 tokenPtr->interp = interp;
54 tokenPtr->tkwin = tkwin;
55 tokenPtr->colorMode = PS_MODE_COLOR;
56 Tcl_DStringInit(&(tokenPtr->dString));
57 return tokenPtr;
58 }
59
60 void
Blt_ReleasePsToken(tokenPtr)61 Blt_ReleasePsToken(tokenPtr)
62 struct PsTokenStruct *tokenPtr;
63 {
64 Tcl_DStringFree(&(tokenPtr->dString));
65 Blt_Free(tokenPtr);
66 }
67
68 char *
Blt_PostScriptFromToken(tokenPtr)69 Blt_PostScriptFromToken(tokenPtr)
70 struct PsTokenStruct *tokenPtr;
71 {
72 return Tcl_DStringValue(&(tokenPtr->dString));
73 }
74
75 char *
Blt_ScratchBufferFromToken(tokenPtr)76 Blt_ScratchBufferFromToken(tokenPtr)
77 struct PsTokenStruct *tokenPtr;
78 {
79 return tokenPtr->scratchArr;
80 }
81
82 void
83 Blt_AppendToPostScript
TCL_VARARGS_DEF(PsToken,arg1)84 TCL_VARARGS_DEF(PsToken, arg1)
85 {
86 va_list argList;
87 struct PsTokenStruct *tokenPtr;
88 char *string;
89
90 tokenPtr = TCL_VARARGS_START(struct PsTokenStruct, arg1, argList);
91 for (;;) {
92 string = va_arg(argList, char *);
93 if (string == NULL) {
94 break;
95 }
96 Tcl_DStringAppend(&(tokenPtr->dString), string, -1);
97 }
98 }
99
100 void
101 Blt_FormatToPostScript
TCL_VARARGS_DEF(PsToken,arg1)102 TCL_VARARGS_DEF(PsToken, arg1)
103 {
104 va_list argList;
105 struct PsTokenStruct *tokenPtr;
106 char *fmt;
107
108 tokenPtr = TCL_VARARGS_START(struct PsTokenStruct, arg1, argList);
109 fmt = va_arg(argList, char *);
110 vsprintf(tokenPtr->scratchArr, fmt, argList);
111 va_end(argList);
112 Tcl_DStringAppend(&(tokenPtr->dString), tokenPtr->scratchArr, -1);
113 }
114
115 int
Blt_FileToPostScript(tokenPtr,fileName)116 Blt_FileToPostScript(tokenPtr, fileName)
117 struct PsTokenStruct *tokenPtr;
118 char *fileName;
119 {
120 Tcl_Channel channel;
121 Tcl_DString dString;
122 Tcl_Interp *interp;
123 char *buf;
124 char *libDir;
125 int nBytes;
126
127 interp = tokenPtr->interp;
128 buf = tokenPtr->scratchArr;
129
130 /*
131 * Read in a standard prolog file from file and append it to the
132 * PostScript output stored in the Tcl_DString in tokenPtr.
133 */
134
135 libDir = (char *)Tcl_GetVar(interp, "blt_library", TCL_GLOBAL_ONLY);
136 if (libDir == NULL) {
137 Tcl_AppendResult(interp, "couldn't find BLT script library:",
138 "global variable \"blt_library\" doesn't exist", (char *)NULL);
139 return TCL_ERROR;
140 }
141 Tcl_DStringInit(&dString);
142 Tcl_DStringAppend(&dString, libDir, -1);
143 Tcl_DStringAppend(&dString, "/", -1);
144 Tcl_DStringAppend(&dString, fileName, -1);
145 fileName = Tcl_DStringValue(&dString);
146 Blt_AppendToPostScript(tokenPtr, "\n% including file \"", fileName,
147 "\"\n\n", (char *)NULL);
148 channel = Tcl_OpenFileChannel(interp, fileName, "r", 0);
149 if (channel == NULL) {
150 Tcl_AppendResult(interp, "couldn't open prologue file \"", fileName,
151 "\": ", Tcl_PosixError(interp), (char *)NULL);
152 return TCL_ERROR;
153 }
154 for(;;) {
155 nBytes = Tcl_Read(channel, buf, PSTOKEN_BUFSIZ);
156 if (nBytes < 0) {
157 Tcl_AppendResult(interp, "error reading prologue file \"",
158 fileName, "\": ", Tcl_PosixError(interp),
159 (char *)NULL);
160 Tcl_Close(interp, channel);
161 Tcl_DStringFree(&dString);
162 return TCL_ERROR;
163 }
164 if (nBytes == 0) {
165 break;
166 }
167 buf[nBytes] = '\0';
168 Blt_AppendToPostScript(tokenPtr, buf, (char *)NULL);
169 }
170 Tcl_DStringFree(&dString);
171 Tcl_Close(interp, channel);
172 return TCL_OK;
173 }
174 /*
175 *----------------------------------------------------------------------
176 *
177 * XColorToPostScript --
178 *
179 * Convert the a XColor (from its RGB values) to a PostScript
180 * command. If a Tk color map variable exists, it will be
181 * consulted for a PostScript translation based upon the color
182 * name.
183 *
184 * Maps an X color intensity (0 to 2^16-1) to a floating point
185 * value [0..1]. Many versions of Tk don't properly handle the
186 * the lower 8 bits of the color intensity, so we can only
187 * consider the upper 8 bits.
188 *
189 * Results:
190 * The string representing the color mode is returned.
191 *
192 *----------------------------------------------------------------------
193 */
194 static void
XColorToPostScript(tokenPtr,colorPtr)195 XColorToPostScript(tokenPtr, colorPtr)
196 struct PsTokenStruct *tokenPtr;
197 XColor *colorPtr; /* Color value to be converted */
198 {
199 /*
200 * Shift off the lower byte before dividing because some versions
201 * of Tk don't fill the lower byte correctly.
202 */
203 Blt_FormatToPostScript(tokenPtr, "%g %g %g",
204 ((double)(colorPtr->red >> 8) / 255.0),
205 ((double)(colorPtr->green >> 8) / 255.0),
206 ((double)(colorPtr->blue >> 8) / 255.0));
207 }
208
209 void
Blt_BackgroundToPostScript(tokenPtr,colorPtr)210 Blt_BackgroundToPostScript(tokenPtr, colorPtr)
211 struct PsTokenStruct *tokenPtr;
212 XColor *colorPtr;
213 {
214 /* If the color name exists in Tcl array variable, use that translation */
215 if (tokenPtr->colorVarName != NULL) {
216 CONST char *psColor;
217
218 psColor = Tcl_GetVar2(tokenPtr->interp, tokenPtr->colorVarName,
219 Tk_NameOfColor(colorPtr), 0);
220 if (psColor != NULL) {
221 Blt_AppendToPostScript(tokenPtr, " ", psColor, "\n", (char *)NULL);
222 return;
223 }
224 }
225 XColorToPostScript(tokenPtr, colorPtr);
226 Blt_AppendToPostScript(tokenPtr, " SetBgColor\n", (char *)NULL);
227 }
228
229 void
Blt_ForegroundToPostScript(tokenPtr,colorPtr)230 Blt_ForegroundToPostScript(tokenPtr, colorPtr)
231 struct PsTokenStruct *tokenPtr;
232 XColor *colorPtr;
233 {
234 /* If the color name exists in Tcl array variable, use that translation */
235 if (tokenPtr->colorVarName != NULL) {
236 CONST char *psColor;
237
238 psColor = Tcl_GetVar2(tokenPtr->interp, tokenPtr->colorVarName,
239 Tk_NameOfColor(colorPtr), 0);
240 if (psColor != NULL) {
241 Blt_AppendToPostScript(tokenPtr, " ", psColor, "\n", (char *)NULL);
242 return;
243 }
244 }
245 XColorToPostScript(tokenPtr, colorPtr);
246 Blt_AppendToPostScript(tokenPtr, " SetFgColor\n", (char *)NULL);
247 }
248
249 /*
250 *----------------------------------------------------------------------
251 *
252 * ReverseBits --
253 *
254 * Convert a byte from a X image into PostScript image order.
255 * This requires not only the nybbles to be reversed but also
256 * their bit values.
257 *
258 * Results:
259 * The converted byte is returned.
260 *
261 *----------------------------------------------------------------------
262 */
263 INLINE static unsigned char
ReverseBits(byte)264 ReverseBits(byte)
265 register unsigned char byte;
266 {
267 byte = ((byte >> 1) & 0x55) | ((byte << 1) & 0xaa);
268 byte = ((byte >> 2) & 0x33) | ((byte << 2) & 0xcc);
269 byte = ((byte >> 4) & 0x0f) | ((byte << 4) & 0xf0);
270 return byte;
271 }
272
273 /*
274 *----------------------------------------------------------------------
275 *
276 * ByteToHex --
277 *
278 * Convert a byte to its ASCII hexidecimal equivalent.
279 *
280 * Results:
281 * The converted 2 ASCII character string is returned.
282 *
283 *----------------------------------------------------------------------
284 */
285 INLINE static void
ByteToHex(byte,string)286 ByteToHex(byte, string)
287 register unsigned char byte;
288 char *string;
289 {
290 static char hexDigits[] = "0123456789ABCDEF";
291
292 string[0] = hexDigits[byte >> 4];
293 string[1] = hexDigits[byte & 0x0F];
294 }
295
296 #ifdef WIN32
297 /*
298 * -------------------------------------------------------------------------
299 *
300 * Blt_BitmapDataToPostScript --
301 *
302 * Output a PostScript image string of the given bitmap image.
303 * It is assumed the image is one bit deep and a zero value
304 * indicates an off-pixel. To convert to PostScript, the bits
305 * need to be reversed from the X11 image order.
306 *
307 * Results:
308 * None.
309 *
310 * Side Effects:
311 * The PostScript image string is appended.
312 *
313 * -------------------------------------------------------------------------
314 */
315 void
Blt_BitmapDataToPostScript(struct PsTokenStruct * tokenPtr,Display * display,Pixmap bitmap,int width,int height)316 Blt_BitmapDataToPostScript(
317 struct PsTokenStruct *tokenPtr,
318 Display *display,
319 Pixmap bitmap,
320 int width, int height)
321 {
322 register unsigned char byte;
323 register int x, y, bitPos;
324 unsigned long pixel;
325 int byteCount;
326 char string[10];
327 unsigned char *srcBits, *srcPtr;
328 int bytesPerRow;
329
330 srcBits = Blt_GetBitmapData(display, bitmap, width, height, &bytesPerRow);
331 if (srcBits == NULL) {
332 OutputDebugString("Can't get bitmap data");
333 return;
334 }
335 Blt_AppendToPostScript(tokenPtr, "\t<", (char *)NULL);
336 byteCount = bitPos = 0; /* Suppress compiler warning */
337 for (y = height - 1; y >= 0; y--) {
338 srcPtr = srcBits + (bytesPerRow * y);
339 byte = 0;
340 for (x = 0; x < width; x++) {
341 bitPos = x % 8;
342 pixel = (*srcPtr & (0x80 >> bitPos));
343 if (pixel) {
344 byte |= (unsigned char)(1 << bitPos);
345 }
346 if (bitPos == 7) {
347 byte = ReverseBits(byte);
348 ByteToHex(byte, string);
349 string[2] = '\0';
350 byteCount++;
351 srcPtr++;
352 byte = 0;
353 if (byteCount >= 30) {
354 string[2] = '\n';
355 string[3] = '\t';
356 string[4] = '\0';
357 byteCount = 0;
358 }
359 Blt_AppendToPostScript(tokenPtr, string, (char *)NULL);
360 }
361 } /* x */
362 if (bitPos != 7) {
363 byte = ReverseBits(byte);
364 ByteToHex(byte, string);
365 string[2] = '\0';
366 Blt_AppendToPostScript(tokenPtr, string, (char *)NULL);
367 byteCount++;
368 }
369 } /* y */
370 Blt_Free(srcBits);
371 Blt_AppendToPostScript(tokenPtr, ">\n", (char *)NULL);
372 }
373
374 #else
375
376 /*
377 * -------------------------------------------------------------------------
378 *
379 * Blt_BitmapDataToPostScript --
380 *
381 * Output a PostScript image string of the given bitmap image.
382 * It is assumed the image is one bit deep and a zero value
383 * indicates an off-pixel. To convert to PostScript, the bits
384 * need to be reversed from the X11 image order.
385 *
386 * Results:
387 * None.
388 *
389 * Side Effects:
390 * The PostScript image string is appended to interp->result.
391 *
392 * -------------------------------------------------------------------------
393 */
394 void
Blt_BitmapDataToPostScript(tokenPtr,display,bitmap,width,height)395 Blt_BitmapDataToPostScript(tokenPtr, display, bitmap, width, height)
396 struct PsTokenStruct *tokenPtr;
397 Display *display;
398 Pixmap bitmap;
399 int width, height;
400 {
401 register unsigned char byte = 0;
402 register int x, y, bitPos;
403 unsigned long pixel;
404 XImage *imagePtr;
405 int byteCount;
406 char string[10];
407
408 imagePtr = XGetImage(display, bitmap, 0, 0, width, height, 1, ZPixmap);
409 Blt_AppendToPostScript(tokenPtr, "\t<", (char *)NULL);
410 byteCount = bitPos = 0; /* Suppress compiler warning */
411 for (y = 0; y < height; y++) {
412 byte = 0;
413 for (x = 0; x < width; x++) {
414 pixel = XGetPixel(imagePtr, x, y);
415 bitPos = x % 8;
416 byte |= (unsigned char)(pixel << bitPos);
417 if (bitPos == 7) {
418 byte = ReverseBits(byte);
419 ByteToHex(byte, string);
420 string[2] = '\0';
421 byteCount++;
422 byte = 0;
423 if (byteCount >= 30) {
424 string[2] = '\n';
425 string[3] = '\t';
426 string[4] = '\0';
427 byteCount = 0;
428 }
429 Blt_AppendToPostScript(tokenPtr, string, (char *)NULL);
430 }
431 } /* x */
432 if (bitPos != 7) {
433 byte = ReverseBits(byte);
434 ByteToHex(byte, string);
435 string[2] = '\0';
436 Blt_AppendToPostScript(tokenPtr, string, (char *)NULL);
437 byteCount++;
438 }
439 } /* y */
440 Blt_AppendToPostScript(tokenPtr, ">\n", (char *)NULL);
441 XDestroyImage(imagePtr);
442 }
443
444 #endif /* WIN32 */
445
446 /*
447 *----------------------------------------------------------------------
448 *
449 * Blt_ColorImageToPsData --
450 *
451 * Converts a color image to PostScript RGB (3 components)
452 * or Greyscale (1 component) output. With 3 components, we
453 * assume the "colorimage" operator is available.
454 *
455 * Note that the image converted from bottom to top, to conform
456 * to the PostScript coordinate system.
457 *
458 * Results:
459 * The PostScript data comprising the color image is written
460 * into the dynamic string.
461 *
462 *----------------------------------------------------------------------
463 */
464 int
Blt_ColorImageToPsData(image,nComponents,resultPtr,prefix)465 Blt_ColorImageToPsData(image, nComponents, resultPtr, prefix)
466 Blt_ColorImage image;
467 int nComponents;
468 Tcl_DString *resultPtr;
469 char *prefix;
470 {
471 char string[10];
472 register int count;
473 register int x, y;
474 register Pix32 *pixelPtr;
475 unsigned char byte;
476 int width, height;
477 int offset;
478 int nLines;
479 width = Blt_ColorImageWidth(image);
480 height = Blt_ColorImageHeight(image);
481
482 nLines = 0;
483 count = 0;
484 offset = (height - 1) * width;
485 if (nComponents == 3) {
486 for (y = (height - 1); y >= 0; y--) {
487 pixelPtr = Blt_ColorImageBits(image) + offset;
488 for (x = 0; x < width; x++, pixelPtr++) {
489 if (count == 0) {
490 Tcl_DStringAppend(resultPtr, prefix, -1);
491 Tcl_DStringAppend(resultPtr, " ", -1);
492 }
493 count += 6;
494 ByteToHex(pixelPtr->Red, string);
495 ByteToHex(pixelPtr->Green, string + 2);
496 ByteToHex(pixelPtr->Blue, string + 4);
497 string[6] = '\0';
498 if (count >= 60) {
499 string[6] = '\n';
500 string[7] = '\0';
501 count = 0;
502 nLines++;
503 }
504 Tcl_DStringAppend(resultPtr, string, -1);
505 }
506 offset -= width;
507 }
508 } else if (nComponents == 1) {
509 for (y = (height - 1); y >= 0; y--) {
510 pixelPtr = Blt_ColorImageBits(image) + offset;
511 for (x = 0; x < width; x++, pixelPtr++) {
512 if (count == 0) {
513 Tcl_DStringAppend(resultPtr, prefix, -1);
514 Tcl_DStringAppend(resultPtr, " ", -1);
515 }
516 count += 2;
517 byte = ~(pixelPtr->Red);
518 ByteToHex(byte, string);
519 string[2] = '\0';
520 if (count >= 60) {
521 string[2] = '\n';
522 string[3] = '\0';
523 count = 0;
524 nLines++;
525 }
526 Tcl_DStringAppend(resultPtr, string, -1);
527 }
528 offset -= width;
529 }
530 }
531 if (count != 0) {
532 Tcl_DStringAppend(resultPtr, "\n", -1);
533 nLines++;
534 }
535 return nLines;
536 }
537
538 /*
539 *----------------------------------------------------------------------
540 *
541 * NameOfAtom --
542 *
543 * Wrapper routine for Tk_GetAtomName. Returns NULL instead of
544 * "?bad atom?" if the atom can't be found.
545 *
546 * Results:
547 * The name of the atom is returned if found. Otherwise NULL.
548 *
549 *----------------------------------------------------------------------
550 */
551 static char *
NameOfAtom(tkwin,atom)552 NameOfAtom(tkwin, atom)
553 Tk_Window tkwin;
554 Atom atom;
555 {
556 char *result;
557
558 result = Tk_GetAtomName(tkwin, atom);
559 if ((result[0] == '?') && (strcmp(result, "?bad atom?") == 0)) {
560 return NULL;
561 }
562 return result;
563 }
564
565
566 typedef struct {
567 char *alias;
568 char *fontName;
569 } FontMap;
570
571 static FontMap psFontMap[] =
572 {
573 {"Arial", "Helvetica",},
574 {"AvantGarde", "AvantGarde",},
575 {"Courier New", "Courier",},
576 {"Courier", "Courier",},
577 {"Geneva", "Helvetica",},
578 {"Helvetica", "Helvetica",},
579 {"Monaco", "Courier",},
580 {"New Century Schoolbook", "NewCenturySchlbk",},
581 {"New York", "Times",},
582 {"Palatino", "Palatino",},
583 {"Symbol", "Symbol",},
584 {"Times New Roman", "Times",},
585 {"Times Roman", "Times",},
586 {"Times", "Times",},
587 {"Utopia", "Utopia",},
588 {"ZapfChancery", "ZapfChancery",},
589 {"ZapfDingbats", "ZapfDingbats",},
590 };
591
592 static int nFontNames = (sizeof(psFontMap) / sizeof(FontMap));
593
594 #ifndef WIN32
595 /*
596 * -----------------------------------------------------------------
597 *
598 * XFontStructToPostScript --
599 *
600 * Map X11 font to a PostScript font. Currently, only fonts whose
601 * FOUNDRY property are "Adobe" are converted. Simply gets the
602 * XA_FULL_NAME and XA_FAMILY properties and pieces together a
603 * PostScript fontname.
604 *
605 * Results:
606 * Returns the mapped PostScript font name if one is possible.
607 * Otherwise returns NULL.
608 *
609 * -----------------------------------------------------------------
610 */
611 static char *
XFontStructToPostScript(tkwin,fontPtr)612 XFontStructToPostScript(tkwin, fontPtr)
613 Tk_Window tkwin; /* Window to query for atoms */
614 XFontStruct *fontPtr; /* Font structure to map to name */
615 {
616 Atom atom;
617 char *fullName, *family, *foundry;
618 register char *src, *dest;
619 int familyLen;
620 char *start;
621 static char string[200]; /* What size? */
622
623 if (XGetFontProperty(fontPtr, XA_FULL_NAME, &atom) == False) {
624 return NULL;
625 }
626 fullName = NameOfAtom(tkwin, atom);
627 if (fullName == NULL) {
628 return NULL;
629 }
630 family = foundry = NULL;
631 if (XGetFontProperty(fontPtr, Tk_InternAtom(tkwin, "FOUNDRY"), &atom)) {
632 foundry = NameOfAtom(tkwin, atom);
633 }
634 if (XGetFontProperty(fontPtr, XA_FAMILY_NAME, &atom)) {
635 family = NameOfAtom(tkwin, atom);
636 }
637 /*
638 * Try to map the font only if the foundry is Adobe
639 */
640 if ((foundry == NULL) || (family == NULL)) {
641 return NULL;
642 }
643 src = NULL;
644 familyLen = strlen(family);
645 if (strncasecmp(fullName, family, familyLen) == 0) {
646 src = fullName + familyLen;
647 }
648 if (strcmp(foundry, "Adobe") != 0) {
649 register int i;
650
651 if (strncasecmp(family, "itc ", 4) == 0) {
652 family += 4; /* Throw out the "itc" prefix */
653 }
654 for (i = 0; i < nFontNames; i++) {
655 if (strcasecmp(family, psFontMap[i].alias) == 0) {
656 family = psFontMap[i].fontName;
657 }
658 }
659 if (i == nFontNames) {
660 family = "Helvetica"; /* Default to a known font */
661 }
662 }
663 /*
664 * PostScript font name is in the form <family>-<type face>
665 */
666 sprintf(string, "%s-", family);
667 dest = start = string + strlen(string);
668
669 /*
670 * Append the type face (part of the full name trailing the family name)
671 * to the the PostScript font name, removing any spaces or dashes
672 *
673 * ex. " Bold Italic" ==> "BoldItalic"
674 */
675 if (src != NULL) {
676 while (*src != '\0') {
677 if ((*src != ' ') && (*src != '-')) {
678 *dest++ = *src;
679 }
680 src++;
681 }
682 }
683 if (dest == start) {
684 --dest; /* Remove '-' to leave just the family name */
685 }
686 *dest = '\0'; /* Make a valid string */
687 return string;
688 }
689
690 #endif /* !WIN32 */
691
692
693 /*
694 * -------------------------------------------------------------------
695 * Routines to convert X drawing functions to PostScript commands.
696 * -------------------------------------------------------------------
697 */
698 void
Blt_ClearBackgroundToPostScript(tokenPtr)699 Blt_ClearBackgroundToPostScript(tokenPtr)
700 struct PsTokenStruct *tokenPtr;
701 {
702 Blt_AppendToPostScript(tokenPtr,
703 " 1.0 1.0 1.0 SetBgColor\n",
704 (char *)NULL);
705 }
706
707 void
Blt_CapStyleToPostScript(tokenPtr,capStyle)708 Blt_CapStyleToPostScript(tokenPtr, capStyle)
709 struct PsTokenStruct *tokenPtr;
710 int capStyle;
711 {
712 /*
713 * X11:not last = 0, butt = 1, round = 2, projecting = 3
714 * PS: butt = 0, round = 1, projecting = 2
715 */
716 if (capStyle > 0) {
717 capStyle--;
718 }
719 Blt_FormatToPostScript(tokenPtr,
720 "%d setlinecap\n",
721 capStyle);
722 }
723
724 void
Blt_JoinStyleToPostScript(tokenPtr,joinStyle)725 Blt_JoinStyleToPostScript(tokenPtr, joinStyle)
726 struct PsTokenStruct *tokenPtr;
727 int joinStyle;
728 {
729 /*
730 * miter = 0, round = 1, bevel = 2
731 */
732 Blt_FormatToPostScript(tokenPtr,
733 "%d setlinejoin\n",
734 joinStyle);
735 }
736
737 void
Blt_LineWidthToPostScript(tokenPtr,lineWidth)738 Blt_LineWidthToPostScript(tokenPtr, lineWidth)
739 struct PsTokenStruct *tokenPtr;
740 int lineWidth;
741 {
742 if (lineWidth < 1) {
743 lineWidth = 1;
744 }
745 Blt_FormatToPostScript(tokenPtr,
746 "%d setlinewidth\n",
747 lineWidth);
748 }
749
750 void
Blt_LineDashesToPostScript(tokenPtr,dashesPtr)751 Blt_LineDashesToPostScript(tokenPtr, dashesPtr)
752 struct PsTokenStruct *tokenPtr;
753 Blt_Dashes *dashesPtr;
754 {
755
756 Blt_AppendToPostScript(tokenPtr, "[ ", (char *)NULL);
757 if (dashesPtr != NULL) {
758 unsigned char *p;
759
760 for (p = dashesPtr->values; *p != 0; p++) {
761 Blt_FormatToPostScript(tokenPtr, " %d", *p);
762 }
763 }
764 Blt_AppendToPostScript(tokenPtr, "] 0 setdash\n", (char *)NULL);
765 }
766
767 void
Blt_LineAttributesToPostScript(tokenPtr,colorPtr,lineWidth,dashesPtr,capStyle,joinStyle)768 Blt_LineAttributesToPostScript(tokenPtr, colorPtr, lineWidth, dashesPtr,
769 capStyle, joinStyle)
770 struct PsTokenStruct *tokenPtr;
771 XColor *colorPtr;
772 int lineWidth;
773 Blt_Dashes *dashesPtr;
774 int capStyle, joinStyle;
775 {
776 Blt_JoinStyleToPostScript(tokenPtr, joinStyle);
777 Blt_CapStyleToPostScript(tokenPtr, capStyle);
778 Blt_ForegroundToPostScript(tokenPtr, colorPtr);
779 Blt_LineWidthToPostScript(tokenPtr, lineWidth);
780 Blt_LineDashesToPostScript(tokenPtr, dashesPtr);
781 Blt_AppendToPostScript(tokenPtr, "/DashesProc {} def\n", (char *)NULL);
782 }
783
784 void
Blt_RectangleToPostScript(tokenPtr,x,y,width,height)785 Blt_RectangleToPostScript(tokenPtr, x, y, width, height)
786 struct PsTokenStruct *tokenPtr;
787 double x, y;
788 int width, height;
789 {
790 Blt_FormatToPostScript(tokenPtr,
791 "%g %g %d %d Box fill\n\n",
792 x, y, width, height);
793 }
794
795 void
Blt_RegionToPostScript(tokenPtr,x,y,width,height)796 Blt_RegionToPostScript(tokenPtr, x, y, width, height)
797 struct PsTokenStruct *tokenPtr;
798 double x, y;
799 int width, height;
800 {
801 Blt_FormatToPostScript(tokenPtr, "%g %g %d %d Box\n\n",
802 x, y, width, height);
803 }
804
805 void
Blt_PathToPostScript(tokenPtr,screenPts,nScreenPts)806 Blt_PathToPostScript(tokenPtr, screenPts, nScreenPts)
807 struct PsTokenStruct *tokenPtr;
808 register Point2D *screenPts;
809 int nScreenPts;
810 {
811 register Point2D *pointPtr, *endPtr;
812
813 if (nScreenPts == 0 ||!screenPts) return;
814 pointPtr = screenPts;
815 Blt_FormatToPostScript(tokenPtr, "newpath %g %g moveto\n",
816 pointPtr->x, pointPtr->y);
817 pointPtr++;
818 endPtr = screenPts + nScreenPts;
819 while (pointPtr < endPtr) {
820 Blt_FormatToPostScript(tokenPtr, "%g %g lineto\n",
821 pointPtr->x, pointPtr->y);
822 pointPtr++;
823 }
824 }
825
826 void
Blt_PolygonToPostScript(tokenPtr,screenPts,nScreenPts)827 Blt_PolygonToPostScript(tokenPtr, screenPts, nScreenPts)
828 struct PsTokenStruct *tokenPtr;
829 Point2D *screenPts;
830 int nScreenPts;
831 {
832 if (nScreenPts == 0 ||!screenPts) return;
833 Blt_PathToPostScript(tokenPtr, screenPts, nScreenPts);
834 Blt_FormatToPostScript(tokenPtr, "%g %g ", screenPts[0].x, screenPts[0].y);
835 Blt_AppendToPostScript(tokenPtr, " lineto closepath Fill\n", (char *)NULL);
836 }
837
838 void
Blt_SegmentsToPostScript(tokenPtr,segPtr,nSegments)839 Blt_SegmentsToPostScript(tokenPtr, segPtr, nSegments)
840 struct PsTokenStruct *tokenPtr;
841 register XSegment *segPtr;
842 int nSegments;
843 {
844 register int i;
845
846 for (i = 0; i < nSegments; i++, segPtr++) {
847 Blt_FormatToPostScript(tokenPtr, "%d %d moveto\n",
848 segPtr->x1, segPtr->y1);
849 Blt_FormatToPostScript(tokenPtr, " %d %d lineto\n",
850 segPtr->x2, segPtr->y2);
851 Blt_AppendToPostScript(tokenPtr, "DashesProc stroke\n", (char *)NULL);
852 }
853 }
854
855
856 void
Blt_RectanglesToPostScript(tokenPtr,rectArr,nRects)857 Blt_RectanglesToPostScript(tokenPtr, rectArr, nRects)
858 struct PsTokenStruct *tokenPtr;
859 XRectangle rectArr[];
860 int nRects;
861 {
862 register int i;
863
864 for (i = 0; i < nRects; i++) {
865 Blt_RectangleToPostScript(tokenPtr,
866 (double)rectArr[i].x, (double)rectArr[i].y,
867 (int)rectArr[i].width, (int)rectArr[i].height);
868 }
869 }
870
871 #ifndef TK_RELIEF_SOLID
872 #define TK_RELIEF_SOLID -1 /* Set the an impossible value. */
873 #endif /* TK_RELIEF_SOLID */
874
875 void
Blt_Draw3DRectangleToPostScript(tokenPtr,border,x,y,width,height,borderWidth,relief)876 Blt_Draw3DRectangleToPostScript(tokenPtr, border, x, y, width, height,
877 borderWidth, relief)
878 struct PsTokenStruct *tokenPtr;
879 Tk_3DBorder border; /* Token for border to draw. */
880 double x, y; /* Coordinates of rectangle */
881 int width, height; /* Region to be drawn. */
882 int borderWidth; /* Desired width for border, in pixels. */
883 int relief; /* Should be either TK_RELIEF_RAISED or
884 * TK_RELIEF_SUNKEN; indicates position of
885 * interior of window relative to exterior. */
886 {
887 TkBorder *borderPtr = (TkBorder *) border;
888 XColor lightColor, darkColor;
889 XColor *lightColorPtr, *darkColorPtr;
890 XColor *topColor, *bottomColor;
891 Point2D points[7];
892 int twiceWidth = (borderWidth * 2);
893
894 if ((width < twiceWidth) || (height < twiceWidth)) {
895 return;
896 }
897 if ((relief == TK_RELIEF_SOLID) ||
898 (borderPtr->lightColorPtr == NULL) || (borderPtr->darkColorPtr == NULL)) {
899 if (relief == TK_RELIEF_SOLID) {
900 darkColor.red = darkColor.blue = darkColor.green = 0x00;
901 lightColor.red = lightColor.blue = lightColor.green = 0x00;
902 relief = TK_RELIEF_SUNKEN;
903 } else {
904 Screen *screenPtr;
905
906 lightColor = *borderPtr->bgColorPtr;
907 screenPtr = Tk_Screen(tokenPtr->tkwin);
908 if (lightColor.pixel == WhitePixelOfScreen(screenPtr)) {
909 darkColor.red = darkColor.blue = darkColor.green = 0x00;
910 } else {
911 darkColor.red = darkColor.blue = darkColor.green = 0xFF;
912 }
913 }
914 lightColorPtr = &lightColor;
915 darkColorPtr = &darkColor;
916 } else {
917 lightColorPtr = borderPtr->lightColorPtr;
918 darkColorPtr = borderPtr->darkColorPtr;
919 }
920
921
922 /*
923 * Handle grooves and ridges with recursive calls.
924 */
925
926 if ((relief == TK_RELIEF_GROOVE) || (relief == TK_RELIEF_RIDGE)) {
927 int halfWidth, insideOffset;
928
929 halfWidth = borderWidth / 2;
930 insideOffset = borderWidth - halfWidth;
931 Blt_Draw3DRectangleToPostScript(tokenPtr, border, (double)x, (double)y,
932 width, height, halfWidth,
933 (relief == TK_RELIEF_GROOVE) ? TK_RELIEF_SUNKEN : TK_RELIEF_RAISED);
934 Blt_Draw3DRectangleToPostScript(tokenPtr, border,
935 (double)(x + insideOffset), (double)(y + insideOffset),
936 width - insideOffset * 2, height - insideOffset * 2, halfWidth,
937 (relief == TK_RELIEF_GROOVE) ? TK_RELIEF_RAISED : TK_RELIEF_SUNKEN);
938 return;
939 }
940 if (relief == TK_RELIEF_RAISED) {
941 topColor = lightColorPtr;
942 bottomColor = darkColorPtr;
943 } else if (relief == TK_RELIEF_SUNKEN) {
944 topColor = darkColorPtr;
945 bottomColor = lightColorPtr;
946 } else {
947 topColor = bottomColor = borderPtr->bgColorPtr;
948 }
949 Blt_BackgroundToPostScript(tokenPtr, bottomColor);
950 Blt_RectangleToPostScript(tokenPtr, x, y + height - borderWidth, width,
951 borderWidth);
952 Blt_RectangleToPostScript(tokenPtr, x + width - borderWidth, y,
953 borderWidth, height);
954 points[0].x = points[1].x = points[6].x = x;
955 points[0].y = points[6].y = y + height;
956 points[1].y = points[2].y = y;
957 points[2].x = x + width;
958 points[3].x = x + width - borderWidth;
959 points[3].y = points[4].y = y + borderWidth;
960 points[4].x = points[5].x = x + borderWidth;
961 points[5].y = y + height - borderWidth;
962 if (relief != TK_RELIEF_FLAT) {
963 Blt_BackgroundToPostScript(tokenPtr, topColor);
964 }
965 Blt_PolygonToPostScript(tokenPtr, points, 7);
966 }
967
968 void
Blt_Fill3DRectangleToPostScript(tokenPtr,border,x,y,width,height,borderWidth,relief)969 Blt_Fill3DRectangleToPostScript(tokenPtr, border, x, y, width, height,
970 borderWidth, relief)
971 struct PsTokenStruct *tokenPtr;
972 Tk_3DBorder border; /* Token for border to draw. */
973 double x, y; /* Coordinates of top-left of border area */
974 int width, height; /* Dimension of border to be drawn. */
975 int borderWidth; /* Desired width for border, in pixels. */
976 int relief; /* Should be either TK_RELIEF_RAISED or
977 * TK_RELIEF_SUNKEN; indicates position of
978 * interior of window relative to exterior. */
979 {
980 TkBorder *borderPtr = (TkBorder *) border;
981
982 /*
983 * I'm assuming that the rectangle is to be drawn as a background.
984 * Setting the pen color as foreground or background only affects
985 * the plot when the colormode option is "monochrome".
986 */
987 Blt_BackgroundToPostScript(tokenPtr, borderPtr->bgColorPtr);
988 Blt_RectangleToPostScript(tokenPtr, x, y, width, height);
989 Blt_Draw3DRectangleToPostScript(tokenPtr, border, x, y, width, height,
990 borderWidth, relief);
991 }
992
993 void
Blt_StippleToPostScript(tokenPtr,display,bitmap)994 Blt_StippleToPostScript(tokenPtr, display, bitmap)
995 struct PsTokenStruct *tokenPtr;
996 Display *display;
997 Pixmap bitmap;
998 {
999 int width, height;
1000
1001 Tk_SizeOfBitmap(display, bitmap, &width, &height);
1002 Blt_FormatToPostScript(tokenPtr,
1003 "gsave\n clip\n %d %d\n",
1004 width, height);
1005 Blt_BitmapDataToPostScript(tokenPtr, display, bitmap, width, height);
1006 Blt_AppendToPostScript(tokenPtr,
1007 " StippleFill\ngrestore\n",
1008 (char *)NULL);
1009 }
1010
1011 /*
1012 *----------------------------------------------------------------------
1013 *
1014 * Blt_ColorImageToPostScript --
1015 *
1016 * Translates a color image into 3 component RGB PostScript output.
1017 * Uses PS Language Level 2 operator "colorimage".
1018 *
1019 * Results:
1020 * The dynamic string will contain the PostScript output.
1021 *
1022 *----------------------------------------------------------------------
1023 */
1024 void
Blt_ColorImageToPostScript(tokenPtr,image,x,y)1025 Blt_ColorImageToPostScript(tokenPtr, image, x, y)
1026 struct PsTokenStruct *tokenPtr;
1027 Blt_ColorImage image;
1028 double x, y;
1029 {
1030 int width, height;
1031 int tmpSize;
1032
1033 width = Blt_ColorImageWidth(image);
1034 height = Blt_ColorImageHeight(image);
1035
1036 tmpSize = width;
1037 if (tokenPtr->colorMode == PS_MODE_COLOR) {
1038 tmpSize *= 3;
1039 }
1040 Blt_FormatToPostScript(tokenPtr, "\n/tmpStr %d string def\n", tmpSize);
1041 Blt_AppendToPostScript(tokenPtr, "gsave\n", (char *)NULL);
1042 Blt_FormatToPostScript(tokenPtr, " %g %g translate\n", x, y);
1043 Blt_FormatToPostScript(tokenPtr, " %d %d scale\n", width, height);
1044 Blt_FormatToPostScript(tokenPtr, " %d %d 8\n", width, height);
1045 Blt_FormatToPostScript(tokenPtr, " [%d 0 0 %d 0 %d] ", width, -height,
1046 height);
1047 Blt_AppendToPostScript(tokenPtr,
1048 "{\n currentfile tmpStr readhexstring pop\n } ",
1049 (char *)NULL);
1050 if (tokenPtr->colorMode != PS_MODE_COLOR) {
1051 Blt_AppendToPostScript(tokenPtr, "image\n", (char *)NULL);
1052 Blt_ColorImageToGreyscale(image);
1053 Blt_ColorImageToPsData(image, 1, &(tokenPtr->dString), " ");
1054 } else {
1055 Blt_AppendToPostScript(tokenPtr,
1056 "false 3 colorimage\n",
1057 (char *)NULL);
1058 Blt_ColorImageToPsData(image, 3, &(tokenPtr->dString), " ");
1059 }
1060 Blt_AppendToPostScript(tokenPtr,
1061 "\ngrestore\n\n",
1062 (char *)NULL);
1063 }
1064
1065 /*
1066 *----------------------------------------------------------------------
1067 *
1068 * Blt_WindowToPostScript --
1069 *
1070 * Converts a Tk window to PostScript. If the window could not
1071 * be "snapped", then a grey rectangle is drawn in its place.
1072 *
1073 * Results:
1074 * None.
1075 *
1076 *----------------------------------------------------------------------
1077 */
1078 void
Blt_WindowToPostScript(tokenPtr,tkwin,x,y)1079 Blt_WindowToPostScript(tokenPtr, tkwin, x, y)
1080 struct PsTokenStruct *tokenPtr;
1081 Tk_Window tkwin;
1082 double x, y;
1083 {
1084 Blt_ColorImage image;
1085 int width, height;
1086
1087 width = Tk_Width(tkwin);
1088 height = Tk_Height(tkwin);
1089 image = Blt_DrawableToColorImage(tkwin, Tk_WindowId(tkwin), 0, 0, width,
1090 height, GAMMA);
1091 if (image == NULL) {
1092 /* Can't grab window image so paint the window area grey */
1093 Blt_AppendToPostScript(tokenPtr, "% Can't grab window \"",
1094 Tk_PathName(tkwin), "\"\n", (char *)NULL);
1095 Blt_AppendToPostScript(tokenPtr, "0.5 0.5 0.5 SetBgColor\n",
1096 (char *)NULL);
1097 Blt_RectangleToPostScript(tokenPtr, x, y, width, height);
1098 return;
1099 }
1100 Blt_ColorImageToPostScript(tokenPtr, image, x, y);
1101 Blt_FreeColorImage(image);
1102 }
1103
1104 /*
1105 * -------------------------------------------------------------------------
1106 *
1107 * Blt_PhotoToPostScript --
1108 *
1109 * Output a PostScript image string of the given photo image.
1110 * The photo is first converted into a color image and then
1111 * translated into PostScript.
1112 *
1113 * Results:
1114 * None.
1115 *
1116 * Side Effects:
1117 * The PostScript output representing the photo is appended to
1118 * the tokenPtr's dynamic string.
1119 *
1120 * -------------------------------------------------------------------------
1121 */
1122 void
Blt_PhotoToPostScript(tokenPtr,photo,x,y)1123 Blt_PhotoToPostScript(tokenPtr, photo, x, y)
1124 struct PsTokenStruct *tokenPtr;
1125 Tk_PhotoHandle photo;
1126 double x, y; /* Origin of photo image */
1127 {
1128 Blt_ColorImage image;
1129
1130 image = Blt_PhotoToColorImage(photo);
1131 Blt_ColorImageToPostScript(tokenPtr, image, x, y);
1132 Blt_FreeColorImage(image);
1133 }
1134
1135 /*
1136 * -----------------------------------------------------------------
1137 *
1138 * Blt_FontToPostScript --
1139 *
1140 * Map the Tk font to a PostScript font and point size.
1141 *
1142 * If a Tcl array variable was specified, each element should be
1143 * indexed by the X11 font name and contain a list of 1-2
1144 * elements; the PostScript font name and the desired point size.
1145 * The point size may be omitted and the X font point size will
1146 * be used.
1147 *
1148 * Otherwise, if the foundry is "Adobe", we try to do a plausible
1149 * mapping looking at the full name of the font and building a
1150 * string in the form of "Family-TypeFace".
1151 *
1152 * Returns:
1153 * None.
1154 *
1155 * Side Effects:
1156 * PostScript commands are output to change the type and the
1157 * point size of the current font.
1158 *
1159 * -----------------------------------------------------------------
1160 */
1161
1162 void
Blt_FontToPostScript(tokenPtr,font)1163 Blt_FontToPostScript(tokenPtr, font)
1164 struct PsTokenStruct *tokenPtr;
1165 Tk_Font font; /* Tk font to query about */
1166 {
1167 XFontStruct *fontPtr = (XFontStruct *)font;
1168 Tcl_Interp *interp = tokenPtr->interp;
1169 char *fontName;
1170 double pointSize;
1171 #if (TK_MAJOR_VERSION > 4)
1172 Tk_Uid family;
1173 register int i;
1174 #endif /* TK_MAJOR_VERSION > 4 */
1175
1176 fontName = Tk_NameOfFont(font);
1177 pointSize = 12.0;
1178 /*
1179 * Use the font variable information if it exists.
1180 */
1181 if (tokenPtr->fontVarName != NULL) {
1182 char *fontInfo;
1183
1184 fontInfo = (char *)Tcl_GetVar2(interp, tokenPtr->fontVarName, fontName,
1185 0);
1186 if (fontInfo != NULL) {
1187 int nProps;
1188 char **propArr = NULL;
1189
1190 if (Tcl_SplitList(interp, fontInfo, &nProps, &propArr) == TCL_OK) {
1191 int newSize;
1192
1193 fontName = propArr[0];
1194 if ((nProps == 2) &&
1195 (Tcl_GetInt(interp, propArr[1], &newSize) == TCL_OK)) {
1196 pointSize = (double)newSize;
1197 }
1198 }
1199 Blt_FormatToPostScript(tokenPtr,
1200 "%g /%s SetFont\n",
1201 pointSize, fontName);
1202 if (propArr != (char **)NULL) {
1203 Blt_Free(propArr);
1204 }
1205 return;
1206 }
1207 }
1208 #if (TK_MAJOR_VERSION > 4)
1209
1210 /*
1211 * Otherwise do a quick test to see if it's a PostScript font.
1212 * Tk_PostScriptFontName will silently generate a bogus PostScript
1213 * font description, so we have to check to see if this is really a
1214 * PostScript font.
1215 */
1216 family = ((TkFont *) fontPtr)->fa.family;
1217 for (i = 0; i < nFontNames; i++) {
1218 if (strncasecmp(psFontMap[i].alias, family, strlen(psFontMap[i].alias))
1219 == 0) {
1220 Tcl_DString dString;
1221
1222 Tcl_DStringInit(&dString);
1223 pointSize = (double)Tk_PostscriptFontName(font, &dString);
1224 fontName = Tcl_DStringValue(&dString);
1225 Blt_FormatToPostScript(tokenPtr, "%g /%s SetFont\n", pointSize,
1226 fontName);
1227 Tcl_DStringFree(&dString);
1228 return;
1229 }
1230 }
1231
1232 #endif /* TK_MAJOR_VERSION > 4 */
1233
1234 /*
1235 * Can't find it. Try to use the current point size.
1236 */
1237 fontName = NULL;
1238 pointSize = 12.0;
1239
1240 #ifndef WIN32
1241 #if (TK_MAJOR_VERSION > 4)
1242 /* Can you believe what I have to go through to get an XFontStruct? */
1243 fontPtr = XLoadQueryFont(Tk_Display(tokenPtr->tkwin), Tk_NameOfFont(font));
1244 #endif
1245 if (fontPtr != NULL) {
1246 unsigned long fontProp;
1247
1248 if (XGetFontProperty(fontPtr, XA_POINT_SIZE, &fontProp) != False) {
1249 pointSize = (double)fontProp / 10.0;
1250 }
1251 fontName = XFontStructToPostScript(tokenPtr->tkwin, fontPtr);
1252 #if (TK_MAJOR_VERSION > 4)
1253 XFreeFont(Tk_Display(tokenPtr->tkwin), fontPtr);
1254 #endif /* TK_MAJOR_VERSION > 4 */
1255 }
1256 #endif /* !WIN32 */
1257 if ((fontName == NULL) || (fontName[0] == '\0')) {
1258 fontName = "Helvetica-Bold"; /* Defaulting to a known PS font */
1259 }
1260 Blt_FormatToPostScript(tokenPtr, "%g /%s SetFont\n", pointSize, fontName);
1261 }
1262
1263 static void
TextLayoutToPostScript(tokenPtr,x,y,textPtr)1264 TextLayoutToPostScript(tokenPtr, x, y, textPtr)
1265 struct PsTokenStruct *tokenPtr;
1266 int x, y;
1267 TextLayout *textPtr;
1268 {
1269 char *src, *dst, *end;
1270 int count; /* Counts the # of bytes written to
1271 * the intermediate scratch buffer. */
1272 TextFragment *fragPtr;
1273 int i;
1274 unsigned char c;
1275 #if HAVE_UTF
1276 Tcl_UniChar ch;
1277 #endif
1278 int limit;
1279
1280 limit = PSTOKEN_BUFSIZ - 4; /* High water mark for the scratch
1281 * buffer. */
1282 fragPtr = textPtr->fragArr;
1283 for (i = 0; i < textPtr->nFrags; i++, fragPtr++) {
1284 if (fragPtr->count < 1) {
1285 continue;
1286 }
1287 Blt_AppendToPostScript(tokenPtr, "(", (char *)NULL);
1288 count = 0;
1289 dst = tokenPtr->scratchArr;
1290 src = fragPtr->text;
1291 end = fragPtr->text + fragPtr->count;
1292 while (src < end) {
1293 if (count > limit) {
1294 /* Don't let the scatch buffer overflow */
1295 dst = tokenPtr->scratchArr;
1296 dst[count] = '\0';
1297 Blt_AppendToPostScript(tokenPtr, dst, (char *)NULL);
1298 count = 0;
1299 }
1300 #if HAVE_UTF
1301 /*
1302 * INTL: For now we just treat the characters as binary
1303 * data and display the lower byte. Eventually this should
1304 * be revised to handle international postscript fonts.
1305 */
1306 src += Tcl_UtfToUniChar(src, &ch);
1307 c = (unsigned char)(ch & 0xff);
1308 #else
1309 c = *src++;
1310 #endif
1311
1312 if ((c == '\\') || (c == '(') || (c == ')')) {
1313 /*
1314 * If special PostScript characters characters "\", "(",
1315 * and ")" are contained in the text string, prepend
1316 * backslashes to them.
1317 */
1318 *dst++ = '\\';
1319 *dst++ = c;
1320 count += 2;
1321 } else if ((c < ' ') || (c > '~')) {
1322 /*
1323 * Present non-printable characters in their octal
1324 * representation.
1325 */
1326 sprintf(dst, "\\%03o", c);
1327 dst += 4;
1328 count += 4;
1329 } else {
1330 *dst++ = c;
1331 count++;
1332 }
1333 }
1334 tokenPtr->scratchArr[count] = '\0';
1335 Blt_AppendToPostScript(tokenPtr, tokenPtr->scratchArr, (char *)NULL);
1336 Blt_FormatToPostScript(tokenPtr, ") %d %d %d DrawAdjText\n",
1337 fragPtr->width, x + fragPtr->x, y + fragPtr->y);
1338 }
1339 }
1340
1341 /*
1342 * -----------------------------------------------------------------
1343 *
1344 * Blt_TextToPostScript --
1345 *
1346 * Output PostScript commands to print a text string. The string
1347 * may be rotated at any arbitrary angle, and placed according
1348 * the anchor type given. The anchor indicates how to interpret
1349 * the window coordinates as an anchor for the text bounding box.
1350 *
1351 * Results:
1352 * None.
1353 *
1354 * Side Effects:
1355 * Text string is drawn using the given font and GC on the graph
1356 * window at the given coordinates, anchor, and rotation
1357 *
1358 * -----------------------------------------------------------------
1359 */
1360 void
Blt_TextToPostScript(tokenPtr,string,tsPtr,x,y)1361 Blt_TextToPostScript(tokenPtr, string, tsPtr, x, y)
1362 struct PsTokenStruct *tokenPtr;
1363 char *string; /* String to convert to PostScript */
1364 TextStyle *tsPtr; /* Text attribute information */
1365 double x, y; /* Window coordinates where to print text */
1366 {
1367 double theta;
1368 double rotWidth, rotHeight;
1369 TextLayout *textPtr;
1370 Point2D anchorPos;
1371
1372 if ((string == NULL) || (*string == '\0')) { /* Empty string, do nothing */
1373 return;
1374 }
1375 theta = FMOD(tsPtr->theta, (double)360.0);
1376 textPtr = Blt_GetTextLayout(string, tsPtr);
1377 Blt_GetBoundingBox(textPtr->width, textPtr->height, theta, &rotWidth,
1378 &rotHeight, (Point2D *)NULL);
1379 /*
1380 * Find the center of the bounding box
1381 */
1382 anchorPos.x = x, anchorPos.y = y;
1383 anchorPos = Blt_TranslatePoint(&anchorPos, ROUND(rotWidth),
1384 ROUND(rotHeight), tsPtr->anchor);
1385 anchorPos.x += (rotWidth * 0.5);
1386 anchorPos.y += (rotHeight * 0.5);
1387
1388 /* Initialize text (sets translation and rotation) */
1389 Blt_FormatToPostScript(tokenPtr, "%d %d %g %g %g BeginText\n",
1390 textPtr->width, textPtr->height, tsPtr->theta, anchorPos.x,
1391 anchorPos.y);
1392
1393 Blt_FontToPostScript(tokenPtr, tsPtr->font);
1394
1395 /* All coordinates are now relative to what was set by BeginText */
1396 if ((tsPtr->shadow.offset > 0) && (tsPtr->shadow.color != NULL)) {
1397 Blt_ForegroundToPostScript(tokenPtr, tsPtr->shadow.color);
1398 TextLayoutToPostScript(tokenPtr, tsPtr->shadow.offset,
1399 tsPtr->shadow.offset, textPtr);
1400 }
1401 Blt_ForegroundToPostScript(tokenPtr, (tsPtr->state & STATE_ACTIVE)
1402 ? tsPtr->activeColor : tsPtr->color);
1403 TextLayoutToPostScript(tokenPtr, 0, 0, textPtr);
1404 Blt_Free(textPtr);
1405 Blt_AppendToPostScript(tokenPtr, "EndText\n", (char *)NULL);
1406 }
1407
1408 /*
1409 * -----------------------------------------------------------------
1410 *
1411 * Blt_LineToPostScript --
1412 *
1413 * Outputs PostScript commands to print a multi-segmented line.
1414 * It assumes a procedure DashesProc was previously defined.
1415 *
1416 * Results:
1417 * None.
1418 *
1419 * Side Effects:
1420 * Segmented line is printed.
1421 *
1422 * -----------------------------------------------------------------
1423 */
1424 void
Blt_LineToPostScript(tokenPtr,pointPtr,nPoints)1425 Blt_LineToPostScript(tokenPtr, pointPtr, nPoints)
1426 struct PsTokenStruct *tokenPtr;
1427 register XPoint *pointPtr;
1428 int nPoints;
1429 {
1430 register int i;
1431
1432 if (nPoints <= 0) {
1433 return;
1434 }
1435 Blt_FormatToPostScript(tokenPtr, " newpath %d %d moveto\n",
1436 pointPtr->x, pointPtr->y);
1437 pointPtr++;
1438 for (i = 1; i < (nPoints - 1); i++, pointPtr++) {
1439 Blt_FormatToPostScript(tokenPtr, " %d %d lineto\n",
1440 pointPtr->x, pointPtr->y);
1441 if ((i % PS_MAXPATH) == 0) {
1442 Blt_FormatToPostScript(tokenPtr,
1443 "DashesProc stroke\n newpath %d %d moveto\n",
1444 pointPtr->x, pointPtr->y);
1445 }
1446 }
1447 Blt_FormatToPostScript(tokenPtr, " %d %d lineto\n",
1448 pointPtr->x, pointPtr->y);
1449 Blt_AppendToPostScript(tokenPtr, "DashesProc stroke\n", (char *)NULL);
1450 }
1451
1452 void
Blt_BitmapToPostScript(tokenPtr,display,bitmap,scaleX,scaleY)1453 Blt_BitmapToPostScript(tokenPtr, display, bitmap, scaleX, scaleY)
1454 struct PsTokenStruct *tokenPtr;
1455 Display *display;
1456 Pixmap bitmap; /* Bitmap to be converted to PostScript */
1457 double scaleX, scaleY;
1458 {
1459 int width, height;
1460 double scaledWidth, scaledHeight;
1461
1462 Tk_SizeOfBitmap(display, bitmap, &width, &height);
1463 scaledWidth = (double)width * scaleX;
1464 scaledHeight = (double)height * scaleY;
1465 Blt_AppendToPostScript(tokenPtr, " gsave\n", (char *)NULL);
1466 Blt_FormatToPostScript(tokenPtr, " %g %g translate\n",
1467 scaledWidth * -0.5, scaledHeight * 0.5);
1468 Blt_FormatToPostScript(tokenPtr, " %g %g scale\n",
1469 scaledWidth, -scaledHeight);
1470 Blt_FormatToPostScript(tokenPtr, " %d %d true [%d 0 0 %d 0 %d] {",
1471 width, height, width, -height, height);
1472 Blt_BitmapDataToPostScript(tokenPtr, display, bitmap, width, height);
1473 Blt_AppendToPostScript(tokenPtr, " } imagemask\n grestore\n",
1474 (char *)NULL);
1475 }
1476
1477 void
Blt_2DSegmentsToPostScript(psToken,segPtr,nSegments)1478 Blt_2DSegmentsToPostScript(psToken, segPtr, nSegments)
1479 PsToken psToken;
1480 register Segment2D *segPtr;
1481 int nSegments;
1482 {
1483 register Segment2D *endPtr;
1484
1485 for (endPtr = segPtr + nSegments; segPtr < endPtr; segPtr++) {
1486 Blt_FormatToPostScript(psToken, "%g %g moveto\n",
1487 segPtr->p.x, segPtr->p.y);
1488 Blt_FormatToPostScript(psToken, " %g %g lineto\n",
1489 segPtr->q.x, segPtr->q.y);
1490 Blt_AppendToPostScript(psToken, "DashesProc stroke\n", (char *)NULL);
1491 }
1492 }
1493