Merge pull request #1361 from notmasteryet/truetype-enc-1
Fixes TrueType cmap re-encoding
This commit is contained in:
		
						commit
						25c0bfaa79
					
				
							
								
								
									
										77
									
								
								src/fonts.js
									
									
									
									
									
								
							
							
						
						
									
										77
									
								
								src/fonts.js
									
									
									
									
									
								
							@ -174,7 +174,6 @@ var Encodings = {
 | 
				
			|||||||
    '', '', 'Lslash', 'Oslash', 'OE', 'ordmasculine', '', '', '', '', '', 'ae',
 | 
					    '', '', 'Lslash', 'Oslash', 'OE', 'ordmasculine', '', '', '', '', '', 'ae',
 | 
				
			||||||
    '', '', '', 'dotlessi', '', '', 'lslash', 'oslash', 'oe', 'germandbls'],
 | 
					    '', '', '', 'dotlessi', '', '', 'lslash', 'oslash', 'oe', 'germandbls'],
 | 
				
			||||||
  WinAnsiEncoding: ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
 | 
					  WinAnsiEncoding: ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
 | 
				
			||||||
 | 
					 | 
				
			||||||
    '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
 | 
					    '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
 | 
				
			||||||
    'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent',
 | 
					    'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent',
 | 
				
			||||||
    'ampersand', 'quotesingle', 'parenleft', 'parenright', 'asterisk', 'plus',
 | 
					    'ampersand', 'quotesingle', 'parenleft', 'parenright', 'asterisk', 'plus',
 | 
				
			||||||
@ -1658,6 +1657,30 @@ var Font = (function FontClosure() {
 | 
				
			|||||||
        glyf.data = newGlyfData.subarray(0, writeOffset);
 | 
					        glyf.data = newGlyfData.subarray(0, writeOffset);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      function findEmptyGlyphs(locaTable, isGlyphLocationsLong, emptyGlyphIds) {
 | 
				
			||||||
 | 
					        var itemSize, itemDecode;
 | 
				
			||||||
 | 
					        if (isGlyphLocationsLong) {
 | 
				
			||||||
 | 
					          itemSize = 4;
 | 
				
			||||||
 | 
					          itemDecode = function fontItemDecodeLong(data, offset) {
 | 
				
			||||||
 | 
					            return (data[offset] << 24) | (data[offset + 1] << 16) |
 | 
				
			||||||
 | 
					                   (data[offset + 2] << 8) | data[offset + 3];
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          itemSize = 2;
 | 
				
			||||||
 | 
					          itemDecode = function fontItemDecode(data, offset) {
 | 
				
			||||||
 | 
					            return (data[offset] << 9) | (data[offset + 1] << 1);
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        var data = locaTable.data, length = data.length;
 | 
				
			||||||
 | 
					        var lastOffset = itemDecode(data, 0);
 | 
				
			||||||
 | 
					        for (var i = itemSize, j = 0; i < length; i += itemSize, j++) {
 | 
				
			||||||
 | 
					          var offset = itemDecode(data, i);
 | 
				
			||||||
 | 
					          if (offset == lastOffset)
 | 
				
			||||||
 | 
					            emptyGlyphIds[j] = true;
 | 
				
			||||||
 | 
					          lastOffset = offset;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      function readGlyphNameMap(post, properties) {
 | 
					      function readGlyphNameMap(post, properties) {
 | 
				
			||||||
        var start = (font.start ? font.start : 0) + post.offset;
 | 
					        var start = (font.start ? font.start : 0) + post.offset;
 | 
				
			||||||
        font.pos = start;
 | 
					        font.pos = start;
 | 
				
			||||||
@ -1784,11 +1807,15 @@ var Font = (function FontClosure() {
 | 
				
			|||||||
      sanitizeMetrics(font, hhea, hmtx, numGlyphs);
 | 
					      sanitizeMetrics(font, hhea, hmtx, numGlyphs);
 | 
				
			||||||
      sanitizeMetrics(font, vhea, vmtx, numGlyphs);
 | 
					      sanitizeMetrics(font, vhea, vmtx, numGlyphs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (head && loca && glyf) {
 | 
					 | 
				
			||||||
      var isGlyphLocationsLong = int16([head.data[50], head.data[51]]);
 | 
					      var isGlyphLocationsLong = int16([head.data[50], head.data[51]]);
 | 
				
			||||||
 | 
					      if (head && loca && glyf) {
 | 
				
			||||||
        sanitizeGlyphLocations(loca, glyf, numGlyphs, isGlyphLocationsLong);
 | 
					        sanitizeGlyphLocations(loca, glyf, numGlyphs, isGlyphLocationsLong);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      var emptyGlyphIds = [];
 | 
				
			||||||
 | 
					      if (glyf)
 | 
				
			||||||
 | 
					        findEmptyGlyphs(loca, isGlyphLocationsLong, emptyGlyphIds);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // Sanitizer reduces the glyph advanceWidth to the maxAdvanceWidth
 | 
					      // Sanitizer reduces the glyph advanceWidth to the maxAdvanceWidth
 | 
				
			||||||
      // Sometimes it's 0. That needs to be fixed
 | 
					      // Sometimes it's 0. That needs to be fixed
 | 
				
			||||||
      if (hhea.data[10] == 0 && hhea.data[11] == 0) {
 | 
					      if (hhea.data[10] == 0 && hhea.data[11] == 0) {
 | 
				
			||||||
@ -1920,6 +1947,25 @@ var Font = (function FontClosure() {
 | 
				
			|||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // remove glyph references outside range of avaialable glyphs or empty
 | 
				
			||||||
 | 
					        var glyphsRemoved = 0;
 | 
				
			||||||
 | 
					        for (var i = ids.length - 1; i >= 0; i--) {
 | 
				
			||||||
 | 
					          if (ids[i] < numGlyphs &&
 | 
				
			||||||
 | 
					              (!emptyGlyphIds[ids[i]] || this.isSymbolicFont))
 | 
				
			||||||
 | 
					            continue;
 | 
				
			||||||
 | 
					          ids.splice(i, 1);
 | 
				
			||||||
 | 
					          glyphs.splice(i, 1);
 | 
				
			||||||
 | 
					          glyphsRemoved++;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // heuristics: if removed more than 2 glyphs encoding WinAnsiEncoding
 | 
				
			||||||
 | 
					        // does not set properly
 | 
				
			||||||
 | 
					        if (glyphsRemoved > 2) {
 | 
				
			||||||
 | 
					          warn('Switching TrueType encoding to MacRomanEncoding for ' +
 | 
				
			||||||
 | 
					               this.name + ' font');
 | 
				
			||||||
 | 
					          encoding = Encodings.MacRomanEncoding;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (hasShortCmap && this.hasEncoding && !this.isSymbolicFont) {
 | 
					        if (hasShortCmap && this.hasEncoding && !this.isSymbolicFont) {
 | 
				
			||||||
          // Re-encode short map encoding to unicode -- that simplifies the
 | 
					          // Re-encode short map encoding to unicode -- that simplifies the
 | 
				
			||||||
          // resolution of MacRoman encoded glyphs logic for TrueType fonts:
 | 
					          // resolution of MacRoman encoded glyphs logic for TrueType fonts:
 | 
				
			||||||
@ -1956,6 +2002,7 @@ var Font = (function FontClosure() {
 | 
				
			|||||||
          for (var i = 0, ii = glyphs.length; i < ii; i++)
 | 
					          for (var i = 0, ii = glyphs.length; i < ii; i++)
 | 
				
			||||||
            reverseMap[glyphs[i].unicode] = i;
 | 
					            reverseMap[glyphs[i].unicode] = i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          var newGlyphUnicodes = [];
 | 
				
			||||||
          for (var i = 0, ii = glyphs.length; i < ii; i++) {
 | 
					          for (var i = 0, ii = glyphs.length; i < ii; i++) {
 | 
				
			||||||
            var code = glyphs[i].unicode;
 | 
					            var code = glyphs[i].unicode;
 | 
				
			||||||
            var changeCode = false;
 | 
					            var changeCode = false;
 | 
				
			||||||
@ -1968,17 +2015,27 @@ var Font = (function FontClosure() {
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
            if (glyphName in GlyphsUnicode) {
 | 
					            if (glyphName in GlyphsUnicode) {
 | 
				
			||||||
              var unicode = GlyphsUnicode[glyphName];
 | 
					              var unicode = GlyphsUnicode[glyphName];
 | 
				
			||||||
              if (!unicode || (unicode in reverseMap))
 | 
					              if (!unicode || reverseMap[unicode] === i)
 | 
				
			||||||
                continue; // unknown glyph name or its place is taken
 | 
					                continue; // unknown glyph name or in its own place
 | 
				
			||||||
 | 
					
 | 
				
			||||||
              glyphs[i].unicode = unicode;
 | 
					              newGlyphUnicodes[i] = unicode;
 | 
				
			||||||
              reverseMap[unicode] = i;
 | 
					 | 
				
			||||||
              if (changeCode)
 | 
					              if (changeCode)
 | 
				
			||||||
                toFontChar[code] = unicode;
 | 
					                toFontChar[code] = unicode;
 | 
				
			||||||
 | 
					              delete reverseMap[code];
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          for (var index in newGlyphUnicodes) {
 | 
				
			||||||
 | 
					            var unicode = newGlyphUnicodes[index];
 | 
				
			||||||
 | 
					            if (reverseMap[unicode]) {
 | 
				
			||||||
 | 
					              // avoiding assigning to the same unicode
 | 
				
			||||||
 | 
					              glyphs[index].unicode = unusedUnicode++;
 | 
				
			||||||
 | 
					              continue;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            glyphs[index].unicode = unicode;
 | 
				
			||||||
 | 
					            reverseMap[unicode] = index;
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
          this.useToFontChar = true;
 | 
					          this.useToFontChar = true;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Moving all symbolic font glyphs into 0xF000 - 0xF0FF range.
 | 
					        // Moving all symbolic font glyphs into 0xF000 - 0xF0FF range.
 | 
				
			||||||
        if (this.isSymbolicFont) {
 | 
					        if (this.isSymbolicFont) {
 | 
				
			||||||
@ -1990,12 +2047,6 @@ var Font = (function FontClosure() {
 | 
				
			|||||||
          this.useToFontChar = true;
 | 
					          this.useToFontChar = true;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // remove glyph references outside range of avaialable glyphs
 | 
					 | 
				
			||||||
        for (var i = 0, ii = ids.length; i < ii; i++) {
 | 
					 | 
				
			||||||
          if (ids[i] >= numGlyphs)
 | 
					 | 
				
			||||||
            ids[i] = 0;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        createGlyphNameMap(glyphs, ids, properties);
 | 
					        createGlyphNameMap(glyphs, ids, properties);
 | 
				
			||||||
        this.glyphNameMap = properties.glyphNameMap;
 | 
					        this.glyphNameMap = properties.glyphNameMap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										1
									
								
								test/pdfs/issue1309.pdf.link
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								test/pdfs/issue1309.pdf.link
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					http://www.lufthansa.com/mediapool/pdf/31/media_907231.pdf
 | 
				
			||||||
							
								
								
									
										1
									
								
								test/pdfs/issue1317.pdf.link
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								test/pdfs/issue1317.pdf.link
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					http://iliad.fr/presse/2012/CP_080312_Free_mobile.pdf
 | 
				
			||||||
@ -530,5 +530,19 @@
 | 
				
			|||||||
      "pageLimit": 2,
 | 
					      "pageLimit": 2,
 | 
				
			||||||
      "link": true,
 | 
					      "link": true,
 | 
				
			||||||
      "type": "eq"
 | 
					      "type": "eq"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {  "id": "issue1309",
 | 
				
			||||||
 | 
					      "file": "pdfs/issue1309.pdf",
 | 
				
			||||||
 | 
					      "md5": "e835fb7f3dab3073ad37d0bd3c6399fa",
 | 
				
			||||||
 | 
					      "rounds": 1,
 | 
				
			||||||
 | 
					      "link": true,
 | 
				
			||||||
 | 
					      "type": "eq"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {  "id": "issue1317",
 | 
				
			||||||
 | 
					      "file": "pdfs/issue1317.pdf",
 | 
				
			||||||
 | 
					      "md5": "6fb46275b30c48c8985617d4f86199e3",
 | 
				
			||||||
 | 
					      "rounds": 1,
 | 
				
			||||||
 | 
					      "link": true,
 | 
				
			||||||
 | 
					      "type": "eq"
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user