]> git.ipfire.org Git - thirdparty/cups.git/blob - filter/texttops.c
Merge changes from CUPS 1.5svn-r8849.
[thirdparty/cups.git] / filter / texttops.c
1 /*
2 * "$Id: texttops.c 7720 2008-07-11 22:46:21Z mike $"
3 *
4 * Text to PostScript filter for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 2007-2008 by Apple Inc.
7 * Copyright 1993-2007 by Easy Software Products.
8 *
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
14 *
15 * This file is subject to the Apple OS-Developed Software exception.
16 *
17 * Contents:
18 *
19 * main() - Main entry for text to PostScript filter.
20 * WriteEpilogue() - Write the PostScript file epilogue.
21 * WritePage() - Write a page of text.
22 * WriteProlog() - Write the PostScript file prolog with options.
23 * write_line() - Write a row of text.
24 * write_string() - Write a string of text.
25 */
26
27 /*
28 * Include necessary headers...
29 */
30
31 #include "textcommon.h"
32 #include <cups/i18n.h>
33
34
35 /*
36 * Globals...
37 */
38
39 char *Glyphs[65536]; /* PostScript glyphs for Unicode */
40 int NumFonts; /* Number of fonts to use */
41 char *Fonts[256][4]; /* Fonts to use */
42 unsigned short Chars[65536]; /* 0xffcc (ff = font, cc = char) */
43 unsigned short Codes[65536]; /* Unicode glyph mapping to fonts */
44 int Widths[256]; /* Widths of each font */
45 int Directions[256];/* Text directions for each font */
46
47
48 /*
49 * Local functions...
50 */
51
52 static void write_line(int row, lchar_t *line);
53 static void write_string(int col, int row, int len, lchar_t *s);
54 static void write_text(const char *s);
55
56
57 /*
58 * 'main()' - Main entry for text to PostScript filter.
59 */
60
61 int /* O - Exit status */
62 main(int argc, /* I - Number of command-line arguments */
63 char *argv[]) /* I - Command-line arguments */
64 {
65 return (TextMain("texttops", argc, argv));
66 }
67
68
69 /*
70 * 'WriteEpilogue()' - Write the PostScript file epilogue.
71 */
72
73 void
74 WriteEpilogue(void)
75 {
76 puts("%%Trailer");
77 printf("%%%%Pages: %d\n", NumPages);
78 puts("%%EOF");
79
80 free(Page[0]);
81 free(Page);
82 }
83
84
85 /*
86 * 'WritePage()' - Write a page of text.
87 */
88
89 void
90 WritePage(void)
91 {
92 int line; /* Current line */
93
94
95 NumPages ++;
96 printf("%%%%Page: %d %d\n", NumPages, NumPages);
97
98 puts("gsave");
99
100 if (PrettyPrint)
101 printf("%d H\n", NumPages);
102
103 for (line = 0; line < SizeLines; line ++)
104 write_line(line, Page[line]);
105
106 puts("grestore");
107 puts("showpage");
108
109 memset(Page[0], 0, sizeof(lchar_t) * SizeColumns * SizeLines);
110 }
111
112
113 /*
114 * 'WriteProlog()' - Write the PostScript file prolog with options.
115 */
116
117 void
118 WriteProlog(const char *title, /* I - Title of job */
119 const char *user, /* I - Username */
120 const char *classification, /* I - Classification */
121 const char *label, /* I - Page label */
122 ppd_file_t *ppd) /* I - PPD file info */
123 {
124 int i, j, k; /* Looping vars */
125 char *charset; /* Character set string */
126 char filename[1024]; /* Glyph filenames */
127 FILE *fp; /* Glyph files */
128 const char *datadir; /* CUPS_DATADIR environment variable */
129 char line[1024], /* Line from file */
130 *lineptr, /* Pointer into line */
131 *valptr; /* Pointer to value in line */
132 int ch, unicode; /* Character values */
133 int start, end; /* Start and end values for range */
134 char glyph[64]; /* Glyph name */
135 time_t curtime; /* Current time */
136 struct tm *curtm; /* Current date */
137 char curdate[255]; /* Current date (text format) */
138 int num_fonts; /* Number of unique fonts */
139 char *fonts[1024]; /* Unique fonts */
140 static char *names[] = /* Font names */
141 {
142 "cupsNormal",
143 "cupsBold",
144 "cupsItalic"
145 };
146
147
148 /*
149 * Get the data directory...
150 */
151
152 if ((datadir = getenv("CUPS_DATADIR")) == NULL)
153 datadir = CUPS_DATADIR;
154
155 /*
156 * Adjust margins as necessary...
157 */
158
159 if (classification || label)
160 {
161 /*
162 * Leave room for labels...
163 */
164
165 PageBottom += 36;
166 PageTop -= 36;
167 }
168
169 /*
170 * Allocate memory for the page...
171 */
172
173 SizeColumns = (PageRight - PageLeft) / 72.0 * CharsPerInch;
174 SizeLines = (PageTop - PageBottom) / 72.0 * LinesPerInch;
175
176 if (SizeColumns <= 0 || SizeColumns > 32767 ||
177 SizeLines <= 0 || SizeLines > 32767)
178 {
179 _cupsLangPrintf(stderr, _("ERROR: Unable to print %dx%d text page\n"),
180 SizeColumns, SizeLines);
181 exit(1);
182 }
183
184 Page = calloc(sizeof(lchar_t *), SizeLines);
185 Page[0] = calloc(sizeof(lchar_t), SizeColumns * SizeLines);
186 for (i = 1; i < SizeLines; i ++)
187 Page[i] = Page[0] + i * SizeColumns;
188
189 if (PageColumns > 1)
190 {
191 ColumnGutter = CharsPerInch / 2;
192 ColumnWidth = (SizeColumns - ColumnGutter * (PageColumns - 1)) /
193 PageColumns;
194 }
195 else
196 ColumnWidth = SizeColumns;
197
198 if (ColumnWidth <= 0)
199 {
200 _cupsLangPrintf(stderr, _("ERROR: Unable to print %d text columns\n"),
201 PageColumns);
202 exit(1);
203 }
204
205 /*
206 * Output the DSC header...
207 */
208
209 curtime = time(NULL);
210 curtm = localtime(&curtime);
211 strftime(curdate, sizeof(curdate), "%c", curtm);
212
213 puts("%!PS-Adobe-3.0");
214 printf("%%%%BoundingBox: 0 0 %.0f %.0f\n", PageWidth, PageLength);
215 printf("%%cupsRotation: %d\n", (Orientation & 3) * 90);
216 puts("%%Creator: texttops/" CUPS_SVERSION);
217 printf("%%%%CreationDate: %s\n", curdate);
218 WriteTextComment("Title", title);
219 WriteTextComment("For", user);
220 puts("%%Pages: (atend)");
221
222 /*
223 * Initialize globals...
224 */
225
226 NumFonts = 0;
227 memset(Fonts, 0, sizeof(Fonts));
228 memset(Glyphs, 0, sizeof(Glyphs));
229 memset(Chars, 0, sizeof(Chars));
230 memset(Codes, 0, sizeof(Codes));
231
232 /*
233 * Load the PostScript glyph names and the corresponding character
234 * set definition...
235 */
236
237 snprintf(filename, sizeof(filename), "%s/data/psglyphs", datadir);
238
239 if ((fp = fopen(filename, "r")) != NULL)
240 {
241 while (fscanf(fp, "%x%63s", &unicode, glyph) == 2)
242 Glyphs[unicode] = strdup(glyph);
243
244 fclose(fp);
245 }
246 else
247 {
248 fprintf(stderr, _("ERROR: Unable to open \"%s\" - %s\n"), filename,
249 strerror(errno));
250 exit(1);
251 }
252
253 /*
254 * Get the output character set...
255 */
256
257 charset = getenv("CHARSET");
258 if (charset != NULL && strcmp(charset, "us-ascii") != 0)
259 {
260 snprintf(filename, sizeof(filename), "%s/charsets/%s", datadir, charset);
261
262 if ((fp = fopen(filename, "r")) == NULL)
263 {
264 /*
265 * Can't open charset file!
266 */
267
268 fprintf(stderr, _("ERROR: Unable to open %s: %s\n"), filename,
269 strerror(errno));
270 exit(1);
271 }
272
273 /*
274 * Opened charset file; now see if this is really a charset file...
275 */
276
277 if (fgets(line, sizeof(line), fp) == NULL)
278 {
279 /*
280 * Bad/empty charset file!
281 */
282
283 fclose(fp);
284 fprintf(stderr, _("ERROR: Bad charset file %s\n"), filename);
285 exit(1);
286 }
287
288 if (strncmp(line, "charset", 7) != 0)
289 {
290 /*
291 * Bad format/not a charset file!
292 */
293
294 fclose(fp);
295 fprintf(stderr, _("ERROR: Bad charset file %s\n"), filename);
296 exit(1);
297 }
298
299 /*
300 * See if this is an 8-bit or UTF-8 character set file...
301 */
302
303 line[strlen(line) - 1] = '\0'; /* Drop \n */
304 for (lineptr = line + 7; isspace(*lineptr & 255); lineptr ++); /* Skip whitespace */
305
306 if (strcmp(lineptr, "utf8") == 0)
307 {
308 /*
309 * UTF-8 (Unicode) text...
310 */
311
312 NumFonts = 0;
313
314 while (fgets(line, sizeof(line), fp) != NULL)
315 {
316 /*
317 * Skip comment and blank lines...
318 */
319
320 if (line[0] == '#' || line[0] == '\n')
321 continue;
322
323 /*
324 * Read the font descriptions that should look like:
325 *
326 * start end direction width normal [bold italic bold-italic]
327 */
328
329 lineptr = line;
330
331 start = strtol(lineptr, &lineptr, 16);
332 end = strtol(lineptr, &lineptr, 16);
333
334 while (isspace(*lineptr & 255))
335 lineptr ++;
336
337 valptr = lineptr;
338
339 while (!isspace(*lineptr & 255) && *lineptr)
340 lineptr ++;
341
342 if (!*lineptr)
343 {
344 /*
345 * Can't have a font without all required values...
346 */
347
348 fprintf(stderr, _("ERROR: Bad font description line: %s\n"), valptr);
349 fclose(fp);
350 exit(1);
351 }
352
353 *lineptr++ = '\0';
354
355 if (strcmp(valptr, "ltor") == 0)
356 Directions[NumFonts] = 1;
357 else if (strcmp(valptr, "rtol") == 0)
358 Directions[NumFonts] = -1;
359 else
360 {
361 fprintf(stderr, _("ERROR: Bad text direction %s\n"), valptr);
362 fclose(fp);
363 exit(1);
364 }
365
366 /*
367 * Got the direction, now get the width...
368 */
369
370 while (isspace(*lineptr & 255))
371 lineptr ++;
372
373 valptr = lineptr;
374
375 while (!isspace(*lineptr & 255) && *lineptr)
376 lineptr ++;
377
378 if (!*lineptr)
379 {
380 /*
381 * Can't have a font without all required values...
382 */
383
384 fprintf(stderr, _("ERROR: Bad font description line: %s\n"), valptr);
385 fclose(fp);
386 exit(1);
387 }
388
389 *lineptr++ = '\0';
390
391 if (strcmp(valptr, "single") == 0)
392 Widths[NumFonts] = 1;
393 else if (strcmp(valptr, "double") == 0)
394 Widths[NumFonts] = 2;
395 else
396 {
397 fprintf(stderr, _("ERROR: Bad text width %s\n"), valptr);
398 fclose(fp);
399 exit(1);
400 }
401
402 /*
403 * Get the fonts...
404 */
405
406 for (i = 0; *lineptr && i < 4; i ++)
407 {
408 while (isspace(*lineptr & 255))
409 lineptr ++;
410
411 valptr = lineptr;
412
413 while (!isspace(*lineptr & 255) && *lineptr)
414 lineptr ++;
415
416 if (*lineptr)
417 *lineptr++ = '\0';
418
419 if (lineptr > valptr)
420 Fonts[NumFonts][i] = strdup(valptr);
421 }
422
423 /*
424 * Fill in remaining fonts as needed...
425 */
426
427 for (j = i; j < 4; j ++)
428 Fonts[NumFonts][j] = strdup(Fonts[NumFonts][0]);
429
430 /*
431 * Define the character mappings...
432 */
433
434 for (i = start, j = NumFonts * 256; i <= end; i ++, j ++)
435 {
436 Chars[i] = j;
437 Codes[j] = i;
438 }
439
440 /*
441 * Move to the next font, stopping if needed...
442 */
443
444 NumFonts ++;
445 if (NumFonts >= 256)
446 break;
447 }
448
449 fclose(fp);
450 }
451 else
452 {
453 fprintf(stderr, _("ERROR: Bad charset type %s\n"), lineptr);
454 fclose(fp);
455 exit(1);
456 }
457 }
458 else
459 {
460 /*
461 * Standard ASCII output just uses Courier, Courier-Bold, and
462 * possibly Courier-Oblique.
463 */
464
465 NumFonts = 1;
466
467 Fonts[0][ATTR_NORMAL] = strdup("Courier");
468 Fonts[0][ATTR_BOLD] = strdup("Courier-Bold");
469 Fonts[0][ATTR_ITALIC] = strdup("Courier-Oblique");
470 Fonts[0][ATTR_BOLDITALIC] = strdup("Courier-BoldOblique");
471
472 Widths[0] = 1;
473 Directions[0] = 1;
474
475 /*
476 * Define US-ASCII characters...
477 */
478
479 for (i = 32; i < 127; i ++)
480 {
481 Chars[i] = i;
482 Codes[i] = i;
483 }
484 }
485
486 /*
487 * Generate a list of unique fonts to use...
488 */
489
490 for (i = 0, num_fonts = 0; i < NumFonts; i ++)
491 for (j = PrettyPrint ? 2 : 1; j >= 0; j --)
492 {
493 for (k = 0; k < num_fonts; k ++)
494 if (strcmp(Fonts[i][j], fonts[k]) == 0)
495 break;
496
497 if (k >= num_fonts)
498 {
499 /*
500 * Add new font...
501 */
502
503 fonts[num_fonts] = Fonts[i][j];
504 num_fonts ++;
505 }
506 }
507
508 /*
509 * List the fonts that will be used...
510 */
511
512 for (i = 0; i < num_fonts; i ++)
513 if (i == 0)
514 printf("%%%%DocumentNeededResources: font %s\n", fonts[i]);
515 else
516 printf("%%%%+ font %s\n", fonts[i]);
517
518 puts("%%DocumentSuppliedResources: procset texttops 1.1 0");
519
520 for (i = 0; i < num_fonts; i ++)
521 {
522 if (ppd != NULL)
523 {
524 fprintf(stderr, "DEBUG: ppd->num_fonts = %d\n", ppd->num_fonts);
525
526 for (j = 0; j < ppd->num_fonts; j ++)
527 {
528 fprintf(stderr, "DEBUG: ppd->fonts[%d] = %s\n", j, ppd->fonts[j]);
529
530 if (strcmp(fonts[i], ppd->fonts[j]) == 0)
531 break;
532 }
533 }
534 else
535 j = 0;
536
537 if ((ppd != NULL && j >= ppd->num_fonts) ||
538 strncmp(fonts[i], "Courier", 7) == 0 ||
539 strcmp(fonts[i], "Symbol") == 0)
540 {
541 /*
542 * Need to embed this font...
543 */
544
545 printf("%%%%+ font %s\n", fonts[i]);
546 }
547 }
548
549 puts("%%EndComments");
550
551 puts("%%BeginProlog");
552
553 /*
554 * Download any missing fonts...
555 */
556
557 for (i = 0; i < num_fonts; i ++)
558 {
559 if (ppd != NULL)
560 {
561 for (j = 0; j < ppd->num_fonts; j ++)
562 if (strcmp(fonts[i], ppd->fonts[j]) == 0)
563 break;
564 }
565 else
566 j = 0;
567
568 if ((ppd != NULL && j >= ppd->num_fonts) ||
569 strncmp(fonts[i], "Courier", 7) == 0 ||
570 strcmp(fonts[i], "Symbol") == 0)
571 {
572 /*
573 * Need to embed this font...
574 */
575
576 printf("%%%%BeginResource: font %s\n", fonts[i]);
577
578 /**** MRS: Need to use CUPS_FONTPATH env var! ****/
579 /**** Also look for Fontmap file or name.pfa, name.pfb... ****/
580 snprintf(filename, sizeof(filename), "%s/fonts/%s", datadir, fonts[i]);
581 if ((fp = fopen(filename, "rb")) != NULL)
582 {
583 while ((j = fread(line, 1, sizeof(line), fp)) > 0)
584 fwrite(line, 1, j, stdout);
585
586 fclose(fp);
587 }
588
589 puts("\n%%EndResource");
590 }
591 }
592
593 /*
594 * Write the encoding array(s)...
595 */
596
597 puts("% character encoding(s)");
598
599 for (i = 0; i < NumFonts; i ++)
600 {
601 printf("/cupsEncoding%02x [\n", i);
602
603 for (ch = 0; ch < 256; ch ++)
604 {
605 if (Glyphs[Codes[i * 256 + ch]])
606 printf("/%s", Glyphs[Codes[i * 256 + ch]]);
607 else if (Codes[i * 256 + ch] > 255)
608 printf("/uni%04X", Codes[i * 256 + ch]);
609 else
610 printf("/.notdef");
611
612 if ((ch & 7) == 7)
613 putchar('\n');
614 }
615
616 puts("] def");
617 }
618
619 /*
620 * Create the fonts...
621 */
622
623 if (NumFonts == 1)
624 {
625 /*
626 * Just reencode the named fonts...
627 */
628
629 puts("% Reencode fonts");
630
631 for (i = PrettyPrint ? 2 : 1; i >= 0; i --)
632 {
633 printf("/%s findfont\n", Fonts[0][i]);
634 puts("dup length 1 add dict begin\n"
635 " { 1 index /FID ne { def } { pop pop } ifelse } forall\n"
636 " /Encoding cupsEncoding00 def\n"
637 " currentdict\n"
638 "end");
639 printf("/%s exch definefont pop\n", names[i]);
640 }
641 }
642 else
643 {
644 /*
645 * Construct composite fonts... Start by reencoding the base fonts...
646 */
647
648 puts("% Reencode base fonts");
649
650 for (i = PrettyPrint ? 2 : 1; i >= 0; i --)
651 for (j = 0; j < NumFonts; j ++)
652 {
653 printf("/%s findfont\n", Fonts[j][i]);
654 printf("dup length 1 add dict begin\n"
655 " { 1 index /FID ne { def } { pop pop } ifelse } forall\n"
656 " /Encoding cupsEncoding%02x def\n"
657 " currentdict\n"
658 "end\n", j);
659 printf("/%s%02x exch definefont /%s%02x exch def\n", names[i], j,
660 names[i], j);
661 }
662
663 /*
664 * Then merge them into composite fonts...
665 */
666
667 puts("% Create composite fonts...");
668
669 for (i = PrettyPrint ? 2 : 1; i >= 0; i --)
670 {
671 puts("8 dict begin");
672 puts("/FontType 0 def/FontMatrix[1.0 0 0 1.0 0 0]def/FMapType 2 def/Encoding[");
673 for (j = 0; j < NumFonts; j ++)
674 if (j == (NumFonts - 1))
675 printf("%d", j);
676 else if ((j & 15) == 15)
677 printf("%d\n", j);
678 else
679 printf("%d ", j);
680 puts("]def/FDepVector[");
681 for (j = 0; j < NumFonts; j ++)
682 if (j == (NumFonts - 1))
683 printf("%s%02x", names[i], j);
684 else if ((j & 3) == 3)
685 printf("%s%02x\n", names[i], j);
686 else
687 printf("%s%02x ", names[i], j);
688 puts("]def currentdict end");
689 printf("/%s exch definefont pop\n", names[i]);
690 }
691 }
692
693 /*
694 * Output the texttops procset...
695 */
696
697 puts("%%BeginResource: procset texttops 1.1 0");
698
699 puts("% Define fonts");
700
701 printf("/FN /cupsNormal findfont [%.3f 0 0 %.3f 0 0] makefont def\n",
702 120.0 / CharsPerInch, 68.0 / LinesPerInch);
703 printf("/FB /cupsBold findfont [%.3f 0 0 %.3f 0 0] makefont def\n",
704 120.0 / CharsPerInch, 68.0 / LinesPerInch);
705 if (PrettyPrint)
706 printf("/FI /cupsItalic findfont [%.3f 0 0 %.3f 0 0] makefont def\n",
707 120.0 / CharsPerInch, 68.0 / LinesPerInch);
708
709 puts("% Common procedures");
710
711 puts("/N { FN setfont moveto } bind def");
712 puts("/B { FB setfont moveto } bind def");
713 printf("/U { gsave 0.5 setlinewidth 0 %.3f rmoveto "
714 "0 rlineto stroke grestore } bind def\n", -6.8 / LinesPerInch);
715
716 if (PrettyPrint)
717 {
718 if (ColorDevice)
719 {
720 puts("/S { 0.0 setgray show } bind def");
721 puts("/r { 0.5 0.0 0.0 setrgbcolor show } bind def");
722 puts("/g { 0.0 0.5 0.0 setrgbcolor show } bind def");
723 puts("/b { 0.0 0.0 0.5 setrgbcolor show } bind def");
724 }
725 else
726 {
727 puts("/S { 0.0 setgray show } bind def");
728 puts("/r { 0.2 setgray show } bind def");
729 puts("/g { 0.2 setgray show } bind def");
730 puts("/b { 0.2 setgray show } bind def");
731 }
732
733 puts("/I { FI setfont moveto } bind def");
734
735 puts("/n {");
736 puts("\t20 string cvs % convert page number to string");
737 if (NumFonts > 1)
738 {
739 /*
740 * Convert a number to double-byte chars...
741 */
742
743 puts("\tdup length % get length");
744 puts("\tdup 2 mul string /P exch def % P = string twice as long");
745 puts("\t0 1 2 index 1 sub { % loop through each character in the page number");
746 puts("\t\tdup 3 index exch get % get character N from the page number");
747 puts("\t\texch 2 mul dup % compute offset in P");
748 puts("\t\tP exch 0 put % font 0");
749 puts("\t\t1 add P exch 2 index put % character");
750 puts("\t\tpop % discard character");
751 puts("\t} for % do for loop");
752 puts("\tpop pop % discard string and length");
753 puts("\tP % put string on stack");
754 }
755 puts("} bind def");
756
757 printf("/T");
758 write_text(title);
759 puts("def");
760
761 printf("/D");
762 write_text(curdate);
763 puts("def");
764
765 puts("/H {");
766 puts("\tgsave");
767 puts("\t0.9 setgray");
768
769 if (Duplex)
770 {
771 puts("\tdup 2 mod 0 eq {");
772 printf("\t\t%.3f %.3f translate } {\n",
773 PageWidth - PageRight, PageTop + 72.0f / LinesPerInch);
774 printf("\t\t%.3f %.3f translate } ifelse\n",
775 PageLeft, PageTop + 72.0f / LinesPerInch);
776 }
777 else
778 printf("\t%.3f %.3f translate\n",
779 PageLeft, PageTop + 72.0f / LinesPerInch);
780
781 printf("\t0 0 %.3f %.3f rectfill\n", PageRight - PageLeft,
782 144.0f / LinesPerInch);
783
784 puts("\tFB setfont");
785 puts("\t0 setgray");
786
787 if (Duplex)
788 {
789 puts("\tdup 2 mod 0 eq {");
790 printf("\t\tT stringwidth pop neg %.3f add %.3f } {\n",
791 PageRight - PageLeft - 36.0f / LinesPerInch,
792 (0.5f + 0.157f) * 72.0f / LinesPerInch);
793 printf("\t\t%.3f %.3f } ifelse\n", 36.0f / LinesPerInch,
794 (0.5f + 0.157f) * 72.0f / LinesPerInch);
795 }
796 else
797 printf("\t%.3f %.3f\n", 36.0f / LinesPerInch,
798 (0.5f + 0.157f) * 72.0f / LinesPerInch);
799
800 puts("\tmoveto T show");
801
802 printf("\tD dup stringwidth pop neg 2 div %.3f add %.3f\n",
803 (PageRight - PageLeft) * 0.5,
804 (0.5f + 0.157f) * 72.0f / LinesPerInch);
805 puts("\tmoveto show");
806
807 if (Duplex)
808 {
809 puts("\tdup n exch 2 mod 0 eq {");
810 printf("\t\t%.3f %.3f } {\n", 36.0f / LinesPerInch,
811 (0.5f + 0.157f) * 72.0f / LinesPerInch);
812 printf("\t\tdup stringwidth pop neg %.3f add %.3f } ifelse\n",
813 PageRight - PageLeft - 36.0f / LinesPerInch,
814 (0.5f + 0.157f) * 72.0f / LinesPerInch);
815 }
816 else
817 printf("\tn dup stringwidth pop neg %.3f add %.3f\n",
818 PageRight - PageLeft - 36.0f / LinesPerInch,
819 (0.5f + 0.157f) * 72.0f / LinesPerInch);
820
821 puts("\tmoveto show");
822 puts("\tgrestore");
823 puts("} bind def");
824 }
825 else
826 puts("/S { show } bind def");
827
828 puts("%%EndResource");
829
830 puts("%%EndProlog");
831 }
832
833
834 /*
835 * 'write_line()' - Write a row of text.
836 */
837
838 static void
839 write_line(int row, /* I - Row number (0 to N) */
840 lchar_t *line) /* I - Line to print */
841 {
842 int i; /* Looping var */
843 int col; /* Current column */
844 int attr; /* Current attribute */
845 int font, /* Font to use */
846 lastfont, /* Last font */
847 mono; /* Monospaced? */
848 lchar_t *start; /* First character in sequence */
849
850
851 for (col = 0; col < SizeColumns;)
852 {
853 while (col < SizeColumns && (line->ch == ' ' || line->ch == 0))
854 {
855 col ++;
856 line ++;
857 }
858
859 if (col >= SizeColumns)
860 break;
861
862 if (NumFonts == 1)
863 {
864 /*
865 * All characters in a single font - assume monospaced...
866 */
867
868 attr = line->attr;
869 start = line;
870
871 while (col < SizeColumns && line->ch != 0 && attr == line->attr)
872 {
873 col ++;
874 line ++;
875 }
876
877 write_string(col - (line - start), row, line - start, start);
878 }
879 else
880 {
881 /*
882 * Multiple fonts; break up based on the font...
883 */
884
885 attr = line->attr;
886 start = line;
887 lastfont = Chars[line->ch] / 256;
888 mono = strncmp(Fonts[lastfont][0], "Courier", 7) == 0;
889 col ++;
890 line ++;
891
892 if (mono)
893 {
894 while (col < SizeColumns && line->ch != 0 && attr == line->attr)
895 {
896 font = Chars[line->ch] / 256;
897 if (strncmp(Fonts[font][0], "Courier", 7) != 0 ||
898 font != lastfont)
899 break;
900
901 col ++;
902 line ++;
903 }
904 }
905
906 if (Directions[lastfont] > 0)
907 write_string(col - (line - start), row, line - start, start);
908 else
909 {
910 /*
911 * Do right-to-left text...
912 */
913
914 while (col < SizeColumns && line->ch != 0 && attr == line->attr)
915 {
916 if (Directions[Chars[line->ch] / 256] > 0 &&
917 !ispunct(line->ch & 255) && !isspace(line->ch & 255))
918 break;
919
920 col ++;
921 line ++;
922 }
923
924 for (i = 1; start < line; i ++, start ++)
925 if (!isspace(start->ch & 255))
926 write_string(col - i, row, 1, start);
927 }
928 }
929 }
930 }
931
932
933 /*
934 * 'write_string()' - Write a string of text.
935 */
936
937 static void
938 write_string(int col, /* I - Start column */
939 int row, /* I - Row */
940 int len, /* I - Number of characters */
941 lchar_t *s) /* I - String to print */
942 {
943 int ch; /* Current character */
944 float x, y; /* Position of text */
945 unsigned attr; /* Character attributes */
946
947
948 /*
949 * Position the text and set the font...
950 */
951
952 if (Duplex && (NumPages & 1) == 0)
953 {
954 x = PageWidth - PageRight;
955 y = PageTop;
956 }
957 else
958 {
959 x = PageLeft;
960 y = PageTop;
961 }
962
963 x += (float)col * 72.0f / (float)CharsPerInch;
964 y -= (float)(row + 0.843) * 72.0f / (float)LinesPerInch;
965
966 attr = s->attr;
967
968 if (attr & ATTR_RAISED)
969 y += 36.0 / (float)LinesPerInch;
970 else if (attr & ATTR_LOWERED)
971 y -= 36.0 / (float)LinesPerInch;
972
973 if (x == (int)x)
974 printf("%.0f ", x);
975 else
976 printf("%.3f ", x);
977
978 if (y == (int)y)
979 printf("%.0f ", y);
980 else
981 printf("%.3f ", y);
982
983 if (attr & ATTR_BOLD)
984 putchar('B');
985 else if (attr & ATTR_ITALIC)
986 putchar('I');
987 else
988 putchar('N');
989
990 if (attr & ATTR_UNDERLINE)
991 printf(" %.3f U", (float)len * 72.0 / (float)CharsPerInch);
992
993 if (NumFonts > 1)
994 {
995 /*
996 * Write a hex string...
997 */
998
999 putchar('<');
1000
1001 while (len > 0)
1002 {
1003 printf("%04x", Chars[s->ch]);
1004
1005 len --;
1006 s ++;
1007 }
1008
1009 putchar('>');
1010 }
1011 else
1012 {
1013 /*
1014 * Write a quoted string...
1015 */
1016
1017 putchar('(');
1018
1019 while (len > 0)
1020 {
1021 ch = Chars[s->ch];
1022
1023 if (ch < 32 || ch > 126)
1024 {
1025 /*
1026 * Quote 8-bit and control characters...
1027 */
1028
1029 printf("\\%03o", ch);
1030 }
1031 else
1032 {
1033 /*
1034 * Quote the parenthesis and backslash as needed...
1035 */
1036
1037 if (ch == '(' || ch == ')' || ch == '\\')
1038 putchar('\\');
1039
1040 putchar(ch);
1041 }
1042
1043 len --;
1044 s ++;
1045 }
1046
1047 putchar(')');
1048 }
1049
1050 if (PrettyPrint)
1051 {
1052 if (attr & ATTR_RED)
1053 puts("r");
1054 else if (attr & ATTR_GREEN)
1055 puts("g");
1056 else if (attr & ATTR_BLUE)
1057 puts("b");
1058 else
1059 puts("S");
1060 }
1061 else
1062 puts("S");
1063 }
1064
1065
1066 /*
1067 * 'write_text()' - Write a text string, quoting/encoding as needed.
1068 */
1069
1070 static void
1071 write_text(const char *s) /* I - String to write */
1072 {
1073 int ch; /* Actual character value (UTF8) */
1074 const unsigned char *utf8; /* UTF8 text */
1075
1076
1077 if (NumFonts > 1)
1078 {
1079 /*
1080 * 8/8 encoding...
1081 */
1082
1083 putchar('<');
1084
1085 utf8 = (const unsigned char *)s;
1086
1087 while (*utf8)
1088 {
1089 if (*utf8 < 0xc0)
1090 ch = *utf8 ++;
1091 else if ((*utf8 & 0xe0) == 0xc0)
1092 {
1093 /*
1094 * Two byte character...
1095 */
1096
1097 ch = ((utf8[0] & 0x1f) << 6) | (utf8[1] & 0x3f);
1098 utf8 += 2;
1099 }
1100 else
1101 {
1102 /*
1103 * Three byte character...
1104 */
1105
1106 ch = ((((utf8[0] & 0x1f) << 6) | (utf8[1] & 0x3f)) << 6) |
1107 (utf8[2] & 0x3f);
1108 utf8 += 3;
1109 }
1110
1111 printf("%04x", Chars[ch]);
1112 }
1113
1114 putchar('>');
1115 }
1116 else
1117 {
1118 /*
1119 * Standard 8-bit encoding...
1120 */
1121
1122 putchar('(');
1123
1124 while (*s)
1125 {
1126 if (*s < 32 || *s > 126)
1127 printf("\\%03o", *s);
1128 else
1129 {
1130 if (*s == '(' || *s == ')' || *s == '\\')
1131 putchar('\\');
1132
1133 putchar(*s);
1134 }
1135
1136 s ++;
1137 }
1138
1139 putchar(')');
1140 }
1141 }
1142
1143
1144 /*
1145 * End of "$Id: texttops.c 7720 2008-07-11 22:46:21Z mike $".
1146 */