1 /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
2
3 Copyright (C) 2007-2014 by Jin-Hwan Cho and Shunsaku Hirata,
4 the dvipdfmx project team.
5
6 Copyright (C) 1998, 1999 by Mark A. Wicks <mwicks@kettering.edu>
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include "system.h"
28 #include "mem.h"
29 #include "error.h"
30
31 #include "dpxfile.h"
32
33 #include "numbers.h"
34 #include "pdfobj.h"
35 #include "pdfdev.h" /* pdf_rect */
36
37 #include "pdfencoding.h"
38 #include "pdffont.h"
39
40 #include "pkfont.h"
41
42 #define ENABLE_GLYPHENC 1
43
44 #ifndef PKFONT_DPI_DEFAULT
45 #define PKFONT_DPI_DEFAULT 600u
46 #endif
47
48 static unsigned base_dpi = PKFONT_DPI_DEFAULT;
49
50 void
PKFont_set_dpi(int dpi)51 PKFont_set_dpi (int dpi)
52 {
53 if (dpi <= 0)
54 ERROR("Invalid DPI: %d\n", dpi);
55 base_dpi = dpi;
56 }
57
58
59 /* (Only) This requires TFM to get design size... */
60 #include "tfm.h"
61
62 static unsigned
truedpi(const char * ident,double point_size,unsigned bdpi)63 truedpi (const char *ident, double point_size, unsigned bdpi)
64 {
65 unsigned dpi = bdpi;
66 double design_size;
67 int tfm_id;
68
69 tfm_id = tfm_open(ident, 0);
70 if (tfm_id < 0)
71 return dpi;
72
73 design_size = tfm_get_design_size(tfm_id);
74 if (design_size <= 0.0)
75 WARN("DESGIN_SIZE <= 0.0? (TFM=\"%s\")", ident);
76 else {
77 dpi = (unsigned) ROUND(base_dpi * point_size / design_size, 1.0);
78 }
79
80 return dpi;
81 }
82
83 static FILE *
dpx_open_pk_font_at(const char * ident,unsigned dpi)84 dpx_open_pk_font_at (const char *ident, unsigned dpi)
85 {
86 FILE *fp;
87 char *fqpn;
88 kpse_glyph_file_type kpse_file_info;
89
90 fqpn = kpse_find_glyph(ident, dpi, kpse_pk_format, &kpse_file_info);
91 if (!fqpn)
92 return NULL;
93 fp = MFOPEN(fqpn, FOPEN_RBIN_MODE);
94 RELEASE(fqpn);
95
96 return fp;
97 }
98
99
100 int
pdf_font_open_pkfont(pdf_font * font)101 pdf_font_open_pkfont (pdf_font *font)
102 {
103 char *ident;
104 double point_size;
105 int encoding_id;
106 unsigned dpi;
107 FILE *fp;
108
109 ident = pdf_font_get_ident(font);
110 point_size = pdf_font_get_param(font, PDF_FONT_PARAM_POINT_SIZE);
111 encoding_id = pdf_font_get_encoding(font);
112
113 if (!ident || point_size <= 0.0)
114 return -1;
115
116 dpi = truedpi(ident, point_size, base_dpi);
117 fp = dpx_open_pk_font_at(ident, dpi);
118 if (!fp)
119 return -1;
120 MFCLOSE(fp);
121
122 /* Type 3 fonts doesn't have FontName.
123 * FontFamily is recommended for PDF 1.5.
124 */
125 pdf_font_set_fontname(font, ident);
126
127 if (encoding_id >= 0) {
128 pdf_encoding_used_by_type3(encoding_id);
129 WARN("PK font is found for font \"%s\" but non built-in encoding \"%s\" is specified.",
130 ident, pdf_encoding_get_name(encoding_id));
131 #if ENABLE_GLYPHENC
132 WARN(">> Assuming this is for glyph name assignment.");
133 #else
134 WARN(">> I can't reencode PK font. (not enough information available)");
135 WARN(">> Maybe you need to install pfb/opentype/truetype font.");
136 #endif
137 }
138
139 return 0;
140 }
141
142
143 /* We are using Mask Image. Fill black is bit clear.
144 * Optimizing those codes doesn't improve things.
145 */
146 static uint32_t
fill_black_run(unsigned char * dp,uint32_t left,uint32_t run_count)147 fill_black_run (unsigned char *dp, uint32_t left, uint32_t run_count)
148 {
149 const static unsigned char mask[8] = {
150 127u, 191u, 223u, 239u, 247u, 251u, 253u, 254u
151 };
152 uint32_t right = left + run_count - 1;
153 for ( ; left <= right; left++) {
154 dp[left / 8] &= mask[left % 8];
155 }
156 return run_count;
157 }
158
159 /* Just skip bits. See decode_packed() */
160 static uint32_t
fill_white_run(uint32_t run_count)161 fill_white_run (uint32_t run_count)
162 {
163 return run_count;
164 }
165
166 static uint32_t
pk_packed_num(uint32_t * np,int dyn_f,unsigned char * dp,uint32_t pl)167 pk_packed_num (uint32_t *np, int dyn_f, unsigned char *dp, uint32_t pl)
168 {
169 uint32_t nmbr = 0, i = *np;
170 int nyb, j;
171 #define get_nyb() ((i % 2) ? dp[i/2] & 0x0f : (dp[i/2] >> 4) & 0x0f)
172
173 if (i / 2 == pl) {
174 WARN("EOD reached while unpacking pk_packed_num.");
175 return 0;
176 }
177 nyb = get_nyb(); i++;
178 if (nyb == 0) {
179 j = 0;
180 do {
181 if (i / 2 == pl) {
182 WARN("EOD reached while unpacking pk_packed_num.");
183 break;
184 }
185 nyb = get_nyb(); i++;
186 j++;
187 } while (nyb == 0);
188 nmbr = nyb;
189 while (j-- > 0) {
190 if (i / 2 == pl) {
191 WARN("EOD reached while unpacking pk_packed_num.");
192 break;
193 }
194 nyb = get_nyb(); i++;
195 nmbr = nmbr * 16 + nyb;
196 }
197 nmbr += (13 - dyn_f) * 16 + dyn_f - 15;
198 } else if (nyb <= dyn_f) {
199 nmbr = nyb;
200 } else if (nyb < 14) {
201 if (i / 2 == pl) {
202 WARN("EOD reached while unpacking pk_packed_num.");
203 return 0;
204 }
205 nmbr = (nyb - dyn_f - 1) * 16 + get_nyb() + dyn_f + 1;
206 i++;
207 }
208
209 *np = i;
210 return nmbr;
211 }
212
213
214 static void
send_out(unsigned char * rowptr,uint32_t rowbytes,pdf_obj * stream)215 send_out (unsigned char *rowptr, uint32_t rowbytes, pdf_obj *stream)
216 {
217 pdf_add_stream(stream, (void *)rowptr, rowbytes);
218 }
219
220 static int
pk_decode_packed(pdf_obj * stream,uint32_t wd,uint32_t ht,int dyn_f,int run_color,unsigned char * dp,uint32_t pl)221 pk_decode_packed (pdf_obj *stream, uint32_t wd, uint32_t ht,
222 int dyn_f, int run_color, unsigned char *dp, uint32_t pl)
223 {
224 unsigned char *rowptr;
225 uint32_t rowbytes;
226 uint32_t i, np = 0;
227 uint32_t run_count = 0, repeat_count = 0;
228
229 rowbytes = (wd + 7) / 8;
230 rowptr = NEW(rowbytes, unsigned char);
231 /* repeat count is applied to the *current* row.
232 * "run" can span across rows.
233 * If there are non-zero repeat count and if run
234 * spans across row, first repeat and then continue.
235 */
236 for (np = 0, i = 0; i < ht; i++) {
237 uint32_t rowbits_left, nbits;
238
239 repeat_count = 0;
240 memset(rowptr, 0xff, rowbytes); /* 1 is white */
241 rowbits_left = wd;
242 /* Fill run left over from previous row */
243 if (run_count > 0) {
244 nbits = MIN(rowbits_left, run_count);
245 switch (run_color) {
246 case 0:
247 rowbits_left -= fill_black_run(rowptr, 0, nbits);
248 break;
249 case 1:
250 rowbits_left -= fill_white_run(nbits);
251 break;
252 }
253 run_count -= nbits;
254 }
255
256 /* Read nybbles until we have a full row */
257 while (np / 2 < pl && rowbits_left > 0) {
258 int nyb;
259
260 nyb = (np % 2) ? dp[np/2] & 0x0f : (dp[np/2] >> 4) & 0x0f;
261 if (nyb == 14) { /* packed number "repeat_count" follows */
262 if (repeat_count != 0)
263 WARN("Second repeat count for this row!");
264 np++; /* Consume this nybble */
265 repeat_count = pk_packed_num(&np, dyn_f, dp, pl);
266 } else if (nyb == 15) {
267 if (repeat_count != 0)
268 WARN("Second repeat count for this row!");
269 np++; /* Consume this nybble */
270 repeat_count = 1;
271 } else { /* run_count */
272 /* Interprete current nybble as packed number */
273 run_count = pk_packed_num(&np, dyn_f, dp, pl);
274 nbits = MIN(rowbits_left, run_count);
275 run_color = !run_color;
276 run_count -= nbits;
277 switch (run_color) {
278 case 0:
279 rowbits_left -= fill_black_run(rowptr, wd - rowbits_left, nbits);
280 break;
281 case 1:
282 rowbits_left -= fill_white_run(nbits);
283 break;
284 }
285 }
286 }
287 /* We got bitmap row data. */
288 send_out(rowptr, rowbytes, stream);
289 for ( ; i < ht && repeat_count > 0; repeat_count--, i++)
290 send_out(rowptr, rowbytes, stream);
291 }
292 RELEASE(rowptr);
293
294 return 0;
295 }
296
297 static int
pk_decode_bitmap(pdf_obj * stream,uint32_t wd,uint32_t ht,int dyn_f,int run_color,unsigned char * dp,uint32_t pl)298 pk_decode_bitmap (pdf_obj *stream, uint32_t wd, uint32_t ht,
299 int dyn_f, int run_color, unsigned char *dp, uint32_t pl)
300 {
301 unsigned char *rowptr, c;
302 uint32_t i, j, rowbytes;
303 const static unsigned char mask[8] = {
304 0x80u, 0x40u, 0x20u, 0x10u, 0x08u, 0x04u, 0x02u, 0x01u
305 };
306
307 ASSERT( dyn_f == 14 );
308 if (run_color != 0) {
309 WARN("run_color != 0 for bitmap pk data?");
310 } else if (pl < (wd * ht + 7) / 8) {
311 WARN("Insufficient bitmap pk data. %ldbytes expected but only %ldbytes read.",
312 (wd * ht + 7) / 8, pl);
313 return -1;
314 }
315
316 rowbytes = (wd + 7) / 8;
317 rowptr = NEW(rowbytes, unsigned char);
318 memset(rowptr, 0, rowbytes);
319 /* Flip. PK bitmap is not byte aligned for each rows. */
320 for (i = 0, j = 0; i < ht * wd; i++) {
321 c = dp[i / 8] & mask[i % 8];
322 if (c == 0)
323 rowptr[j / 8] |= mask[i % 8]; /* flip bit */
324 j++;
325 if (j == wd) {
326 send_out(rowptr, rowbytes, stream);
327 memset(rowptr, 0, rowbytes);
328 j = 0;
329 }
330 }
331
332 return 0;
333 }
334
335
336 static void
do_preamble(FILE * fp)337 do_preamble (FILE *fp)
338 {
339 /* Check for id byte */
340 if (fgetc(fp) == 89) {
341 /* Skip comment */
342 skip_bytes(get_unsigned_byte(fp), fp);
343 /* Skip other header info. It's normally used for verifying this
344 is the file wethink it is */
345 skip_bytes(16, fp);
346 } else {
347 ERROR("embed_pk_font: PK ID byte is incorrect. Are you sure this is a PK file?");
348 }
349 return;
350 }
351
352 struct pk_header_
353 {
354 uint32_t pkt_len;
355 int32_t chrcode;
356 int32_t wd, dx, dy;
357 uint32_t bm_wd, bm_ht;
358 int32_t bm_hoff, bm_voff;
359 int dyn_f, run_color;
360 };
361
362 static int
read_pk_char_header(struct pk_header_ * h,unsigned char opcode,FILE * fp)363 read_pk_char_header (struct pk_header_ *h, unsigned char opcode, FILE *fp)
364 {
365 ASSERT(h);
366
367 if ((opcode & 4) == 0) { /* short */
368 h->pkt_len = (opcode & 3) << 8 | get_unsigned_byte(fp);
369 h->chrcode = get_unsigned_byte(fp);
370 h->wd = get_unsigned_triple(fp); /* TFM width */
371 h->dx = get_unsigned_byte(fp) << 16; /* horizontal escapement */
372 h->dy = 0;
373 h->bm_wd = get_unsigned_byte(fp);
374 h->bm_ht = get_unsigned_byte(fp);
375 h->bm_hoff = get_signed_byte(fp);
376 h->bm_voff = get_signed_byte(fp);
377 h->pkt_len -= 8;
378 } else if ((opcode & 7) == 7) { /* long */
379 h->pkt_len = get_positive_quad(fp, "PK", "pkt_len");
380 h->chrcode = get_signed_quad(fp);
381 h->wd = get_signed_quad(fp);
382 h->dx = get_signed_quad(fp); /* 16.16 fixed point number in pixels */
383 h->dy = get_signed_quad(fp);
384 h->bm_wd = get_positive_quad(fp, "PK", "bm_wd");
385 h->bm_ht = get_positive_quad(fp, "PK", "bm_ht");
386 h->bm_hoff = get_signed_quad(fp);
387 h->bm_voff = get_signed_quad(fp);
388 h->pkt_len -= 28;
389 } else { /* extended short */
390 h->pkt_len = (opcode & 3) << 16 | get_unsigned_pair(fp);
391 h->chrcode = get_unsigned_byte(fp);
392 h->wd = get_unsigned_triple(fp);
393 h->dx = get_unsigned_pair(fp) << 16;
394 h->dy = 0;
395 h->bm_wd = get_unsigned_pair(fp);
396 h->bm_ht = get_unsigned_pair(fp);
397 h->bm_hoff = get_signed_pair(fp);
398 h->bm_voff = get_signed_pair(fp);
399 h->pkt_len -= 13;
400 }
401
402 h->dyn_f = opcode / 16;
403 h->run_color = (opcode & 8) ? 1 : 0;
404
405 if ((uint32_t)h->chrcode > 0xff)
406 {
407 WARN("Unable to handle long characters in PK files: code=0x%04x", h->chrcode);
408 return -1;
409 }
410
411 return 0;
412 }
413
414 /* CCITT Group 4 filter may reduce file size. */
415 static pdf_obj *
create_pk_CharProc_stream(struct pk_header_ * pkh,double chrwid,unsigned char * pkt_ptr,uint32_t pkt_len)416 create_pk_CharProc_stream (struct pk_header_ *pkh,
417 double chrwid,
418 unsigned char *pkt_ptr, uint32_t pkt_len)
419 {
420 pdf_obj *stream; /* charproc */
421 int32_t llx, lly, urx, ury;
422 int len;
423
424 llx = -pkh->bm_hoff;
425 lly = pkh->bm_voff - pkh->bm_ht;
426 urx = pkh->bm_wd - pkh->bm_hoff;
427 ury = pkh->bm_voff;
428
429 stream = pdf_new_stream(STREAM_COMPRESS);
430 /*
431 * The following line is a "metric" for the PDF reader:
432 *
433 * PDF Reference Reference, 4th ed., p.385.
434 *
435 * The wx (first operand of d1) must be consistent with the corresponding
436 * width in the font's Widths array. The format string of sprint() must be
437 * consistent with write_number() in pdfobj.c.
438 */
439 len = pdf_sprint_number(work_buffer, chrwid);
440 len += sprintf (work_buffer + len, " 0 %d %d %d %d d1\n", llx, lly, urx, ury);
441 pdf_add_stream(stream, work_buffer, len);
442 /*
443 * Acrobat dislike transformation [0 0 0 0 dx dy].
444 * PDF Reference, 4th ed., p.147, says,
445 *
446 * Use of a noninvertible matrix when painting graphics objects can result in
447 * unpredictable behavior.
448 *
449 * but it does not forbid use of such transformation.
450 */
451 if (pkh->bm_wd != 0 && pkh->bm_ht != 0 && pkt_len > 0) {
452 /* Scale and translate origin to lower left corner for raster data */
453 len = sprintf (work_buffer, "q\n%u 0 0 %u %d %d cm\n", pkh->bm_wd, pkh->bm_ht, llx, lly);
454 pdf_add_stream(stream, work_buffer, len);
455 len = sprintf (work_buffer, "BI\n/W %u\n/H %u\n/IM true\n/BPC 1\nID ", pkh->bm_wd, pkh->bm_ht);
456 pdf_add_stream(stream, work_buffer, len);
457 /* Add bitmap data */
458 if (pkh->dyn_f == 14) /* bitmap */
459 pk_decode_bitmap(stream,
460 pkh->bm_wd, pkh->bm_ht,
461 pkh->dyn_f, pkh->run_color,
462 pkt_ptr, pkt_len);
463 else
464 pk_decode_packed(stream,
465 pkh->bm_wd, pkh->bm_ht,
466 pkh->dyn_f, pkh->run_color,
467 pkt_ptr, pkt_len);
468 len = sprintf (work_buffer, "\nEI\nQ");
469 pdf_add_stream(stream, work_buffer, len);
470 } /* Otherwise we embed an empty stream :-( */
471
472 return stream;
473 }
474
475 #define PK_XXX1 240
476 #define PK_XXX2 241
477 #define PK_XXX3 242
478 #define PK_XXX4 243
479 #define PK_YYY 244
480 #define PK_POST 245
481 #define PK_NO_OP 246
482 #define PK_PRE 247
483
484 #define pk_char2name(b,c) sprintf((b), "x%02X", (unsigned char)(c))
485 int
pdf_font_load_pkfont(pdf_font * font)486 pdf_font_load_pkfont (pdf_font *font)
487 {
488 pdf_obj *fontdict;
489 char *usedchars;
490 char *ident;
491 unsigned dpi;
492 FILE *fp;
493 double point_size, pix2charu;
494 int opcode, code, firstchar, lastchar, prev;
495 pdf_obj *charprocs, *procset, *encoding, *tmp_array;
496 double widths[256];
497 pdf_rect bbox;
498 char charavail[256];
499 #if ENABLE_GLYPHENC
500 int encoding_id;
501 char **enc_vec;
502 #endif /* ENABLE_GLYPHENC */
503 int error = 0;
504
505 if (!pdf_font_is_in_use(font)) {
506 return 0;
507 }
508
509 ident = pdf_font_get_ident(font);
510 point_size = pdf_font_get_param(font, PDF_FONT_PARAM_POINT_SIZE);
511 usedchars = pdf_font_get_usedchars(font);
512 #if ENABLE_GLYPHENC
513 encoding_id = pdf_font_get_encoding(font);
514 if (encoding_id < 0)
515 enc_vec = NULL;
516 else {
517 enc_vec = pdf_encoding_get_encoding(encoding_id);
518 }
519 #endif /* ENABLE_GLYPHENC */
520
521 ASSERT(ident && usedchars && point_size > 0.0);
522
523 dpi = truedpi(ident, point_size, base_dpi);
524 fp = dpx_open_pk_font_at(ident, dpi);
525 if (!fp) {
526 ERROR("Could not find/open PK font file: %s (at %udpi)", ident, dpi);
527 }
528
529 memset(charavail, 0, 256);
530 charprocs = pdf_new_dict();
531 /* Include bitmap as 72dpi image:
532 * There seems to be problems in "scaled" bitmap glyph
533 * rendering in several viewers.
534 */
535 pix2charu = 72. * 1000. / ((double) base_dpi) / point_size;
536 bbox.llx = bbox.lly = HUGE_VAL;
537 bbox.urx = bbox.ury = -HUGE_VAL;
538 while ((opcode = fgetc(fp)) >= 0 && opcode != PK_POST) {
539 if (opcode < 240) {
540 struct pk_header_ pkh;
541
542 error = read_pk_char_header(&pkh, opcode, fp);
543 if (error)
544 ERROR("Error in reading PK character header.");
545 else if (charavail[pkh.chrcode & 0xff])
546 WARN("More than two bitmap image for single glyph?: font=\"%s\" code=0x%02x",
547 ident, pkh.chrcode);
548
549 if (!usedchars[pkh.chrcode & 0xff])
550 skip_bytes(pkh.pkt_len, fp);
551 else {
552 char *charname;
553 pdf_obj *charproc;
554 unsigned char *pkt_ptr;
555 size_t bytesread;
556 double charwidth;
557
558 /* Charwidth in PDF units */
559 charwidth = ROUND(1000.0 * pkh.wd / (((double) (1<<20))*pix2charu), 0.1);
560 widths[pkh.chrcode & 0xff] = charwidth;
561
562 /* Update font BBox info */
563 bbox.llx = MIN(bbox.llx, -pkh.bm_hoff);
564 bbox.lly = MIN(bbox.lly, (double)pkh.bm_voff - (double)pkh.bm_ht);
565 bbox.urx = MAX(bbox.urx, (double)pkh.bm_wd - (double)pkh.bm_hoff);
566 bbox.ury = MAX(bbox.ury, pkh.bm_voff);
567
568 pkt_ptr = NEW(pkh.pkt_len, unsigned char);
569 if ((bytesread = fread(pkt_ptr, 1, pkh.pkt_len, fp))!= pkh.pkt_len) {
570 ERROR("Only %ld bytes PK packet read. (expected %ld bytes)",
571 bytesread, pkh.pkt_len);
572 }
573 charproc = create_pk_CharProc_stream(&pkh, charwidth, pkt_ptr, bytesread);
574 RELEASE(pkt_ptr);
575 if (!charproc)
576 ERROR("Unpacking PK character data failed.");
577 #if ENABLE_GLYPHENC
578 if (encoding_id >= 0 && enc_vec) {
579 charname = (char *) enc_vec[pkh.chrcode & 0xff];
580 if (!charname) {
581 WARN("\".notdef\" glyph used in font (code=0x%02x): %s", pkh.chrcode, ident);
582 charname = work_buffer;
583 pk_char2name(charname, pkh.chrcode);
584 }
585 }
586 else
587 #endif /* ENABLE_GLYPHENC */
588 {
589 charname = work_buffer;
590 pk_char2name(charname, pkh.chrcode);
591 }
592
593 pdf_add_dict(charprocs, pdf_new_name(charname), pdf_ref_obj(charproc)); /* _FIXME_ */
594 pdf_release_obj(charproc);
595 }
596 charavail[pkh.chrcode & 0xff] = 1;
597 } else { /* A command byte */
598 switch (opcode) {
599 case PK_NO_OP: break;
600 case PK_XXX1: case PK_XXX2: case PK_XXX3: case PK_XXX4:
601 {
602 int32_t len = get_unsigned_num(fp, opcode-PK_XXX1);
603 if (len < 0)
604 WARN("PK: Special with %d bytes???", len);
605 else
606 skip_bytes(len, fp);
607 break;
608 }
609 case PK_YYY: skip_bytes(4, fp); break;
610 case PK_PRE: do_preamble(fp); break;
611 }
612 }
613 }
614 MFCLOSE(fp);
615
616 /* Check if we really got all glyphs needed. */
617 for (code = 0; code < 256; code++) {
618 if (usedchars[code] && !charavail[code])
619 WARN("Missing glyph code=0x%02x in PK font \"%s\".", code, ident);
620 }
621
622 /* Now actually fill fontdict. */
623 fontdict = pdf_font_get_resource(font);
624
625 pdf_add_dict(fontdict,
626 pdf_new_name("CharProcs"), pdf_ref_obj(charprocs));
627 pdf_release_obj(charprocs);
628
629 /*
630 * Resources:
631 *
632 * PDF Reference 4th ed. describes it as "Optional but strongly recommended".
633 * There are no reason to put it in our case, but we will put this.
634 * We do not care about compatibility with Acrobat 2.x. (See implementation
635 * note 47, Appendix H of PDF Ref., 4th ed.).
636 */
637 procset = pdf_new_dict();
638 tmp_array = pdf_new_array();
639 pdf_add_array(tmp_array, pdf_new_name("PDF"));
640 pdf_add_array(tmp_array, pdf_new_name("ImageB"));
641 pdf_add_dict(procset,
642 pdf_new_name("ProcSet"), tmp_array);
643 pdf_add_dict(fontdict,
644 pdf_new_name("Resources"), procset);
645
646 /* Encoding */
647 tmp_array = pdf_new_array();
648 prev = -2; firstchar = 255; lastchar = 0;
649 for (code = 0; code < 256; code++) {
650 char *charname;
651 if (usedchars[code]) {
652 if (code < firstchar) firstchar = code;
653 if (code > lastchar) lastchar = code;
654 if (code != prev + 1)
655 pdf_add_array(tmp_array, pdf_new_number(code));
656
657 #if ENABLE_GLYPHENC
658 if (encoding_id >= 0 && enc_vec) {
659 charname = (char *) enc_vec[(unsigned char) code];
660 if (!charname) {
661 charname = work_buffer;
662 pk_char2name(charname, code);
663 }
664 }
665 else
666 #endif /* ENABLE_GLYPHENC */
667 {
668 charname = work_buffer;
669 pk_char2name(charname, code);
670 }
671 pdf_add_array(tmp_array, pdf_new_name(charname));
672 prev = code;
673 }
674 }
675 if (firstchar > lastchar) {
676 ERROR("Unexpected error: firstchar > lastchar (%d %d)",
677 firstchar, lastchar);
678 pdf_release_obj(tmp_array);
679 return -1;
680 }
681 #if ENABLE_GLYPHENC
682 if (encoding_id < 0 || !enc_vec) {
683 #else
684 if (1) {
685 #endif /* ENABLE_GLYPHENC */
686 encoding = pdf_new_dict();
687 pdf_add_dict(encoding,
688 pdf_new_name("Type"), pdf_new_name("Encoding"));
689 pdf_add_dict(encoding,
690 pdf_new_name("Differences"), tmp_array);
691 pdf_add_dict(fontdict,
692 pdf_new_name("Encoding"), pdf_ref_obj(encoding));
693 pdf_release_obj(encoding);
694 } else
695 pdf_release_obj(tmp_array);
696
697 /* FontBBox: Accurate value is important.
698 */
699 tmp_array = pdf_new_array();
700 pdf_add_array(tmp_array, pdf_new_number(bbox.llx));
701 pdf_add_array(tmp_array, pdf_new_number(bbox.lly));
702 pdf_add_array(tmp_array, pdf_new_number(bbox.urx));
703 pdf_add_array(tmp_array, pdf_new_number(bbox.ury));
704 pdf_add_dict (fontdict , pdf_new_name("FontBBox"), tmp_array);
705
706 /* Widths:
707 * Indirect reference preffered. (See PDF Reference)
708 */
709 tmp_array = pdf_new_array();
710 for (code = firstchar; code <= lastchar; code++) {
711 if (usedchars[code])
712 pdf_add_array(tmp_array, pdf_new_number(widths[code]));
713 else {
714 pdf_add_array(tmp_array, pdf_new_number(0));
715 }
716 }
717 pdf_add_dict(fontdict,
718 pdf_new_name("Widths"), pdf_ref_obj(tmp_array));
719 pdf_release_obj(tmp_array);
720
721 /* FontMatrix */
722 tmp_array = pdf_new_array();
723 pdf_add_array(tmp_array, pdf_new_number(0.001 * pix2charu));
724 pdf_add_array(tmp_array, pdf_new_number(0.0));
725 pdf_add_array(tmp_array, pdf_new_number(0.0));
726 pdf_add_array(tmp_array, pdf_new_number(0.001 * pix2charu));
727 pdf_add_array(tmp_array, pdf_new_number(0.0));
728 pdf_add_array(tmp_array, pdf_new_number(0.0));
729 pdf_add_dict (fontdict , pdf_new_name("FontMatrix"), tmp_array);
730
731
732 pdf_add_dict(fontdict,
733 pdf_new_name("FirstChar"), pdf_new_number(firstchar));
734 pdf_add_dict(fontdict,
735 pdf_new_name("LastChar"), pdf_new_number(lastchar));
736
737 return 0;
738 }
739