Back to index

tetex-bin  3.0
Classes | Defines | Functions | Variables
pkfont.c File Reference
#include <stdio.h>
#include "system.h"
#include "mem.h"
#include "error.h"
#include "mfileio.h"
#include "numbers.h"
#include "pkfont.h"
#include "pdfobj.h"
#include "pdflimits.h"
#include "tfm.h"
#include "ctype.h"

Go to the source code of this file.

Classes

struct  a_pk_font

Defines

#define advance_nybble()
#define current_nybble()   (partial_byte? (*pk_data%16): (*pk_data/16))
#define set_bits(n)
#define skip_bits(n)
#define get_bit(p, n)   (p[(n)/8] & (128u>>((n)%8)))
#define SHORT_FORM   1
#define MED_FORM   2
#define LONG_FORM   3
#define PK_XXX1   240
#define PK_XXX2   241
#define PK_XXX3   242
#define PK_XXX4   243
#define PK_YYY   244
#define PK_POST   245
#define PK_NO_OP   246
#define PK_PRE   247

Functions

void pk_set_verbose (void)
void pk_set_dpi (int dpi)
static void make_pk_encoding_ref (void)
static void release_pk_encoding_ref (void)
void init_pk_record (struct a_pk_font *p)
int pk_font (const char *tex_name, double ptsize, int tfm_font_id, char *res_name)
pdf_objpk_font_resource (int pk_id)
char * pk_font_used (int pk_id)
static void do_skip (unsigned long length)
static void add_raster_data (pdf_obj *glyph, long w, long h, int dyn_f, int run_color, unsigned char *pk_data, unsigned char *eod)
static void do_preamble (void)
static void do_character (unsigned char flag, int pk_id, pdf_obj *char_procs)
static void embed_pk_font (int pk_id)
void pk_close_all (void)

Variables

pdf_objpk_encoding_ref = NULL
static unsigned char verbose = 0
static unsigned char debug = 0
static unsigned font_dpi = 600
struct a_pk_fontpk_fonts
int num_pk_fonts = 0
int max_pk_fonts = 0
static FILEpk_file

Class Documentation

struct a_pk_font

Definition at line 85 of file pkfont.c.

Collaboration diagram for a_pk_font:
Class Members
pdf_obj * direct
pdf_obj * indirect
char * pk_file_name
double ptsize
char * tex_name
char * used_chars

Define Documentation

#define advance_nybble ( )
Value:
{ \
  if (partial_byte) { \
    partial_byte=0; \
    pk_data++; \
  } else \
    partial_byte=1; \
}
#define current_nybble ( )    (partial_byte? (*pk_data%16): (*pk_data/16))
#define get_bit (   p,
  n 
)    (p[(n)/8] & (128u>>((n)%8)))
#define LONG_FORM   3

Definition at line 408 of file pkfont.c.

#define MED_FORM   2

Definition at line 407 of file pkfont.c.

#define PK_NO_OP   246

Definition at line 552 of file pkfont.c.

#define PK_POST   245

Definition at line 551 of file pkfont.c.

#define PK_PRE   247

Definition at line 553 of file pkfont.c.

#define PK_XXX1   240

Definition at line 546 of file pkfont.c.

#define PK_XXX2   241

Definition at line 547 of file pkfont.c.

#define PK_XXX3   242

Definition at line 548 of file pkfont.c.

#define PK_XXX4   243

Definition at line 549 of file pkfont.c.

#define PK_YYY   244

Definition at line 550 of file pkfont.c.

#define set_bits (   n)
Value:
{\
  int i; \
  for (i=0; i<(n); i++) { \
    row[next_col] |= (128u>>next_bit++); \
    if (next_bit > 7) { \
      next_bit = 0; \
      next_col += 1; \
    } \
  } \
}
#define SHORT_FORM   1

Definition at line 406 of file pkfont.c.

#define skip_bits (   n)
Value:
{\
  next_col += (n)/8; \
  next_bit += (n)%8; \
  if (next_bit > 7) { \
    next_bit -= 8; \
    next_col += 1; \
  } \
}

Function Documentation

static void add_raster_data ( pdf_obj glyph,
long  w,
long  h,
int  dyn_f,
int  run_color,
unsigned char *  pk_data,
unsigned char *  eod 
) [static]

Definition at line 234 of file pkfont.c.

{ \
  if (partial_byte) { \
    partial_byte=0; \
    pk_data++; \
  } else \
    partial_byte=1; \
}

#define current_nybble() (partial_byte? (*pk_data%16): (*pk_data/16))
#define set_bits(n) {\
  int i; \
  for (i=0; i<(n); i++) { \
    row[next_col] |= (128u>>next_bit++); \
    if (next_bit > 7) { \
      next_bit = 0; \
      next_col += 1; \
    } \
  } \
}

#define skip_bits(n) {\
  next_col += (n)/8; \
  next_bit += (n)%8; \
  if (next_bit > 7) { \
    next_bit -= 8; \
    next_col += 1; \
  } \
}

#define get_bit(p,n) (p[(n)/8] & (128u>>((n)%8)))

{
  long i, w_bytes, repeat_count, run_count = 0;
  int partial_byte = 0;
  unsigned char *row;
  w_bytes = (w%8 == 0)? w/8: (w/8+1);
  row = NEW (w_bytes, unsigned char);
  /* Make sure we output "h" rows of data */
  if (dyn_f == 14) {
    for (i=0; i<h; i++) {
      int next_col = 0, next_bit = 0;
      int j;
      for (j=0; j<w_bytes; j++) row[j] = 0;
      for (j=0; j<w; j++) {
       if (get_bit(pk_data,i*w+j)) {
         skip_bits(1);
       }
       else {
         set_bits(1);
       }
      }
      pdf_add_stream (glyph, (char *) row, w_bytes);
    }
  } else
    for (i=0; i<h; i++) {
      int next_col = 0, next_bit = 0;
      int j, row_bits_left = w;
      /* Initialize row to all zeros */
      for (j=0; j<w_bytes; j++) row[j] = 0;
      repeat_count = 0;
      /* Fill any run left over from previous rows */
      if (run_count != 0) {
       int nbits;
       nbits = MIN (w, run_count);
       run_count -= nbits;
       switch (run_color) {
       case 1:  /* This is actually white ! */
         set_bits(nbits);
         break;
       case 0:
         skip_bits(nbits);
         break;
       }
       row_bits_left -= nbits;
      }
      /* Read nybbles until we have a full row */
      while (pk_data < eod && row_bits_left>0) {
       int com_nyb;
       long packed = 0;
       com_nyb = current_nybble();
       if (com_nyb == 15) {
         repeat_count = 1;
         advance_nybble();
         continue;
       }
       if (com_nyb == 14) {
         advance_nybble();
       }
       /* Get a packed number */
       {
         int nyb;
         nyb = current_nybble();
         /* Test for single nybble case */
         if (nyb > 0 && nyb <= dyn_f) {
           packed = nyb;
           advance_nybble();
         }
         if (nyb > dyn_f) {
           advance_nybble();
           packed = (nyb-dyn_f-1)*16+current_nybble()+dyn_f+1; 
           advance_nybble();
         }
         if (nyb == 0) {
           int nnybs = 1;
           while (current_nybble() == 0) {
             advance_nybble();
             nnybs += 1;
           }
           packed = 0;
           while (nnybs) {
             packed = packed*16 + current_nybble();
             advance_nybble();
             nnybs -= 1;
           }
           packed += (13-dyn_f)*16-15+dyn_f;
         }
       }
       if (com_nyb == 14) {
         repeat_count = packed;
         continue;
       }
       {
         int nbits;
         run_count = packed;    
         run_color = !run_color;
         nbits = MIN (row_bits_left, run_count);
         run_count -= nbits;
         row_bits_left -= nbits;
         switch (run_color) {
         case 1: 
           set_bits(nbits);
           break;
         case 0:
           skip_bits(nbits);
           break;
         }
       }
       continue;
      }
      pdf_add_stream (glyph, (char *) row, w_bytes);
      /* Duplicate the row "repeat_count" times */
      for (j=0; j<repeat_count; j++) {
       pdf_add_stream (glyph, (char *) row, w_bytes);
      }
      /* Skip repeat_count interations */
      i += repeat_count;
    }
  RELEASE (row);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void do_character ( unsigned char  flag,
int  pk_id,
pdf_obj char_procs 
) [static]

Definition at line 409 of file pkfont.c.

{
  int format;
  unsigned long packet_length = 0, code = 0;
  /* Last three bits of flag determine packet size in a complex way */
  if ((flag & 4) == 0) {
    format = SHORT_FORM;
  } else if ((flag & 7) == 7) {
    format = LONG_FORM;
  } else {
    format = MED_FORM;
  }
  if (debug) {
    fprintf (stderr, "packet format: %d\n", format);
  }
  switch (format) {
  case SHORT_FORM:
    packet_length = (flag & 3) * 256u + get_unsigned_byte (pk_file);
    code = get_unsigned_byte (pk_file);
    break;
  case MED_FORM:
    packet_length = (flag & 3) * 65536ul + get_unsigned_pair(pk_file);
    code = get_unsigned_byte (pk_file);
    break;
  case LONG_FORM:
    packet_length = get_unsigned_quad (pk_file);
    code = get_unsigned_quad (pk_file);
    if (code > 255)
      ERROR ("Unable to handle long characters in PK files");
    break;
  }
  if (debug) {
    fprintf (stderr, "\npk_do_character: code=%lu, packet_length=%lu\n",
            code, packet_length);
  }
  if ((pk_fonts[pk_id].used_chars)[code%256]) {
    int dyn_f;
    unsigned long tfm_width = 0;
    long dm=0, dx=0, dy=0, w=0, h=0;
    int hoff=0, voff=0;
    dyn_f = flag/16;
    switch (format) {
    case SHORT_FORM:
      tfm_width = get_unsigned_triple (pk_file);
      dm = get_unsigned_byte (pk_file);
      w = get_unsigned_byte (pk_file);
      h = get_unsigned_byte (pk_file);
      hoff = get_signed_byte (pk_file);
      voff = get_signed_byte (pk_file);
      packet_length -= 8;
      break;
    case MED_FORM:
      tfm_width = get_unsigned_triple (pk_file);
      dm = get_unsigned_pair (pk_file);
      w = get_unsigned_pair (pk_file);
      h = get_unsigned_pair (pk_file);
      hoff = get_signed_pair (pk_file);
      voff = get_signed_pair (pk_file);
      packet_length -= 13;
      break;
    case LONG_FORM:
      tfm_width = get_signed_quad (pk_file);
      dx = get_signed_quad (pk_file);
      dy = get_signed_quad (pk_file);
      w = get_signed_quad (pk_file);
      h = get_signed_quad (pk_file);
      hoff = get_signed_quad (pk_file);
      voff = get_signed_quad (pk_file);
      packet_length -= 28;
      break;
    }
    {
      pdf_obj *glyph;
      double char_width, llx, lly, urx, ury;
      double pix2charu;
      int len;
      pix2charu = 72000.0/((double) font_dpi)/pk_fonts[pk_id].ptsize;
      char_width = tfm_width / (double) (1<<20) * 1000.0;
      char_width = ROUND (char_width, 0.01);
      llx = -hoff*pix2charu;
      lly = (voff-h)*pix2charu;
      urx = (w-hoff)*pix2charu;
      ury = voff*pix2charu;
      glyph = pdf_new_stream(STREAM_COMPRESS);
      /* The following line is a "metric" for the PDF reader */
      sprintf (work_buffer, "%.2f %.2f %.2f %.2f %.2f %.2f d1",
              char_width, 0.0,
              llx, lly, urx, ury);
      len = strlen (work_buffer);
      pdf_add_stream (glyph, work_buffer, len);
      /* For now add an outline box for debugging purposes */
      /*      len = sprintf (work_buffer, " %.2f %.2f m %.2f %.2f l %.2f %.2f l %.2f %.2f l s",
                   llx, lly, urx, lly, urx, ury, llx, ury);
                   pdf_add_stream (glyph, work_buffer, len); */
      /* Scale and translate origin to lower left corner for raster data */
      sprintf (work_buffer, " q %.2f 0 0 %.2f %.2f %.2f cm",
              w*pix2charu, h*pix2charu, llx, lly);
      len = strlen (work_buffer);
      pdf_add_stream (glyph, work_buffer, len);
      if (w != 0 && h != 0 && packet_length != 0) {
       unsigned char *pk_data;
       long read_len;
       sprintf (work_buffer, "\nBI\n/W %ld\n/H %ld\n/IM true\n/BPC 1\n/I true\n", w, h);
        len = strlen (work_buffer);
       pdf_add_stream (glyph, work_buffer, len);
       sprintf (work_buffer, "ID ");
        len = strlen (work_buffer);
       pdf_add_stream (glyph, work_buffer, len);
       pk_data = NEW (packet_length, unsigned char);
       if ((read_len=fread (pk_data, 1, packet_length, pk_file))!=
           packet_length) {
         fprintf (stderr, "packet length should be %ld, but only %ld bytes were read\n",
                 packet_length, read_len);
         ERROR ("Error reading character packet from PK file\n");
       }
       add_raster_data (glyph, w, h, dyn_f, (flag&8)>>3, pk_data, pk_data+packet_length);
       RELEASE (pk_data);
       sprintf (work_buffer, "\nEI");
        len = strlen (work_buffer);
       pdf_add_stream (glyph, work_buffer, len);
      } /* Otherwise we embed an empty stream :-( */
      sprintf (work_buffer, "\nQ");
      len = strlen (work_buffer);
      pdf_add_stream (glyph, work_buffer, len);
      sprintf (work_buffer, "x%x", (int)code%256);
      pdf_add_dict (char_procs, pdf_new_name (work_buffer),
                  pdf_ref_obj (glyph));
      pdf_release_obj (glyph);
    }
  } else {
    if (debug)
      fprintf (stderr, "\npk_do_character: Skipping code=%ld, length=%ld\n", code,
              packet_length);
    do_skip (packet_length);
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void do_preamble ( void  ) [static]

Definition at line 391 of file pkfont.c.

{
  /* Check for id byte */
  if (fgetc (pk_file) == 89) {
    /* Skip comment */
    do_skip (get_unsigned_byte (pk_file));
    /* Skip other header info.  It's normally used for verifying this
       is the file wethink it is */
    do_skip (16);
  } else {
    ERROR ("embed_pk_font: PK ID byte is incorrect.  Are you sure this is a PK file?");
  }
  return;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void do_skip ( unsigned long  length) [static]

Definition at line 226 of file pkfont.c.

{
  unsigned long i;
  for (i=0; i<length; i++) 
    fgetc (pk_file);
  return;
}

Here is the caller graph for this function:

static void embed_pk_font ( int  pk_id) [static]

Definition at line 555 of file pkfont.c.

{
  if (verbose)
    fprintf (stderr, "(%s", pk_fonts[pk_id].pk_file_name);
  if ((pk_file = MFOPEN (pk_fonts[pk_id].pk_file_name,
                     FOPEN_RBIN_MODE))) {
    int pk_command_byte;
    pdf_obj *char_procs;
    char_procs = pdf_new_dict();
    while ((pk_command_byte = fgetc(pk_file)) >= 0 &&
          pk_command_byte != PK_POST) {
      if (pk_command_byte < 240) {
       do_character (pk_command_byte, pk_id, char_procs);
      } else  /* A command byte */
       switch (pk_command_byte) {
       case PK_NO_OP:
         break;
       case PK_XXX1:
         do_skip(get_unsigned_byte(pk_file));
         break;
       case PK_XXX2:
         do_skip(get_unsigned_pair(pk_file));
         break;
       case PK_XXX3:
         do_skip(get_unsigned_triple(pk_file));
         break;
       case PK_XXX4:
         do_skip(get_unsigned_quad(pk_file));
         break;
       case PK_YYY:
         do_skip(4);
         break;
       case PK_PRE:
         do_preamble();
         break;
       }
    }
    MFCLOSE (pk_file);
    if (verbose) 
      fprintf (stderr, ")\n");
    pdf_add_dict (pk_fonts[pk_id].direct,
                pdf_new_name ("CharProcs"),
                pdf_ref_obj(char_procs));
    pdf_release_obj (char_procs);
  } else {
    ERROR ("embed_pk_font: Failed to open PK file");
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void init_pk_record ( struct a_pk_font p)

Definition at line 93 of file pkfont.c.

{
  int i;
  p->used_chars = NEW (256, char);
  for (i=0; i<256; i++) {
    (p->used_chars)[i] = 0;
  }
  p->tex_name = NULL;
  p->pk_file_name = NULL;
}

Here is the caller graph for this function:

static void make_pk_encoding_ref ( void  ) [static]

Definition at line 54 of file pkfont.c.

{
  static char first = 1;
  if (first) {
    int i;
    pdf_obj *encoding, *differences;
    encoding = pdf_new_dict();
    pdf_add_dict (encoding, 
                pdf_new_name ("Type"),
                pdf_new_name ("Encoding"));
    differences = pdf_new_array();
    pdf_add_dict (encoding,
                pdf_new_name ("Differences"),
                differences);
    pdf_add_array (differences, pdf_new_number (0.0));
    for (i=0; i<256; i++) {
      sprintf (work_buffer, "x%x", i);
      pdf_add_array (differences, pdf_new_name(work_buffer));
    }
    pk_encoding_ref = pdf_ref_obj (encoding);
    pdf_release_obj (encoding);
  }
  first = 0;
  return;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 604 of file pkfont.c.

{
  int i;
  if (pk_encoding_ref)
    pdf_release_obj (pk_encoding_ref);
  for (i=0; i<num_pk_fonts; i++) {
    embed_pk_font (i);
    pdf_release_obj (pk_fonts[i].direct);
    pdf_release_obj (pk_fonts[i].indirect);
    RELEASE (pk_fonts[i].tex_name);
    RELEASE (pk_fonts[i].pk_file_name);
    RELEASE (pk_fonts[i].used_chars);
  }
  if (pk_fonts)
    RELEASE (pk_fonts);
}

Here is the call graph for this function:

Here is the caller graph for this function:

int pk_font ( const char *  tex_name,
double  ptsize,
int  tfm_font_id,
char *  res_name 
)

Definition at line 107 of file pkfont.c.

{
  int i, j;
  int firstchar, lastchar;
  pdf_obj *tmp1;
  for (i=0; i<num_pk_fonts; i++) {
    if (!strcmp (tex_name, pk_fonts[i].tex_name) &&
       (ptsize == pk_fonts[i].ptsize))
      break;
  }
  if (i == num_pk_fonts) {
    char *pk_file_name;
    kpse_glyph_file_type kpse_file_info;
    if ((pk_file_name = kpse_find_glyph(tex_name,
                                   font_dpi*ptsize/tfm_get_design_size(tfm_font_id)+0.5,
                                   kpse_pk_format,
                                   &kpse_file_info))) {
      /* Make sure there is enough room in pk_fonts for this entry */
      if (num_pk_fonts >= max_pk_fonts) {
       max_pk_fonts += MAX_FONTS;
       pk_fonts = RENEW (pk_fonts, max_pk_fonts, struct a_pk_font);
      }
      init_pk_record (pk_fonts+i);
      pk_fonts[i].pk_file_name = NEW (strlen(pk_file_name)+1, char);
      strcpy (pk_fonts[i].pk_file_name, pk_file_name);
      pk_fonts[i].tex_name = NEW (strlen (tex_name)+1, char);
      strcpy (pk_fonts[i].tex_name, tex_name);
      pk_fonts[i].ptsize = ptsize;
      pk_fonts[i].direct = pdf_new_dict ();
      pdf_add_dict (pk_fonts[i].direct,
                  pdf_new_name ("Type"),
                  pdf_new_name ("Font"));
      pdf_add_dict (pk_fonts[i].direct,
                  pdf_new_name ("Name"),
                  pdf_new_name (res_name));
      pdf_add_dict (pk_fonts[i].direct,
                  pdf_new_name ("Subtype"),
                  pdf_new_name ("Type3"));
      firstchar = tfm_get_firstchar(tfm_font_id);
      pdf_add_dict (pk_fonts[i].direct,
                  pdf_new_name ("FirstChar"),
                  pdf_new_number (firstchar));
      lastchar = tfm_get_lastchar(tfm_font_id);
      pdf_add_dict (pk_fonts[i].direct,
                  pdf_new_name ("LastChar"),
                  pdf_new_number (lastchar));
      tmp1 = pdf_new_array ();
      for (j=firstchar; j<=lastchar; j++) {
       pdf_add_array (tmp1,
                     pdf_new_number(ROUND(tfm_get_width (tfm_font_id, j)*1000.0,0.01)));
      }
      pdf_add_dict (pk_fonts[i].direct,
                  pdf_new_name ("Widths"),
                  tmp1);
      {
       double max_height, max_depth, max_width;
       max_height = tfm_get_max_height (tfm_font_id)*1000.0;
       max_depth = tfm_get_max_depth (tfm_font_id)*1000.0;
       max_width = tfm_get_max_width (tfm_font_id)*1000.0;
       max_height = ROUND(max_height, 1.0);
       max_depth = ROUND(max_depth, 1.0);
       max_width = ROUND(max_width, 1.0);
       tmp1 = pdf_new_array();
       pdf_add_array (tmp1, pdf_new_number(-0.10*max_width));
       pdf_add_array (tmp1,
                     pdf_new_number(-max_depth-0.20*(max_height+max_depth)));
       pdf_add_array (tmp1, pdf_new_number(1.10*max_width));
       pdf_add_array (tmp1, pdf_new_number(max_height+0.10*(max_height+max_depth)));
       pdf_add_dict (pk_fonts[i].direct, 
                    pdf_new_name ("FontBBox"), tmp1);
      }
      {
       tmp1 = pdf_new_array();
       pdf_add_array (tmp1, pdf_new_number (0.001));
       pdf_add_array (tmp1, pdf_new_number (0.0));
       pdf_add_array (tmp1, pdf_new_number (0.0));
       pdf_add_array (tmp1, pdf_new_number (0.001));
       pdf_add_array (tmp1, pdf_new_number (0.0));
       pdf_add_array (tmp1, pdf_new_number (0.0));
       pdf_add_dict (pk_fonts[i].direct, pdf_new_name ("FontMatrix"),
                    tmp1);
      }
      if (pk_encoding_ref == NULL) {
       make_pk_encoding_ref();
      }
      pdf_add_dict (pk_fonts[i].direct,
                  pdf_new_name ("Encoding"),
                  pdf_link_obj (pk_encoding_ref));
      pk_fonts[i].indirect = pdf_ref_obj (pk_fonts[i].direct);
      num_pk_fonts += 1;
    } else { /* Found no glyph file */
      i = -1;
    }
  }
  return i;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 205 of file pkfont.c.

{
  if (pk_id <0 || pk_id >= num_pk_fonts) {
    fprintf (stderr, "pk_id = %d\n", pk_id);
    ERROR ("pk_font_resource:  Invalid pk_id\n");
  }
  return pdf_link_obj (pk_fonts[pk_id].indirect);
}

Here is the call graph for this function:

Here is the caller graph for this function:

char* pk_font_used ( int  pk_id)

Definition at line 214 of file pkfont.c.

{
  if (pk_id < 0 || pk_id >= num_pk_fonts) {
    fprintf (stderr, "pk_id = %d\n", pk_id);
    ERROR ("pk_font_used:  Invalid pk_id\n");
  }
  return pk_fonts[pk_id].used_chars;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void pk_set_dpi ( int  dpi)

Definition at line 48 of file pkfont.c.

{
  font_dpi = dpi;
}

Here is the caller graph for this function:

Definition at line 41 of file pkfont.c.

{
  if (verbose < 255) {
    verbose += 1;
  }
}

Here is the caller graph for this function:

static void release_pk_encoding_ref ( void  ) [static]

Definition at line 80 of file pkfont.c.

Here is the call graph for this function:


Variable Documentation

unsigned char debug = 0 [static]

Definition at line 38 of file pkfont.c.

unsigned font_dpi = 600 [static]

Definition at line 39 of file pkfont.c.

Definition at line 105 of file pkfont.c.

Definition at line 105 of file pkfont.c.

Definition at line 37 of file pkfont.c.

FILE* pk_file [static]

Definition at line 224 of file pkfont.c.

struct a_pk_font * pk_fonts
unsigned char verbose = 0 [static]

Definition at line 38 of file pkfont.c.