[gs-cvs] rev 8622 - trunk/gs/src

ken at ghostscript.com ken at ghostscript.com
Fri Apr 4 01:53:58 PDT 2008


Author: ken
Date: 2008-04-04 01:53:57 -0700 (Fri, 04 Apr 2008)
New Revision: 8622

Modified:
   trunk/gs/src/gdevpdtb.c
   trunk/gs/src/gdevpsf.h
   trunk/gs/src/gdevpsft.c
Log:
Fix (pdfwrite): Incorrect cmap aubtables written for 'non-symbolic' TrueType
 fonts, when PDF/A output is enabled.

Details:
Bug #689754 "Substituting .notdef for "german umlauts" when generating PDFA".

Normally when writing TrueType fonts GS emits 'symbolic' TrueType fonts, and
correctly outputs both a 1,0 and 3,0 cmap subtable (with appropriate character
offsets, see section 5.5.5 of recent PDF specs).

However, when PDF/A output is enabled, and the TT font to be output only
contains glyphs from the Adobe Latin set, and these are ordered in
accordance with that set, then we emit a 'non-symbolic' TT font. (For PDF/A
we do not emit 'symbolic' fonts, if the font is not 'non-symbolic' then we
write a CIDFont instead.)

However, when writing the non-symbolic font, we continued to write the same
cmap subtables. Acrobat does not use the 3,0 subtable with non-symbolic fonts,
and falls back to the Mac Roman (1,0) subtable instead. For many glyphs this
works correctly, but if the font is WinAnsi compliant, and the glyph is one
of those for which the character position differs between Mac and Windows,
then the glyph cannot be found by Acrobat.

By writing a 3,1 (Windows Unicode) cmap subtable we can ensure this does not
happen, as Acrobat will use this in preference to the 1,0 subtable.

(gdevpsf.h) Add a new TrueType writing control flag WRITE_TRUETYPE_UNICODE_CMAP
 This is used to control whether we write a 3,0 or 3,1 cmap subtable.

(gdevpdtb.c) When setting options for TrueType font writing, if we are
 writing PDF/A, then set the new flag so we get a 3,1 Unicode subtable.

(gdevpsft.c) Create new boilerplate for a type 6 Mac Roman subtable,
 followed by a type 4 Windows Unicode subtable. Create a new routine
 'write_unicode_cmap_6' which uses the new boilerplate to write this
 kind of subtable. In write_cmap, check if we have been asked to write a
 Unicode cmap subtable, and use the new routine if so. Do not bias the
 character codes if writing a Unicode table.

EXPECTED DIFFERENCES:
None.


Modified: trunk/gs/src/gdevpdtb.c
===================================================================
--- trunk/gs/src/gdevpdtb.c	2008-04-04 08:39:33 UTC (rev 8621)
+++ trunk/gs/src/gdevpdtb.c	2008-04-04 08:53:57 UTC (rev 8622)
@@ -559,6 +559,7 @@
 #define TRUETYPE_OPTIONS (WRITE_TRUETYPE_NAME | WRITE_TRUETYPE_HVMTX)
 	/* Acrobat Reader 3 doesn't handle cmap format 6 correctly. */
 	const int options = TRUETYPE_OPTIONS |
+	    (pdev->PDFA ? WRITE_TRUETYPE_UNICODE_CMAP : 0) |
 	    (pdev->CompatibilityLevel <= 1.2 ?
 	     WRITE_TRUETYPE_NO_TRIMMED_TABLE : 0) |
 	    /* Generate a cmap only for incrementally downloaded fonts

Modified: trunk/gs/src/gdevpsf.h
===================================================================
--- trunk/gs/src/gdevpsf.h	2008-04-04 08:39:33 UTC (rev 8621)
+++ trunk/gs/src/gdevpsf.h	2008-04-04 08:53:57 UTC (rev 8622)
@@ -241,6 +241,10 @@
 #define WRITE_TRUETYPE_POST 4	/* generate post if missing */
 #define WRITE_TRUETYPE_NO_TRIMMED_TABLE 8  /* not OK to use cmap format 6 */
 #define WRITE_TRUETYPE_HVMTX 16	/* generate [hv]mtx from glyph_info */
+#define WRITE_TRUETYPE_UNICODE_CMAP 32 /* For PDF/A or other non-symbolic TT font, 
+					* write a 3,1 (Windows Unicode) cmap instead of
+					* a 3,0 one.
+					*/
 int psf_write_truetype_font(stream *s, gs_font_type42 *pfont, int options,
 			    gs_glyph *subset_glyphs, uint subset_size,
 			    const gs_const_string *alt_font_name);

Modified: trunk/gs/src/gdevpsft.c
===================================================================
--- trunk/gs/src/gdevpsft.c	2008-04-04 08:39:33 UTC (rev 8621)
+++ trunk/gs/src/gdevpsft.c	2008-04-04 08:53:57 UTC (rev 8622)
@@ -238,6 +238,27 @@
     0, 0,		/* first character code */
     0, 0		/* # of entries *VARIABLE* */
 };
+static const byte cmap_unicode_initial_6[] = {
+    0, 0,		/* table version # = 0 */
+    0, 2,		/* # of encoding tables = 2 */
+
+	/* First table, Macintosh */
+    0, 1,		/* platform ID = Macintosh */
+    0, 0,		/* platform encoding ID = ??? */
+    0, 0, 0, 4+8+8,	/* offset to table start */
+	/* Second table, Windows */
+    0, 3,		/* platform ID = Microsoft */
+    0, 1,		/* platform encoding ID = Unicode */
+    0, 0, 0, 4+8+8+10,	/* offset to table start */
+			/* *VARIABLE*, add 2 x # of entries */
+
+	/* Start of Macintosh format 6 table */
+    0, 6,		/* format = 6, trimmed table mapping */
+    0, 10,		/* length *VARIABLE*, add 2 x # of entries */
+    0, 0,		/* version number */
+    0, 0,		/* first character code */
+    0, 0		/* # of entries *VARIABLE* */
+};
 static const byte cmap_initial_4[] = {
     0, 0,		/* table version # = 0 */
     0, 1,		/* # of encoding tables = 2 */
@@ -301,6 +322,21 @@
     stream_write(s, cmap_data, sizeof(cmap_data));
     stream_write(s, entries + first_entry * 2, num_entries * 2);
 }
+static void write_unicode_cmap_6(stream *s, byte *entries, uint first_code,
+	     uint first_entry, uint num_entries)
+{
+    byte cmap_data[sizeof(cmap_unicode_initial_6)];
+
+    memcpy(cmap_data, cmap_unicode_initial_6, sizeof(cmap_unicode_initial_6));
+    put_u16(cmap_data + 18,
+	    U16(cmap_data + 18) + num_entries * 2);  /* offset */
+    put_u16(cmap_data + 22,
+	    U16(cmap_data + 22) + num_entries * 2);  /* length */
+    put_u16(cmap_data + 26, first_entry);
+    put_u16(cmap_data + 28, num_entries);
+    stream_write(s, cmap_data, sizeof(cmap_data));
+    stream_write(s, entries + first_entry * 2, num_entries * 2);
+}
 static void
 write_cmap(stream *s, gs_font *font, uint first_code, int num_glyphs,
 	   gs_glyph max_glyph, int options, uint cmap_length)
@@ -336,6 +372,19 @@
 
     /* Write the table header and Macintosh sub-table (if any). */
 
+    if (options & WRITE_TRUETYPE_UNICODE_CMAP) {
+	write_unicode_cmap_6(s, entries, first_code, first_entry, num_entries);
+
+	/* Write the Windows sub-table. */
+	memcpy(cmap_sub, cmap_sub_initial, sizeof(cmap_sub_initial));
+	put_u16(cmap_sub + 2, U16(cmap_sub + 2) + num_entries * 2); /* length */
+	put_u16(cmap_sub + 14, end_entry - 1); /* endCount[0] */
+	put_u16(cmap_sub + 20, first_entry); /* startCount[0] */
+	stream_write(s, cmap_sub, sizeof(cmap_sub));
+	stream_write(s, entries + first_entry * 2, num_entries * 2);
+	put_pad(s, cmap_length);
+	return;
+    } 
 #if TT_FORCE_CMAP_6 > 0
     /* Always use format 6. */
     write_cmap_6(s, entries, first_code, first_entry, num_entries);



More information about the gs-cvs mailing list