]> git.parisson.com Git - pdf.js.git/commitdiff
#502 Adding basic Type3 font support.
author= <=>
Mon, 3 Oct 2011 23:36:01 +0000 (16:36 -0700)
committer= <=>
Mon, 3 Oct 2011 23:36:01 +0000 (16:36 -0700)
fonts.js
pdf.js
test/pdfs/simpletype3font.pdf [new file with mode: 0644]
test/test_manifest.json

index 28242f7ca7bf4539b66592070f98f06c77407934..706f8ef6ee0c013a0a0e54c10285c998bfe2fa4f 100644 (file)
--- a/fonts.js
+++ b/fonts.js
@@ -414,6 +414,8 @@ var Font = (function Font() {
   var constructor = function font_constructor(name, file, properties) {
     this.name = name;
     this.encoding = properties.encoding;
+    this.coded = properties.coded;
+    this.resources = properties.resources;
     this.sizes = [];
 
     var names = name.split('+');
@@ -428,6 +430,9 @@ var Font = (function Font() {
       this.loading = false;
       return;
     }
+    this.fontMatrix = properties.fontMatrix;
+    if (properties.type == 'Type3')
+      return;
 
     if (!file) {
       // The file data is not specified. Trying to fix the font name
@@ -478,7 +483,7 @@ var Font = (function Font() {
 
     this.data = data;
     this.type = type;
-    this.textMatrix = properties.textMatrix;
+    this.fontMatrix = properties.fontMatrix;
     this.defaultWidth = properties.defaultWidth;
     this.loadedName = getUniqueName();
     this.composite = properties.composite;
@@ -1929,7 +1934,7 @@ var Type1Parser = function type1Parser() {
             // Make the angle into the right direction
             matrix[2] *= -1;
 
-            properties.textMatrix = matrix;
+            properties.fontMatrix = matrix;
             break;
           case '/Encoding':
             var size = parseInt(getToken(), 10);
diff --git a/pdf.js b/pdf.js
index 449fd9c16f858e29b69517d51efadb10c4eb8aa0..18368aa0bd17a40df829261fa0bdc9d2c4ffc027 100644 (file)
--- a/pdf.js
+++ b/pdf.js
@@ -4498,6 +4498,7 @@ var PartialEvaluator = (function partialEvaluator() {
             baseEncoding = Encodings.WinAnsiEncoding.slice();
             break;
           case 'Type1':
+          case 'Type3':
             baseEncoding = Encodings.StandardEncoding.slice();
             break;
           default:
@@ -4684,35 +4685,43 @@ var PartialEvaluator = (function partialEvaluator() {
         composite = true;
       }
 
-      // Before PDF 1.5 if the font was one of the base 14 fonts, having a
-      // FontDescriptor was not required.
-      // This case is here for compatibility.
       var descriptor = xref.fetchIfRef(dict.get('FontDescriptor'));
       if (!descriptor) {
-        var baseFontName = dict.get('BaseFont');
-        if (!IsName(baseFontName))
-          return null;
+        if (type.name == 'Type3') {
+          // FontDescriptor is only required for Type3 fonts when the document
+          // is a tagged pdf. Create a barbebones one to get by.
+          descriptor = new Dict();
+          descriptor.set('FontName', new Name(type.name));
+        } else {
+          // Before PDF 1.5 if the font was one of the base 14 fonts, having a
+          // FontDescriptor was not required.
+          // This case is here for compatibility.
+          var baseFontName = dict.get('BaseFont');
+          if (!IsName(baseFontName))
+            return null;
 
-        // Using base font name as a font name.
-        baseFontName = baseFontName.name.replace(/,/g, '_');
-        var metricsAndMap = this.getBaseFontMetricsAndMap(baseFontName);
-
-        var properties = {
-          type: type.name,
-          encoding: metricsAndMap.map,
-          differences: [],
-          widths: metricsAndMap.widths,
-          defaultWidth: metricsAndMap.defaultWidth,
-          firstChar: 0,
-          lastChar: 256
-        };
-        this.extractEncoding(dict, xref, properties);
+          // Using base font name as a font name.
+          baseFontName = baseFontName.name.replace(/,/g, '_');
+          var metricsAndMap = this.getBaseFontMetricsAndMap(baseFontName);
+
+          var properties = {
+            type: type.name,
+            encoding: metricsAndMap.map,
+            differences: [],
+            widths: metricsAndMap.widths,
+            defaultWidth: metricsAndMap.defaultWidth,
+            firstChar: 0,
+            lastChar: 256
+          };
+          this.extractEncoding(dict, xref, properties);
+
+          return {
+            name: baseFontName,
+            dict: baseDict,
+            properties: properties
+          };
+        }
 
-        return {
-          name: baseFontName,
-          dict: baseDict,
-          properties: properties
-        };
       }
 
       // According to the spec if 'FontDescriptor' is declared, 'FirstChar',
@@ -4771,7 +4780,7 @@ var PartialEvaluator = (function partialEvaluator() {
         length2: length2,
         composite: composite,
         fixedPitch: false,
-        textMatrix: IDENTITY_MATRIX,
+        fontMatrix: dict.get('FontMatrix') || IDENTITY_MATRIX,
         firstChar: firstChar || 0,
         lastChar: lastChar || 256,
         bbox: descriptor.get('FontBBox'),
@@ -4784,10 +4793,24 @@ var PartialEvaluator = (function partialEvaluator() {
         italicAngle: descriptor.get('ItalicAngle'),
         differences: [],
         widths: glyphWidths,
-        encoding: encoding
+        encoding: encoding,
+        coded: false
       };
       properties.glyphs = this.extractEncoding(dict, xref, properties);
 
+      if (type.name == 'Type3') {
+        properties.coded = true;
+        var charProcs = xref.fetchIfRef(dict.get('CharProcs'));
+        var fontResources = xref.fetchIfRef(dict.get('Resources')) || resources;
+        properties.resources = fontResources;
+        for (var key in charProcs.map) {
+          var glyphStream = xref.fetchIfRef(charProcs.map[key]);
+          properties.glyphs[key].code = this.evaluate(glyphStream,
+                                                       xref,
+                                                       fontResources);
+        }
+      }
+
       return {
         name: fontName.name,
         dict: baseDict,
@@ -5223,41 +5246,72 @@ var CanvasGraphics = (function canvasGraphics() {
       var ctx = this.ctx;
       var current = this.current;
       var font = current.font;
-
-      ctx.save();
-      ctx.transform.apply(ctx, current.textMatrix);
-      ctx.scale(1, -1);
-      ctx.translate(current.x, -1 * current.y);
-      ctx.transform.apply(ctx, font.textMatrix || IDENTITY_MATRIX);
-
       var glyphs = font.charsToGlyphs(text);
       var fontSize = current.fontSize;
       var charSpacing = current.charSpacing;
       var wordSpacing = current.wordSpacing;
       var textHScale = current.textHScale;
-      ctx.scale(1 / textHScale, 1);
-
-      var width = 0;
       var glyphsLength = glyphs.length;
-      for (var i = 0; i < glyphsLength; ++i) {
-        var glyph = glyphs[i];
-        if (glyph === null) {
-          // word break
-          width += wordSpacing;
-          continue;
+      if (font.coded) {
+        ctx.save();
+        ctx.transform.apply(ctx, current.textMatrix);
+        ctx.translate(current.x, current.y);
+
+        var fontMatrix = font.fontMatrix || IDENTITY_MATRIX;
+        ctx.scale(1 / textHScale, 1);
+        for (var i = 0; i < glyphsLength; ++i) {
+
+          var glyph = glyphs[i];
+          if (glyph === null) {
+            // word break
+            this.ctx.translate(wordSpacing, 0);
+            continue;
+          }
+
+          this.save();
+          ctx.scale(fontSize, fontSize);
+          ctx.transform.apply(ctx, fontMatrix);
+          this.execute(glyph.code, this.xref, font.resources);
+          this.restore();
+
+          var transformed = Util.applyTransform([glyph.width, 0], fontMatrix);
+          var width = transformed[0] * fontSize + charSpacing;
+
+          ctx.translate(width, 0);
+          current.x += width;
+
         }
+        ctx.restore();
+      } else {
+        ctx.save();
+        ctx.transform.apply(ctx, current.textMatrix);
+        ctx.scale(1, -1);
+        ctx.translate(current.x, -1 * current.y);
+        ctx.transform.apply(ctx, font.fontMatrix || IDENTITY_MATRIX);
+
+        ctx.scale(1 / textHScale, 1);
+
+        var width = 0;
+        for (var i = 0; i < glyphsLength; ++i) {
+          var glyph = glyphs[i];
+          if (glyph === null) {
+            // word break
+            width += wordSpacing;
+            continue;
+          }
 
-        var unicode = glyph.unicode;
-        var char = (unicode >= 0x10000) ?
-          String.fromCharCode(0xD800 | ((unicode - 0x10000) >> 10),
-          0xDC00 | (unicode & 0x3FF)) : String.fromCharCode(unicode);
+          var unicode = glyph.unicode;
+          var char = (unicode >= 0x10000) ?
+            String.fromCharCode(0xD800 | ((unicode - 0x10000) >> 10),
+            0xDC00 | (unicode & 0x3FF)) : String.fromCharCode(unicode);
 
-        ctx.fillText(char, width, 0);
-        width += glyph.width * fontSize * 0.001 + charSpacing;
-      }
-      current.x += width;
+          ctx.fillText(char, width, 0);
+          width += glyph.width * fontSize * 0.001 + charSpacing;
+        }
+        current.x += width;
 
-      this.ctx.restore();
+        ctx.restore();
+      }
     },
     showSpacedText: function canvasGraphicsShowSpacedText(arr) {
       var ctx = this.ctx;
@@ -5295,8 +5349,8 @@ var CanvasGraphics = (function canvasGraphics() {
 
     // Type3 fonts
     setCharWidth: function canvasGraphicsSetCharWidth(xWidth, yWidth) {
-      TODO('type 3 fonts ("d0" operator) xWidth: ' + xWidth + ' yWidth: ' +
-           yWidth);
+      // We can safely ignore this since the width should be the same
+      // as the width in the Widths array.
     },
     setCharWidthAndBounds: function canvasGraphicsSetCharWidthAndBounds(xWidth,
                                                                         yWidth,
@@ -5304,9 +5358,11 @@ var CanvasGraphics = (function canvasGraphics() {
                                                                         lly,
                                                                         urx,
                                                                         ury) {
-      TODO('type 3 fonts ("d1" operator) xWidth: ' + xWidth + ' yWidth: ' +
-           yWidth + ' llx: ' + llx + ' lly: ' + lly + ' urx: ' + urx +
-           ' ury ' + ury);
+      // TODO? According the spec we're also suppose to ignore any operators
+      // that set color or include images while processing this type3 font.
+      this.rectangle(llx, lly, urx - llx, ury - lly);
+      this.clip();
+      this.endPath();
     },
 
     // Color
@@ -6413,6 +6469,7 @@ var PDFImage = (function pdfImage() {
     applyStencilMask: function applyStencilMask(buffer, inverseDecode) {
       var width = this.width, height = this.height;
       var bitStrideLength = (width + 7) >> 3;
+      this.image.reset();
       var imgArray = this.image.getBytes(bitStrideLength * height);
       var imgArrayPos = 0;
       var i, j, mask, buf;
@@ -6441,6 +6498,7 @@ var PDFImage = (function pdfImage() {
 
       // rows start at byte boundary;
       var rowBytes = (width * numComps * bpc + 7) >> 3;
+      this.image.reset();
       var imgArray = this.image.getBytes(height * rowBytes);
 
       var comps = this.colorSpace.getRgbBuffer(
@@ -6468,6 +6526,7 @@ var PDFImage = (function pdfImage() {
 
       // rows start at byte boundary;
       var rowBytes = (width * numComps * bpc + 7) >> 3;
+      this.image.reset();
       var imgArray = this.image.getBytes(height * rowBytes);
 
       var comps = this.getComponents(imgArray);
diff --git a/test/pdfs/simpletype3font.pdf b/test/pdfs/simpletype3font.pdf
new file mode 100644 (file)
index 0000000..f6fc571
--- /dev/null
@@ -0,0 +1,141 @@
+%PDF-1.4
+%öäüß
+1 0 obj
+<<
+/Type /Catalog
+/Version /1.4
+/Pages 2 0 R
+>>
+endobj
+2 0 obj
+<<
+/Type /Pages
+/Kids [3 0 R]
+/Count 1
+>>
+endobj
+3 0 obj
+<<
+/Type /Page
+/MediaBox [0 0 612 792]
+/Parent 2 0 R
+/Resources 4 0 R
+/Contents 5 0 R
+>>
+endobj
+4 0 obj
+<<
+/Font 6 0 R
+/XObject <<
+>>
+>>
+endobj
+5 0 obj
+<<
+/Length 7 0 R
+>>
+stream\r
+/F0 12 Tf
+BT
+100 700 Td
+(ababab) Tj
+ET
+\r
+endstream
+endobj
+6 0 obj
+<<
+/F0 8 0 R
+>>
+endobj
+7 0 obj
+39
+endobj
+8 0 obj
+<<
+/Type /Font
+/Subtype /Type3
+/FontBBox [0 0 750 750]
+/FontMatrix [0.001 0 0 0.001 0 0]
+/CharProcs 9 0 R
+/Encoding 10 0 R
+/FirstChar 97
+/LastChar 98
+/Widths [1000 1000]
+/FontDescriptor 11 0 R
+>>
+endobj
+9 0 obj
+<<
+/square 12 0 R
+/triangle 13 0 R
+>>
+endobj
+10 0 obj
+<<
+/Type /Encoding
+/Differences [97 /square /triangle]
+>>
+endobj
+11 0 obj
+<<
+/Type /FontDescriptor
+/FontName /SandT
+/Flags 262178
+/Ascent 0
+/CapHeight 0
+/Descent 0
+/ItalicAngle 0
+/StemV 0
+/FontBBox [0 0 750 750]
+>>
+endobj
+12 0 obj
+<<
+/Length 14 0 R
+>>
+stream\r
+1000 0 0 0 750 750 d1 0 0 750 750 re f\r
+endstream
+endobj
+13 0 obj
+<<
+/Length 15 0 R
+>>
+stream\r
+1000 0 0 0 750 750 d1 0 0 m 375 750 l 750 0 l f\r
+endstream
+endobj
+14 0 obj
+38
+endobj
+15 0 obj
+47
+endobj
+xref
+0 16
+0000000000 65535 f\r
+0000000015 00000 n\r
+0000000078 00000 n\r
+0000000135 00000 n\r
+0000000239 00000 n\r
+0000000287 00000 n\r
+0000000381 00000 n\r
+0000000412 00000 n\r
+0000000430 00000 n\r
+0000000641 00000 n\r
+0000000694 00000 n\r
+0000000768 00000 n\r
+0000000925 00000 n\r
+0000001020 00000 n\r
+0000001124 00000 n\r
+0000001143 00000 n\r
+trailer
+<<
+/Root 1 0 R
+/ID [<DD02410A8B7AD4A0EE0D50E4180FABAC> <DD02410A8B7AD4A0EE0D50E4180FABAC>]
+/Size 16
+>>
+startxref
+1162
+%%EOF
index 71738f1924e18e500be9712043dfc2ebd8e35d72..1d3904ca124d3454549602ed2e7e138eafbcd977 100644 (file)
        "rounds": 1,
        "skipPages": [ 16 ],
        "type": "load"
+    },
+    {  "id": "simpletype3font",
+       "file": "pdfs/simpletype3font.pdf",
+       "link": false,
+       "rounds": 1,
+       "type": "load"
     }
 ]