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