Merge branch 'master' of https://github.com/andreasgal/pdf.js.git into cff-issues2
This commit is contained in:
commit
75758ffec5
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,3 +1,5 @@
|
|||||||
|
*~
|
||||||
pdf.pdf
|
pdf.pdf
|
||||||
intelisa.pdf
|
intelisa.pdf
|
||||||
openweb_tm-PRINT.pdf
|
openweb_tm-PRINT.pdf
|
||||||
|
local.mk
|
||||||
|
5
Makefile
5
Makefile
@ -3,6 +3,9 @@ BUILD_DIR := build
|
|||||||
DEFAULT_BROWSERS := test/resources/browser_manifests/browser_manifest.json
|
DEFAULT_BROWSERS := test/resources/browser_manifests/browser_manifest.json
|
||||||
DEFAULT_TESTS := test/test_manifest.json
|
DEFAULT_TESTS := test/test_manifest.json
|
||||||
|
|
||||||
|
# Let folks define custom rules for their clones.
|
||||||
|
-include local.mk
|
||||||
|
|
||||||
# JS files needed for pdf.js.
|
# JS files needed for pdf.js.
|
||||||
# This list doesn't account for the 'worker' directory.
|
# This list doesn't account for the 'worker' directory.
|
||||||
PDF_JS_FILES = \
|
PDF_JS_FILES = \
|
||||||
@ -156,5 +159,5 @@ clean:
|
|||||||
help:
|
help:
|
||||||
@echo "Read the comments in the Makefile for guidance.";
|
@echo "Read the comments in the Makefile for guidance.";
|
||||||
|
|
||||||
.PHONY: all test browser-test font-test shell-test \
|
.PHONY:: all test browser-test font-test shell-test \
|
||||||
shell-msg lint clean web compiler help server
|
shell-msg lint clean web compiler help server
|
||||||
|
192
fonts.js
192
fonts.js
@ -2,7 +2,6 @@
|
|||||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var isWorker = (typeof window == 'undefined');
|
var isWorker = (typeof window == 'undefined');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -15,20 +14,6 @@ var kMaxFontFileSize = 40000;
|
|||||||
*/
|
*/
|
||||||
var kMaxWaitForFontFace = 1000;
|
var kMaxWaitForFontFace = 1000;
|
||||||
|
|
||||||
/**
|
|
||||||
* Useful for debugging when you want to certains operations depending on how
|
|
||||||
* many fonts are loaded.
|
|
||||||
*/
|
|
||||||
var fontCount = 0;
|
|
||||||
var fontName = '';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If for some reason one want to debug without fonts activated, it just need
|
|
||||||
* to turn this pref to true/false.
|
|
||||||
*/
|
|
||||||
var kDisableFonts = false;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hold a map of decoded fonts and of the standard fourteen Type1 fonts and
|
* Hold a map of decoded fonts and of the standard fourteen Type1 fonts and
|
||||||
* their acronyms.
|
* their acronyms.
|
||||||
@ -37,91 +22,33 @@ var kDisableFonts = false;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
var Fonts = (function Fonts() {
|
var Fonts = (function Fonts() {
|
||||||
var kScalePrecision = 40;
|
var fonts = [];
|
||||||
var fonts = Object.create(null);
|
var fontCount = 0;
|
||||||
|
|
||||||
if (!isWorker) {
|
function FontInfo(name, data, properties) {
|
||||||
var ctx = document.createElement('canvas').getContext('2d');
|
|
||||||
ctx.scale(1 / kScalePrecision, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
function Font(name, data, properties) {
|
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.data = data;
|
this.data = data;
|
||||||
this.properties = properties;
|
this.properties = properties;
|
||||||
|
this.id = fontCount++;
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
this.charsCache = Object.create(null);
|
|
||||||
this.sizes = [];
|
this.sizes = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
var current;
|
var current;
|
||||||
var charsCache;
|
|
||||||
var measureCache;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
registerFont: function fonts_registerFont(fontName, data, properties) {
|
registerFont: function fonts_registerFont(fontName, data, properties) {
|
||||||
fonts[fontName] = new Font(fontName, data, properties);
|
var font = new FontInfo(fontName, data, properties);
|
||||||
|
fonts.push(font);
|
||||||
|
return font.id;
|
||||||
},
|
},
|
||||||
blacklistFont: function fonts_blacklistFont(fontName) {
|
blacklistFont: function fonts_blacklistFont(fontName) {
|
||||||
registerFont(fontName, null, {});
|
var id = registerFont(fontName, null, {});
|
||||||
markLoaded(fontName);
|
markLoaded(fontName);
|
||||||
|
return id;
|
||||||
},
|
},
|
||||||
lookup: function fonts_lookup(fontName) {
|
lookupById: function fonts_lookupById(id) {
|
||||||
return fonts[fontName];
|
return fonts[id];
|
||||||
},
|
|
||||||
setActive: function fonts_setActive(fontName, size) {
|
|
||||||
// |current| can be null is fontName is a built-in font
|
|
||||||
// (e.g. "sans-serif")
|
|
||||||
if ((current = fonts[fontName])) {
|
|
||||||
charsCache = current.charsCache;
|
|
||||||
var sizes = current.sizes;
|
|
||||||
if (!(measureCache = sizes[size]))
|
|
||||||
measureCache = sizes[size] = Object.create(null);
|
|
||||||
}
|
|
||||||
ctx.font = (size * kScalePrecision) + 'px "' + fontName + '"';
|
|
||||||
},
|
|
||||||
charsToUnicode: function fonts_chars2Unicode(chars) {
|
|
||||||
if (!charsCache)
|
|
||||||
return chars;
|
|
||||||
|
|
||||||
// if we translated this string before, just grab it from the cache
|
|
||||||
var str = charsCache[chars];
|
|
||||||
if (str)
|
|
||||||
return str;
|
|
||||||
|
|
||||||
// translate the string using the font's encoding
|
|
||||||
var encoding = current ? current.properties.encoding : null;
|
|
||||||
if (!encoding)
|
|
||||||
return chars;
|
|
||||||
|
|
||||||
str = '';
|
|
||||||
for (var i = 0; i < chars.length; ++i) {
|
|
||||||
var charcode = chars.charCodeAt(i);
|
|
||||||
var unicode = encoding[charcode];
|
|
||||||
|
|
||||||
// Check if the glyph has already been converted
|
|
||||||
if (!IsNum(unicode))
|
|
||||||
unicode = encoding[unicode] = GlyphsUnicode[unicode.name];
|
|
||||||
|
|
||||||
// Handle surrogate pairs
|
|
||||||
if (unicode > 0xFFFF) {
|
|
||||||
str += String.fromCharCode(unicode & 0xFFFF);
|
|
||||||
unicode >>= 16;
|
|
||||||
}
|
|
||||||
str += String.fromCharCode(unicode);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enter the translated string into the cache
|
|
||||||
return charsCache[chars] = str;
|
|
||||||
},
|
|
||||||
measureText: function fonts_measureText(text) {
|
|
||||||
var width;
|
|
||||||
if (measureCache && (width = measureCache[text]))
|
|
||||||
return width;
|
|
||||||
width = ctx.measureText(text).width / kScalePrecision;
|
|
||||||
if (measureCache)
|
|
||||||
measureCache[text] = width;
|
|
||||||
return width;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
@ -131,9 +58,9 @@ var FontLoader = {
|
|||||||
|
|
||||||
bind: function(fonts, callback) {
|
bind: function(fonts, callback) {
|
||||||
function checkFontsLoaded() {
|
function checkFontsLoaded() {
|
||||||
for (var i = 0; i < fonts.length; i++) {
|
for (var i = 0; i < allIds.length; i++) {
|
||||||
var font = fonts[i];
|
var id = allIds[i];
|
||||||
if (Fonts.lookup(font.name).loading) {
|
if (Fonts.lookupById(id).loading) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -145,14 +72,18 @@ var FontLoader = {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var rules = [], names = [];
|
var allIds = [];
|
||||||
|
var rules = [], names = [], ids = [];
|
||||||
|
|
||||||
for (var i = 0; i < fonts.length; i++) {
|
for (var i = 0; i < fonts.length; i++) {
|
||||||
var font = fonts[i];
|
var font = fonts[i];
|
||||||
if (!Fonts.lookup(font.name)) {
|
|
||||||
var obj = new Font(font.name, font.file, font.properties);
|
var obj = new Font(font.name, font.file, font.properties);
|
||||||
|
font.fontDict.fontObj = obj;
|
||||||
|
allIds.push(obj.id);
|
||||||
|
|
||||||
var str = '';
|
var str = '';
|
||||||
var data = Fonts.lookup(font.name).data;
|
var data = Fonts.lookupById(obj.id).data;
|
||||||
var length = data.length;
|
var length = data.length;
|
||||||
for (var j = 0; j < length; j++)
|
for (var j = 0; j < length; j++)
|
||||||
str += String.fromCharCode(data[j]);
|
str += String.fromCharCode(data[j]);
|
||||||
@ -160,13 +91,14 @@ var FontLoader = {
|
|||||||
var rule = isWorker ? obj.bindWorker(str) : obj.bindDOM(str);
|
var rule = isWorker ? obj.bindWorker(str) : obj.bindDOM(str);
|
||||||
if (rule) {
|
if (rule) {
|
||||||
rules.push(rule);
|
rules.push(rule);
|
||||||
names.push(font.name);
|
names.push(obj.loadedName);
|
||||||
}
|
ids.push(obj.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.listeningForFontLoad = false;
|
||||||
if (!isWorker && rules.length) {
|
if (!isWorker && rules.length) {
|
||||||
FontLoader.prepareFontLoadEvent(rules, names);
|
FontLoader.prepareFontLoadEvent(rules, names, ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!checkFontsLoaded()) {
|
if (!checkFontsLoaded()) {
|
||||||
@ -181,7 +113,7 @@ var FontLoader = {
|
|||||||
// loaded in a subdocument. It's expected that the load of |rules|
|
// loaded in a subdocument. It's expected that the load of |rules|
|
||||||
// has already started in this (outer) document, so that they should
|
// has already started in this (outer) document, so that they should
|
||||||
// be ordered before the load in the subdocument.
|
// be ordered before the load in the subdocument.
|
||||||
prepareFontLoadEvent: function(rules, names) {
|
prepareFontLoadEvent: function(rules, names, ids) {
|
||||||
/** Hack begin */
|
/** Hack begin */
|
||||||
// There's no event when a font has finished downloading so the
|
// There's no event when a font has finished downloading so the
|
||||||
// following code is a dirty hack to 'guess' when a font is
|
// following code is a dirty hack to 'guess' when a font is
|
||||||
@ -217,13 +149,13 @@ var FontLoader = {
|
|||||||
div.innerHTML = html;
|
div.innerHTML = html;
|
||||||
document.body.appendChild(div);
|
document.body.appendChild(div);
|
||||||
|
|
||||||
if (!this.listeneningForFontLoad) {
|
if (!this.listeningForFontLoad) {
|
||||||
window.addEventListener(
|
window.addEventListener(
|
||||||
'message',
|
'message',
|
||||||
function(e) {
|
function(e) {
|
||||||
var fontNames = JSON.parse(e.data);
|
var fontNames = JSON.parse(e.data);
|
||||||
for (var i = 0; i < fontNames.length; ++i) {
|
for (var i = 0; i < fontNames.length; ++i) {
|
||||||
var font = Fonts.lookup(fontNames[i]);
|
var font = Fonts.lookupById(fontNames[i].substring(7) | 0);
|
||||||
font.loading = false;
|
font.loading = false;
|
||||||
}
|
}
|
||||||
var evt = document.createEvent('Events');
|
var evt = document.createEvent('Events');
|
||||||
@ -231,7 +163,7 @@ var FontLoader = {
|
|||||||
document.documentElement.dispatchEvent(evt);
|
document.documentElement.dispatchEvent(evt);
|
||||||
},
|
},
|
||||||
false);
|
false);
|
||||||
this.listeneningForFontLoad = true;
|
this.listeningForFontLoad = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// XXX we should have a time-out here too, and maybe fire
|
// XXX we should have a time-out here too, and maybe fire
|
||||||
@ -253,7 +185,7 @@ var FontLoader = {
|
|||||||
src += ' }';
|
src += ' }';
|
||||||
src += '</script></head><body>';
|
src += '</script></head><body>';
|
||||||
for (var i = 0; i < names.length; ++i) {
|
for (var i = 0; i < names.length; ++i) {
|
||||||
src += '<p style="font-family:\'' + fontName + '\'">Hi</p>';
|
src += '<p style="font-family:\'' + names[i] + '\'">Hi</p>';
|
||||||
}
|
}
|
||||||
src += '</body></html>';
|
src += '</body></html>';
|
||||||
var frame = document.createElement('iframe');
|
var frame = document.createElement('iframe');
|
||||||
@ -413,20 +345,14 @@ function getUnicodeRangeFor(value) {
|
|||||||
var Font = (function() {
|
var Font = (function() {
|
||||||
var constructor = function font_constructor(name, file, properties) {
|
var constructor = function font_constructor(name, file, properties) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
this.textMatrix = properties.textMatrix || IDENTITY_MATRIX;
|
||||||
this.encoding = properties.encoding;
|
this.encoding = properties.encoding;
|
||||||
|
|
||||||
// If the font has already been decoded simply return it
|
|
||||||
if (Fonts.lookup(name)) {
|
|
||||||
this.font = Fonts.lookup(name).data;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
fontCount++;
|
|
||||||
fontName = name;
|
|
||||||
|
|
||||||
// If the font is to be ignored, register it like an already loaded font
|
// If the font is to be ignored, register it like an already loaded font
|
||||||
// to avoid the cost of waiting for it be be loaded by the platform.
|
// to avoid the cost of waiting for it be be loaded by the platform.
|
||||||
if (properties.ignore || kDisableFonts) {
|
if (properties.ignore) {
|
||||||
Fonts.blacklistFont(name);
|
this.id = Fonts.blacklistFont(name);
|
||||||
|
this.loadedName = 'pdfFont' + this.id;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -453,7 +379,9 @@ var Font = (function() {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
this.data = data;
|
this.data = data;
|
||||||
Fonts.registerFont(name, data, properties);
|
|
||||||
|
this.id = Fonts.registerFont(name, data, properties);
|
||||||
|
this.loadedName = 'pdfFont' + this.id;
|
||||||
};
|
};
|
||||||
|
|
||||||
function stringToArray(str) {
|
function stringToArray(str) {
|
||||||
@ -1128,14 +1056,14 @@ var Font = (function() {
|
|||||||
action: 'font',
|
action: 'font',
|
||||||
data: {
|
data: {
|
||||||
raw: data,
|
raw: data,
|
||||||
fontName: this.name,
|
fontName: this.loadedName,
|
||||||
mimetype: this.mimetype
|
mimetype: this.mimetype
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
bindDOM: function font_bindDom(data) {
|
bindDOM: function font_bindDom(data) {
|
||||||
var fontName = this.name;
|
var fontName = this.loadedName;
|
||||||
|
|
||||||
// Add the font-face rule to the document
|
// Add the font-face rule to the document
|
||||||
var url = ('url(data:' + this.mimetype + ';base64,' +
|
var url = ('url(data:' + this.mimetype + ';base64,' +
|
||||||
@ -1145,6 +1073,46 @@ var Font = (function() {
|
|||||||
styleSheet.insertRule(rule, styleSheet.cssRules.length);
|
styleSheet.insertRule(rule, styleSheet.cssRules.length);
|
||||||
|
|
||||||
return rule;
|
return rule;
|
||||||
|
},
|
||||||
|
|
||||||
|
charsToUnicode: function fonts_charsToUnicode(chars) {
|
||||||
|
var charsCache = this.charsCache;
|
||||||
|
|
||||||
|
// if we translated this string before, just grab it from the cache
|
||||||
|
if (charsCache) {
|
||||||
|
var str = charsCache[chars];
|
||||||
|
if (str)
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
// translate the string using the font's encoding
|
||||||
|
var encoding = this.encoding;
|
||||||
|
if (!encoding)
|
||||||
|
return chars;
|
||||||
|
|
||||||
|
// lazily create the translation cache
|
||||||
|
if (!charsCache)
|
||||||
|
charsCache = this.charsCache = Object.create(null);
|
||||||
|
|
||||||
|
str = '';
|
||||||
|
for (var i = 0; i < chars.length; ++i) {
|
||||||
|
var charcode = chars.charCodeAt(i);
|
||||||
|
var unicode = encoding[charcode];
|
||||||
|
|
||||||
|
// Check if the glyph has already been converted
|
||||||
|
if (!IsNum(unicode))
|
||||||
|
unicode = encoding[unicode] = GlyphsUnicode[unicode.name];
|
||||||
|
|
||||||
|
// Handle surrogate pairs
|
||||||
|
if (unicode > 0xFFFF) {
|
||||||
|
str += String.fromCharCode(unicode & 0xFFFF);
|
||||||
|
unicode >>= 16;
|
||||||
|
}
|
||||||
|
str += String.fromCharCode(unicode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enter the translated string into the cache
|
||||||
|
return charsCache[chars] = str;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1676,7 +1644,7 @@ CFF.prototype = {
|
|||||||
var unicode = GlyphsUnicode[glyph.glyph];
|
var unicode = GlyphsUnicode[glyph.glyph];
|
||||||
if (!unicode) {
|
if (!unicode) {
|
||||||
if (glyph.glyph != '.notdef') {
|
if (glyph.glyph != '.notdef') {
|
||||||
warn(glyph +
|
warn(glyph.glyph +
|
||||||
' does not have an entry in the glyphs unicode dictionary');
|
' does not have an entry in the glyphs unicode dictionary');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
370
pdf.js
370
pdf.js
@ -904,6 +904,74 @@ var Ascii85Stream = (function() {
|
|||||||
return constructor;
|
return constructor;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
var AsciiHexStream = (function() {
|
||||||
|
function constructor(str) {
|
||||||
|
this.str = str;
|
||||||
|
this.dict = str.dict;
|
||||||
|
|
||||||
|
DecodeStream.call(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
var hexvalueMap = {
|
||||||
|
9: -1, // \t
|
||||||
|
32: -1, // space
|
||||||
|
48: 0,
|
||||||
|
49: 1,
|
||||||
|
50: 2,
|
||||||
|
51: 3,
|
||||||
|
52: 4,
|
||||||
|
53: 5,
|
||||||
|
54: 6,
|
||||||
|
55: 7,
|
||||||
|
56: 8,
|
||||||
|
57: 9,
|
||||||
|
65: 10,
|
||||||
|
66: 11,
|
||||||
|
67: 12,
|
||||||
|
68: 13,
|
||||||
|
69: 14,
|
||||||
|
70: 15,
|
||||||
|
97: 10,
|
||||||
|
98: 11,
|
||||||
|
99: 12,
|
||||||
|
100: 13,
|
||||||
|
101: 14,
|
||||||
|
102: 15
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor.prototype = Object.create(DecodeStream.prototype);
|
||||||
|
|
||||||
|
constructor.prototype.readBlock = function() {
|
||||||
|
var gtCode = '>'.charCodeAt(0), bytes = this.str.getBytes(), c, n,
|
||||||
|
decodeLength, buffer, bufferLength, i, length;
|
||||||
|
|
||||||
|
decodeLength = (bytes.length + 1) >> 1;
|
||||||
|
buffer = this.ensureBuffer(this.bufferLength + decodeLength);
|
||||||
|
bufferLength = this.bufferLength;
|
||||||
|
|
||||||
|
for(i = 0, length = bytes.length; i < length; i++) {
|
||||||
|
c = hexvalueMap[bytes[i]];
|
||||||
|
while (c == -1 && (i+1) < length) {
|
||||||
|
c = hexvalueMap[bytes[++i]];
|
||||||
|
}
|
||||||
|
|
||||||
|
if((i+1) < length && (bytes[i+1] !== gtCode)) {
|
||||||
|
n = hexvalueMap[bytes[++i]];
|
||||||
|
buffer[bufferLength++] = c*16+n;
|
||||||
|
} else {
|
||||||
|
if(bytes[i] !== gtCode) { // EOD marker at an odd number, behave as if a 0 followed the last digit.
|
||||||
|
buffer[bufferLength++] = c*16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.bufferLength = bufferLength;
|
||||||
|
this.eof = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
return constructor;
|
||||||
|
})();
|
||||||
|
|
||||||
var CCITTFaxStream = (function() {
|
var CCITTFaxStream = (function() {
|
||||||
|
|
||||||
var ccittEOL = -2;
|
var ccittEOL = -2;
|
||||||
@ -1613,7 +1681,7 @@ var CCITTFaxStream = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.byteAlign)
|
if (this.byteAlign)
|
||||||
inputBits &= ~7;
|
this.inputBits &= ~7;
|
||||||
|
|
||||||
var gotEOL = false;
|
var gotEOL = false;
|
||||||
|
|
||||||
@ -1921,28 +1989,33 @@ var Dict = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
constructor.prototype = {
|
constructor.prototype = {
|
||||||
get: function(key) {
|
get: function(key1, key2, key3) {
|
||||||
if (key in this.map)
|
var value;
|
||||||
return this.map[key];
|
if (typeof (value = this.map[key1]) != 'undefined' || key1 in this.map || typeof key2 == 'undefined') {
|
||||||
return null;
|
return value;
|
||||||
},
|
}
|
||||||
get2: function(key1, key2) {
|
if (typeof (value = this.map[key2]) != 'undefined' || key2 in this.map || typeof key3 == 'undefined') {
|
||||||
return this.get(key1) || this.get(key2);
|
return value;
|
||||||
},
|
}
|
||||||
get3: function(key1, key2, key3) {
|
|
||||||
return this.get(key1) || this.get(key2) || this.get(key3);
|
return this.map[key3] || null;
|
||||||
},
|
|
||||||
has: function(key) {
|
|
||||||
return key in this.map;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
set: function(key, value) {
|
set: function(key, value) {
|
||||||
this.map[key] = value;
|
this.map[key] = value;
|
||||||
},
|
},
|
||||||
forEach: function(aCallback) {
|
|
||||||
for (var key in this.map)
|
has: function(key) {
|
||||||
aCallback(key, this.map[key]);
|
return key in this.map;
|
||||||
|
},
|
||||||
|
|
||||||
|
forEach: function(callback) {
|
||||||
|
for (var key in this.map) {
|
||||||
|
callback(key, this.map[key]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return constructor;
|
return constructor;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
@ -2459,8 +2532,8 @@ var Parser = (function() {
|
|||||||
return stream;
|
return stream;
|
||||||
},
|
},
|
||||||
filter: function(stream, dict, length) {
|
filter: function(stream, dict, length) {
|
||||||
var filter = dict.get2('Filter', 'F');
|
var filter = dict.get('Filter', 'F');
|
||||||
var params = dict.get2('DecodeParms', 'DP');
|
var params = dict.get('DecodeParms', 'DP');
|
||||||
if (IsName(filter))
|
if (IsName(filter))
|
||||||
return this.makeFilter(stream, filter.name, length, params);
|
return this.makeFilter(stream, filter.name, length, params);
|
||||||
if (IsArray(filter)) {
|
if (IsArray(filter)) {
|
||||||
@ -2491,6 +2564,8 @@ var Parser = (function() {
|
|||||||
return new JpegStream(bytes, stream.dict);
|
return new JpegStream(bytes, stream.dict);
|
||||||
} else if (name == 'ASCII85Decode') {
|
} else if (name == 'ASCII85Decode') {
|
||||||
return new Ascii85Stream(stream);
|
return new Ascii85Stream(stream);
|
||||||
|
} else if (name == 'ASCIIHexDecode') {
|
||||||
|
return new AsciiHexStream(stream);
|
||||||
} else if (name == 'CCITTFaxDecode') {
|
} else if (name == 'CCITTFaxDecode') {
|
||||||
TODO('implement fax stream');
|
TODO('implement fax stream');
|
||||||
return new CCITTFaxStream(stream, params);
|
return new CCITTFaxStream(stream, params);
|
||||||
@ -3472,7 +3547,7 @@ var CanvasGraphics = (function() {
|
|||||||
assertWellFormed(IsName(fontName), 'invalid font name');
|
assertWellFormed(IsName(fontName), 'invalid font name');
|
||||||
fontName = fontName.name.replace('+', '_');
|
fontName = fontName.name.replace('+', '_');
|
||||||
|
|
||||||
var fontFile = descriptor.get3('FontFile', 'FontFile2', 'FontFile3');
|
var fontFile = descriptor.get('FontFile', 'FontFile2', 'FontFile3');
|
||||||
if (!fontFile)
|
if (!fontFile)
|
||||||
error('FontFile not found for font: ' + fontName);
|
error('FontFile not found for font: ' + fontName);
|
||||||
fontFile = xref.fetchIfRef(fontFile);
|
fontFile = xref.fetchIfRef(fontFile);
|
||||||
@ -3482,7 +3557,19 @@ var CanvasGraphics = (function() {
|
|||||||
if (fontDict.has('Encoding')) {
|
if (fontDict.has('Encoding')) {
|
||||||
var encoding = xref.fetchIfRef(fontDict.get('Encoding'));
|
var encoding = xref.fetchIfRef(fontDict.get('Encoding'));
|
||||||
if (IsDict(encoding)) {
|
if (IsDict(encoding)) {
|
||||||
// Build a map between codes and glyphs
|
// Build a map of between codes and glyphs
|
||||||
|
// Load the base encoding
|
||||||
|
var baseName = encoding.get('BaseEncoding');
|
||||||
|
if (baseName) {
|
||||||
|
var base = Encodings[baseName.name];
|
||||||
|
var index = 0;
|
||||||
|
for (var j = 0, end = base.length; j < end; j++)
|
||||||
|
encodingMap[index++] = GlyphsUnicode[base[j]];
|
||||||
|
} else {
|
||||||
|
TODO('need to load default encoding');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load the differences between the base and original
|
||||||
var differences = encoding.get('Differences');
|
var differences = encoding.get('Differences');
|
||||||
var index = 0;
|
var index = 0;
|
||||||
for (var j = 0; j < differences.length; j++) {
|
for (var j = 0; j < differences.length; j++) {
|
||||||
@ -3605,6 +3692,7 @@ var CanvasGraphics = (function() {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
name: fontName,
|
name: fontName,
|
||||||
|
fontDict: fontDict,
|
||||||
file: fontFile,
|
file: fontFile,
|
||||||
properties: properties
|
properties: properties
|
||||||
};
|
};
|
||||||
@ -3868,25 +3956,22 @@ var CanvasGraphics = (function() {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var fontName = '';
|
var fontName = '';
|
||||||
var fontDescriptor = font.get('FontDescriptor');
|
var fontObj = font.fontObj;
|
||||||
if (fontDescriptor && fontDescriptor.num) {
|
if (fontObj)
|
||||||
var fontDescriptor = this.xref.fetchIfRef(fontDescriptor);
|
fontName = fontObj.loadedName;
|
||||||
fontName = fontDescriptor.get('FontName').name.replace('+', '_');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!fontName) {
|
if (!fontName) {
|
||||||
// TODO: fontDescriptor is not available, fallback to default font
|
// TODO: fontDescriptor is not available, fallback to default font
|
||||||
fontName = 'sans-serif';
|
fontName = 'sans-serif';
|
||||||
}
|
}
|
||||||
|
|
||||||
this.current.fontName = fontName;
|
this.current.font = fontObj;
|
||||||
this.current.fontSize = size;
|
this.current.fontSize = size;
|
||||||
|
|
||||||
if (this.ctx.$setFont) {
|
if (this.ctx.$setFont) {
|
||||||
this.ctx.$setFont(fontName, size);
|
this.ctx.$setFont(fontName, size);
|
||||||
} else {
|
} else {
|
||||||
this.ctx.font = size + 'px "' + fontName + '"';
|
this.ctx.font = size + 'px "' + fontName + '"';
|
||||||
Fonts.setActive(fontName, size);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setTextRenderingMode: function(mode) {
|
setTextRenderingMode: function(mode) {
|
||||||
@ -3921,25 +4006,28 @@ var CanvasGraphics = (function() {
|
|||||||
showText: function(text) {
|
showText: function(text) {
|
||||||
// TODO: apply charSpacing, wordSpacing, textHScale
|
// TODO: apply charSpacing, wordSpacing, textHScale
|
||||||
|
|
||||||
this.ctx.save();
|
var ctx = this.ctx;
|
||||||
this.ctx.transform.apply(this.ctx, this.current.textMatrix);
|
var current = this.current;
|
||||||
this.ctx.scale(1, -1);
|
|
||||||
|
|
||||||
if (this.ctx.$showText) {
|
if (this.ctx.$showText) {
|
||||||
this.ctx.$showText(this.current.y, Fonts.charsToUnicode(text));
|
ctx.$showText(current.y, text);
|
||||||
} else {
|
} else {
|
||||||
text = Fonts.charsToUnicode(text);
|
ctx.save();
|
||||||
this.ctx.translate(this.current.x, -1 * this.current.y);
|
|
||||||
|
|
||||||
var font = Fonts.lookup(this.current.fontName);
|
ctx.transform.apply(ctx, current.textMatrix);
|
||||||
if (font && font.properties.textMatrix)
|
ctx.scale(1, -1);
|
||||||
this.ctx.transform.apply(this.ctx, font.properties.textMatrix);
|
ctx.translate(current.x, -current.y);
|
||||||
|
|
||||||
this.ctx.fillText(text, 0, 0);
|
var font = current.font;
|
||||||
this.current.x += Fonts.measureText(text);
|
ctx.transform.apply(ctx, font.textMatrix);
|
||||||
|
|
||||||
|
text = font.charsToUnicode(text);
|
||||||
|
|
||||||
|
ctx.fillText(text, 0, 0);
|
||||||
|
current.x += ctx.measureText(text).width;
|
||||||
|
|
||||||
|
ctx.restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.ctx.restore();
|
|
||||||
},
|
},
|
||||||
showSpacedText: function(arr) {
|
showSpacedText: function(arr) {
|
||||||
for (var i = 0; i < arr.length; ++i) {
|
for (var i = 0; i < arr.length; ++i) {
|
||||||
@ -4003,14 +4091,28 @@ var CanvasGraphics = (function() {
|
|||||||
var cs = this.getFillColorSpace();
|
var cs = this.getFillColorSpace();
|
||||||
|
|
||||||
if (cs.name == 'Pattern') {
|
if (cs.name == 'Pattern') {
|
||||||
var patternName = arguments[0];
|
var length = arguments.length;
|
||||||
this.setFillPattern(patternName);
|
var base = cs.base;
|
||||||
|
if (base) {
|
||||||
|
var baseComps = base.numComps;
|
||||||
|
|
||||||
|
if (baseComps != length - 1)
|
||||||
|
error("invalid base color for pattern colorspace");
|
||||||
|
|
||||||
|
var color = [];
|
||||||
|
for (var i = 0; i < baseComps; ++i)
|
||||||
|
color.push(arguments[i]);
|
||||||
|
|
||||||
|
color = base.getRgb(color);
|
||||||
|
}
|
||||||
|
var patternName = arguments[length - 1];
|
||||||
|
this.setFillPattern(patternName, base, color);
|
||||||
} else {
|
} else {
|
||||||
// TODO real impl
|
// TODO real impl
|
||||||
this.setFillColor.apply(this, arguments);
|
this.setFillColor.apply(this, arguments);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setFillPattern: function(patternName) {
|
setFillPattern: function(patternName, baseCS, color) {
|
||||||
if (!IsName(patternName))
|
if (!IsName(patternName))
|
||||||
error("Bad args to getPattern");
|
error("Bad args to getPattern");
|
||||||
|
|
||||||
@ -4028,7 +4130,7 @@ var CanvasGraphics = (function() {
|
|||||||
var patternFn = types[typeNum];
|
var patternFn = types[typeNum];
|
||||||
if (!patternFn)
|
if (!patternFn)
|
||||||
error("Unhandled pattern type");
|
error("Unhandled pattern type");
|
||||||
patternFn.call(this, pattern, dict);
|
patternFn.call(this, pattern, dict, baseCS, color);
|
||||||
},
|
},
|
||||||
setShadingPattern: function(pattern, dict) {
|
setShadingPattern: function(pattern, dict) {
|
||||||
var matrix = dict.get("Matrix");
|
var matrix = dict.get("Matrix");
|
||||||
@ -4051,7 +4153,7 @@ var CanvasGraphics = (function() {
|
|||||||
this.ctx.fillRect(0,0,0,0);
|
this.ctx.fillRect(0,0,0,0);
|
||||||
this.transform.apply(this, inv);
|
this.transform.apply(this, inv);
|
||||||
},
|
},
|
||||||
setTilingPattern: function(pattern, dict) {
|
setTilingPattern: function(pattern, dict, baseCS, color) {
|
||||||
function multiply(m, tm) {
|
function multiply(m, tm) {
|
||||||
var a = m[0] * tm[0] + m[1] * tm[2];
|
var a = m[0] * tm[0] + m[1] * tm[2];
|
||||||
var b = m[0] * tm[1] + m[1] * tm[3];
|
var b = m[0] * tm[1] + m[1] * tm[3];
|
||||||
@ -4065,17 +4167,6 @@ var CanvasGraphics = (function() {
|
|||||||
this.save();
|
this.save();
|
||||||
var ctx = this.ctx;
|
var ctx = this.ctx;
|
||||||
|
|
||||||
var paintType = dict.get('PaintType');
|
|
||||||
switch (paintType) {
|
|
||||||
case PAINT_TYPE_COLORED:
|
|
||||||
// should go to default for color space
|
|
||||||
ctx.fillStyle = this.makeCssRgb(1, 1, 1);
|
|
||||||
ctx.strokeStyle = this.makeCssRgb(0, 0, 0);
|
|
||||||
break;
|
|
||||||
case PAINT_TYPE_UNCOLORED:
|
|
||||||
default:
|
|
||||||
error('Unsupported paint type');
|
|
||||||
}
|
|
||||||
|
|
||||||
TODO('TilingType');
|
TODO('TilingType');
|
||||||
|
|
||||||
@ -4106,6 +4197,21 @@ var CanvasGraphics = (function() {
|
|||||||
var savedCtx = ctx;
|
var savedCtx = ctx;
|
||||||
this.ctx = tmpCtx;
|
this.ctx = tmpCtx;
|
||||||
|
|
||||||
|
var paintType = dict.get('PaintType');
|
||||||
|
switch (paintType) {
|
||||||
|
case PAINT_TYPE_COLORED:
|
||||||
|
// should go to default for color space
|
||||||
|
tmpCtx.fillStyle = this.makeCssRgb(1, 1, 1);
|
||||||
|
tmpCtx.strokeStyle = this.makeCssRgb(0, 0, 0);
|
||||||
|
break;
|
||||||
|
case PAINT_TYPE_UNCOLORED:
|
||||||
|
tmpCtx.fillStyle = this.makeCssRgb.apply(this, baseCS.getRgb(color));
|
||||||
|
tmpCtx.strokeStyle = this.makeCssRgb.apply(this, baseCS.getRgb(color));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error('Unsupported paint type');
|
||||||
|
}
|
||||||
|
|
||||||
// normalize transform matrix so each step
|
// normalize transform matrix so each step
|
||||||
// takes up the entire tmpCanvas (need to remove white borders)
|
// takes up the entire tmpCanvas (need to remove white borders)
|
||||||
if (matrix[1] === 0 && matrix[2] === 0) {
|
if (matrix[1] === 0 && matrix[2] === 0) {
|
||||||
@ -4219,7 +4325,7 @@ var CanvasGraphics = (function() {
|
|||||||
if (background)
|
if (background)
|
||||||
TODO('handle background colors');
|
TODO('handle background colors');
|
||||||
|
|
||||||
var cs = shading.get2('ColorSpace', 'CS');
|
var cs = shading.get('ColorSpace', 'CS');
|
||||||
cs = ColorSpace.parse(cs, this.xref, this.res);
|
cs = ColorSpace.parse(cs, this.xref, this.res);
|
||||||
|
|
||||||
var types = [null,
|
var types = [null,
|
||||||
@ -4229,8 +4335,12 @@ var CanvasGraphics = (function() {
|
|||||||
|
|
||||||
var typeNum = shading.get('ShadingType');
|
var typeNum = shading.get('ShadingType');
|
||||||
var shadingFn = types[typeNum];
|
var shadingFn = types[typeNum];
|
||||||
|
|
||||||
|
// Most likely we will not implement other types of shading
|
||||||
|
// unless the browser supports them
|
||||||
if (!shadingFn)
|
if (!shadingFn)
|
||||||
error("Unknown or NYI type of shading '"+ typeNum +"'");
|
TODO("Unknown or NYI type of shading '"+ typeNum +"'");
|
||||||
|
|
||||||
return shadingFn.call(this, shading, cs);
|
return shadingFn.call(this, shading, cs);
|
||||||
},
|
},
|
||||||
getAxialShading: function(sh, cs) {
|
getAxialShading: function(sh, cs) {
|
||||||
@ -4383,8 +4493,8 @@ var CanvasGraphics = (function() {
|
|||||||
|
|
||||||
var ctx = this.ctx;
|
var ctx = this.ctx;
|
||||||
var dict = image.dict;
|
var dict = image.dict;
|
||||||
var w = dict.get2('Width', 'W');
|
var w = dict.get('Width', 'W');
|
||||||
var h = dict.get2('Height', 'H');
|
var h = dict.get('Height', 'H');
|
||||||
// scale the image to the unit square
|
// scale the image to the unit square
|
||||||
ctx.scale(1 / w, -1 / h);
|
ctx.scale(1 / w, -1 / h);
|
||||||
|
|
||||||
@ -4520,10 +4630,24 @@ var CanvasGraphics = (function() {
|
|||||||
})();
|
})();
|
||||||
|
|
||||||
var ColorSpace = (function() {
|
var ColorSpace = (function() {
|
||||||
|
// Constructor should define this.numComps, this.defaultColor, this.name
|
||||||
function constructor() {
|
function constructor() {
|
||||||
error('should not call ColorSpace constructor');
|
error('should not call ColorSpace constructor');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
constructor.prototype = {
|
||||||
|
// Input: array of size numComps representing color component values
|
||||||
|
// Output: array of rgb values, each value ranging from [0.1]
|
||||||
|
getRgb: function cs_getRgb(color) {
|
||||||
|
error('Should not call ColorSpace.getRgb');
|
||||||
|
},
|
||||||
|
// Input: Uint8Array of component values, each value scaled to [0,255]
|
||||||
|
// Output: Uint8Array of rgb values, each value scaled to [0,255]
|
||||||
|
getRgbBuffer: function cs_getRgbBuffer(input) {
|
||||||
|
error('Should not call ColorSpace.getRgbBuffer');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
constructor.parse = function colorspace_parse(cs, xref, res) {
|
constructor.parse = function colorspace_parse(cs, xref, res) {
|
||||||
if (IsName(cs)) {
|
if (IsName(cs)) {
|
||||||
var colorSpaces = res.get('ColorSpace');
|
var colorSpaces = res.get('ColorSpace');
|
||||||
@ -4594,15 +4718,24 @@ var ColorSpace = (function() {
|
|||||||
return new DeviceCmykCS();
|
return new DeviceCmykCS();
|
||||||
break;
|
break;
|
||||||
case 'Pattern':
|
case 'Pattern':
|
||||||
return new PatternCS();
|
var baseCS = cs[1];
|
||||||
|
if (baseCS)
|
||||||
|
baseCS = ColorSpace.parse(baseCS, xref, res);
|
||||||
|
return new PatternCS(baseCS);
|
||||||
break;
|
break;
|
||||||
case 'Indexed':
|
case 'Indexed':
|
||||||
var base = ColorSpace.parse(cs[1], xref, res);
|
var base = ColorSpace.parse(cs[1], xref, res);
|
||||||
var hiVal = cs[2] + 1;
|
var hiVal = cs[2] + 1;
|
||||||
var lookup = xref.fetchIfRef(cs[3]);
|
var lookup = xref.fetchIfRef(cs[3]);
|
||||||
return new IndexedCS(base, hiVal, lookup);
|
return new IndexedCS(base, hiVal, lookup);
|
||||||
|
break;
|
||||||
|
case 'Separation':
|
||||||
|
var name = cs[1];
|
||||||
|
var alt = ColorSpace.parse(cs[2], xref, res);
|
||||||
|
var tintFn = new PDFFunction(xref, xref.fetchIfRef(cs[3]));
|
||||||
|
return new SeparationCS(alt, tintFn);
|
||||||
|
break;
|
||||||
case 'Lab':
|
case 'Lab':
|
||||||
case 'Seperation':
|
|
||||||
case 'DeviceN':
|
case 'DeviceN':
|
||||||
default:
|
default:
|
||||||
error("unrecognized color space object '" + mode + "'");
|
error("unrecognized color space object '" + mode + "'");
|
||||||
@ -4615,9 +4748,48 @@ var ColorSpace = (function() {
|
|||||||
return constructor;
|
return constructor;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
var SeparationCS = (function() {
|
||||||
|
function constructor(base, tintFn) {
|
||||||
|
this.name = "Separation";
|
||||||
|
this.numComps = 1;
|
||||||
|
this.defaultColor = [1];
|
||||||
|
|
||||||
|
this.base = base;
|
||||||
|
this.tintFn = tintFn;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor.prototype = {
|
||||||
|
getRgb: function sepcs_getRgb(color) {
|
||||||
|
var tinted = this.tintFn.func(color);
|
||||||
|
return this.base.getRgb(tinted);
|
||||||
|
},
|
||||||
|
getRgbBuffer: function sepcs_getRgbBuffer(input) {
|
||||||
|
var tintFn = this.tintFn;
|
||||||
|
var base = this.base;
|
||||||
|
|
||||||
|
var length = 3 * input.length;
|
||||||
|
var pos = 0;
|
||||||
|
|
||||||
|
var numComps = base.numComps;
|
||||||
|
var baseBuf = new Uint8Array(numComps * input.length);
|
||||||
|
for (var i = 0, ii = input.length; i < ii; ++i) {
|
||||||
|
var scaled = input[i] / 255;
|
||||||
|
var tinted = tintFn.func([scaled]);
|
||||||
|
for (var j = 0; j < numComps; ++j)
|
||||||
|
baseBuf[pos++] = 255 * tinted[j];
|
||||||
|
}
|
||||||
|
return base.getRgbBuffer(baseBuf);
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return constructor;
|
||||||
|
})();
|
||||||
|
|
||||||
var PatternCS = (function() {
|
var PatternCS = (function() {
|
||||||
function constructor() {
|
function constructor(baseCS) {
|
||||||
this.name = 'Pattern';
|
this.name = 'Pattern';
|
||||||
|
this.base = baseCS;
|
||||||
}
|
}
|
||||||
constructor.prototype = {};
|
constructor.prototype = {};
|
||||||
|
|
||||||
@ -4649,17 +4821,18 @@ var IndexedCS = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
constructor.prototype = {
|
constructor.prototype = {
|
||||||
getRgb: function graycs_getRgb(color) {
|
getRgb: function indexcs_getRgb(color) {
|
||||||
var lookup = this.lookup;
|
|
||||||
var base = this.base;
|
|
||||||
var numComps = base.numComps;
|
var numComps = base.numComps;
|
||||||
|
|
||||||
|
var start = color[0] * numComps;
|
||||||
var c = [];
|
var c = [];
|
||||||
for (var i = 0; i < numComps; ++i)
|
|
||||||
c.push(lookup[i]);
|
for (var i = start, ii = start + numComps; i < ii; ++i)
|
||||||
|
c.push(this.lookup[i]);
|
||||||
|
|
||||||
return this.base.getRgb(c);
|
return this.base.getRgb(c);
|
||||||
},
|
},
|
||||||
getRgbBuffer: function graycs_getRgbBuffer(input) {
|
getRgbBuffer: function indexcs_getRgbBuffer(input) {
|
||||||
var base = this.base;
|
var base = this.base;
|
||||||
var numComps = base.numComps;
|
var numComps = base.numComps;
|
||||||
var lookup = this.lookup;
|
var lookup = this.lookup;
|
||||||
@ -4668,7 +4841,7 @@ var IndexedCS = (function() {
|
|||||||
var baseBuf = new Uint8Array(length * numComps);
|
var baseBuf = new Uint8Array(length * numComps);
|
||||||
var baseBufPos = 0;
|
var baseBufPos = 0;
|
||||||
for (var i = 0; i < length; ++i) {
|
for (var i = 0; i < length; ++i) {
|
||||||
var lookupPos = input[i];
|
var lookupPos = input[i] * numComps;
|
||||||
for (var j = 0; j < numComps; ++j) {
|
for (var j = 0; j < numComps; ++j) {
|
||||||
baseBuf[baseBufPos++] = lookup[lookupPos + j];
|
baseBuf[baseBufPos++] = lookup[lookupPos + j];
|
||||||
}
|
}
|
||||||
@ -4693,7 +4866,7 @@ var DeviceGrayCS = (function() {
|
|||||||
return [c, c, c];
|
return [c, c, c];
|
||||||
},
|
},
|
||||||
getRgbBuffer: function graycs_getRgbBuffer(input) {
|
getRgbBuffer: function graycs_getRgbBuffer(input) {
|
||||||
var length = input.length;
|
var length = input.length * 3;
|
||||||
var rgbBuf = new Uint8Array(length);
|
var rgbBuf = new Uint8Array(length);
|
||||||
for (var i = 0, j = 0; i < length; ++i) {
|
for (var i = 0, j = 0; i < length; ++i) {
|
||||||
var c = input[i];
|
var c = input[i];
|
||||||
@ -4786,8 +4959,22 @@ var DeviceCmykCS = (function() {
|
|||||||
return [r, g, b];
|
return [r, g, b];
|
||||||
},
|
},
|
||||||
getRgbBuffer: function cmykcs_getRgbBuffer(colorBuf) {
|
getRgbBuffer: function cmykcs_getRgbBuffer(colorBuf) {
|
||||||
error('conversion from rgb to cmyk not implemented for images');
|
var length = colorBuf.length / 4;
|
||||||
return colorBuf;
|
var rgbBuf = new Uint8Array(length * 3);
|
||||||
|
var rgbBufPos = 0;
|
||||||
|
var colorBufPos = 0;
|
||||||
|
|
||||||
|
for (var i = 0; i < length; i++) {
|
||||||
|
var cmyk = [];
|
||||||
|
for (var j = 0; j < 4; ++j)
|
||||||
|
cmyk.push(colorBuf[colorBufPos++]/255);
|
||||||
|
|
||||||
|
var rgb = this.getRgb(cmyk);
|
||||||
|
for (var j = 0; j < 3; ++j)
|
||||||
|
rgbBuf[rgbBufPos++] = Math.round(rgb[j] * 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rgbBuf;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return constructor;
|
return constructor;
|
||||||
@ -4806,18 +4993,18 @@ var PDFImage = (function() {
|
|||||||
// TODO cache rendered images?
|
// TODO cache rendered images?
|
||||||
|
|
||||||
var dict = image.dict;
|
var dict = image.dict;
|
||||||
this.width = dict.get2('Width', 'W');
|
this.width = dict.get('Width', 'W');
|
||||||
this.height = dict.get2('Height', 'H');
|
this.height = dict.get('Height', 'H');
|
||||||
|
|
||||||
if (this.width < 1 || this.height < 1)
|
if (this.width < 1 || this.height < 1)
|
||||||
error('Invalid image width or height');
|
error('Invalid image width or height');
|
||||||
|
|
||||||
this.interpolate = dict.get2('Interpolate', 'I') || false;
|
this.interpolate = dict.get('Interpolate', 'I') || false;
|
||||||
this.imageMask = dict.get2('ImageMask', 'IM') || false;
|
this.imageMask = dict.get('ImageMask', 'IM') || false;
|
||||||
|
|
||||||
var bitsPerComponent = image.bitsPerComponent;
|
var bitsPerComponent = image.bitsPerComponent;
|
||||||
if (!bitsPerComponent) {
|
if (!bitsPerComponent) {
|
||||||
bitsPerComponent = dict.get2('BitsPerComponent', 'BPC');
|
bitsPerComponent = dict.get('BitsPerComponent', 'BPC');
|
||||||
if (!bitsPerComponent) {
|
if (!bitsPerComponent) {
|
||||||
if (this.imageMask)
|
if (this.imageMask)
|
||||||
bitsPerComponent = 1;
|
bitsPerComponent = 1;
|
||||||
@ -4827,11 +5014,11 @@ var PDFImage = (function() {
|
|||||||
}
|
}
|
||||||
this.bpc = bitsPerComponent;
|
this.bpc = bitsPerComponent;
|
||||||
|
|
||||||
var colorSpace = dict.get2('ColorSpace', 'CS');
|
var colorSpace = dict.get('ColorSpace', 'CS');
|
||||||
this.colorSpace = ColorSpace.parse(colorSpace, xref, res);
|
this.colorSpace = ColorSpace.parse(colorSpace, xref, res);
|
||||||
|
|
||||||
this.numComps = this.colorSpace.numComps;
|
this.numComps = this.colorSpace.numComps;
|
||||||
this.decode = dict.get2('Decode', 'D');
|
this.decode = dict.get('Decode', 'D');
|
||||||
|
|
||||||
var mask = xref.fetchIfRef(image.dict.get('Mask'));
|
var mask = xref.fetchIfRef(image.dict.get('Mask'));
|
||||||
var smask = xref.fetchIfRef(image.dict.get('SMask'));
|
var smask = xref.fetchIfRef(image.dict.get('SMask'));
|
||||||
@ -4904,7 +5091,7 @@ var PDFImage = (function() {
|
|||||||
output[i] = Math.round(255 * ret / ((1 << bpc) - 1));
|
output[i] = Math.round(255 * ret / ((1 << bpc) - 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return this.colorSpace.getRbaBuffer(output);
|
return output;
|
||||||
},
|
},
|
||||||
getOpacity: function getOpacity() {
|
getOpacity: function getOpacity() {
|
||||||
var smask = this.smask;
|
var smask = this.smask;
|
||||||
@ -4936,33 +5123,18 @@ var PDFImage = (function() {
|
|||||||
var rowBytes = (width * numComps * bpc + 7) >> 3;
|
var rowBytes = (width * numComps * bpc + 7) >> 3;
|
||||||
var imgArray = this.image.getBytes(height * rowBytes);
|
var imgArray = this.image.getBytes(height * rowBytes);
|
||||||
|
|
||||||
var comps = this.getComponents(imgArray);
|
var comps = this.colorSpace.getRgbBuffer(this.getComponents(imgArray));
|
||||||
var compsPos = 0;
|
var compsPos = 0;
|
||||||
var opacity = this.getOpacity();
|
var opacity = this.getOpacity();
|
||||||
var opacityPos = 0;
|
var opacityPos = 0;
|
||||||
var length = width * height * 4;
|
var length = width * height * 4;
|
||||||
|
|
||||||
switch (numComps) {
|
|
||||||
case 1:
|
|
||||||
for (var i = 0; i < length; i += 4) {
|
|
||||||
var p = comps[compsPos++];
|
|
||||||
buffer[i] = p;
|
|
||||||
buffer[i + 1] = p;
|
|
||||||
buffer[i + 2] = p;
|
|
||||||
buffer[i + 3] = opacity[opacityPos++];
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
for (var i = 0; i < length; i += 4) {
|
for (var i = 0; i < length; i += 4) {
|
||||||
buffer[i] = comps[compsPos++];
|
buffer[i] = comps[compsPos++];
|
||||||
buffer[i + 1] = comps[compsPos++];
|
buffer[i + 1] = comps[compsPos++];
|
||||||
buffer[i + 2] = comps[compsPos++];
|
buffer[i + 2] = comps[compsPos++];
|
||||||
buffer[i + 3] = opacity[opacityPos++];
|
buffer[i + 3] = opacity[opacityPos++];
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
default:
|
|
||||||
TODO('Images with ' + numComps + ' components per pixel');
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
fillGrayBuffer: function fillGrayBuffer(buffer) {
|
fillGrayBuffer: function fillGrayBuffer(buffer) {
|
||||||
var numComps = this.numComps;
|
var numComps = this.numComps;
|
||||||
@ -5004,7 +5176,7 @@ var PDFFunction = (function() {
|
|||||||
if (!typeFn)
|
if (!typeFn)
|
||||||
error('Unknown type of function');
|
error('Unknown type of function');
|
||||||
|
|
||||||
typeFn.apply(this, [fn, dict]);
|
typeFn.call(this, fn, dict);
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor.prototype = {
|
constructor.prototype = {
|
||||||
|
55
test/pdfs/asciihexdecode.pdf
Normal file
55
test/pdfs/asciihexdecode.pdf
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
%PDF-1.0
|
||||||
|
1 0 obj
|
||||||
|
<<
|
||||||
|
/Pages 2 0 R
|
||||||
|
/Type /Catalog
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
2 0 obj
|
||||||
|
<<
|
||||||
|
/Count 1
|
||||||
|
/Kids [ 3 0 R ]
|
||||||
|
/Type /Pages
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
3 0 obj
|
||||||
|
<<
|
||||||
|
/MediaBox [ 0 0 795 842 ]
|
||||||
|
/Parent 2 0 R
|
||||||
|
/Contents 4 0 R
|
||||||
|
/Resources <<
|
||||||
|
/Font <<
|
||||||
|
/F1 <<
|
||||||
|
/Name /F1
|
||||||
|
/BaseFont /Helvetica
|
||||||
|
/Subtype /Type1
|
||||||
|
/Type /Font
|
||||||
|
>>
|
||||||
|
>>
|
||||||
|
>>
|
||||||
|
/Type /Page
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
4 0 obj
|
||||||
|
<<
|
||||||
|
/Filter /ASCIIHexDecode
|
||||||
|
/Length 111
|
||||||
|
>>stream
|
||||||
|
42540A2F46312033302054660A333530203735302054640A323020544C0A312054720A2848656C6C6F20776F726C642920546A0A45540A>
|
||||||
|
endstream
|
||||||
|
endobj
|
||||||
|
xref
|
||||||
|
0 5
|
||||||
|
0000000000 65535 f
|
||||||
|
0000000010 00000 n
|
||||||
|
0000000067 00000 n
|
||||||
|
0000000136 00000 n
|
||||||
|
0000000373 00000 n
|
||||||
|
trailer
|
||||||
|
<<
|
||||||
|
/Root 1 0 R
|
||||||
|
/Size 5
|
||||||
|
>>
|
||||||
|
startxref
|
||||||
|
568
|
||||||
|
%%EOF
|
Loading…
Reference in New Issue
Block a user