TTF/TTC to CIDFontType2 patch

Ling Li <[email protected]>
Newsgroups gmane.comp.gnome.print
Organization Beijing Institute of Technology
Message-ID <20040414041427.GA4696@liling-coral>
Hi all,

I found that in gnome-print, large TTF/TTC fonts for CJK characters is
converted to Type1 font by ttf2pt1. This method has changed the font and it
looks not exactly the same as original TTF/TTC ones.

In order to subset large TTF/TTC font into PostScript, Adobe has developed
Type 2 CIDFont, it's a extension to Type 42 font.

I have write a patch to make gnome-print use CIDFontType2 when its too large
for Type 42 font. I have tested it using Chinese SimSun font and gs-gpl 8.0.
(In gs-esp 7, theirs some bug to deal metrics data saved in GlyphDirectory.)

The patch is in attachment and it should be applied to files in libgnomeprint
directory. File gp-tt-cid2.c and gp-tt-cid2.h should be put in that directory
too.
cid2.patch (text/plain, 12.7 KB)
Index: gnome-font-face.c
===================================================================
RCS file: /cvs/gnome/libgnomeprint/libgnomeprint/gnome-font-face.c,v
retrieving revision 1.75
diff -r1.75 gnome-font-face.c
44a45
> #include <libgnomeprint/gp-tt-cid2.h>
849,852c850,853
<  		{
<  			found = charmap;
<  			break;
<  		}
---
> 			{
> 				found = charmap;
> 				break;
> 			}
1128d1128
< 
1335a1336,1338
> void sfnts_write_byte_array (GnomeFontPsObject *pso, GByteArray* array);
> void sfnts_write_tt_table (GnomeFontPsObject *pso, const guchar *buf, guint buf_len, struct tt_table *table);
> 
1344a1348,1349
> 	GHashTable *tables;
> 	GByteArray *head;
1350a1356,1357
> 	guchar *required[] = {"head", "prep", "cvt ", "hhea", "fpgm", "maxp", "vhea", "gdir", NULL};
> 	gint metrics_count, num_glyphs;
1427,1443d1433
< 	} else {
< 		guchar *afm;
< 		/* This is somewhat experimental - convert TTF to Type1 */
< 		afm = ttf2pfa (pso->face->ft_face, embeddedname, pso->glyphs);
< 		if (!afm) {
< 			gnome_print_buffer_munmap (&b);
< 			g_warning ("file %s: line %d: Cannot convert TTF %s to Type1", __FILE__, __LINE__, file_name);
< 			gnome_font_face_ps_embed_empty (pso);
< 			return;
< 		}
< 		/* We take over ownership of afm here (be careful) */
< 		pso->buf = afm;
< 		pso->bufsize = strlen (afm);
< 		pso->length = pso->bufsize;
< 	}
< 
< 	gnome_print_buffer_munmap (&b);
1445,1491c1435,1449
< 	/*
< 	 * We have font downloaded (hopefully)
< 	 *
< 	 * With CharStrings: .nodef _1 _2 _3
< 	 *
< 	 * Now we have to build usable 2-byte encoded font from it
< 	 *
< 	 */
< 
< 	/* fixme: That is crap. We should use CID */
< 	/* Bitch 'o' bitches (Lauris) ! */
< 	if (pso->face->num_glyphs < 256) {
< 		gint glyph;
< 		/* 8-bit vector */
< 		pso->encodedbytes = 1;
< 		gf_pso_sprintf (pso, "(%s) cvn findfont dup length dict begin\n", embeddedname);
< 		gf_pso_sprintf (pso, "{1 index /FID ne {def} {pop pop} ifelse} forall\n");
< 		gf_pso_sprintf (pso, "/Encoding [\n");
< 		for (glyph = 0; glyph < 256; glyph++) {
< 			guint g;
< 			g = (glyph < pso->face->num_glyphs) ? glyph : 0;
< 			if ((g == 0) || !PSO_GLYPH_MARKED (pso, glyph)) {
< 				gf_pso_sprintf (pso, ((glyph & 0xf) == 0xf) ? "/.notdef\n" : "/.notdef ", g);
< 			} else {
< 				gf_pso_sprintf (pso, ((glyph & 0xf) == 0xf) ? "/_%d\n" : "/_%d ", g);
< 			}
< 		}
< 		gf_pso_sprintf (pso, "] def currentdict end\n");
< 		gf_pso_sprintf (pso, "(%s) cvn exch definefont pop\n", pso->encodedname);
< 	} else {
< 		gint nfonts, nglyphs, i, j;
< 		/* 16-bit vector */
< 		pso->encodedbytes = 2;
< 		nglyphs = pso->face->num_glyphs;
< 		nfonts = (nglyphs + 255) >> 8;
< 
< 		gf_pso_sprintf (pso, "32 dict begin\n");
< 		/* Common entries */
< 		gf_pso_sprintf (pso, "/FontType 0 def\n");
< 		gf_pso_sprintf (pso, "/FontMatrix [1 0 0 1 0 0] def\n");
< 		gf_pso_sprintf (pso, "/FontName (%s-Glyph-Composite) cvn def\n", embeddedname);
< 		gf_pso_sprintf (pso, "/LanguageLevel 2 def\n");
< 		/* Type 0 entries */
< 		gf_pso_sprintf (pso, "/FMapType 2 def\n");
< 		/* Bitch 'o' bitches */
< 		gf_pso_sprintf (pso, "/FDepVector [\n");
< 		for (i = 0; i < nfonts; i++) {
---
> 		/*
> 		 * We have font downloaded (hopefully)
> 		 *
> 		 * With CharStrings: .nodef _1 _2 _3
> 		 *
> 		 * Now we have to build usable 2-byte encoded font from it
> 		 *
> 		 */
> 		
> 		/* fixme: That is crap. We should use CID */
> 		/* Bitch 'o' bitches (Lauris) ! */
> 		if (pso->face->num_glyphs < 256) {
> 			gint glyph;
> 			/* 8-bit vector */
> 			pso->encodedbytes = 1;
1495,1501c1453,1457
< 			for (j = 0; j < 256; j++) {
< 				gint glyph;
< 				glyph = 256 * i + j;
< 				if (glyph >= nglyphs)
< 					glyph = 0;
< 				if ((glyph == 0) || !PSO_GLYPH_MARKED (pso, glyph)) {
< 					gf_pso_sprintf (pso, ((j & 0xf) == 0xf) ? "/.notdef\n" : "/.notdef ");
---
> 			for (glyph = 0; glyph < 256; glyph++) {
> 				guint g;
> 				g = (glyph < pso->face->num_glyphs) ? glyph : 0;
> 				if ((g == 0) || !PSO_GLYPH_MARKED (pso, glyph)) {
> 					gf_pso_sprintf (pso, ((glyph & 0xf) == 0xf) ? "/.notdef\n" : "/.notdef ", g);
1503c1459,1494
< 					gf_pso_sprintf (pso, ((j & 0xf) == 0xf) ? "/_%d\n" : "/_%d ", glyph);
---
> 					gf_pso_sprintf (pso, ((glyph & 0xf) == 0xf) ? "/_%d\n" : "/_%d ", g);
> 				}
> 			}
> 			gf_pso_sprintf (pso, "] def currentdict end\n");
> 			gf_pso_sprintf (pso, "(%s) cvn exch definefont pop\n", pso->encodedname);
> 		} else {
> 			gint nfonts, nglyphs, i, j;
> 			/* 16-bit vector */
> 			pso->encodedbytes = 2;
> 			nglyphs = pso->face->num_glyphs;
> 			nfonts = (nglyphs + 255) >> 8;
> 
> 			gf_pso_sprintf (pso, "32 dict begin\n");
> 			/* Common entries */
> 			gf_pso_sprintf (pso, "/FontType 0 def\n");
> 			gf_pso_sprintf (pso, "/FontMatrix [1 0 0 1 0 0] def\n");
> 			gf_pso_sprintf (pso, "/FontName (%s-Glyph-Composite) cvn def\n", embeddedname);
> 			gf_pso_sprintf (pso, "/LanguageLevel 2 def\n");
> 			/* Type 0 entries */
> 			gf_pso_sprintf (pso, "/FMapType 2 def\n");
> 			/* Bitch 'o' bitches */
> 			gf_pso_sprintf (pso, "/FDepVector [\n");
> 			for (i = 0; i < nfonts; i++) {
> 				gf_pso_sprintf (pso, "(%s) cvn findfont dup length dict begin\n", embeddedname);
> 				gf_pso_sprintf (pso, "{1 index /FID ne {def} {pop pop} ifelse} forall\n");
> 				gf_pso_sprintf (pso, "/Encoding [\n");
> 				for (j = 0; j < 256; j++) {
> 					gint glyph;
> 					glyph = 256 * i + j;
> 					if (glyph >= nglyphs)
> 						glyph = 0;
> 					if ((glyph == 0) || !PSO_GLYPH_MARKED (pso, glyph)) {
> 						gf_pso_sprintf (pso, ((j & 0xf) == 0xf) ? "/.notdef\n" : "/.notdef ");
> 					} else {
> 						gf_pso_sprintf (pso, ((j & 0xf) == 0xf) ? "/_%d\n" : "/_%d ", glyph);
> 					}
1504a1496,1497
> 				gf_pso_sprintf (pso, "] def\n");
> 				gf_pso_sprintf (pso, "currentdict end (%s-Glyph-Page-%d) cvn exch definefont\n", embeddedname, i);
1507c1500,1508
< 			gf_pso_sprintf (pso, "currentdict end (%s-Glyph-Page-%d) cvn exch definefont\n", embeddedname, i);
---
> 			gf_pso_sprintf (pso, "/Encoding [\n");
> 			for (i = 0; i < 256; i++) {
> 				gint fn;
> 				fn = (i < nfonts) ? i : 0;
> 				gf_pso_sprintf (pso, ((i & 0xf) == 0xf) ? "%d\n" : "%d  ", fn);
> 			}
> 			gf_pso_sprintf (pso, "] def\n");
> 			gf_pso_sprintf (pso, "currentdict end\n");
> 			gf_pso_sprintf (pso, "(%s) cvn exch definefont pop\n", pso->encodedname);
1508a1510,1547
> 
> 	} else {
> 		tables = gp_tt_get_tables (fbuf, b.buf_size, pso->face->entry->index);
> 		/* Relatively easy - just embed TTF into PS stream */
> 		/* Download master font */
> 		TTVersion = 1.0;
> 		MfrRevision = 1.0;
> 		gf_pso_sprintf (pso, "%%!PS-TrueTypeFont-");
> 		gf_pso_print_double (pso, "%g", TTVersion);
> 		gf_pso_sprintf (pso, "-");
> 		gf_pso_print_double (pso, "%g", MfrRevision);
> 		gf_pso_sprintf (pso, "\n");
> 
> 		gf_pso_sprintf (pso, "/CIDInit /ProcSet findresource begin\n\n");
> 		gf_pso_sprintf (pso, "20 dict begin\n");
> 		gf_pso_sprintf (pso, "/CIDFontName (%s) cvn def\n", embeddedname);
> 		gf_pso_sprintf (pso, "/CIDFontVersion 1 def\n");
> 		gf_pso_sprintf (pso, "/CIDFontType 2 def\n");
> 		gf_pso_sprintf (pso, "/FontType 42 def\n");
> 		gf_pso_sprintf (pso, "/CIDSystemInfo 3 dict dup begin\n");
> 		gf_pso_sprintf (pso, "  /Registry (Adobe) def\n");
> 		gf_pso_sprintf (pso, "  /Ordering (Identity) def\n");
> 		gf_pso_sprintf (pso, "  /Supplement 0 def\n");
> 		gf_pso_sprintf (pso, "  end def\n");
> 		gf_pso_sprintf (pso, "/CIDCount %d def\n", pso->face->num_glyphs);
> 		gf_pso_sprintf (pso, "/GDBytes 2 def\n");
> 		gf_pso_sprintf (pso, "/CIDMap 0 def\n");
> 		gf_pso_sprintf (pso, "/PaintType 0 def\n");
> 		gf_pso_sprintf (pso, "/FontMatrix [1 0 0 1 0 0] def\n");
> 		bbox = gnome_font_face_get_stdbbox (pso->face);
> 		gf_pso_sprintf (pso, "/FontBBox [");
> 		gf_pso_print_double (pso, "%g",  bbox->x0);
> 		gf_pso_sprintf (pso, " ");
> 		gf_pso_print_double (pso, "%g", bbox->y0);
> 		gf_pso_sprintf (pso, " ");
> 		gf_pso_print_double (pso, "%g",  bbox->x1);
> 		gf_pso_sprintf (pso, " ");
> 		gf_pso_print_double (pso, "%g",  bbox->y1);
1510,1514c1549,1562
< 		gf_pso_sprintf (pso, "/Encoding [\n");
< 		for (i = 0; i < 256; i++) {
< 			gint fn;
< 			fn = (i < nfonts) ? i : 0;
< 			gf_pso_sprintf (pso, ((i & 0xf) == 0xf) ? "%d\n" : "%d  ", fn);
---
> 		gf_pso_sprintf (pso, "/Encoding [] readonly def\n");
> 		gf_pso_sprintf (pso, "/CharStrings 1 dict dup begin\n");
> 		gf_pso_sprintf (pso, "  /.notdef 0 def\n");
> 		gf_pso_sprintf (pso, "  end readonly def\n");
> 		gf_pso_sprintf (pso, "/sfnts [\n");
> 		head = gp_tt_build_header (fbuf, b.buf_size, tables, required);
> 		sfnts_write_byte_array (pso, head);
> 		g_byte_array_free (head, TRUE);
> 		i = 0;
> 		for (i = 0; required[i] != NULL; i++) {
> 			struct tt_table *table;
> 			table = (struct tt_table *) g_hash_table_lookup (tables, (gpointer) required[i]);
> 			if (table == NULL) continue;
> 			sfnts_write_tt_table (pso, fbuf, b.buf_size, table);
1517,1518c1565,1629
< 		gf_pso_sprintf (pso, "currentdict end\n");
< 		gf_pso_sprintf (pso, "(%s) cvn exch definefont pop\n", pso->encodedname);
---
> 
> 		metrics_count = 0;
> 		if (g_hash_table_lookup (tables, "hmtx")) {
> 			metrics_count += 2;
> 			if (g_hash_table_lookup (tables, "vmtx")) {
> 				metrics_count += 2;
> 			}
> 		}
> 		gf_pso_sprintf (pso, "/MetricsCount %d def\n", metrics_count);
> 		num_glyphs = 1;
> 		for (i = 0; i < pso->face->num_glyphs; i++) {
> 			if (PSO_GLYPH_MARKED(pso, i)) num_glyphs++;
> 		}
> 		gf_pso_sprintf (pso, "/GlyphDirectory %d dict dup begin\n", num_glyphs);
> 		for (i = 0; i < pso->face->num_glyphs; i++) {
> 			GByteArray *glyph_desc;
> 			if (i != 0 && ! PSO_GLYPH_MARKED(pso, i)) continue;
> 			gf_pso_sprintf (pso, "  %d ", i);
> 			glyph_desc = gp_tt_get_glyph_desc(fbuf, b.buf_size, tables, i, metrics_count);
> 			sfnts_write_byte_array(pso, glyph_desc);
> 			g_byte_array_free (glyph_desc, TRUE);
> 			gf_pso_sprintf (pso, "    def\n");
> 		}
> 		gf_pso_sprintf (pso, "  end def\n");
> 		gf_pso_sprintf (pso, "CIDFontName currentdict end /CIDFont defineresource pop\n\n");
> 
> 		gf_pso_sprintf (pso, "(%s) cvn /Identity-H /CMap findresource[(%s) cvn /CIDFont findresource] composefont pop\n", pso->encodedname, embeddedname);
> 		g_hash_table_destroy (tables);
> 	}
> 	
> 	gnome_print_buffer_munmap (&b);
> }
> 
> void
> sfnts_write_byte_array (GnomeFontPsObject *pso, GByteArray* array)
> {
> 	guint i, j;
> 	guint8 *b;
> 
> 	gf_pso_sprintf (pso, "<");
> 	for (b = array->data, i = 0; i < array->len; i += 32) {
> 		for (j = 0; j < 32 && (i + j) < array->len; j++)
> 			gf_pso_sprintf(pso, "%02x", *b++);
> 		if (j == 32)
> 			gf_pso_sprintf(pso, "\n");
> 	}
> 	gf_pso_sprintf (pso, "00>\n");
> }
> 
> void
> sfnts_write_tt_table (GnomeFontPsObject *pso, const guchar *buf, guint buf_len, struct tt_table *table)
> {
> 	const guchar *b;
> 	guint32 i, j;
> 	
> 	gf_pso_sprintf (pso, "<");
> 	for (b = buf + table->offset, i = 0; i < table->length; i+=32) {
> 		for (j = 0; j < 32 && (i + j) < table->length; j++)
> 			gf_pso_sprintf(pso, "%02x", *b++);
> 		if (j == 32)
> 			gf_pso_sprintf(pso, "\n");
> 	}
> 	if (table->length % 4 != 0) {
> 		for (i = 0; i < (4 - table->length % 4); i++)
> 			gf_pso_sprintf(pso, "00");
1519a1631
> 	gf_pso_sprintf (pso, "00>\n");
Index: gnome-print-ps2.c
===================================================================
RCS file: /cvs/gnome/libgnomeprint/libgnomeprint/gnome-print-ps2.c,v
retrieving revision 1.79
diff -r1.79 gnome-print-ps2.c
47a48
> #define CMAP_IDENTITY "/CIDInit /ProcSet findresource begin\n10 dict begin\n  begincmap\n  /CMapType 1 def\n  /CMapName /Identity-H def\n  /CIDSystemInfo 3 dict dup begin\n    /Registry (Adobe) def\n    /Ordering (Identity) def\n    /Supplement 0 def\n  end def\n  1 begincodespacerange\n    <0000> <ffff>\n  endcodespacerange\n  0 usefont\n  1 begincidrange\n    <0000> <ffff> 0\n  endcidrange\n  endcmap\n  currentdict CMapName exch /CMap defineresource pop\nend\n10 dict begin\n  begincmap\n  /CMapType 1 def\n  /CMapName /Identity-V def\n  /CIDSystemInfo 3 dict dup begin\n    /Registry (Adobe) def\n    /Ordering (Identity) def\n    /Supplement 0 def\n  end def\n  /WMode 1 def\n  1 begincodespacerange\n    <0000> <ffff>\n  endcodespacerange\n  0 usefont\n  1 begincidrange\n    <0000> <ffff> 0\n  endcidrange\n  endcmap\n  currentdict CMapName exch /CMap defineresource pop\nend\nend\n"
768a770
> 	gboolean need_cmap_identity;
850a853,861
> 	need_cmap_identity = FALSE;
> 	for (font = ps2->fonts; font != NULL; font = font->next) {
> 		if (font->pso->face->entry->type == GP_FONT_ENTRY_TRUETYPE) {
> 			need_cmap_identity = TRUE;
> 			break;
> 		}
> 	}
> 	if (need_cmap_identity)
> 		gnome_print_transport_printf (pc->transport, CMAP_IDENTITY);
Index: Makefile.am
===================================================================
RCS file: /cvs/gnome/libgnomeprint/libgnomeprint/Makefile.am,v
retrieving revision 1.100
diff -r1.100 Makefile.am
17c17,18
< 	gp-tt-t1.c gp-tt-t1.h
---
> 	gp-tt-t1.c gp-tt-t1.h \
> 	gp-tt-cid2.c gp-tt-cid2.h
gp-tt-cid2.c (text/x-csrc, 7.2 KB)
#include "gp-tt-cid2.h"

#include <glib.h>
#include <string.h>

#define GUINT32FROMPTR(p) ((*(guchar*)((p))<<24)|(*((guchar*)(p)+1)<<16)|(*((guchar*)(p)+2)<<8)|(*((guchar*)(p)+3)))
#define GUINT16FROMPTR(p) ((*(guchar*)((p))<<8)|(*((guchar*)(p)+1)))
#define GP_TT_IS_TTC(b) (!strncmp (b, "ttcf", 4))
#define GUINT16TOPTR(p,i) (*((guint8*)p)=(i>>8)&0xFF,*((guint8*)p+1)=i&0xFF)
#define GUINT32TOPTR(p,i) (*((guint8*)p)=(i>>24)&0xFF,*((guint8*)p+1)=(i>>16)&0xFF,*((guint8*)p+2)=(i>>8)&0xFF,*((guint8*)p+3)=i&0xFF)

struct tt_glyph_loca* gp_tt_loca_get (const guchar *buf, guint buf_len, GHashTable *tables, guint glyph);
GByteArray* gp_tt_glyf_get (const guchar *buf, guint buf_len, GHashTable *tables, guint glyph);
guint32 gp_tt_vmtx_get (const guchar *buf, guint buf_len, GHashTable *tables, guint glyph);
guint32 gp_tt_hmtx_get (const guchar *buf, guint buf_len, GHashTable *tables, guint glyph);

guint gp_tt_head_get_index_to_loc_format (const guchar *buf, guint buf_len, GHashTable *tables);

GHashTable *
gp_tt_get_tables (const guchar *buf, guint buf_len, guint face)
{
  const guchar *b;
  guint32 scaler_type;
  guint i, offset = 0, numTables;
  GHashTable *tt_tables;

  b = buf;
  
  if (GP_TT_IS_TTC (b)) {
    guint32 version, num_fonts;
    
    /* this file is TrueType Collection file */
    version = GUINT32FROMPTR (b + 4);
    if (version >= 0x00010000) {
      num_fonts = GUINT32FROMPTR (b + 8);
      if (face > num_fonts) {
        g_warning ("font doesn't have a face %d. number of face is %d.", face, num_fonts);
        return NULL;
      }
      offset = GUINT32FROMPTR (b + 12 + face * 4);
    } else {
      g_warning ("unknown TTC version %X", version);
      return NULL;
    }
  }

  scaler_type   = GUINT32FROMPTR (b + offset);
  numTables     = GUINT16FROMPTR (b + offset + 4);
  if ((scaler_type != 0x74727565) && (scaler_type != 0x00010000))
    return NULL;

  b = buf + offset + 12;
  tt_tables = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free);

  for (i = 0; i < numTables; i++) {
    guint j;
    struct tt_table *table;

    table = (struct tt_table *) g_malloc (sizeof(struct tt_table));
    table->tag[4] = 0;
    for (j = 0; j < 4; j++)
      table->tag[j] = *(b + j);
    table->checksum = GUINT32FROMPTR (b + 4);
    table->offset = GUINT32FROMPTR (b + 8);
    table->length = GUINT32FROMPTR (b + 12);
    g_hash_table_insert (tt_tables, table->tag, table);
    b += 16;
  }

  return tt_tables;
}

GByteArray*
gp_tt_build_header (const guchar *buf, guint buf_len, GHashTable *tables, guchar **required)
{
  GByteArray *head;
  guchar *headbuf;
  guint8 *b;
  guchar **tag;
  guint num_tables, search_range, entry_selector, range_shift;
  guint i;
  guint32 len, offset;

  num_tables = 0;
  for (tag = required; *tag != NULL; tag++) {
    struct tt_table *table;
    table = g_hash_table_lookup (tables, *tag);
    if (table != NULL || !strcmp(*tag, "gdir"))
      num_tables++;
  }

  /* needs check */
  entry_selector = 1;
  while ((entry_selector << 1) <= num_tables)
    entry_selector <<= 1;
  search_range = entry_selector * 16;
  range_shift = num_tables * 16 - search_range;
  len = offset = 12 + 16 * num_tables;

  headbuf = g_malloc (sizeof(guchar[len]));
  headbuf[0] = 0;
  headbuf[1] = 1;
  headbuf[2] = 0;
  headbuf[3] = 0;
  GUINT16TOPTR (headbuf + 4, num_tables);
  GUINT16TOPTR (headbuf + 6, search_range);
  GUINT16TOPTR (headbuf + 8, entry_selector);
  GUINT16TOPTR (headbuf + 10, range_shift);

  for (b = headbuf + 12, tag = required; *tag != NULL; tag++) {
    struct tt_table *table;

    table = g_hash_table_lookup (tables, *tag);
    if (table == NULL && strcmp (*tag, "gdir"))
      continue;

    if (strcmp(*tag, "gdir") != 0) {
      for (i = 0; i < 4; i++) *(b+i) = *(table->tag+i);
      GUINT32TOPTR (b + 4, table->checksum);
      GUINT32TOPTR (b + 8, offset);
      GUINT32TOPTR (b + 12, table->length);
      offset += table->length;
    } else {
      *b = 'g', *(b+1) = 'd', *(b+2) = 'i', *(b+3) = 'r';
      GUINT32TOPTR (b + 4, 0);
      GUINT32TOPTR (b + 8, 0);
      GUINT32TOPTR (b + 12, 0);
    }

    if (offset % 4 != 0)
      offset += 4 - offset % 4;

    b += 16;
  }

  head = g_byte_array_sized_new (len);
  g_byte_array_append (head, headbuf, len);
  g_free (headbuf);

  return head;
}

GByteArray*
gp_tt_get_glyph_desc (const guchar * buf, guint buf_len, GHashTable *tables, guint glyph, guint metrics_count)
{
  GByteArray *glyf, *desc;
  guint32 hmtx, vmtx;

  glyf = gp_tt_glyf_get (buf, buf_len, tables, glyph);
  switch (metrics_count) {
  case 0:
    desc = glyf;
    break;
  case 2:
    desc = g_byte_array_sized_new (glyf->len + (metrics_count << 1));
    hmtx = gp_tt_hmtx_get (buf, buf_len, tables, glyph);
    GUINT32TOPTR (desc->data, hmtx);
    desc->len = 4;
    g_byte_array_append (desc, glyf->data, glyf->len);
    g_byte_array_free (glyf, TRUE);
    break;
  case 4:
    desc = g_byte_array_sized_new (glyf->len + (metrics_count << 1));
    hmtx = gp_tt_hmtx_get (buf, buf_len, tables, glyph);
    vmtx = gp_tt_vmtx_get (buf, buf_len, tables, glyph);
    GUINT32TOPTR (desc->data, vmtx);
    GUINT32TOPTR (desc->data + 4, hmtx);
    desc->len = 8;
    g_byte_array_append (desc, glyf->data, glyf->len);
    g_byte_array_free (glyf, TRUE);
    break;
  default:
    desc = NULL;
  }

  return desc;
}

GByteArray*
gp_tt_glyf_get (const guchar *buf, guint buf_len, GHashTable *tables, guint glyph)
{
  struct tt_glyph_loca *loca;
  struct tt_table *glyf;
  GByteArray *desc;

  glyf = g_hash_table_lookup (tables, "glyf");
  loca = gp_tt_loca_get (buf, buf_len, tables, glyph);
  desc = g_byte_array_sized_new (loca->length);
  g_byte_array_append (desc, buf + glyf->offset + loca->offset, loca->length);
  g_free (loca);

  return desc;
}

struct tt_glyph_loca*
gp_tt_loca_get (const guchar *buf, guint buf_len, GHashTable *tables, guint index)
{
  guint format;
  struct tt_table *loca;
  struct tt_glyph_loca *result;
  const guchar * b;

  loca = g_hash_table_lookup (tables, "loca");
  format = gp_tt_head_get_index_to_loc_format (buf, buf_len, tables);
  
  result = (struct tt_glyph_loca *) g_malloc (sizeof(struct tt_glyph_loca));
  if (format == 0) {
    b = buf + loca->offset + index * 2;
    result->offset = GUINT16FROMPTR (b);
    result->length = GUINT16FROMPTR (b + 2) - result->offset;
    result->offset <<= 1;
    result->length <<= 1;
  } else if (format == 1) {
    b = buf + loca->offset + index * 4;
    result->offset = GUINT32FROMPTR (b);
    result->length = GUINT32FROMPTR (b + 4) - result->offset;
  } else {
    g_free (result);
    return NULL;
  }

  return result;
}

guint32
gp_tt_hmtx_get (const guchar *buf, guint buf_len, GHashTable *tables, guint glyph)
{
  struct tt_table *hmtx;

  hmtx = g_hash_table_lookup (tables, "hmtx");
  return GUINT32FROMPTR (buf + hmtx->offset + glyph * 4);
}

guint32
gp_tt_vmtx_get (const guchar *buf, guint buf_len, GHashTable *tables, guint glyph)
{
  struct tt_table *vmtx;

  vmtx = g_hash_table_lookup (tables, "vmtx");
  return GUINT32FROMPTR (buf + vmtx->offset + glyph * 4);
}

guint
gp_tt_head_get_index_to_loc_format (const guchar *buf, guint buf_len, GHashTable *tables)
{
  struct tt_table *head;

  head = (struct tt_table *) g_hash_table_lookup (tables, "head");
  return GUINT16FROMPTR (buf + head->offset + 50);
}
gp-tt-cid2.h (text/x-chdr, 570 B)
#ifndef __GP_TT_CID2_H__
#define __GP_TT_CID2_H__

#include <glib.h>

G_BEGIN_DECLS

struct tt_table {
  guchar tag[5];
  guint32 checksum;
  guint32 offset;
  guint32 length;
};

struct tt_glyph_loca {
  guint32 offset;
  guint32 length;
};

GHashTable* gp_tt_get_tables (const guchar *buf, guint buf_len, guint face);
GByteArray* gp_tt_build_header (const guchar *buf, guint buf_len, GHashTable *tables, guchar **required);
GByteArray* gp_tt_get_glyph_desc (const guchar *buf, guint buf_len, GHashTable *tables, guint glyph, guint metrics_count);

G_END_DECLS

#endif
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.