]> git.ipfire.org Git - thirdparty/cups.git/blob - filter/pstext.c
Merge changes from CUPS 1.4svn-r8067 (tentative CUPS 1.4b1)
[thirdparty/cups.git] / filter / pstext.c
1 /*
2 * "$Id$"
3 *
4 * Common PostScript text code for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 2008 by Apple Inc.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Apple Inc. and are protected by Federal copyright
10 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
11 * which should have been included with this file. If this file is
12 * file is missing or damaged, see the license at "http://www.cups.org/".
13 *
14 * This file is subject to the Apple OS-Developed Software exception.
15 *
16 * Contents:
17 *
18 * psTextEmbedFonts() - Embed PostScript fonts.
19 * psTextListFonts() - List PostScript fonts.
20 * psTextInitialize() - Load and embed font data for UTF-8 text.
21 * psTextUTF8() - Output UTF-8 text at the current position.
22 * psTextUTF32() - Output UTF-32 text at the current position.
23 */
24
25 /*
26 * Include necessary headers...
27 */
28
29 #include "pstext.h"
30 #include <cups/i18n.h>
31
32
33 /*
34 * Composite font names...
35 */
36
37 static const char * const ps_font_names[] =
38 {
39 "cupsNormal",
40 "cupsBold",
41 "cupsItalic",
42 "cupsBoldItalic"
43 };
44
45
46 /*
47 * 'psTextEmbedFonts()'- Embed PostScript fonts.
48 */
49
50 void
51 psTextEmbedFonts(ps_text_t *fonts) /* I - Font data */
52 {
53 int i, j; /* Looping vars */
54 const char *cups_datadir; /* CUPS_DATADIR environment variable */
55 char *font; /* Current font */
56 char filename[1024]; /* Current filename */
57 FILE *fp; /* Current file */
58 char line[1024]; /* Line from file */
59 int ch; /* Character value */
60
61
62 /*
63 * Get the data directory...
64 */
65
66 if ((cups_datadir = getenv("CUPS_DATADIR")) == NULL)
67 cups_datadir = CUPS_DATADIR;
68
69 /*
70 * Embed each font...
71 */
72
73 for (font = (char *)cupsArrayFirst(fonts->unique);
74 font;
75 font = (char *)cupsArrayNext(fonts->unique))
76 {
77 printf("%%%%BeginResource: font %s\n", font);
78
79 snprintf(filename, sizeof(filename), "%s/fonts/%s", cups_datadir, font);
80 if ((fp = fopen(filename, "rb")) != NULL)
81 {
82 while ((j = fread(line, 1, sizeof(line), fp)) > 0)
83 fwrite(line, 1, j, stdout);
84
85 fclose(fp);
86 }
87 else
88 fprintf(stderr, "DEBUG: Unable to open font file \"%s\" - %s\n",
89 filename, strerror(errno));
90
91 puts("\n%%EndResource");
92 }
93
94 /*
95 * Write the encoding arrays...
96 */
97
98 puts("% Character encodings");
99
100 for (i = 0; i < fonts->num_fonts; i ++)
101 {
102 printf("/cupsEncoding%02x [\n", i);
103
104 for (ch = 0; ch < 256; ch ++)
105 {
106 if (fonts->glyphs[fonts->codes[i * 256 + ch]])
107 printf("/%s", fonts->glyphs[fonts->codes[i * 256 + ch]]);
108 else if (fonts->codes[i * 256 + ch] > 255)
109 printf("/uni%04X", fonts->codes[i * 256 + ch]);
110 else
111 printf("/.notdef");
112
113 if ((ch & 7) == 7)
114 putchar('\n');
115 }
116
117 puts("] def");
118 }
119
120 /*
121 * Construct composite fonts... Start by reencoding the base fonts...
122 */
123
124 puts("% Reencode base fonts");
125
126 for (i = 0; i < 4; i ++)
127 for (j = 0; j < fonts->num_fonts; j ++)
128 {
129 printf("/%s findfont\n", fonts->fonts[j][i]);
130 printf("dup length 1 add dict begin\n"
131 " { 1 index /FID ne { def } { pop pop } ifelse } forall\n"
132 " /Encoding cupsEncoding%02x def\n"
133 " currentdict\n"
134 "end\n", j);
135 printf("/%s%02x exch definefont /%s%02x exch def\n", ps_font_names[i], j,
136 ps_font_names[i], j);
137 }
138
139 /*
140 * Then merge them into composite fonts...
141 */
142
143 puts("% Create composite fonts");
144
145 for (i = 0; i < 4; i ++)
146 {
147 puts("8 dict begin");
148 puts("/FontType 0 def/FontMatrix[1.0 0 0 1.0 0 0]def/FMapType 2 def"
149 "/Encoding[");
150 for (j = 0; j < fonts->num_fonts; j ++)
151 if (j == (fonts->num_fonts - 1))
152 printf("%d", j);
153 else if ((j & 15) == 15)
154 printf("%d\n", j);
155 else
156 printf("%d ", j);
157 puts("]def/FDepVector[");
158 for (j = 0; j < fonts->num_fonts; j ++)
159 if (j == (fonts->num_fonts - 1))
160 printf("%s%02x", ps_font_names[i], j);
161 else if ((j & 3) == 3)
162 printf("%s%02x\n", ps_font_names[i], j);
163 else
164 printf("%s%02x ", ps_font_names[i], j);
165 puts("]def currentdict end");
166 printf("/%s exch definefont pop\n", ps_font_names[i]);
167 }
168
169 /*
170 * Procedures...
171 */
172
173 puts("% Procedures to justify text...\n"
174 "/showcenter{dup stringwidth pop -0.5 mul 0 rmoveto show}bind def\n"
175 "/showleft{show}bind def\n"
176 "/showright{dup stringwidth pop neg 0 rmoveto show}bind def");
177 }
178
179
180 /*
181 * 'psTextListFonts()' - List PostScript fonts.
182 */
183
184 void
185 psTextListFonts(ps_text_t *fonts) /* I - Font data */
186 {
187 char *font; /* Current font */
188
189
190 font = (char *)cupsArrayFirst(fonts->unique);
191 printf("%%%%DocumentSuppliedResources: font %s\n", font);
192 while ((font = (char *)cupsArrayNext(fonts->unique)) != NULL)
193 printf("%%%%+ font %s\n", font);
194 }
195
196
197 /*
198 * 'psTextInitialize()' - Load and embed font data for UTF-8 text.
199 */
200
201 ps_text_t * /* O - Font data */
202 psTextInitialize(void)
203 {
204 ps_text_t *fonts; /* Font data */
205 int i, j; /* Looping vars */
206 char filename[1024]; /* Current filename */
207 FILE *fp; /* Current file */
208 const char *cups_datadir; /* CUPS_DATADIR environment variable */
209 char line[1024], /* Line from file */
210 *lineptr, /* Pointer into line */
211 *valptr; /* Pointer to value in line */
212 int unicode; /* Character value */
213 int start, end; /* Start and end values for range */
214 char glyph[64]; /* Glyph name */
215
216
217 /*
218 * Get the data directory...
219 */
220
221 if ((cups_datadir = getenv("CUPS_DATADIR")) == NULL)
222 cups_datadir = CUPS_DATADIR;
223
224 /*
225 * Initialize the PostScript text data...
226 */
227
228 fonts = (ps_text_t *)calloc(1, sizeof(ps_text_t));
229 fonts->size = -1.0;
230 fonts->style = -1;
231
232 /*
233 * Load the PostScript glyph names...
234 */
235
236 snprintf(filename, sizeof(filename), "%s/data/psglyphs", cups_datadir);
237
238 if ((fp = fopen(filename, "r")) != NULL)
239 {
240 while (fscanf(fp, "%x%63s", &unicode, glyph) == 2)
241 fonts->glyphs[unicode] = _cupsStrAlloc(glyph);
242
243 fclose(fp);
244 }
245 else
246 {
247 _cupsLangPrintf(stderr, _("ERROR: Unable to open \"%s\" - %s\n"), filename,
248 strerror(errno));
249 exit(1);
250 }
251
252 /*
253 * Open the UTF-8 character set definition...
254 */
255
256 snprintf(filename, sizeof(filename), "%s/charsets/utf-8", cups_datadir);
257
258 if ((fp = fopen(filename, "r")) == NULL)
259 {
260 /*
261 * Can't open charset file!
262 */
263
264 _cupsLangPrintf(stderr, _("ERROR: Unable to open %s: %s\n"), filename,
265 strerror(errno));
266 exit(1);
267 }
268
269 if (!fgets(line, sizeof(line), fp) || strncmp(line, "charset utf8", 12))
270 {
271 /*
272 * Bad/empty charset file!
273 */
274
275 fclose(fp);
276 _cupsLangPrintf(stderr, _("ERROR: Bad charset file %s\n"), filename);
277 exit(1);
278 }
279
280 /*
281 * Read the font descriptions...
282 */
283
284 fonts->unique = cupsArrayNew((cups_array_func_t)strcmp, NULL);
285
286 while (fgets(line, sizeof(line), fp) != NULL)
287 {
288 /*
289 * Skip comment and blank lines...
290 */
291
292 if (line[0] == '#' || line[0] == '\n')
293 continue;
294
295 /*
296 * Read the font descriptions that should look like:
297 *
298 * start end direction width normal [bold italic bold-italic]
299 */
300
301 lineptr = line;
302
303 start = strtol(lineptr, &lineptr, 16);
304 end = strtol(lineptr, &lineptr, 16);
305
306 while (isspace(*lineptr & 255))
307 lineptr ++;
308
309 valptr = lineptr;
310
311 while (!isspace(*lineptr & 255) && *lineptr)
312 lineptr ++;
313
314 if (!*lineptr)
315 {
316 /*
317 * Can't have a font without all required values...
318 */
319
320 _cupsLangPrintf(stderr, _("ERROR: Bad font description line: %s\n"),
321 valptr);
322 fclose(fp);
323 exit(1);
324 }
325
326 *lineptr++ = '\0';
327
328 if (!strcmp(valptr, "ltor"))
329 fonts->directions[fonts->num_fonts] = 1;
330 else if (!strcmp(valptr, "rtol"))
331 fonts->directions[fonts->num_fonts] = -1;
332 else
333 {
334 _cupsLangPrintf(stderr, _("ERROR: Bad text direction %s\n"), valptr);
335 fclose(fp);
336 exit(1);
337 }
338
339 /*
340 * Got the direction, now get the width...
341 */
342
343 while (isspace(*lineptr & 255))
344 lineptr ++;
345
346 valptr = lineptr;
347
348 while (!isspace(*lineptr & 255) && *lineptr)
349 lineptr ++;
350
351 if (!*lineptr)
352 {
353 /*
354 * Can't have a font without all required values...
355 */
356
357 _cupsLangPrintf(stderr, _("ERROR: Bad font description line: %s\n"),
358 valptr);
359 fclose(fp);
360 exit(1);
361 }
362
363 *lineptr++ = '\0';
364
365 if (!strcmp(valptr, "single"))
366 fonts->widths[fonts->num_fonts] = 1;
367 else if (!strcmp(valptr, "double"))
368 fonts->widths[fonts->num_fonts] = 2;
369 else
370 {
371 _cupsLangPrintf(stderr, _("ERROR: Bad text width %s\n"), valptr);
372 fclose(fp);
373 exit(1);
374 }
375
376 /*
377 * Get the fonts...
378 */
379
380 for (i = 0; *lineptr && i < 4; i ++)
381 {
382 while (isspace(*lineptr & 255))
383 lineptr ++;
384
385 valptr = lineptr;
386
387 while (!isspace(*lineptr & 255) && *lineptr)
388 lineptr ++;
389
390 if (*lineptr)
391 *lineptr++ = '\0';
392
393 if (lineptr > valptr)
394 {
395 if (!cupsArrayFind(fonts->unique, valptr))
396 cupsArrayAdd(fonts->unique, _cupsStrAlloc(valptr));
397
398 fonts->fonts[fonts->num_fonts][i] = _cupsStrAlloc(valptr);
399 }
400 }
401
402 /*
403 * Fill in remaining fonts as needed...
404 */
405
406 for (j = i; j < 4; j ++)
407 fonts->fonts[fonts->num_fonts][j] =
408 _cupsStrAlloc(fonts->fonts[fonts->num_fonts][0]);
409
410 /*
411 * Define the character mappings...
412 */
413
414 for (i = start, j = fonts->num_fonts * 256; i <= end; i ++, j ++)
415 {
416 fonts->chars[i] = j;
417 fonts->codes[j] = i;
418 }
419
420 /*
421 * Move to the next font, stopping if needed...
422 */
423
424 fonts->num_fonts ++;
425 if (fonts->num_fonts >= 256)
426 break;
427 }
428
429 fclose(fp);
430
431 if (cupsArrayCount(fonts->unique) == 0)
432 {
433 _cupsLangPrintf(stderr, _("ERROR: No fonts in charset file %s\n"), filename);
434 exit(1);
435 }
436
437 return (fonts);
438 }
439
440
441 /*
442 * 'psTextUTF8()' - Output UTF-8 text at the current position.
443 */
444
445 void
446 psTextUTF8(ps_text_t *fonts, /* I - Font data */
447 float size, /* I - Size in points */
448 int style, /* I - Style */
449 int align, /* I - Alignment */
450 const char *text) /* I - UTF-8 text */
451 {
452 cups_utf32_t utf32[2048]; /* Temporary buffer */
453 int utf32len; /* Number of characters */
454
455
456 if (!text)
457 {
458 puts("");
459 return;
460 }
461
462 if ((utf32len = cupsUTF8ToUTF32(utf32, (cups_utf8_t *)text,
463 (int)(sizeof(utf32) / sizeof(utf32[0])))) > 0)
464 psTextUTF32(fonts, size, style, align, utf32, utf32len);
465 }
466
467
468 /*
469 * 'psTextUTF32()' - Output UTF-32 text at the current position.
470 */
471
472 void
473 psTextUTF32(ps_text_t *fonts, /* I - Font data */
474 float size, /* I - Size in points */
475 int style, /* I - Font style */
476 int align, /* I - Alignment */
477 const cups_utf32_t *text, /* I - UTF-32 text */
478 int textlen) /* I - Length of text */
479 {
480 if (size != fonts->size || style != fonts->style)
481 {
482 printf("/%s findfont %g scalefont setfont\n", ps_font_names[style], size);
483 fonts->size = size;
484 fonts->style = style;
485 }
486
487 putchar('<');
488 while (textlen > 0)
489 {
490 printf("%04x", fonts->chars[*text]);
491 text ++;
492 textlen --;
493 }
494
495 if (align == PS_CENTER)
496 puts(">showcenter");
497 else if (align == PS_RIGHT)
498 puts(">showright");
499 else
500 puts(">showleft");
501 }
502
503
504 /*
505 * End of "$Id$".
506 */