]> git.ipfire.org Git - thirdparty/cups.git/blob - filter/pstext.c
Merge changes from CUPS 1.5svn-r9400
[thirdparty/cups.git] / filter / pstext.c
1 /*
2 * "$Id$"
3 *
4 * Common PostScript text code for CUPS.
5 *
6 * Copyright 2008-2010 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/language-private.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 _cupsLangPrintError("ERROR", _("Unable to open print file"));
248 exit(1);
249 }
250
251 /*
252 * Open the UTF-8 character set definition...
253 */
254
255 snprintf(filename, sizeof(filename), "%s/charsets/utf-8", cups_datadir);
256
257 if ((fp = fopen(filename, "r")) == NULL)
258 {
259 /*
260 * Can't open charset file!
261 */
262
263 _cupsLangPrintError("ERROR", _("Unable to open print file"));
264 exit(1);
265 }
266
267 if (!fgets(line, sizeof(line), fp) || strncmp(line, "charset utf8", 12))
268 {
269 /*
270 * Bad/empty charset file!
271 */
272
273 fclose(fp);
274 _cupsLangPrintFilter(stderr, "ERROR", _("Bad charset file \"%s\"."),
275 filename);
276 exit(1);
277 }
278
279 /*
280 * Read the font descriptions...
281 */
282
283 fonts->unique = cupsArrayNew((cups_array_func_t)strcmp, NULL);
284
285 while (fgets(line, sizeof(line), fp) != NULL)
286 {
287 /*
288 * Skip comment and blank lines...
289 */
290
291 if (line[0] == '#' || line[0] == '\n')
292 continue;
293
294 /*
295 * Read the font descriptions that should look like:
296 *
297 * start end direction width normal [bold italic bold-italic]
298 */
299
300 lineptr = line;
301
302 start = strtol(lineptr, &lineptr, 16);
303 end = strtol(lineptr, &lineptr, 16);
304
305 while (isspace(*lineptr & 255))
306 lineptr ++;
307
308 valptr = lineptr;
309
310 while (!isspace(*lineptr & 255) && *lineptr)
311 lineptr ++;
312
313 if (!*lineptr)
314 {
315 /*
316 * Can't have a font without all required values...
317 */
318
319 _cupsLangPrintFilter(stderr, "ERROR",
320 _("Bad font description line \"%s\"."), valptr);
321 fclose(fp);
322 exit(1);
323 }
324
325 *lineptr++ = '\0';
326
327 if (!strcmp(valptr, "ltor"))
328 fonts->directions[fonts->num_fonts] = 1;
329 else if (!strcmp(valptr, "rtol"))
330 fonts->directions[fonts->num_fonts] = -1;
331 else
332 {
333 _cupsLangPrintFilter(stderr, "ERROR", _("Bad text direction \"%s\"."),
334 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 _cupsLangPrintFilter(stderr, "ERROR",
358 _("Bad font description line \"%s\"."), 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 _cupsLangPrintFilter(stderr, "ERROR", _("Bad text width \"%s\"."),
372 valptr);
373 fclose(fp);
374 exit(1);
375 }
376
377 /*
378 * Get the fonts...
379 */
380
381 for (i = 0; *lineptr && i < 4; i ++)
382 {
383 while (isspace(*lineptr & 255))
384 lineptr ++;
385
386 valptr = lineptr;
387
388 while (!isspace(*lineptr & 255) && *lineptr)
389 lineptr ++;
390
391 if (*lineptr)
392 *lineptr++ = '\0';
393
394 if (lineptr > valptr)
395 {
396 if (!cupsArrayFind(fonts->unique, valptr))
397 cupsArrayAdd(fonts->unique, _cupsStrAlloc(valptr));
398
399 fonts->fonts[fonts->num_fonts][i] = _cupsStrAlloc(valptr);
400 }
401 }
402
403 /*
404 * Fill in remaining fonts as needed...
405 */
406
407 for (j = i; j < 4; j ++)
408 fonts->fonts[fonts->num_fonts][j] =
409 _cupsStrAlloc(fonts->fonts[fonts->num_fonts][0]);
410
411 /*
412 * Define the character mappings...
413 */
414
415 for (i = start, j = fonts->num_fonts * 256; i <= end; i ++, j ++)
416 {
417 fonts->chars[i] = j;
418 fonts->codes[j] = i;
419 }
420
421 /*
422 * Move to the next font, stopping if needed...
423 */
424
425 fonts->num_fonts ++;
426 if (fonts->num_fonts >= 256)
427 break;
428 }
429
430 fclose(fp);
431
432 if (cupsArrayCount(fonts->unique) == 0)
433 {
434 _cupsLangPrintFilter(stderr, "ERROR", _("No fonts in charset file."));
435 exit(1);
436 }
437
438 return (fonts);
439 }
440
441
442 /*
443 * 'psTextUTF8()' - Output UTF-8 text at the current position.
444 */
445
446 void
447 psTextUTF8(ps_text_t *fonts, /* I - Font data */
448 float size, /* I - Size in points */
449 int style, /* I - Style */
450 int align, /* I - Alignment */
451 const char *text) /* I - UTF-8 text */
452 {
453 cups_utf32_t utf32[2048]; /* Temporary buffer */
454 int utf32len; /* Number of characters */
455
456
457 if (!text)
458 {
459 puts("");
460 return;
461 }
462
463 if ((utf32len = cupsUTF8ToUTF32(utf32, (cups_utf8_t *)text,
464 (int)(sizeof(utf32) / sizeof(utf32[0])))) > 0)
465 psTextUTF32(fonts, size, style, align, utf32, utf32len);
466 }
467
468
469 /*
470 * 'psTextUTF32()' - Output UTF-32 text at the current position.
471 */
472
473 void
474 psTextUTF32(ps_text_t *fonts, /* I - Font data */
475 float size, /* I - Size in points */
476 int style, /* I - Font style */
477 int align, /* I - Alignment */
478 const cups_utf32_t *text, /* I - UTF-32 text */
479 int textlen) /* I - Length of text */
480 {
481 if (size != fonts->size || style != fonts->style)
482 {
483 printf("/%s findfont %g scalefont setfont\n", ps_font_names[style], size);
484 fonts->size = size;
485 fonts->style = style;
486 }
487
488 putchar('<');
489 while (textlen > 0)
490 {
491 printf("%04x", fonts->chars[*text]);
492 text ++;
493 textlen --;
494 }
495
496 if (align == PS_CENTER)
497 puts(">showcenter");
498 else if (align == PS_RIGHT)
499 puts(">showright");
500 else
501 puts(">showleft");
502 }
503
504
505 /*
506 * End of "$Id$".
507 */