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