Back to index

texmacs  1.0.7.15
pkfont.c
Go to the documentation of this file.
00001 /*  $Header: /home/cvsroot/dvipdfmx/src/pkfont.c,v 1.19 2008/11/03 22:18:52 matthias Exp $
00002 
00003     This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
00004 
00005     Copyright (C) 2007 by Jin-Hwan Cho and Shunsaku Hirata,
00006     the dvipdfmx project team <dvipdfmx@project.ktug.or.kr>
00007     
00008     Copyright (C) 1998, 1999 by Mark A. Wicks <mwicks@kettering.edu>
00009 
00010     This program is free software; you can redistribute it and/or modify
00011     it under the terms of the GNU General Public License as published by
00012     the Free Software Foundation; either version 2 of the License, or
00013     (at your option) any later version.
00014     
00015     This program is distributed in the hope that it will be useful,
00016     but WITHOUT ANY WARRANTY; without even the implied warranty of
00017     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018     GNU General Public License for more details.
00019     
00020     You should have received a copy of the GNU General Public License
00021     along with this program; if not, write to the Free Software
00022     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
00023 */
00024 
00025 #if HAVE_CONFIG_H
00026 #include "config.h"
00027 #endif
00028 
00029 #include <string.h>
00030 
00031 #include "system.h"
00032 #include "mem.h"
00033 #include "error.h"
00034 
00035 #include "dpxfile.h"
00036 
00037 #include "numbers.h"
00038 #include "pdfobj.h"
00039 #include "pdfdev.h" /* pdf_rect */
00040 
00041 #include "pdfencoding.h"
00042 #include "pdffont.h"
00043 
00044 #include "pkfont.h"
00045 
00046 #define ENABLE_GLYPHENC  1
00047 
00048 #ifndef PKFONT_DPI_DEFAULT
00049 #define PKFONT_DPI_DEFAULT 600u
00050 #endif
00051 
00052 static unsigned base_dpi = PKFONT_DPI_DEFAULT;
00053 
00054 void
00055 PKFont_set_dpi (int dpi)
00056 {
00057   if (dpi <= 0)
00058     ERROR("Invalid DPI: %d\n", dpi);
00059   base_dpi = dpi;
00060 }
00061 
00062 
00063 /* (Only) This requires TFM to get design size... */
00064 #include "tfm.h"
00065 
00066 static unsigned
00067 truedpi (const char *ident, double point_size, unsigned bdpi)
00068 {
00069   unsigned  dpi = bdpi;
00070   double    design_size;
00071   int       tfm_id;
00072 
00073   tfm_id = MFOPEN(ident, FOPEN_RBIN_MODE);
00074   if (tfm_id < 0)
00075     return  dpi;
00076 
00077   design_size = tfm_get_design_size(tfm_id);
00078 
00079   MFCLOSE(tfm_id);
00080 
00081   if (design_size <= 0.0)
00082     WARN("DESGIN_SIZE <= 0.0? (TFM=\"%s\")", ident);
00083   else {
00084     dpi  = (unsigned) ROUND(base_dpi * point_size / design_size, 1.0);
00085   }
00086 
00087   return  dpi;
00088 }
00089 
00090 static FILE *
00091 dpx_open_pk_font_at (const char *ident, unsigned dpi)
00092 {
00093 #ifdef NOKPSE
00094   FILE  *fp;
00095   char  *fqpn;
00096   kpse_glyph_file_type kpse_file_info;
00097 
00098   fqpn = kpse_find_glyph(ident, dpi, kpse_pk_format, &kpse_file_info);
00099   if (!fqpn)
00100     return  NULL;
00101   fp   = MFOPEN(fqpn, FOPEN_RBIN_MODE);
00102   RELEASE(fqpn);
00103 
00104   return  fp;
00105 #else
00106   return NULL;
00107 #endif
00108 }
00109 
00110 
00111 int
00112 pdf_font_open_pkfont (pdf_font *font)
00113 {
00114   char     *ident;
00115   double    point_size;
00116   int       encoding_id;
00117   unsigned  dpi;
00118   FILE     *fp;
00119 
00120   ident       = pdf_font_get_ident(font);
00121   point_size  = pdf_font_get_param(font, PDF_FONT_PARAM_POINT_SIZE);
00122   encoding_id = pdf_font_get_encoding(font);
00123 
00124   if (!ident || point_size <= 0.0)
00125     return  -1;
00126 
00127   {
00128     char *fontfile =   pdf_font_get_fontfile  (font);
00129     char *tfmfile =   pdf_font_get_tfmfile  (font);
00130     
00131     if (fontfile)
00132       fp = MFOPEN(fontfile, FOPEN_RBIN_MODE);
00133     else
00134       fp = dpx_open_pk_font_at(ident, dpi);
00135 
00136     if (tfmfile) 
00137       dpi = truedpi(tfmfile, point_size, base_dpi);
00138     else 
00139       dpi = base_dpi;
00140   
00141   }
00142   
00143   if (!fp)
00144     return  -1;
00145   MFCLOSE(fp);
00146 
00147   /* Type 3 fonts doesn't have FontName.
00148    * FontFamily is recommended for PDF 1.5.
00149    */
00150   pdf_font_set_fontname(font, ident);
00151 
00152   if (encoding_id >= 0) {
00153     pdf_encoding_used_by_type3(encoding_id);
00154     WARN("PK font is found for font \"%s\" but non built-in encoding \"%s\" is specified.",
00155          ident, pdf_encoding_get_name(encoding_id));
00156 #if  ENABLE_GLYPHENC
00157     WARN(">> Assuming this is for glyph name assignment.");
00158 #else
00159     WARN(">> I can't reencode PK font. (not enough information available)");
00160     WARN(">> Maybe you need to install pfb/opentype/truetype font.");
00161 #endif
00162   }
00163 
00164   return  0;
00165 }
00166 
00167 
00168 /* We are using Mask Image. Fill black is bit clear.
00169  * Optimizing those codes doesn't improve things.
00170  */
00171 static long
00172 fill_black_run (unsigned char *dp, long left, long run_count)
00173 {
00174   const static unsigned char mask[8] = {
00175     127u, 191u, 223u, 239u, 247u, 251u, 253u, 254u
00176   };
00177   long  right = left + run_count - 1;
00178   for ( ; left <= right; left++) {
00179     dp[left / 8] &= mask[left % 8];
00180   }
00181   return  run_count;
00182 }
00183 
00184 /* Just skip bits. See decode_packed() */
00185 static long
00186 fill_white_run (unsigned char *dp, long left, long run_count)
00187 {
00188   return  run_count;
00189 }
00190 
00191 static long
00192 pk_packed_num (long *np, int dyn_f, unsigned char *dp, long pl)
00193 {
00194   long  nmbr = 0, i = *np;
00195   int   nyb, j;
00196 #define get_nyb() ((i % 2) ? dp[i/2] & 0x0f : (dp[i/2] >> 4) & 0x0f)
00197 
00198   if (i / 2 == pl) {
00199     WARN("EOD reached while unpacking pk_packed_num.");
00200     return  0;
00201   }
00202   nyb = get_nyb(); i++;
00203   if (nyb == 0) {
00204     j = 0;
00205     do {
00206       if (i / 2 == pl) {
00207         WARN("EOD reached while unpacking pk_packed_num.");
00208         break;
00209       }
00210       nyb = get_nyb(); i++;
00211       j++;
00212     } while (nyb == 0);
00213     nmbr = nyb;
00214     while (j-- > 0) {
00215       if (i / 2 == pl) {
00216         WARN("EOD reached while unpacking pk_packed_num.");
00217         break;
00218       }
00219       nyb  = get_nyb(); i++;
00220       nmbr = nmbr * 16 + nyb;
00221     }
00222     nmbr += (13 - dyn_f) * 16 + dyn_f - 15;
00223   } else if (nyb <= dyn_f) {
00224     nmbr = nyb;
00225   } else if (nyb < 14) {
00226     if (i / 2 == pl) {
00227       WARN("EOD reached while unpacking pk_packed_num.");
00228       return  0;
00229     }
00230     nmbr = (nyb - dyn_f - 1) * 16 + get_nyb() + dyn_f + 1;
00231     i++;
00232   }
00233 
00234   *np = i;
00235   return  nmbr;
00236 }
00237 
00238 
00239 #if  DEBUG == 2
00240 static void
00241 send_out (unsigned char *rowptr, long rowbytes, long  wd, pdf_obj *stream)
00242 #else
00243 static void
00244 send_out (unsigned char *rowptr, long rowbytes, pdf_obj *stream)
00245 #endif
00246 {
00247   pdf_add_stream(stream, (void *)rowptr, rowbytes);
00248 #if  DEBUG == 2
00249   {
00250     long  i, n, len = (wd + 7) / 8;
00251     int   c;
00252     fputc('|', stderr);
00253     for (n = 0; n < len; n++) {
00254       c = rowptr[n];
00255       for (i = 0; i < 8; i++) {
00256         if (n * 8 + i == wd)
00257           break;
00258         if (c & 1 << (7 - i))
00259           fputc(' ', stderr);
00260         else
00261           fputc('*', stderr);
00262       }
00263     }
00264     fputc('|', stderr);
00265     fputc('\n', stderr);
00266   }
00267 #endif /* DEBUG2 */
00268 }
00269 
00270 static int
00271 pk_decode_packed (pdf_obj *stream, long wd, long ht,
00272                   int dyn_f, int run_color, unsigned char *dp, long pl)
00273 {
00274   unsigned char  *rowptr;
00275   long            rowbytes;
00276   long            i, np = 0;
00277   long            run_count = 0, repeat_count = 0;
00278 
00279   rowbytes = (wd + 7) / 8;
00280   rowptr   = NEW(rowbytes, unsigned char);
00281   /* repeat count is applied to the *current* row.
00282    * "run" can span across rows.
00283    * If there are non-zero repeat count and if run
00284    * spans across row, first repeat and then continue.
00285    */
00286 #ifdef  DEBUG
00287   MESG("\npkfont>> wd: %ld, ht: %ld, dyn_f: %d\n", wd, ht, dyn_f);
00288 #endif
00289   for (np = 0, i = 0; i < ht; i++) {
00290     long  rowbits_left, nbits;
00291 
00292     repeat_count = 0;
00293     memset(rowptr, 0xff, rowbytes); /* 1 is white */
00294     rowbits_left = wd;
00295     /* Fill run left over from previous row */
00296     if (run_count > 0) {
00297       nbits = MIN(rowbits_left, run_count);
00298       switch (run_color) {
00299       case  0:
00300         rowbits_left -= fill_black_run(rowptr, 0, nbits);
00301         break;
00302       case  1:
00303         rowbits_left -= fill_white_run(rowptr, 0, nbits);
00304         break;
00305       }
00306       run_count -= nbits;
00307     }
00308 
00309     /* Read nybbles until we have a full row */
00310     while (np / 2 < pl && rowbits_left > 0) {
00311       int  nyb;
00312 
00313       nyb = (np % 2) ? dp[np/2] & 0x0f : (dp[np/2] >> 4) & 0x0f;
00314 #if  DEBUG == 3
00315       MESG("\npk_nyb: %d", nyb);
00316 #endif
00317       if (nyb == 14) { /* packed number "repeat_count" follows */
00318         if (repeat_count != 0)
00319           WARN("Second repeat count for this row!");
00320         np++; /* Consume this nybble */
00321         repeat_count = pk_packed_num(&np, dyn_f, dp, pl);
00322 #if  DEBUG == 3
00323         MESG(" --> rep: %ld\n", repeat_count);
00324 #endif
00325       } else if (nyb == 15) {
00326         if (repeat_count != 0)
00327           WARN("Second repeat count for this row!");
00328         np++; /* Consume this nybble */
00329         repeat_count = 1;
00330 #if  DEBUG == 3
00331         MESG(" --> rep: %ld\n", repeat_count);
00332 #endif
00333       } else { /* run_count */
00334         /* Interprete current nybble as packed number */
00335         run_count = pk_packed_num(&np, dyn_f, dp, pl);
00336 #if  DEBUG == 3
00337         MESG(" --> run: %ld (%d)\n", run_count, run_color);
00338 #endif
00339         nbits = MIN(rowbits_left, run_count);
00340         run_color  = !run_color;
00341         run_count -= nbits;
00342         switch (run_color) {
00343         case  0:
00344           rowbits_left -= fill_black_run(rowptr, wd - rowbits_left, nbits);
00345           break;
00346         case  1:
00347           rowbits_left -= fill_white_run(rowptr, wd - rowbits_left, nbits);
00348           break;
00349         }
00350       }
00351     }
00352     /* We got bitmap row data. */
00353 #if  DEBUG == 2
00354     send_out(rowptr, rowbytes, wd, stream);
00355 #else
00356     send_out(rowptr, rowbytes, stream);
00357 #endif
00358     for ( ; i < ht && repeat_count > 0; repeat_count--, i++)
00359 #if  DEBUG == 2
00360       send_out(rowptr, rowbytes, wd, stream);
00361 #else
00362     send_out(rowptr, rowbytes, stream);
00363 #endif
00364   }
00365   RELEASE(rowptr);
00366 
00367   return  0;
00368 }
00369 
00370 static int
00371 pk_decode_bitmap (pdf_obj *stream, long wd, long ht,
00372                   int dyn_f, int run_color, unsigned char *dp, long pl)
00373 {
00374   unsigned char  *rowptr, c;
00375   long            i, j, rowbytes;
00376   const static unsigned char mask[8] = {
00377     0x80u, 0x40u, 0x20u, 0x10u, 0x08u, 0x04u, 0x02u, 0x01u
00378   };
00379 
00380   ASSERT( dyn_f == 14 );
00381   if (run_color != 0) {
00382     WARN("run_color != 0 for bitmap pk data?");
00383   } else if (pl < (wd * ht + 7) / 8) {
00384     WARN("Insufficient bitmap pk data. %ldbytes expected but only %ldbytes read.",
00385          (wd * ht + 7) / 8, pl);
00386     return  -1;
00387   }
00388 
00389   rowbytes = (wd + 7) / 8;
00390   rowptr   = NEW(rowbytes, unsigned char);
00391   memset(rowptr, 0, rowbytes);
00392   /* Flip. PK bitmap is not byte aligned for each rows. */
00393   for (i = 0, j = 0; i < ht * wd; i++) {
00394     c = dp[i / 8] & mask[i % 8];
00395     if (c == 0)
00396       rowptr[j / 8] |= mask[i % 8]; /* flip bit */
00397     j++;
00398     if (j == wd) {
00399 #if  DEBUG == 2
00400       send_out(rowptr, rowbytes, wd, stream);
00401 #else
00402       send_out(rowptr, rowbytes, stream);
00403 #endif
00404       memset(rowptr, 0, rowbytes);
00405       j = 0;
00406     }
00407   }
00408 
00409   return  0;
00410 }
00411 
00412 
00413 /* Read PK font file */
00414 static void
00415 do_skip (FILE *fp, unsigned long length) 
00416 {
00417   while (length-- > 0)
00418     fgetc(fp);
00419 }
00420 
00421 static void
00422 do_preamble (FILE *fp)
00423 {
00424   /* Check for id byte */
00425   if (fgetc(fp) == 89) {
00426     /* Skip comment */
00427     do_skip(fp, get_unsigned_byte(fp));
00428     /* Skip other header info.  It's normally used for verifying this
00429        is the file wethink it is */
00430     do_skip(fp, 16);
00431   } else {
00432     ERROR("embed_pk_font: PK ID byte is incorrect.  Are you sure this is a PK file?");
00433   }
00434   return;
00435 }
00436 
00437 struct pk_header_
00438 {
00439   unsigned long  pkt_len;
00440   SIGNED_QUAD    chrcode;
00441   SIGNED_QUAD    wd, dx, dy;
00442   SIGNED_QUAD    bm_wd, bm_ht, bm_hoff, bm_voff;
00443   int            dyn_f, run_color;
00444 };
00445 
00446 static int
00447 read_pk_char_header (struct pk_header_ *h, unsigned char opcode, FILE *fp)
00448 {
00449   ASSERT(h);
00450 
00451   if ((opcode & 4) == 0) { /* short */
00452     h->pkt_len = (opcode & 3) * 0x100U + get_unsigned_byte(fp);
00453     h->chrcode = get_unsigned_byte(fp);
00454     h->wd = get_unsigned_triple(fp);     /* TFM width */
00455     h->dx = get_unsigned_byte(fp) << 16; /* horizontal escapement */
00456     h->dy = 0L;
00457     h->bm_wd    = get_unsigned_byte(fp);
00458     h->bm_ht    = get_unsigned_byte(fp);
00459     h->bm_hoff  = get_signed_byte(fp);
00460     h->bm_voff  = get_signed_byte(fp);
00461     h->pkt_len -= 8;
00462   } else if ((opcode & 7) == 7) { /* long */
00463     h->pkt_len = get_unsigned_quad(fp);
00464     h->chrcode = get_signed_quad(fp);
00465     h->wd = get_signed_quad(fp);
00466     h->dx = get_signed_quad(fp); /* 16.16 fixed point number in pixels */
00467     h->dy = get_signed_quad(fp);
00468     h->bm_wd    = get_signed_quad(fp);
00469     h->bm_ht    = get_signed_quad(fp);
00470     h->bm_hoff  = get_signed_quad(fp);
00471     h->bm_voff  = get_signed_quad(fp);
00472     h->pkt_len -= 28;
00473   } else { /* extended short */
00474     h->pkt_len = (opcode & 3) * 0x10000UL + get_unsigned_pair(fp);
00475     h->chrcode = get_unsigned_byte(fp);
00476     h->wd = get_unsigned_triple(fp);
00477     h->dx = get_unsigned_pair(fp) << 16;
00478     h->dy = 0x0L;
00479     h->bm_wd    = get_unsigned_pair(fp);
00480     h->bm_ht    = get_unsigned_pair(fp);
00481     h->bm_hoff  = get_signed_pair(fp);
00482     h->bm_voff  = get_signed_pair(fp);
00483     h->pkt_len -= 13;
00484   }
00485 
00486   h->dyn_f     = opcode / 16;
00487   h->run_color = (opcode & 8) ? 1 : 0;
00488 
00489   if (h->chrcode > 0xff)
00490   {
00491     WARN("Unable to handle long characters in PK files: code=0x%04x", h->chrcode);
00492     return  -1;
00493   }
00494 
00495   return  0;
00496 }
00497 
00498 /* CCITT Group 4 filter may reduce file size. */
00499 static pdf_obj *
00500 create_pk_CharProc_stream (struct pk_header_ *pkh,
00501                            double             chrwid,
00502                            unsigned char     *pkt_ptr, long pkt_len)
00503 {
00504   pdf_obj  *stream; /* charproc */
00505   long      llx, lly, urx, ury;
00506   int       len, error = 0;
00507 
00508   llx = -pkh->bm_hoff;
00509   lly =  pkh->bm_voff - pkh->bm_ht;
00510   urx =  pkh->bm_wd - pkh->bm_hoff;
00511   ury =  pkh->bm_voff;
00512 
00513   stream = pdf_new_stream(STREAM_COMPRESS);
00514   /*
00515    * The following line is a "metric" for the PDF reader:
00516    *
00517    * PDF Reference Reference, 4th ed., p.385.
00518    *
00519    * The wx (first operand of d1) must be consistent with the corresponding
00520    * width in the font's Widths array. The format string of sprint() must be
00521    * consistent with write_number() in pdfobj.c.
00522    */
00523   len = pdf_sprint_number(work_buffer, chrwid);
00524   len += sprintf (work_buffer + len, " 0 %ld %ld %ld %ld d1\n", llx, lly, urx, ury);
00525   pdf_add_stream(stream, work_buffer, len);
00526   /*
00527    * Acrobat dislike transformation [0 0 0 0 dx dy].
00528    * PDF Reference, 4th ed., p.147, says,
00529    *
00530    *   Use of a noninvertible matrix when painting graphics objects can result in
00531    *   unpredictable behavior.
00532    *
00533    * but it does not forbid use of such transformation.
00534    */
00535   if (pkh->bm_wd != 0 && pkh->bm_ht != 0 && pkt_len > 0) {
00536     /* Scale and translate origin to lower left corner for raster data */
00537     len = sprintf (work_buffer, "q\n%ld 0 0 %ld %ld %ld cm\n", pkh->bm_wd, pkh->bm_ht, llx, lly);
00538     pdf_add_stream(stream, work_buffer, len);
00539     len = sprintf (work_buffer, "BI\n/W %ld\n/H %ld\n/IM true\n/BPC 1\nID ", pkh->bm_wd, pkh->bm_ht);
00540     pdf_add_stream(stream, work_buffer, len);
00541     /* Add bitmap data */
00542     if (pkh->dyn_f == 14) /* bitmap */
00543       error = pk_decode_bitmap(stream,
00544                                pkh->bm_wd, pkh->bm_ht,
00545                                pkh->dyn_f, pkh->run_color,
00546                                pkt_ptr,    pkt_len);
00547     else
00548       error = pk_decode_packed(stream,
00549                                pkh->bm_wd, pkh->bm_ht,
00550                                pkh->dyn_f, pkh->run_color,
00551                                pkt_ptr,    pkt_len);
00552     len = sprintf (work_buffer, "\nEI\nQ");
00553     pdf_add_stream(stream, work_buffer, len);
00554   } /* Otherwise we embed an empty stream :-( */
00555 
00556   return  stream;
00557 }
00558 
00559 #define PK_XXX1  240
00560 #define PK_XXX2  241
00561 #define PK_XXX3  242
00562 #define PK_XXX4  243
00563 #define PK_YYY   244
00564 #define PK_POST  245
00565 #define PK_NO_OP 246
00566 #define PK_PRE   247
00567 
00568 #define pk_char2name(b,c) sprintf((b), "x%02X", (unsigned char)(c))
00569 int
00570 pdf_font_load_pkfont (pdf_font *font)
00571 {
00572   pdf_obj  *fontdict;
00573   char     *usedchars;
00574   char     *ident;
00575   unsigned  dpi;
00576   FILE     *fp;
00577   double    point_size, pix2charu;
00578   int       opcode, code, firstchar, lastchar, prev;
00579   pdf_obj  *charprocs, *procset, *encoding, *tmp_array;
00580   double    widths[256];
00581   pdf_rect  bbox;
00582   char      charavail[256];
00583 #if  ENABLE_GLYPHENC
00584   int       encoding_id;
00585   char    **enc_vec;
00586 #endif /* ENABLE_GLYPHENC */
00587   int       error = 0;
00588 
00589   if (!pdf_font_is_in_use(font)) {
00590     return 0;
00591   }
00592 
00593   ident       = pdf_font_get_ident(font);
00594   point_size  = pdf_font_get_param(font, PDF_FONT_PARAM_POINT_SIZE);
00595   usedchars   = pdf_font_get_usedchars(font);
00596 #if  ENABLE_GLYPHENC
00597   encoding_id = pdf_font_get_encoding(font);
00598   if (encoding_id < 0)
00599     enc_vec = NULL;
00600   else {
00601     enc_vec = pdf_encoding_get_encoding(encoding_id);
00602   }
00603 #endif /* ENABLE_GLYPHENC */
00604 
00605   ASSERT(ident && usedchars && point_size > 0.0);
00606 
00607   dpi  = truedpi(ident, point_size, base_dpi);
00608   
00609   {
00610     char *fontfile =   pdf_font_get_fontfile  (font);
00611     
00612     if (fontfile)
00613       fp = MFOPEN(fontfile, FOPEN_RBIN_MODE);
00614     else
00615       fp = dpx_open_pk_font_at(ident, dpi);
00616   }
00617   
00618   
00619   
00620   if (!fp) {
00621     ERROR("Could not find/open PK font file: %s (at %udpi)", ident, dpi);
00622   }
00623 
00624   memset(charavail, 0, 256);
00625   charprocs  = pdf_new_dict();
00626   /* Include bitmap as 72dpi image:
00627    * There seems to be problems in "scaled" bitmap glyph
00628    * rendering in several viewers.
00629    */
00630   pix2charu  = 72. * 1000. / ((double) base_dpi) / point_size;
00631   bbox.llx = bbox.lly =  HUGE_VAL;
00632   bbox.urx = bbox.ury = -HUGE_VAL;
00633   while ((opcode = fgetc(fp)) >= 0 && opcode != PK_POST) {
00634     if (opcode < 240) {
00635       struct pk_header_  pkh;
00636 
00637       error = read_pk_char_header(&pkh, opcode, fp);
00638       if (error)
00639         ERROR("Error in reading PK character header.");
00640       else if (charavail[pkh.chrcode & 0xff])
00641         WARN("More than two bitmap image for single glyph?: font=\"%s\" code=0x%02x",
00642              ident, pkh.chrcode);
00643 
00644       if (!usedchars[pkh.chrcode & 0xff])
00645         do_skip(fp, pkh.pkt_len);
00646       else {
00647         char          *charname;
00648         pdf_obj       *charproc;
00649         unsigned char *pkt_ptr;
00650         size_t         bytesread;
00651         double         charwidth;
00652 
00653         /* Charwidth in PDF units */
00654         charwidth = ROUND(1000.0 * pkh.wd / (((double) (1<<20))*pix2charu), 0.1);
00655         widths[pkh.chrcode & 0xff] = charwidth;
00656 
00657         /* Update font BBox info */
00658         bbox.llx = MIN(bbox.llx, -pkh.bm_hoff);
00659         bbox.lly = MIN(bbox.lly,  pkh.bm_voff - pkh.bm_ht);
00660         bbox.urx = MAX(bbox.urx,  pkh.bm_wd - pkh.bm_hoff);
00661         bbox.ury = MAX(bbox.ury,  pkh.bm_voff);
00662 
00663         pkt_ptr = NEW(pkh.pkt_len, unsigned char);
00664         if ((bytesread = fread(pkt_ptr, 1, pkh.pkt_len, fp))!= pkh.pkt_len) {
00665           ERROR("Only %ld bytes PK packet read. (expected %ld bytes)",
00666                 bytesread, pkh.pkt_len);
00667         }
00668         charproc = create_pk_CharProc_stream(&pkh, charwidth, pkt_ptr, bytesread);
00669         RELEASE(pkt_ptr);
00670         if (!charproc)
00671           ERROR("Unpacking PK character data failed.");
00672 #if  ENABLE_GLYPHENC
00673         if (encoding_id >= 0 && enc_vec) {
00674           charname = (char *) enc_vec[pkh.chrcode & 0xff];
00675           if (!charname) {
00676             WARN("\".notdef\" glyph used in font (code=0x%02x): %s", pkh.chrcode, ident);
00677             charname = work_buffer;
00678             pk_char2name(charname, pkh.chrcode);
00679           }
00680         }
00681         else
00682 #endif /* ENABLE_GLYPHENC */
00683         {
00684           charname = work_buffer;
00685           pk_char2name(charname, pkh.chrcode);
00686         }
00687 
00688         pdf_add_dict(charprocs, pdf_new_name(charname), pdf_ref_obj(charproc)); /* _FIXME_ */
00689         pdf_release_obj(charproc);
00690       }
00691       charavail[pkh.chrcode & 0xff] = 1;
00692     } else { /* A command byte */
00693       switch (opcode) {
00694       case PK_NO_OP: break;
00695       case PK_XXX1: do_skip(fp, get_unsigned_byte(fp));   break;
00696       case PK_XXX2: do_skip(fp, get_unsigned_pair(fp));   break;
00697       case PK_XXX3: do_skip(fp, get_unsigned_triple(fp)); break;
00698       case PK_XXX4: do_skip(fp, get_unsigned_quad(fp));   break;
00699       case PK_YYY:  do_skip(fp, 4);  break;
00700       case PK_PRE:  do_preamble(fp); break;
00701       }
00702     }
00703   }
00704   MFCLOSE(fp);
00705 
00706   /* Check if we really got all glyphs needed. */
00707   for (code = 0; code < 256; code++) {
00708     if (usedchars[code] && !charavail[code])
00709       WARN("Missing glyph code=0x%02x in PK font \"%s\".", code, ident);
00710   }
00711 
00712   /* Now actually fill fontdict. */
00713   fontdict = pdf_font_get_resource(font);
00714 
00715   pdf_add_dict(fontdict,
00716                pdf_new_name("CharProcs"), pdf_ref_obj(charprocs));
00717   pdf_release_obj(charprocs);
00718 
00719   /*
00720    * Resources:
00721    *
00722    *  PDF Reference 4th ed. describes it as "Optional but strongly recommended".
00723    *  There are no reason to put it in our case, but we will put this.
00724    *  We do not care about compatibility with Acrobat 2.x. (See implementation
00725    *  note 47, Appendix H of PDF Ref., 4th ed.).
00726    */
00727   procset   = pdf_new_dict();
00728   tmp_array = pdf_new_array();
00729   pdf_add_array(tmp_array, pdf_new_name("PDF"));
00730   pdf_add_array(tmp_array, pdf_new_name("ImageB"));
00731   pdf_add_dict(procset,
00732                pdf_new_name("ProcSet"), tmp_array);
00733   pdf_add_dict(fontdict,
00734                pdf_new_name("Resources"), procset);
00735 
00736   /* Encoding */
00737   tmp_array = pdf_new_array();
00738   prev = -2; firstchar = 255; lastchar = 0;
00739   for (code = 0; code < 256; code++) {
00740     char  *charname;
00741     if (usedchars[code]) {
00742       if (code < firstchar) firstchar = code;
00743       if (code > lastchar)  lastchar  = code;
00744       if (code != prev + 1)
00745         pdf_add_array(tmp_array, pdf_new_number(code));
00746 
00747 #if  ENABLE_GLYPHENC
00748       if (encoding_id >= 0 && enc_vec) {
00749         charname = (char *) enc_vec[(unsigned char) code];
00750         if (!charname) {
00751           charname = work_buffer;
00752           pk_char2name(charname, code);
00753         }
00754       }
00755       else
00756 #endif /* ENABLE_GLYPHENC */
00757       {
00758         charname = work_buffer;
00759         pk_char2name(charname, code);
00760       }
00761       pdf_add_array(tmp_array, pdf_new_name(charname));
00762       prev = code;
00763     }
00764   }
00765   if (firstchar > lastchar) {
00766     ERROR("Unexpected error: firstchar > lastchar (%d %d)",
00767           firstchar, lastchar);
00768     pdf_release_obj(tmp_array);
00769     return  -1;
00770   }
00771 #if  ENABLE_GLYPHENC
00772   if (encoding_id < 0 || !enc_vec) {
00773 #else
00774   if (1) {
00775 #endif /* ENABLE_GLYPHENC */
00776     encoding  = pdf_new_dict();
00777     pdf_add_dict(encoding,
00778                pdf_new_name("Type"), pdf_new_name("Encoding"));
00779     pdf_add_dict(encoding,
00780                pdf_new_name("Differences"), tmp_array);
00781     pdf_add_dict(fontdict,
00782                pdf_new_name("Encoding"),    pdf_ref_obj(encoding));
00783     pdf_release_obj(encoding);
00784   } else
00785     pdf_release_obj(tmp_array);
00786 
00787   /* FontBBox: Accurate value is important.
00788    */
00789   tmp_array = pdf_new_array();
00790   pdf_add_array(tmp_array, pdf_new_number(bbox.llx));
00791   pdf_add_array(tmp_array, pdf_new_number(bbox.lly));
00792   pdf_add_array(tmp_array, pdf_new_number(bbox.urx));
00793   pdf_add_array(tmp_array, pdf_new_number(bbox.ury));
00794   pdf_add_dict (fontdict , pdf_new_name("FontBBox"), tmp_array);
00795 
00796   /* Widths:
00797    *  Indirect reference preffered. (See PDF Reference)
00798    */
00799   tmp_array = pdf_new_array();
00800   for (code = firstchar; code <= lastchar; code++) {
00801     if (usedchars[code])
00802       pdf_add_array(tmp_array, pdf_new_number(widths[code]));
00803     else {
00804       pdf_add_array(tmp_array, pdf_new_number(0));
00805     }
00806   }
00807   pdf_add_dict(fontdict,
00808                pdf_new_name("Widths"), pdf_ref_obj(tmp_array));
00809   pdf_release_obj(tmp_array);
00810 
00811   /* FontMatrix */
00812   tmp_array = pdf_new_array();
00813   pdf_add_array(tmp_array, pdf_new_number(0.001 * pix2charu));
00814   pdf_add_array(tmp_array, pdf_new_number(0.0));
00815   pdf_add_array(tmp_array, pdf_new_number(0.0));
00816   pdf_add_array(tmp_array, pdf_new_number(0.001 * pix2charu));
00817   pdf_add_array(tmp_array, pdf_new_number(0.0));
00818   pdf_add_array(tmp_array, pdf_new_number(0.0));
00819   pdf_add_dict (fontdict , pdf_new_name("FontMatrix"), tmp_array);
00820 
00821 
00822   pdf_add_dict(fontdict,
00823                pdf_new_name("FirstChar"), pdf_new_number(firstchar));
00824   pdf_add_dict(fontdict,
00825                pdf_new_name("LastChar"),  pdf_new_number(lastchar));
00826 
00827   return  0;
00828 }