pdfjs updated from github
|
@ -0,0 +1,432 @@
|
||||||
|
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var bidi = PDFJS.bidi = (function bidiClosure() {
|
||||||
|
// Character types for symbols from 0000 to 00FF.
|
||||||
|
var baseTypes = [
|
||||||
|
'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'S', 'B', 'S', 'WS',
|
||||||
|
'B', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN',
|
||||||
|
'BN', 'BN', 'B', 'B', 'B', 'S', 'WS', 'ON', 'ON', 'ET', 'ET', 'ET', 'ON',
|
||||||
|
'ON', 'ON', 'ON', 'ON', 'ON', 'CS', 'ON', 'CS', 'ON', 'EN', 'EN', 'EN',
|
||||||
|
'EN', 'EN', 'EN', 'EN', 'EN', 'EN', 'EN', 'ON', 'ON', 'ON', 'ON', 'ON',
|
||||||
|
'ON', 'ON', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L',
|
||||||
|
'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'ON', 'ON',
|
||||||
|
'ON', 'ON', 'ON', 'ON', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L',
|
||||||
|
'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L',
|
||||||
|
'L', 'ON', 'ON', 'ON', 'ON', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'B', 'BN',
|
||||||
|
'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN',
|
||||||
|
'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN',
|
||||||
|
'BN', 'CS', 'ON', 'ET', 'ET', 'ET', 'ET', 'ON', 'ON', 'ON', 'ON', 'L', 'ON',
|
||||||
|
'ON', 'ON', 'ON', 'ON', 'ET', 'ET', 'EN', 'EN', 'ON', 'L', 'ON', 'ON', 'ON',
|
||||||
|
'EN', 'L', 'ON', 'ON', 'ON', 'ON', 'ON', 'L', 'L', 'L', 'L', 'L', 'L', 'L',
|
||||||
|
'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L',
|
||||||
|
'L', 'ON', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L',
|
||||||
|
'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L',
|
||||||
|
'L', 'L', 'L', 'ON', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L'
|
||||||
|
];
|
||||||
|
|
||||||
|
// Character types for symbols from 0600 to 06FF
|
||||||
|
var arabicTypes = [
|
||||||
|
'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
|
||||||
|
'CS', 'AL', 'ON', 'ON', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'AL',
|
||||||
|
'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
|
||||||
|
'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
|
||||||
|
'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
|
||||||
|
'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
|
||||||
|
'AL', 'AL', 'AL', 'AL', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM',
|
||||||
|
'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'AL', 'AL', 'AL', 'AL',
|
||||||
|
'AL', 'AL', 'AL', 'AN', 'AN', 'AN', 'AN', 'AN', 'AN', 'AN', 'AN', 'AN',
|
||||||
|
'AN', 'ET', 'AN', 'AN', 'AL', 'AL', 'AL', 'NSM', 'AL', 'AL', 'AL', 'AL',
|
||||||
|
'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
|
||||||
|
'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
|
||||||
|
'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
|
||||||
|
'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
|
||||||
|
'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
|
||||||
|
'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
|
||||||
|
'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
|
||||||
|
'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
|
||||||
|
'AL', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM',
|
||||||
|
'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'ON', 'NSM',
|
||||||
|
'NSM', 'NSM', 'NSM', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
|
||||||
|
'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL'
|
||||||
|
];
|
||||||
|
|
||||||
|
function isOdd(i) {
|
||||||
|
return (i & 1) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isEven(i) {
|
||||||
|
return (i & 1) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function findUnequal(arr, start, value) {
|
||||||
|
var j;
|
||||||
|
for (var j = start, jj = arr.length; j < jj; ++j) {
|
||||||
|
if (arr[j] != value)
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setValues(arr, start, end, value) {
|
||||||
|
for (var j = start; j < end; ++j) {
|
||||||
|
arr[j] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function reverseValues(arr, start, end) {
|
||||||
|
for (var i = start, j = end - 1; i < j; ++i, --j) {
|
||||||
|
var temp = arr[i];
|
||||||
|
arr[i] = arr[j];
|
||||||
|
arr[j] = temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function mirrorGlyphs(c) {
|
||||||
|
/*
|
||||||
|
# BidiMirroring-1.txt
|
||||||
|
0028; 0029 # LEFT PARENTHESIS
|
||||||
|
0029; 0028 # RIGHT PARENTHESIS
|
||||||
|
003C; 003E # LESS-THAN SIGN
|
||||||
|
003E; 003C # GREATER-THAN SIGN
|
||||||
|
005B; 005D # LEFT SQUARE BRACKET
|
||||||
|
005D; 005B # RIGHT SQUARE BRACKET
|
||||||
|
007B; 007D # LEFT CURLY BRACKET
|
||||||
|
007D; 007B # RIGHT CURLY BRACKET
|
||||||
|
00AB; 00BB # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
|
||||||
|
00BB; 00AB # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
|
||||||
|
*/
|
||||||
|
switch (c) {
|
||||||
|
case '(':
|
||||||
|
return ')';
|
||||||
|
case ')':
|
||||||
|
return '(';
|
||||||
|
case '<':
|
||||||
|
return '>';
|
||||||
|
case '>':
|
||||||
|
return '<';
|
||||||
|
case ']':
|
||||||
|
return '[';
|
||||||
|
case '[':
|
||||||
|
return ']';
|
||||||
|
case '}':
|
||||||
|
return '{';
|
||||||
|
case '{':
|
||||||
|
return '}';
|
||||||
|
case '\u00AB':
|
||||||
|
return '\u00BB';
|
||||||
|
case '\u00BB':
|
||||||
|
return '\u00AB';
|
||||||
|
default:
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function bidi(text, startLevel) {
|
||||||
|
var str = text.str;
|
||||||
|
var strLength = str.length;
|
||||||
|
if (strLength == 0)
|
||||||
|
return str;
|
||||||
|
|
||||||
|
// get types, fill arrays
|
||||||
|
|
||||||
|
var chars = [];
|
||||||
|
var types = [];
|
||||||
|
var oldtypes = [];
|
||||||
|
var numBidi = 0;
|
||||||
|
|
||||||
|
for (var i = 0; i < strLength; ++i) {
|
||||||
|
chars[i] = str.charAt(i);
|
||||||
|
|
||||||
|
var charCode = str.charCodeAt(i);
|
||||||
|
var charType = 'L';
|
||||||
|
if (charCode <= 0x00ff)
|
||||||
|
charType = baseTypes[charCode];
|
||||||
|
else if (0x0590 <= charCode && charCode <= 0x05f4)
|
||||||
|
charType = 'R';
|
||||||
|
else if (0x0600 <= charCode && charCode <= 0x06ff)
|
||||||
|
charType = arabicTypes[charCode & 0xff];
|
||||||
|
else if (0x0700 <= charCode && charCode <= 0x08AC)
|
||||||
|
charType = 'AL';
|
||||||
|
|
||||||
|
if (charType == 'R' || charType == 'AL' || charType == 'AN')
|
||||||
|
numBidi++;
|
||||||
|
|
||||||
|
oldtypes[i] = types[i] = charType;
|
||||||
|
}
|
||||||
|
|
||||||
|
// detect the bidi method
|
||||||
|
// if there are no rtl characters then no bidi needed
|
||||||
|
// if less than 30% chars are rtl then string is primarily ltr
|
||||||
|
// if more than 30% chars are rtl then string is primarily rtl
|
||||||
|
if (numBidi == 0) {
|
||||||
|
text.direction = 'ltr';
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startLevel == -1) {
|
||||||
|
if ((strLength / numBidi) < 0.3) {
|
||||||
|
text.direction = 'ltr';
|
||||||
|
startLevel = 0;
|
||||||
|
} else {
|
||||||
|
text.direction = 'rtl';
|
||||||
|
startLevel = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var levels = [];
|
||||||
|
|
||||||
|
for (var i = 0; i < strLength; ++i) {
|
||||||
|
levels[i] = startLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
X1-X10: skip most of this, since we are NOT doing the embeddings.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var e = isOdd(startLevel) ? 'R' : 'L';
|
||||||
|
var sor = e;
|
||||||
|
var eor = sor;
|
||||||
|
|
||||||
|
/*
|
||||||
|
W1. Examine each non-spacing mark (NSM) in the level run, and change the
|
||||||
|
type of the NSM to the type of the previous character. If the NSM is at the
|
||||||
|
start of the level run, it will get the type of sor.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var lastType = sor;
|
||||||
|
for (var i = 0; i < strLength; ++i) {
|
||||||
|
if (types[i] == 'NSM')
|
||||||
|
types[i] = lastType;
|
||||||
|
else
|
||||||
|
lastType = types[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
W2. Search backwards from each instance of a European number until the
|
||||||
|
first strong type (R, L, AL, or sor) is found. If an AL is found, change
|
||||||
|
the type of the European number to Arabic number.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var lastType = sor;
|
||||||
|
for (var i = 0; i < strLength; ++i) {
|
||||||
|
var t = types[i];
|
||||||
|
if (t == 'EN')
|
||||||
|
types[i] = (lastType == 'AL') ? 'AN' : 'EN';
|
||||||
|
else if (t == 'R' || t == 'L' || t == 'AL')
|
||||||
|
lastType = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
W3. Change all ALs to R.
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (var i = 0; i < strLength; ++i) {
|
||||||
|
var t = types[i];
|
||||||
|
if (t == 'AL')
|
||||||
|
types[i] = 'R';
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
W4. A single European separator between two European numbers changes to a
|
||||||
|
European number. A single common separator between two numbers of the same
|
||||||
|
type changes to that type:
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (var i = 1; i < strLength - 1; ++i) {
|
||||||
|
if (types[i] == 'ES' && types[i - 1] == 'EN' && types[i + 1] == 'EN')
|
||||||
|
types[i] = 'EN';
|
||||||
|
if (types[i] == 'CS' && (types[i - 1] == 'EN' || types[i - 1] == 'AN') &&
|
||||||
|
types[i + 1] == types[i - 1])
|
||||||
|
types[i] = types[i - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
W5. A sequence of European terminators adjacent to European numbers changes
|
||||||
|
to all European numbers:
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (var i = 0; i < strLength; ++i) {
|
||||||
|
if (types[i] == 'EN') {
|
||||||
|
// do before
|
||||||
|
for (var j = i - 1; j >= 0; --j) {
|
||||||
|
if (types[j] != 'ET')
|
||||||
|
break;
|
||||||
|
types[j] = 'EN';
|
||||||
|
}
|
||||||
|
// do after
|
||||||
|
for (var j = i + 1; j < strLength; --j) {
|
||||||
|
if (types[j] != 'ET')
|
||||||
|
break;
|
||||||
|
types[j] = 'EN';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
W6. Otherwise, separators and terminators change to Other Neutral:
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (var i = 0; i < strLength; ++i) {
|
||||||
|
var t = types[i];
|
||||||
|
if (t == 'WS' || t == 'ES' || t == 'ET' || t == 'CS')
|
||||||
|
types[i] = 'ON';
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
W7. Search backwards from each instance of a European number until the
|
||||||
|
first strong type (R, L, or sor) is found. If an L is found, then change
|
||||||
|
the type of the European number to L.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var lastType = sor;
|
||||||
|
for (var i = 0; i < strLength; ++i) {
|
||||||
|
var t = types[i];
|
||||||
|
if (t == 'EN')
|
||||||
|
types[i] = (lastType == 'L') ? 'L' : 'EN';
|
||||||
|
else if (t == 'R' || t == 'L')
|
||||||
|
lastType = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
N1. A sequence of neutrals takes the direction of the surrounding strong
|
||||||
|
text if the text on both sides has the same direction. European and Arabic
|
||||||
|
numbers are treated as though they were R. Start-of-level-run (sor) and
|
||||||
|
end-of-level-run (eor) are used at level run boundaries.
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (var i = 0; i < strLength; ++i) {
|
||||||
|
if (types[i] == 'ON') {
|
||||||
|
var end = findUnequal(types, i + 1, 'ON');
|
||||||
|
var before = sor;
|
||||||
|
if (i > 0)
|
||||||
|
before = types[i - 1];
|
||||||
|
var after = eor;
|
||||||
|
if (end + 1 < strLength)
|
||||||
|
after = types[end + 1];
|
||||||
|
if (before != 'L')
|
||||||
|
before = 'R';
|
||||||
|
if (after != 'L')
|
||||||
|
after = 'R';
|
||||||
|
if (before == after)
|
||||||
|
setValues(types, i, end, before);
|
||||||
|
i = end - 1; // reset to end (-1 so next iteration is ok)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
N2. Any remaining neutrals take the embedding direction.
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (var i = 0; i < strLength; ++i) {
|
||||||
|
if (types[i] == 'ON')
|
||||||
|
types[i] = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
I1. For all characters with an even (left-to-right) embedding direction,
|
||||||
|
those of type R go up one level and those of type AN or EN go up two
|
||||||
|
levels.
|
||||||
|
I2. For all characters with an odd (right-to-left) embedding direction,
|
||||||
|
those of type L, EN or AN go up one level.
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (var i = 0; i < strLength; ++i) {
|
||||||
|
var t = types[i];
|
||||||
|
if (isEven(levels[i])) {
|
||||||
|
if (t == 'R') {
|
||||||
|
levels[i] += 1;
|
||||||
|
} else if (t == 'AN' || t == 'EN') {
|
||||||
|
levels[i] += 2;
|
||||||
|
}
|
||||||
|
} else { // isOdd, so
|
||||||
|
if (t == 'L' || t == 'AN' || t == 'EN') {
|
||||||
|
levels[i] += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
L1. On each line, reset the embedding level of the following characters to
|
||||||
|
the paragraph embedding level:
|
||||||
|
|
||||||
|
segment separators,
|
||||||
|
paragraph separators,
|
||||||
|
any sequence of whitespace characters preceding a segment separator or
|
||||||
|
paragraph separator, and any sequence of white space characters at the end
|
||||||
|
of the line.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// don't bother as text is only single line
|
||||||
|
|
||||||
|
/*
|
||||||
|
L2. From the highest level found in the text to the lowest odd level on
|
||||||
|
each line, reverse any contiguous sequence of characters that are at that
|
||||||
|
level or higher.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// find highest level & lowest odd level
|
||||||
|
|
||||||
|
var highestLevel = -1;
|
||||||
|
var lowestOddLevel = 99;
|
||||||
|
for (var i = 0, ii = levels.length; i < ii; ++i) {
|
||||||
|
var level = levels[i];
|
||||||
|
if (highestLevel < level)
|
||||||
|
highestLevel = level;
|
||||||
|
if (lowestOddLevel > level && isOdd(level))
|
||||||
|
lowestOddLevel = level;
|
||||||
|
}
|
||||||
|
|
||||||
|
// now reverse between those limits
|
||||||
|
|
||||||
|
for (var level = highestLevel; level >= lowestOddLevel; --level) {
|
||||||
|
// find segments to reverse
|
||||||
|
var start = -1;
|
||||||
|
for (var i = 0, ii = levels.length; i < ii; ++i) {
|
||||||
|
if (levels[i] < level) {
|
||||||
|
if (start >= 0) {
|
||||||
|
reverseValues(chars, start, i);
|
||||||
|
start = -1;
|
||||||
|
}
|
||||||
|
} else if (start < 0) {
|
||||||
|
start = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (start >= 0) {
|
||||||
|
reverseValues(chars, start, levels.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
L3. Combining marks applied to a right-to-left base character will at this
|
||||||
|
point precede their base character. If the rendering engine expects them to
|
||||||
|
follow the base characters in the final display process, then the ordering
|
||||||
|
of the marks and the base character must be reversed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// don't bother for now
|
||||||
|
|
||||||
|
/*
|
||||||
|
L4. A character that possesses the mirrored property as specified by
|
||||||
|
Section 4.7, Mirrored, must be depicted by a mirrored glyph if the resolved
|
||||||
|
directionality of that character is R.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// don't mirror as characters are already mirrored in the pdf
|
||||||
|
|
||||||
|
// Finally, return string
|
||||||
|
|
||||||
|
var result = '';
|
||||||
|
for (var i = 0, ii = chars.length; i < ii; ++i) {
|
||||||
|
var ch = chars[i];
|
||||||
|
if (ch != '<' && ch != '>')
|
||||||
|
result += ch;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bidi;
|
||||||
|
})();
|
||||||
|
|
|
@ -3,34 +3,34 @@
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var ColorSpace = (function colorSpaceColorSpace() {
|
var ColorSpace = (function ColorSpaceClosure() {
|
||||||
// Constructor should define this.numComps, this.defaultColor, this.name
|
// Constructor should define this.numComps, this.defaultColor, this.name
|
||||||
function constructor() {
|
function ColorSpace() {
|
||||||
error('should not call ColorSpace constructor');
|
error('should not call ColorSpace constructor');
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor.prototype = {
|
ColorSpace.prototype = {
|
||||||
// Input: array of size numComps representing color component values
|
// Input: array of size numComps representing color component values
|
||||||
// Output: array of rgb values, each value ranging from [0.1]
|
// Output: array of rgb values, each value ranging from [0.1]
|
||||||
getRgb: function colorSpaceGetRgb(color) {
|
getRgb: function ColorSpace_getRgb(color) {
|
||||||
error('Should not call ColorSpace.getRgb: ' + color);
|
error('Should not call ColorSpace.getRgb: ' + color);
|
||||||
},
|
},
|
||||||
// Input: Uint8Array of component values, each value scaled to [0,255]
|
// Input: Uint8Array of component values, each value scaled to [0,255]
|
||||||
// Output: Uint8Array of rgb values, each value scaled to [0,255]
|
// Output: Uint8Array of rgb values, each value scaled to [0,255]
|
||||||
getRgbBuffer: function colorSpaceGetRgbBuffer(input) {
|
getRgbBuffer: function ColorSpace_getRgbBuffer(input) {
|
||||||
error('Should not call ColorSpace.getRgbBuffer: ' + input);
|
error('Should not call ColorSpace.getRgbBuffer: ' + input);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor.parse = function colorSpaceParse(cs, xref, res) {
|
ColorSpace.parse = function ColorSpace_parse(cs, xref, res) {
|
||||||
var IR = constructor.parseToIR(cs, xref, res);
|
var IR = ColorSpace.parseToIR(cs, xref, res);
|
||||||
if (IR instanceof AlternateCS)
|
if (IR instanceof AlternateCS)
|
||||||
return IR;
|
return IR;
|
||||||
|
|
||||||
return constructor.fromIR(IR);
|
return ColorSpace.fromIR(IR);
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor.fromIR = function colorSpaceFromIR(IR) {
|
ColorSpace.fromIR = function ColorSpace_fromIR(IR) {
|
||||||
var name = isArray(IR) ? IR[0] : IR;
|
var name = isArray(IR) ? IR[0] : IR;
|
||||||
|
|
||||||
switch (name) {
|
switch (name) {
|
||||||
|
@ -57,15 +57,20 @@ var ColorSpace = (function colorSpaceColorSpace() {
|
||||||
|
|
||||||
return new AlternateCS(numComps, ColorSpace.fromIR(alt),
|
return new AlternateCS(numComps, ColorSpace.fromIR(alt),
|
||||||
PDFFunction.fromIR(tintFnIR));
|
PDFFunction.fromIR(tintFnIR));
|
||||||
|
case 'LabCS':
|
||||||
|
var whitePoint = IR[1].WhitePoint;
|
||||||
|
var blackPoint = IR[1].BlackPoint;
|
||||||
|
var range = IR[1].Range;
|
||||||
|
return new LabCS(whitePoint, blackPoint, range);
|
||||||
default:
|
default:
|
||||||
error('Unkown name ' + name);
|
error('Unkown name ' + name);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor.parseToIR = function colorSpaceParseToIR(cs, xref, res) {
|
ColorSpace.parseToIR = function ColorSpace_parseToIR(cs, xref, res) {
|
||||||
if (isName(cs)) {
|
if (isName(cs)) {
|
||||||
var colorSpaces = xref.fetchIfRef(res.get('ColorSpace'));
|
var colorSpaces = res.get('ColorSpace');
|
||||||
if (isDict(colorSpaces)) {
|
if (isDict(colorSpaces)) {
|
||||||
var refcs = colorSpaces.get(cs.name);
|
var refcs = colorSpaces.get(cs.name);
|
||||||
if (refcs)
|
if (refcs)
|
||||||
|
@ -130,6 +135,7 @@ var ColorSpace = (function colorSpaceColorSpace() {
|
||||||
basePatternCS = ColorSpace.parseToIR(basePatternCS, xref, res);
|
basePatternCS = ColorSpace.parseToIR(basePatternCS, xref, res);
|
||||||
return ['PatternCS', basePatternCS];
|
return ['PatternCS', basePatternCS];
|
||||||
case 'Indexed':
|
case 'Indexed':
|
||||||
|
case 'I':
|
||||||
var baseIndexedCS = ColorSpace.parseToIR(cs[1], xref, res);
|
var baseIndexedCS = ColorSpace.parseToIR(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]);
|
||||||
|
@ -146,6 +152,8 @@ var ColorSpace = (function colorSpaceColorSpace() {
|
||||||
var tintFnIR = PDFFunction.getIR(xref, xref.fetchIfRef(cs[3]));
|
var tintFnIR = PDFFunction.getIR(xref, xref.fetchIfRef(cs[3]));
|
||||||
return ['AlternateCS', numComps, alt, tintFnIR];
|
return ['AlternateCS', numComps, alt, tintFnIR];
|
||||||
case 'Lab':
|
case 'Lab':
|
||||||
|
var params = cs[1].getAll();
|
||||||
|
return ['LabCS', params];
|
||||||
default:
|
default:
|
||||||
error('unimplemented color space object "' + mode + '"');
|
error('unimplemented color space object "' + mode + '"');
|
||||||
}
|
}
|
||||||
|
@ -154,8 +162,31 @@ var ColorSpace = (function colorSpaceColorSpace() {
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
/**
|
||||||
|
* Checks if a decode map matches the default decode map for a color space.
|
||||||
|
* This handles the general decode maps where there are two values per
|
||||||
|
* component. e.g. [0, 1, 0, 1, 0, 1] for a RGB color.
|
||||||
|
* This does not handle Lab, Indexed, or Pattern decode maps since they are
|
||||||
|
* slightly different.
|
||||||
|
* @param {Array} decode Decode map (usually from an image).
|
||||||
|
* @param {Number} n Number of components the color space has.
|
||||||
|
*/
|
||||||
|
ColorSpace.isDefaultDecode = function ColorSpace_isDefaultDecode(decode, n) {
|
||||||
|
if (!decode)
|
||||||
|
return true;
|
||||||
|
|
||||||
return constructor;
|
if (n * 2 !== decode.length) {
|
||||||
|
warning('The decode map is not the correct length');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
for (var i = 0, ii = decode.length; i < ii; i += 2) {
|
||||||
|
if (decode[i] != 0 || decode[i + 1] != 1)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
return ColorSpace;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -164,8 +195,8 @@ var ColorSpace = (function colorSpaceColorSpace() {
|
||||||
* Both color spaces use a tinting function to convert colors to a base color
|
* Both color spaces use a tinting function to convert colors to a base color
|
||||||
* space.
|
* space.
|
||||||
*/
|
*/
|
||||||
var AlternateCS = (function alternateCS() {
|
var AlternateCS = (function AlternateCSClosure() {
|
||||||
function constructor(numComps, base, tintFn) {
|
function AlternateCS(numComps, base, tintFn) {
|
||||||
this.name = 'Alternate';
|
this.name = 'Alternate';
|
||||||
this.numComps = numComps;
|
this.numComps = numComps;
|
||||||
this.defaultColor = [];
|
this.defaultColor = [];
|
||||||
|
@ -175,12 +206,12 @@ var AlternateCS = (function alternateCS() {
|
||||||
this.tintFn = tintFn;
|
this.tintFn = tintFn;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor.prototype = {
|
AlternateCS.prototype = {
|
||||||
getRgb: function altcs_getRgb(color) {
|
getRgb: function AlternateCS_getRgb(color) {
|
||||||
var tinted = this.tintFn(color);
|
var tinted = this.tintFn(color);
|
||||||
return this.base.getRgb(tinted);
|
return this.base.getRgb(tinted);
|
||||||
},
|
},
|
||||||
getRgbBuffer: function altcs_getRgbBuffer(input, bits) {
|
getRgbBuffer: function AlternateCS_getRgbBuffer(input, bits) {
|
||||||
var tintFn = this.tintFn;
|
var tintFn = this.tintFn;
|
||||||
var base = this.base;
|
var base = this.base;
|
||||||
var scale = 1 / ((1 << bits) - 1);
|
var scale = 1 / ((1 << bits) - 1);
|
||||||
|
@ -189,7 +220,7 @@ var AlternateCS = (function alternateCS() {
|
||||||
var baseNumComps = base.numComps;
|
var baseNumComps = base.numComps;
|
||||||
var baseBuf = new Uint8Array(baseNumComps * length);
|
var baseBuf = new Uint8Array(baseNumComps * length);
|
||||||
var numComps = this.numComps;
|
var numComps = this.numComps;
|
||||||
var scaled = new Array(numComps);
|
var scaled = [];
|
||||||
|
|
||||||
for (var i = 0; i < length; i += numComps) {
|
for (var i = 0; i < length; i += numComps) {
|
||||||
for (var z = 0; z < numComps; ++z)
|
for (var z = 0; z < numComps; ++z)
|
||||||
|
@ -200,24 +231,27 @@ var AlternateCS = (function alternateCS() {
|
||||||
baseBuf[pos++] = 255 * tinted[j];
|
baseBuf[pos++] = 255 * tinted[j];
|
||||||
}
|
}
|
||||||
return base.getRgbBuffer(baseBuf, 8);
|
return base.getRgbBuffer(baseBuf, 8);
|
||||||
|
},
|
||||||
|
isDefaultDecode: function AlternateCS_isDefaultDecode(decodeMap) {
|
||||||
|
return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return constructor;
|
return AlternateCS;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
var PatternCS = (function patternCS() {
|
var PatternCS = (function PatternCSClosure() {
|
||||||
function constructor(baseCS) {
|
function PatternCS(baseCS) {
|
||||||
this.name = 'Pattern';
|
this.name = 'Pattern';
|
||||||
this.base = baseCS;
|
this.base = baseCS;
|
||||||
}
|
}
|
||||||
constructor.prototype = {};
|
PatternCS.prototype = {};
|
||||||
|
|
||||||
return constructor;
|
return PatternCS;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
var IndexedCS = (function indexedCS() {
|
var IndexedCS = (function IndexedCSClosure() {
|
||||||
function constructor(base, highVal, lookup) {
|
function IndexedCS(base, highVal, lookup) {
|
||||||
this.name = 'Indexed';
|
this.name = 'Indexed';
|
||||||
this.numComps = 1;
|
this.numComps = 1;
|
||||||
this.defaultColor = [0];
|
this.defaultColor = [0];
|
||||||
|
@ -240,8 +274,8 @@ var IndexedCS = (function indexedCS() {
|
||||||
this.lookup = lookupArray;
|
this.lookup = lookupArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor.prototype = {
|
IndexedCS.prototype = {
|
||||||
getRgb: function indexcs_getRgb(color) {
|
getRgb: function IndexedCS_getRgb(color) {
|
||||||
var numComps = this.base.numComps;
|
var numComps = this.base.numComps;
|
||||||
var start = color[0] * numComps;
|
var start = color[0] * numComps;
|
||||||
var c = [];
|
var c = [];
|
||||||
|
@ -251,7 +285,7 @@ var IndexedCS = (function indexedCS() {
|
||||||
|
|
||||||
return this.base.getRgb(c);
|
return this.base.getRgb(c);
|
||||||
},
|
},
|
||||||
getRgbBuffer: function indexcs_getRgbBuffer(input) {
|
getRgbBuffer: function IndexedCS_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;
|
||||||
|
@ -267,24 +301,28 @@ var IndexedCS = (function indexedCS() {
|
||||||
}
|
}
|
||||||
|
|
||||||
return base.getRgbBuffer(baseBuf, 8);
|
return base.getRgbBuffer(baseBuf, 8);
|
||||||
|
},
|
||||||
|
isDefaultDecode: function IndexedCS_isDefaultDecode(decodeMap) {
|
||||||
|
// indexed color maps shouldn't be changed
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return constructor;
|
return IndexedCS;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
var DeviceGrayCS = (function deviceGrayCS() {
|
var DeviceGrayCS = (function DeviceGrayCSClosure() {
|
||||||
function constructor() {
|
function DeviceGrayCS() {
|
||||||
this.name = 'DeviceGray';
|
this.name = 'DeviceGray';
|
||||||
this.numComps = 1;
|
this.numComps = 1;
|
||||||
this.defaultColor = [0];
|
this.defaultColor = [0];
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor.prototype = {
|
DeviceGrayCS.prototype = {
|
||||||
getRgb: function graycs_getRgb(color) {
|
getRgb: function DeviceGrayCS_getRgb(color) {
|
||||||
var c = color[0];
|
var c = color[0];
|
||||||
return [c, c, c];
|
return [c, c, c];
|
||||||
},
|
},
|
||||||
getRgbBuffer: function graycs_getRgbBuffer(input, bits) {
|
getRgbBuffer: function DeviceGrayCS_getRgbBuffer(input, bits) {
|
||||||
var scale = 255 / ((1 << bits) - 1);
|
var scale = 255 / ((1 << bits) - 1);
|
||||||
var length = input.length;
|
var length = input.length;
|
||||||
var rgbBuf = new Uint8Array(length * 3);
|
var rgbBuf = new Uint8Array(length * 3);
|
||||||
|
@ -295,22 +333,25 @@ var DeviceGrayCS = (function deviceGrayCS() {
|
||||||
rgbBuf[j++] = c;
|
rgbBuf[j++] = c;
|
||||||
}
|
}
|
||||||
return rgbBuf;
|
return rgbBuf;
|
||||||
|
},
|
||||||
|
isDefaultDecode: function DeviceGrayCS_isDefaultDecode(decodeMap) {
|
||||||
|
return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return constructor;
|
return DeviceGrayCS;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
var DeviceRgbCS = (function deviceRgbCS() {
|
var DeviceRgbCS = (function DeviceRgbCSClosure() {
|
||||||
function constructor() {
|
function DeviceRgbCS() {
|
||||||
this.name = 'DeviceRGB';
|
this.name = 'DeviceRGB';
|
||||||
this.numComps = 3;
|
this.numComps = 3;
|
||||||
this.defaultColor = [0, 0, 0];
|
this.defaultColor = [0, 0, 0];
|
||||||
}
|
}
|
||||||
constructor.prototype = {
|
DeviceRgbCS.prototype = {
|
||||||
getRgb: function rgbcs_getRgb(color) {
|
getRgb: function DeviceRgbCS_getRgb(color) {
|
||||||
return color;
|
return color;
|
||||||
},
|
},
|
||||||
getRgbBuffer: function rgbcs_getRgbBuffer(input, bits) {
|
getRgbBuffer: function DeviceRgbCS_getRgbBuffer(input, bits) {
|
||||||
if (bits == 8)
|
if (bits == 8)
|
||||||
return input;
|
return input;
|
||||||
var scale = 255 / ((1 << bits) - 1);
|
var scale = 255 / ((1 << bits) - 1);
|
||||||
|
@ -319,73 +360,37 @@ var DeviceRgbCS = (function deviceRgbCS() {
|
||||||
for (i = 0; i < length; ++i)
|
for (i = 0; i < length; ++i)
|
||||||
rgbBuf[i] = (scale * input[i]) | 0;
|
rgbBuf[i] = (scale * input[i]) | 0;
|
||||||
return rgbBuf;
|
return rgbBuf;
|
||||||
|
},
|
||||||
|
isDefaultDecode: function DeviceRgbCS_isDefaultDecode(decodeMap) {
|
||||||
|
return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return constructor;
|
return DeviceRgbCS;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
var DeviceCmykCS = (function deviceCmykCS() {
|
var DeviceCmykCS = (function DeviceCmykCSClosure() {
|
||||||
function constructor() {
|
function DeviceCmykCS() {
|
||||||
this.name = 'DeviceCMYK';
|
this.name = 'DeviceCMYK';
|
||||||
this.numComps = 4;
|
this.numComps = 4;
|
||||||
this.defaultColor = [0, 0, 0, 1];
|
this.defaultColor = [0, 0, 0, 1];
|
||||||
}
|
}
|
||||||
constructor.prototype = {
|
DeviceCmykCS.prototype = {
|
||||||
getRgb: function cmykcs_getRgb(color) {
|
getRgb: function DeviceCmykCS_getRgb(color) {
|
||||||
var c = color[0], m = color[1], y = color[2], k = color[3];
|
var c = color[0], m = color[1], y = color[2], k = color[3];
|
||||||
var c1 = 1 - c, m1 = 1 - m, y1 = 1 - y, k1 = 1 - k;
|
|
||||||
|
|
||||||
var x, r, g, b;
|
// CMYK -> CMY: http://www.easyrgb.com/index.php?X=MATH&H=14#text14
|
||||||
// this is a matrix multiplication, unrolled for performance
|
c = (c * (1 - k) + k);
|
||||||
// code is taken from the poppler implementation
|
m = (m * (1 - k) + k);
|
||||||
x = c1 * m1 * y1 * k1; // 0 0 0 0
|
y = (y * (1 - k) + k);
|
||||||
r = g = b = x;
|
|
||||||
x = c1 * m1 * y1 * k; // 0 0 0 1
|
// CMY -> RGB: http://www.easyrgb.com/index.php?X=MATH&H=12#text12
|
||||||
r += 0.1373 * x;
|
var r = (1 - c);
|
||||||
g += 0.1216 * x;
|
var g = (1 - m);
|
||||||
b += 0.1255 * x;
|
var b = (1 - y);
|
||||||
x = c1 * m1 * y * k1; // 0 0 1 0
|
|
||||||
r += x;
|
|
||||||
g += 0.9490 * x;
|
|
||||||
x = c1 * m1 * y * k; // 0 0 1 1
|
|
||||||
r += 0.1098 * x;
|
|
||||||
g += 0.1020 * x;
|
|
||||||
x = c1 * m * y1 * k1; // 0 1 0 0
|
|
||||||
r += 0.9255 * x;
|
|
||||||
b += 0.5490 * x;
|
|
||||||
x = c1 * m * y1 * k; // 0 1 0 1
|
|
||||||
r += 0.1412 * x;
|
|
||||||
x = c1 * m * y * k1; // 0 1 1 0
|
|
||||||
r += 0.9294 * x;
|
|
||||||
g += 0.1098 * x;
|
|
||||||
b += 0.1412 * x;
|
|
||||||
x = c1 * m * y * k; // 0 1 1 1
|
|
||||||
r += 0.1333 * x;
|
|
||||||
x = c * m1 * y1 * k1; // 1 0 0 0
|
|
||||||
g += 0.6784 * x;
|
|
||||||
b += 0.9373 * x;
|
|
||||||
x = c * m1 * y1 * k; // 1 0 0 1
|
|
||||||
g += 0.0588 * x;
|
|
||||||
b += 0.1412 * x;
|
|
||||||
x = c * m1 * y * k1; // 1 0 1 0
|
|
||||||
g += 0.6510 * x;
|
|
||||||
b += 0.3137 * x;
|
|
||||||
x = c * m1 * y * k; // 1 0 1 1
|
|
||||||
g += 0.0745 * x;
|
|
||||||
x = c * m * y1 * k1; // 1 1 0 0
|
|
||||||
r += 0.1804 * x;
|
|
||||||
g += 0.1922 * x;
|
|
||||||
b += 0.5725 * x;
|
|
||||||
x = c * m * y1 * k; // 1 1 0 1
|
|
||||||
b += 0.0078 * x;
|
|
||||||
x = c * m * y * k1; // 1 1 1 0
|
|
||||||
r += 0.2118 * x;
|
|
||||||
g += 0.2119 * x;
|
|
||||||
b += 0.2235 * x;
|
|
||||||
|
|
||||||
return [r, g, b];
|
return [r, g, b];
|
||||||
},
|
},
|
||||||
getRgbBuffer: function cmykcs_getRgbBuffer(colorBuf, bits) {
|
getRgbBuffer: function DeviceCmykCS_getRgbBuffer(colorBuf, bits) {
|
||||||
var scale = 1 / ((1 << bits) - 1);
|
var scale = 1 / ((1 << bits) - 1);
|
||||||
var length = colorBuf.length / 4;
|
var length = colorBuf.length / 4;
|
||||||
var rgbBuf = new Uint8Array(length * 3);
|
var rgbBuf = new Uint8Array(length * 3);
|
||||||
|
@ -403,9 +408,125 @@ var DeviceCmykCS = (function deviceCmykCS() {
|
||||||
}
|
}
|
||||||
|
|
||||||
return rgbBuf;
|
return rgbBuf;
|
||||||
|
},
|
||||||
|
isDefaultDecode: function DeviceCmykCS_isDefaultDecode(decodeMap) {
|
||||||
|
return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return constructor;
|
return DeviceCmykCS;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
//
|
||||||
|
// LabCS: Based on "PDF Reference, Sixth Ed", p.250
|
||||||
|
//
|
||||||
|
var LabCS = (function LabCSClosure() {
|
||||||
|
function LabCS(whitePoint, blackPoint, range) {
|
||||||
|
this.name = 'Lab';
|
||||||
|
this.numComps = 3;
|
||||||
|
this.defaultColor = [0, 0, 0];
|
||||||
|
|
||||||
|
if (!whitePoint)
|
||||||
|
error('WhitePoint missing - required for color space Lab');
|
||||||
|
blackPoint = blackPoint || [0, 0, 0];
|
||||||
|
range = range || [-100, 100, -100, 100];
|
||||||
|
|
||||||
|
// Translate args to spec variables
|
||||||
|
this.XW = whitePoint[0];
|
||||||
|
this.YW = whitePoint[1];
|
||||||
|
this.ZW = whitePoint[2];
|
||||||
|
this.amin = range[0];
|
||||||
|
this.amax = range[1];
|
||||||
|
this.bmin = range[2];
|
||||||
|
this.bmax = range[3];
|
||||||
|
|
||||||
|
// These are here just for completeness - the spec doesn't offer any
|
||||||
|
// formulas that use BlackPoint in Lab
|
||||||
|
this.XB = blackPoint[0];
|
||||||
|
this.YB = blackPoint[1];
|
||||||
|
this.ZB = blackPoint[2];
|
||||||
|
|
||||||
|
// Validate vars as per spec
|
||||||
|
if (this.XW < 0 || this.ZW < 0 || this.YW !== 1)
|
||||||
|
error('Invalid WhitePoint components, no fallback available');
|
||||||
|
|
||||||
|
if (this.XB < 0 || this.YB < 0 || this.ZB < 0) {
|
||||||
|
warn('Invalid BlackPoint, falling back to default');
|
||||||
|
this.XB = this.YB = this.ZB = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.amin > this.amax || this.bmin > this.bmax) {
|
||||||
|
warn('Invalid Range, falling back to defaults');
|
||||||
|
this.amin = -100;
|
||||||
|
this.amax = 100;
|
||||||
|
this.bmin = -100;
|
||||||
|
this.bmax = 100;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Function g(x) from spec
|
||||||
|
function g(x) {
|
||||||
|
if (x >= 6 / 29)
|
||||||
|
return x * x * x;
|
||||||
|
else
|
||||||
|
return (108 / 841) * (x - 4 / 29);
|
||||||
|
}
|
||||||
|
|
||||||
|
LabCS.prototype = {
|
||||||
|
getRgb: function LabCS_getRgb(color) {
|
||||||
|
// Ls,as,bs <---> L*,a*,b* in the spec
|
||||||
|
var Ls = color[0], as = color[1], bs = color[2];
|
||||||
|
|
||||||
|
// Adjust limits of 'as' and 'bs'
|
||||||
|
as = as > this.amax ? this.amax : as;
|
||||||
|
as = as < this.amin ? this.amin : as;
|
||||||
|
bs = bs > this.bmax ? this.bmax : bs;
|
||||||
|
bs = bs < this.bmin ? this.bmin : bs;
|
||||||
|
|
||||||
|
// Computes intermediate variables X,Y,Z as per spec
|
||||||
|
var M = (Ls + 16) / 116;
|
||||||
|
var L = M + (as / 500);
|
||||||
|
var N = M - (bs / 200);
|
||||||
|
var X = this.XW * g(L);
|
||||||
|
var Y = this.YW * g(M);
|
||||||
|
var Z = this.ZW * g(N);
|
||||||
|
|
||||||
|
// XYZ to RGB 3x3 matrix, from:
|
||||||
|
// http://www.poynton.com/notes/colour_and_gamma/ColorFAQ.html#RTFToC18
|
||||||
|
var XYZtoRGB = [3.240479, -1.537150, -0.498535,
|
||||||
|
-0.969256, 1.875992, 0.041556,
|
||||||
|
0.055648, -0.204043, 1.057311];
|
||||||
|
|
||||||
|
return Util.apply3dTransform(XYZtoRGB, [X, Y, Z]);
|
||||||
|
},
|
||||||
|
getRgbBuffer: function LabCS_getRgbBuffer(input, bits) {
|
||||||
|
if (bits == 8)
|
||||||
|
return input;
|
||||||
|
var scale = 255 / ((1 << bits) - 1);
|
||||||
|
var i, length = input.length / 3;
|
||||||
|
var rgbBuf = new Uint8Array(length);
|
||||||
|
|
||||||
|
var j = 0;
|
||||||
|
for (i = 0; i < length; ++i) {
|
||||||
|
// Convert L*, a*, s* into RGB
|
||||||
|
var rgb = this.getRgb([input[i], input[i + 1], input[i + 2]]);
|
||||||
|
rgbBuf[j++] = rgb[0];
|
||||||
|
rgbBuf[j++] = rgb[1];
|
||||||
|
rgbBuf[j++] = rgb[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
return rgbBuf;
|
||||||
|
},
|
||||||
|
isDefaultDecode: function LabCS_isDefaultDecode(decodeMap) {
|
||||||
|
// From Table 90 in Adobe's:
|
||||||
|
// "Document management - Portable document format", 1st ed, 2008
|
||||||
|
if (decodeMap[0] === 0 && decodeMap[1] === 100 &&
|
||||||
|
decodeMap[2] === this.amin && decodeMap[3] === this.amax &&
|
||||||
|
decodeMap[4] === this.bmin && decodeMap[5] === this.bmax)
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return LabCS;
|
||||||
|
})();
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
|
|
||||||
var globalScope = (typeof window === 'undefined') ? this : window;
|
var globalScope = (typeof window === 'undefined') ? this : window;
|
||||||
|
|
||||||
|
var isWorker = (typeof window == 'undefined');
|
||||||
|
|
||||||
var ERRORS = 0, WARNINGS = 1, TODOS = 5;
|
var ERRORS = 0, WARNINGS = 1, TODOS = 5;
|
||||||
var verbosity = WARNINGS;
|
var verbosity = WARNINGS;
|
||||||
|
|
||||||
|
@ -31,7 +33,9 @@ function getPdf(arg, callback) {
|
||||||
var xhr = new XMLHttpRequest();
|
var xhr = new XMLHttpRequest();
|
||||||
xhr.open('GET', params.url);
|
xhr.open('GET', params.url);
|
||||||
xhr.mozResponseType = xhr.responseType = 'arraybuffer';
|
xhr.mozResponseType = xhr.responseType = 'arraybuffer';
|
||||||
xhr.expected = (document.URL.indexOf('file:') === 0) ? 0 : 200;
|
var protocol = params.url.indexOf(':') < 0 ? window.location.protocol :
|
||||||
|
params.url.substring(0, params.url.indexOf(':') + 1);
|
||||||
|
xhr.expected = (protocol === 'http:' || protocol === 'https:') ? 200 : 0;
|
||||||
|
|
||||||
if ('progress' in params)
|
if ('progress' in params)
|
||||||
xhr.onprogress = params.progress || undefined;
|
xhr.onprogress = params.progress || undefined;
|
||||||
|
@ -39,41 +43,43 @@ function getPdf(arg, callback) {
|
||||||
if ('error' in params)
|
if ('error' in params)
|
||||||
xhr.onerror = params.error || undefined;
|
xhr.onerror = params.error || undefined;
|
||||||
|
|
||||||
xhr.onreadystatechange = function getPdfOnreadystatechange() {
|
xhr.onreadystatechange = function getPdfOnreadystatechange(e) {
|
||||||
if (xhr.readyState === 4 && xhr.status === xhr.expected) {
|
if (xhr.readyState === 4) {
|
||||||
|
if (xhr.status === xhr.expected) {
|
||||||
var data = (xhr.mozResponseArrayBuffer || xhr.mozResponse ||
|
var data = (xhr.mozResponseArrayBuffer || xhr.mozResponse ||
|
||||||
xhr.responseArrayBuffer || xhr.response);
|
xhr.responseArrayBuffer || xhr.response);
|
||||||
callback(data);
|
callback(data);
|
||||||
|
} else if (params.error) {
|
||||||
|
params.error(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
xhr.send(null);
|
xhr.send(null);
|
||||||
}
|
}
|
||||||
globalScope.PDFJS.getPdf = getPdf;
|
globalScope.PDFJS.getPdf = getPdf;
|
||||||
|
globalScope.PDFJS.pdfBug = false;
|
||||||
|
|
||||||
var Page = (function pagePage() {
|
var Page = (function PageClosure() {
|
||||||
function constructor(xref, pageNumber, pageDict, ref) {
|
function Page(xref, pageNumber, pageDict, ref) {
|
||||||
this.pageNumber = pageNumber;
|
this.pageNumber = pageNumber;
|
||||||
this.pageDict = pageDict;
|
this.pageDict = pageDict;
|
||||||
this.stats = {
|
this.stats = new StatTimer();
|
||||||
create: Date.now(),
|
this.stats.enabled = !!globalScope.PDFJS.enableStats;
|
||||||
compile: 0.0,
|
|
||||||
fonts: 0.0,
|
|
||||||
images: 0.0,
|
|
||||||
render: 0.0
|
|
||||||
};
|
|
||||||
this.xref = xref;
|
this.xref = xref;
|
||||||
this.ref = ref;
|
this.ref = ref;
|
||||||
|
|
||||||
|
this.displayReadyPromise = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor.prototype = {
|
Page.prototype = {
|
||||||
getPageProp: function pageGetPageProp(key) {
|
getPageProp: function Page_getPageProp(key) {
|
||||||
return this.xref.fetchIfRef(this.pageDict.get(key));
|
return this.pageDict.get(key);
|
||||||
},
|
},
|
||||||
inheritPageProp: function pageInheritPageProp(key) {
|
inheritPageProp: function Page_inheritPageProp(key) {
|
||||||
var dict = this.pageDict;
|
var dict = this.pageDict;
|
||||||
var obj = dict.get(key);
|
var obj = dict.get(key);
|
||||||
while (obj === undefined) {
|
while (obj === undefined) {
|
||||||
dict = this.xref.fetchIfRef(dict.get('Parent'));
|
dict = dict.get('Parent');
|
||||||
if (!dict)
|
if (!dict)
|
||||||
break;
|
break;
|
||||||
obj = dict.get(key);
|
obj = dict.get(key);
|
||||||
|
@ -94,23 +100,35 @@ var Page = (function pagePage() {
|
||||||
return shadow(this, 'mediaBox', obj);
|
return shadow(this, 'mediaBox', obj);
|
||||||
},
|
},
|
||||||
get view() {
|
get view() {
|
||||||
var obj = this.inheritPageProp('CropBox');
|
var cropBox = this.inheritPageProp('CropBox');
|
||||||
var view = {
|
var view = {
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0,
|
y: 0,
|
||||||
width: this.width,
|
width: this.width,
|
||||||
height: this.height
|
height: this.height
|
||||||
};
|
};
|
||||||
if (isArray(obj) && obj.length == 4) {
|
if (!isArray(cropBox) || cropBox.length !== 4)
|
||||||
var tl = this.rotatePoint(obj[0], obj[1]);
|
return shadow(this, 'view', view);
|
||||||
var br = this.rotatePoint(obj[2], obj[3]);
|
|
||||||
|
var mediaBox = this.mediaBox;
|
||||||
|
var offsetX = mediaBox[0], offsetY = mediaBox[1];
|
||||||
|
|
||||||
|
// From the spec, 6th ed., p.963:
|
||||||
|
// "The crop, bleed, trim, and art boxes should not ordinarily
|
||||||
|
// extend beyond the boundaries of the media box. If they do, they are
|
||||||
|
// effectively reduced to their intersection with the media box."
|
||||||
|
cropBox = Util.intersect(cropBox, mediaBox);
|
||||||
|
if (!cropBox)
|
||||||
|
return shadow(this, 'view', view);
|
||||||
|
|
||||||
|
var tl = this.rotatePoint(cropBox[0] - offsetX, cropBox[1] - offsetY);
|
||||||
|
var br = this.rotatePoint(cropBox[2] - offsetX, cropBox[3] - offsetY);
|
||||||
view.x = Math.min(tl.x, br.x);
|
view.x = Math.min(tl.x, br.x);
|
||||||
view.y = Math.min(tl.y, br.y);
|
view.y = Math.min(tl.y, br.y);
|
||||||
view.width = Math.abs(tl.x - br.x);
|
view.width = Math.abs(tl.x - br.x);
|
||||||
view.height = Math.abs(tl.y - br.y);
|
view.height = Math.abs(tl.y - br.y);
|
||||||
}
|
|
||||||
|
|
||||||
return shadow(this, 'cropBox', view);
|
return shadow(this, 'view', view);
|
||||||
},
|
},
|
||||||
get annotations() {
|
get annotations() {
|
||||||
return shadow(this, 'annotations', this.inheritPageProp('Annots'));
|
return shadow(this, 'annotations', this.inheritPageProp('Annots'));
|
||||||
|
@ -152,77 +170,80 @@ var Page = (function pagePage() {
|
||||||
return shadow(this, 'rotate', rotate);
|
return shadow(this, 'rotate', rotate);
|
||||||
},
|
},
|
||||||
|
|
||||||
startRenderingFromIRQueue: function pageStartRenderingFromIRQueue(
|
startRenderingFromOperatorList:
|
||||||
IRQueue, fonts) {
|
function Page_startRenderingFromOperatorList(operatorList, fonts) {
|
||||||
var self = this;
|
var self = this;
|
||||||
this.IRQueue = IRQueue;
|
this.operatorList = operatorList;
|
||||||
var gfx = new CanvasGraphics(this.ctx, this.objs);
|
|
||||||
|
|
||||||
var displayContinuation = function pageDisplayContinuation() {
|
var displayContinuation = function pageDisplayContinuation() {
|
||||||
// Always defer call to display() to work around bug in
|
// Always defer call to display() to work around bug in
|
||||||
// Firefox error reporting from XHR callbacks.
|
// Firefox error reporting from XHR callbacks.
|
||||||
setTimeout(function pageSetTimeout() {
|
setTimeout(function pageSetTimeout() {
|
||||||
try {
|
self.displayReadyPromise.resolve();
|
||||||
self.display(gfx, self.callback);
|
|
||||||
} catch (e) {
|
|
||||||
if (self.callback) self.callback(e.toString());
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
this.ensureFonts(fonts,
|
this.ensureFonts(fonts,
|
||||||
function pageStartRenderingFromIRQueueEnsureFonts() {
|
function pageStartRenderingFromOperatorListEnsureFonts() {
|
||||||
displayContinuation();
|
displayContinuation();
|
||||||
});
|
}
|
||||||
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
getIRQueue: function pageGetIRQueue(handler, dependency) {
|
getOperatorList: function Page_getOperatorList(handler, dependency) {
|
||||||
if (this.IRQueue) {
|
if (this.operatorList) {
|
||||||
// content was compiled
|
// content was compiled
|
||||||
return this.IRQueue;
|
return this.operatorList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.stats.time('Build IR Queue');
|
||||||
|
|
||||||
var xref = this.xref;
|
var xref = this.xref;
|
||||||
var content = xref.fetchIfRef(this.content);
|
var content = this.content;
|
||||||
var resources = xref.fetchIfRef(this.resources);
|
var resources = this.resources;
|
||||||
if (isArray(content)) {
|
if (isArray(content)) {
|
||||||
// fetching items
|
// fetching items
|
||||||
var i, n = content.length;
|
var i, n = content.length;
|
||||||
for (i = 0; i < n; ++i)
|
for (i = 0; i < n; ++i)
|
||||||
content[i] = xref.fetchIfRef(content[i]);
|
content[i] = xref.fetchIfRef(content[i]);
|
||||||
content = new StreamsSequenceStream(content);
|
content = new StreamsSequenceStream(content);
|
||||||
|
} else if (!content) {
|
||||||
|
// replacing non-existent page content with empty one
|
||||||
|
content = new Stream(new Uint8Array(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
var pe = this.pe = new PartialEvaluator(
|
var pe = this.pe = new PartialEvaluator(
|
||||||
xref, handler, 'p' + this.pageNumber + '_');
|
xref, handler, 'p' + this.pageNumber + '_');
|
||||||
var IRQueue = {};
|
|
||||||
return (this.IRQueue = pe.getIRQueue(content, resources, IRQueue,
|
this.operatorList = pe.getOperatorList(content, resources, dependency);
|
||||||
dependency));
|
this.stats.timeEnd('Build IR Queue');
|
||||||
|
return this.operatorList;
|
||||||
},
|
},
|
||||||
|
|
||||||
ensureFonts: function pageEnsureFonts(fonts, callback) {
|
ensureFonts: function Page_ensureFonts(fonts, callback) {
|
||||||
|
this.stats.time('Font Loading');
|
||||||
// Convert the font names to the corresponding font obj.
|
// Convert the font names to the corresponding font obj.
|
||||||
for (var i = 0, ii = fonts.length; i < ii; i++) {
|
for (var i = 0, ii = fonts.length; i < ii; i++) {
|
||||||
fonts[i] = this.objs.objs[fonts[i]].data;
|
fonts[i] = this.objs.objs[fonts[i]].data;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load all the fonts
|
// Load all the fonts
|
||||||
var fontObjs = FontLoader.bind(
|
FontLoader.bind(
|
||||||
fonts,
|
fonts,
|
||||||
function pageEnsureFontsFontObjs(fontObjs) {
|
function pageEnsureFontsFontObjs(fontObjs) {
|
||||||
this.stats.fonts = Date.now();
|
this.stats.timeEnd('Font Loading');
|
||||||
|
|
||||||
callback.call(this);
|
callback.call(this);
|
||||||
}.bind(this),
|
}.bind(this)
|
||||||
this.objs
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
display: function pageDisplay(gfx, callback) {
|
display: function Page_display(gfx, callback) {
|
||||||
|
var stats = this.stats;
|
||||||
|
stats.time('Rendering');
|
||||||
var xref = this.xref;
|
var xref = this.xref;
|
||||||
var resources = xref.fetchIfRef(this.resources);
|
var resources = this.resources;
|
||||||
var mediaBox = xref.fetchIfRef(this.mediaBox);
|
var mediaBox = this.mediaBox;
|
||||||
assertWellFormed(isDict(resources), 'invalid page resources');
|
assertWellFormed(isDict(resources), 'invalid page resources');
|
||||||
|
|
||||||
gfx.xref = xref;
|
gfx.xref = xref;
|
||||||
|
@ -233,20 +254,29 @@ var Page = (function pagePage() {
|
||||||
rotate: this.rotate });
|
rotate: this.rotate });
|
||||||
|
|
||||||
var startIdx = 0;
|
var startIdx = 0;
|
||||||
var length = this.IRQueue.fnArray.length;
|
var length = this.operatorList.fnArray.length;
|
||||||
var IRQueue = this.IRQueue;
|
var operatorList = this.operatorList;
|
||||||
|
var stepper = null;
|
||||||
|
if (PDFJS.pdfBug && StepperManager.enabled) {
|
||||||
|
stepper = StepperManager.create(this.pageNumber);
|
||||||
|
stepper.init(operatorList);
|
||||||
|
stepper.nextBreakPoint = stepper.getNextBreakPoint();
|
||||||
|
}
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
function next() {
|
function next() {
|
||||||
startIdx = gfx.executeIRQueue(IRQueue, startIdx, next);
|
startIdx =
|
||||||
|
gfx.executeOperatorList(operatorList, startIdx, next, stepper);
|
||||||
if (startIdx == length) {
|
if (startIdx == length) {
|
||||||
self.stats.render = Date.now();
|
gfx.endDrawing();
|
||||||
|
stats.timeEnd('Rendering');
|
||||||
|
stats.timeEnd('Overall');
|
||||||
if (callback) callback();
|
if (callback) callback();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
next();
|
next();
|
||||||
},
|
},
|
||||||
rotatePoint: function pageRotatePoint(x, y, reverse) {
|
rotatePoint: function Page_rotatePoint(x, y, reverse) {
|
||||||
var rotate = reverse ? (360 - this.rotate) : this.rotate;
|
var rotate = reverse ? (360 - this.rotate) : this.rotate;
|
||||||
switch (rotate) {
|
switch (rotate) {
|
||||||
case 180:
|
case 180:
|
||||||
|
@ -261,35 +291,81 @@ var Page = (function pagePage() {
|
||||||
return {x: x, y: this.height - y};
|
return {x: x, y: this.height - y};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getLinks: function pageGetLinks() {
|
getLinks: function Page_getLinks() {
|
||||||
var xref = this.xref;
|
|
||||||
var annotations = xref.fetchIfRef(this.annotations) || [];
|
|
||||||
var i, n = annotations.length;
|
|
||||||
var links = [];
|
var links = [];
|
||||||
|
var annotations = pageGetAnnotations();
|
||||||
|
var i, n = annotations.length;
|
||||||
for (i = 0; i < n; ++i) {
|
for (i = 0; i < n; ++i) {
|
||||||
var annotation = xref.fetch(annotations[i]);
|
if (annotations[i].type != 'Link')
|
||||||
|
continue;
|
||||||
|
links.push(annotations[i]);
|
||||||
|
}
|
||||||
|
return links;
|
||||||
|
},
|
||||||
|
getAnnotations: function Page_getAnnotations() {
|
||||||
|
var xref = this.xref;
|
||||||
|
function getInheritableProperty(annotation, name) {
|
||||||
|
var item = annotation;
|
||||||
|
while (item && !item.has(name)) {
|
||||||
|
item = item.get('Parent');
|
||||||
|
}
|
||||||
|
if (!item)
|
||||||
|
return null;
|
||||||
|
return item.get(name);
|
||||||
|
}
|
||||||
|
function isValidUrl(url) {
|
||||||
|
if (!url)
|
||||||
|
return false;
|
||||||
|
var colon = url.indexOf(':');
|
||||||
|
if (colon < 0)
|
||||||
|
return false;
|
||||||
|
var protocol = url.substr(0, colon);
|
||||||
|
switch (protocol) {
|
||||||
|
case 'http':
|
||||||
|
case 'https':
|
||||||
|
case 'ftp':
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var annotations = this.annotations || [];
|
||||||
|
var i, n = annotations.length;
|
||||||
|
var items = [];
|
||||||
|
for (i = 0; i < n; ++i) {
|
||||||
|
var annotationRef = annotations[i];
|
||||||
|
var annotation = xref.fetch(annotationRef);
|
||||||
if (!isDict(annotation))
|
if (!isDict(annotation))
|
||||||
continue;
|
continue;
|
||||||
var subtype = annotation.get('Subtype');
|
var subtype = annotation.get('Subtype');
|
||||||
if (!isName(subtype) || subtype.name != 'Link')
|
if (!isName(subtype))
|
||||||
continue;
|
continue;
|
||||||
var rect = annotation.get('Rect');
|
var rect = annotation.get('Rect');
|
||||||
var topLeftCorner = this.rotatePoint(rect[0], rect[1]);
|
var topLeftCorner = this.rotatePoint(rect[0], rect[1]);
|
||||||
var bottomRightCorner = this.rotatePoint(rect[2], rect[3]);
|
var bottomRightCorner = this.rotatePoint(rect[2], rect[3]);
|
||||||
|
|
||||||
var link = {};
|
var item = {};
|
||||||
link.x = Math.min(topLeftCorner.x, bottomRightCorner.x);
|
item.type = subtype.name;
|
||||||
link.y = Math.min(topLeftCorner.y, bottomRightCorner.y);
|
item.x = Math.min(topLeftCorner.x, bottomRightCorner.x);
|
||||||
link.width = Math.abs(topLeftCorner.x - bottomRightCorner.x);
|
item.y = Math.min(topLeftCorner.y, bottomRightCorner.y);
|
||||||
link.height = Math.abs(topLeftCorner.y - bottomRightCorner.y);
|
item.width = Math.abs(topLeftCorner.x - bottomRightCorner.x);
|
||||||
var a = this.xref.fetchIfRef(annotation.get('A'));
|
item.height = Math.abs(topLeftCorner.y - bottomRightCorner.y);
|
||||||
|
switch (subtype.name) {
|
||||||
|
case 'Link':
|
||||||
|
var a = annotation.get('A');
|
||||||
if (a) {
|
if (a) {
|
||||||
switch (a.get('S').name) {
|
switch (a.get('S').name) {
|
||||||
case 'URI':
|
case 'URI':
|
||||||
link.url = a.get('URI');
|
var url = a.get('URI');
|
||||||
|
// TODO: pdf spec mentions urls can be relative to a Base
|
||||||
|
// entry in the dictionary.
|
||||||
|
if (!isValidUrl(url))
|
||||||
|
url = '';
|
||||||
|
item.url = url;
|
||||||
break;
|
break;
|
||||||
case 'GoTo':
|
case 'GoTo':
|
||||||
link.dest = a.get('D');
|
item.dest = a.get('D');
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
TODO('other link types');
|
TODO('other link types');
|
||||||
|
@ -297,22 +373,101 @@ var Page = (function pagePage() {
|
||||||
} else if (annotation.has('Dest')) {
|
} else if (annotation.has('Dest')) {
|
||||||
// simple destination link
|
// simple destination link
|
||||||
var dest = annotation.get('Dest');
|
var dest = annotation.get('Dest');
|
||||||
link.dest = isName(dest) ? dest.name : dest;
|
item.dest = isName(dest) ? dest.name : dest;
|
||||||
}
|
}
|
||||||
links.push(link);
|
break;
|
||||||
|
case 'Widget':
|
||||||
|
var fieldType = getInheritableProperty(annotation, 'FT');
|
||||||
|
if (!isName(fieldType))
|
||||||
|
break;
|
||||||
|
item.fieldType = fieldType.name;
|
||||||
|
// Building the full field name by collecting the field and
|
||||||
|
// its ancestors 'T' properties and joining them using '.'.
|
||||||
|
var fieldName = [];
|
||||||
|
var namedItem = annotation, ref = annotationRef;
|
||||||
|
while (namedItem) {
|
||||||
|
var parent = namedItem.get('Parent');
|
||||||
|
var parentRef = namedItem.getRaw('Parent');
|
||||||
|
var name = namedItem.get('T');
|
||||||
|
if (name) {
|
||||||
|
fieldName.unshift(stringToPDFString(name));
|
||||||
|
} else {
|
||||||
|
// The field name is absent, that means more than one field
|
||||||
|
// with the same name may exist. Replacing the empty name
|
||||||
|
// with the '`' plus index in the parent's 'Kids' array.
|
||||||
|
// This is not in the PDF spec but necessary to id the
|
||||||
|
// the input controls.
|
||||||
|
var kids = parent.get('Kids');
|
||||||
|
var j, jj;
|
||||||
|
for (j = 0, jj = kids.length; j < jj; j++) {
|
||||||
|
var kidRef = kids[j];
|
||||||
|
if (kidRef.num == ref.num && kidRef.gen == ref.gen)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return links;
|
fieldName.unshift('`' + j);
|
||||||
|
}
|
||||||
|
namedItem = parent;
|
||||||
|
ref = parentRef;
|
||||||
|
}
|
||||||
|
item.fullName = fieldName.join('.');
|
||||||
|
var alternativeText = stringToPDFString(annotation.get('TU') || '');
|
||||||
|
item.alternativeText = alternativeText;
|
||||||
|
var da = getInheritableProperty(annotation, 'DA') || '';
|
||||||
|
var m = /([\d\.]+)\sTf/.exec(da);
|
||||||
|
if (m)
|
||||||
|
item.fontSize = parseFloat(m[1]);
|
||||||
|
item.textAlignment = getInheritableProperty(annotation, 'Q');
|
||||||
|
item.flags = getInheritableProperty(annotation, 'Ff') || 0;
|
||||||
|
break;
|
||||||
|
case 'Text':
|
||||||
|
var content = annotation.get('Contents');
|
||||||
|
var title = annotation.get('T');
|
||||||
|
item.content = stringToPDFString(content || '');
|
||||||
|
item.title = stringToPDFString(title || '');
|
||||||
|
item.name = annotation.get('Name').name;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
TODO('unimplemented annotation type: ' + subtype.name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
items.push(item);
|
||||||
|
}
|
||||||
|
return items;
|
||||||
},
|
},
|
||||||
startRendering: function pageStartRendering(ctx, callback) {
|
startRendering: function Page_startRendering(ctx, callback, textLayer) {
|
||||||
this.ctx = ctx;
|
var stats = this.stats;
|
||||||
this.callback = callback;
|
stats.time('Overall');
|
||||||
|
// If there is no displayReadyPromise yet, then the operatorList was never
|
||||||
this.startRenderingTime = Date.now();
|
// requested before. Make the request and create the promise.
|
||||||
|
if (!this.displayReadyPromise) {
|
||||||
this.pdf.startRendering(this);
|
this.pdf.startRendering(this);
|
||||||
|
this.displayReadyPromise = new Promise();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Once the operatorList and fonts are loaded, do the actual rendering.
|
||||||
|
this.displayReadyPromise.then(
|
||||||
|
function pageDisplayReadyPromise() {
|
||||||
|
var gfx = new CanvasGraphics(ctx, this.objs, textLayer);
|
||||||
|
try {
|
||||||
|
this.display(gfx, callback);
|
||||||
|
} catch (e) {
|
||||||
|
if (callback)
|
||||||
|
callback(e);
|
||||||
|
else
|
||||||
|
error(e);
|
||||||
|
}
|
||||||
|
}.bind(this),
|
||||||
|
function pageDisplayReadPromiseError(reason) {
|
||||||
|
if (callback)
|
||||||
|
callback(reason);
|
||||||
|
else
|
||||||
|
error(reason);
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return constructor;
|
return Page;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -321,12 +476,9 @@ var Page = (function pagePage() {
|
||||||
* Right now there exists one PDFDocModel on the main thread + one object
|
* Right now there exists one PDFDocModel on the main thread + one object
|
||||||
* for each worker. If there is no worker support enabled, there are two
|
* for each worker. If there is no worker support enabled, there are two
|
||||||
* `PDFDocModel` objects on the main thread created.
|
* `PDFDocModel` objects on the main thread created.
|
||||||
* TODO: Refactor the internal object structure, such that there is no
|
|
||||||
* need for the `PDFDocModel` anymore and there is only one object on the
|
|
||||||
* main thread and not one entire copy on each worker instance.
|
|
||||||
*/
|
*/
|
||||||
var PDFDocModel = (function pdfDoc() {
|
var PDFDocModel = (function PDFDocModelClosure() {
|
||||||
function constructor(arg, callback) {
|
function PDFDocModel(arg, callback) {
|
||||||
if (isStream(arg))
|
if (isStream(arg))
|
||||||
init.call(this, arg);
|
init.call(this, arg);
|
||||||
else if (isArrayBuffer(arg))
|
else if (isArrayBuffer(arg))
|
||||||
|
@ -339,6 +491,7 @@ var PDFDocModel = (function pdfDoc() {
|
||||||
assertWellFormed(stream.length > 0, 'stream must have data');
|
assertWellFormed(stream.length > 0, 'stream must have data');
|
||||||
this.stream = stream;
|
this.stream = stream;
|
||||||
this.setup();
|
this.setup();
|
||||||
|
this.acroForm = this.catalog.catDict.get('AcroForm');
|
||||||
}
|
}
|
||||||
|
|
||||||
function find(stream, needle, limit, backwards) {
|
function find(stream, needle, limit, backwards) {
|
||||||
|
@ -357,7 +510,7 @@ var PDFDocModel = (function pdfDoc() {
|
||||||
return true; /* found */
|
return true; /* found */
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor.prototype = {
|
PDFDocModel.prototype = {
|
||||||
get linearization() {
|
get linearization() {
|
||||||
var length = this.stream.length;
|
var length = this.stream.length;
|
||||||
var linearization = false;
|
var linearization = false;
|
||||||
|
@ -379,12 +532,17 @@ var PDFDocModel = (function pdfDoc() {
|
||||||
if (find(stream, 'endobj', 1024))
|
if (find(stream, 'endobj', 1024))
|
||||||
startXRef = stream.pos + 6;
|
startXRef = stream.pos + 6;
|
||||||
} else {
|
} else {
|
||||||
// Find startxref at the end of the file.
|
// Find startxref by jumping backward from the end of the file.
|
||||||
var start = stream.end - 1024;
|
var step = 1024;
|
||||||
if (start < 0)
|
var found = false, pos = stream.end;
|
||||||
start = 0;
|
while (!found && pos > 0) {
|
||||||
stream.pos = start;
|
pos -= step - 'startxref'.length;
|
||||||
if (find(stream, 'startxref', 1024, true)) {
|
if (pos < 0)
|
||||||
|
pos = 0;
|
||||||
|
stream.pos = pos;
|
||||||
|
found = find(stream, 'startxref', step, true);
|
||||||
|
}
|
||||||
|
if (found) {
|
||||||
stream.skip(9);
|
stream.skip(9);
|
||||||
var ch;
|
var ch;
|
||||||
do {
|
do {
|
||||||
|
@ -413,7 +571,7 @@ var PDFDocModel = (function pdfDoc() {
|
||||||
},
|
},
|
||||||
// Find the header, remove leading garbage and setup the stream
|
// Find the header, remove leading garbage and setup the stream
|
||||||
// starting from the header.
|
// starting from the header.
|
||||||
checkHeader: function pdfDocCheckHeader() {
|
checkHeader: function PDFDocModel_checkHeader() {
|
||||||
var stream = this.stream;
|
var stream = this.stream;
|
||||||
stream.reset();
|
stream.reset();
|
||||||
if (find(stream, '%PDF-', 1024)) {
|
if (find(stream, '%PDF-', 1024)) {
|
||||||
|
@ -423,12 +581,13 @@ var PDFDocModel = (function pdfDoc() {
|
||||||
}
|
}
|
||||||
// May not be a PDF file, continue anyway.
|
// May not be a PDF file, continue anyway.
|
||||||
},
|
},
|
||||||
setup: function pdfDocSetup(ownerPassword, userPassword) {
|
setup: function PDFDocModel_setup(ownerPassword, userPassword) {
|
||||||
this.checkHeader();
|
this.checkHeader();
|
||||||
this.xref = new XRef(this.stream,
|
var xref = new XRef(this.stream,
|
||||||
this.startXRef,
|
this.startXRef,
|
||||||
this.mainXRefEntriesOffset);
|
this.mainXRefEntriesOffset);
|
||||||
this.catalog = new Catalog(this.xref);
|
this.xref = xref;
|
||||||
|
this.catalog = new Catalog(xref);
|
||||||
},
|
},
|
||||||
get numPages() {
|
get numPages() {
|
||||||
var linearization = this.linearization;
|
var linearization = this.linearization;
|
||||||
|
@ -436,16 +595,51 @@ var PDFDocModel = (function pdfDoc() {
|
||||||
// shadow the prototype getter
|
// shadow the prototype getter
|
||||||
return shadow(this, 'numPages', num);
|
return shadow(this, 'numPages', num);
|
||||||
},
|
},
|
||||||
getPage: function pdfDocGetPage(n) {
|
getDocumentInfo: function PDFDocModel_getDocumentInfo() {
|
||||||
|
var info;
|
||||||
|
if (this.xref.trailer.has('Info')) {
|
||||||
|
var infoDict = this.xref.trailer.get('Info');
|
||||||
|
|
||||||
|
info = {};
|
||||||
|
infoDict.forEach(function(key, value) {
|
||||||
|
info[key] = typeof value !== 'string' ? value :
|
||||||
|
stringToPDFString(value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return shadow(this, 'getDocumentInfo', info);
|
||||||
|
},
|
||||||
|
getFingerprint: function PDFDocModel_getFingerprint() {
|
||||||
|
var xref = this.xref, fileID;
|
||||||
|
if (xref.trailer.has('ID')) {
|
||||||
|
fileID = '';
|
||||||
|
var id = xref.trailer.get('ID')[0];
|
||||||
|
id.split('').forEach(function(el) {
|
||||||
|
fileID += Number(el.charCodeAt(0)).toString(16);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// If we got no fileID, then we generate one,
|
||||||
|
// from the first 100 bytes of PDF
|
||||||
|
var data = this.stream.bytes.subarray(0, 100);
|
||||||
|
var hash = calculateMD5(data, 0, data.length);
|
||||||
|
fileID = '';
|
||||||
|
for (var i = 0, length = hash.length; i < length; i++) {
|
||||||
|
fileID += Number(hash[i]).toString(16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return shadow(this, 'getFingerprint', fileID);
|
||||||
|
},
|
||||||
|
getPage: function PDFDocModel_getPage(n) {
|
||||||
return this.catalog.getPage(n);
|
return this.catalog.getPage(n);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return constructor;
|
return PDFDocModel;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
var PDFDoc = (function pdfDoc() {
|
var PDFDoc = (function PDFDocClosure() {
|
||||||
function constructor(arg, callback) {
|
function PDFDoc(arg, callback) {
|
||||||
var stream = null;
|
var stream = null;
|
||||||
var data = null;
|
var data = null;
|
||||||
|
|
||||||
|
@ -461,9 +655,10 @@ var PDFDoc = (function pdfDoc() {
|
||||||
|
|
||||||
this.data = data;
|
this.data = data;
|
||||||
this.stream = stream;
|
this.stream = stream;
|
||||||
this.pdf = new PDFDocModel(stream);
|
this.pdfModel = new PDFDocModel(stream);
|
||||||
|
this.fingerprint = this.pdfModel.getFingerprint();
|
||||||
this.catalog = this.pdf.catalog;
|
this.info = this.pdfModel.getDocumentInfo();
|
||||||
|
this.catalog = this.pdfModel.catalog;
|
||||||
this.objs = new PDFObjects();
|
this.objs = new PDFObjects();
|
||||||
|
|
||||||
this.pageCache = [];
|
this.pageCache = [];
|
||||||
|
@ -478,49 +673,59 @@ var PDFDoc = (function pdfDoc() {
|
||||||
if (!globalScope.PDFJS.disableWorker && typeof Worker !== 'undefined') {
|
if (!globalScope.PDFJS.disableWorker && typeof Worker !== 'undefined') {
|
||||||
var workerSrc = PDFJS.workerSrc;
|
var workerSrc = PDFJS.workerSrc;
|
||||||
if (typeof workerSrc === 'undefined') {
|
if (typeof workerSrc === 'undefined') {
|
||||||
throw 'No PDFJS.workerSrc specified';
|
error('No PDFJS.workerSrc specified');
|
||||||
}
|
}
|
||||||
|
|
||||||
var worker;
|
|
||||||
try {
|
try {
|
||||||
worker = new Worker(workerSrc);
|
var worker;
|
||||||
} catch (e) {
|
if (PDFJS.isFirefoxExtension) {
|
||||||
|
// The firefox extension can't load the worker from the resource://
|
||||||
|
// url so we have to inline the script and then use the blob loader.
|
||||||
|
var bb = new MozBlobBuilder();
|
||||||
|
bb.append(document.querySelector('#PDFJS_SCRIPT_TAG').textContent);
|
||||||
|
var blobUrl = window.URL.createObjectURL(bb.getBlob());
|
||||||
|
worker = new Worker(blobUrl);
|
||||||
|
} else {
|
||||||
// Some versions of FF can't create a worker on localhost, see:
|
// Some versions of FF can't create a worker on localhost, see:
|
||||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=683280
|
// https://bugzilla.mozilla.org/show_bug.cgi?id=683280
|
||||||
globalScope.PDFJS.disableWorker = true;
|
worker = new Worker(workerSrc);
|
||||||
this.setupFakeWorker();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var messageHandler = new MessageHandler('main', worker);
|
var messageHandler = new MessageHandler('main', worker);
|
||||||
|
|
||||||
// Tell the worker the file it was created from.
|
|
||||||
messageHandler.send('workerSrc', workerSrc);
|
|
||||||
|
|
||||||
messageHandler.on('test', function pdfDocTest(supportTypedArray) {
|
messageHandler.on('test', function pdfDocTest(supportTypedArray) {
|
||||||
if (supportTypedArray) {
|
if (supportTypedArray) {
|
||||||
this.worker = worker;
|
this.worker = worker;
|
||||||
this.setupMessageHandler(messageHandler);
|
this.setupMessageHandler(messageHandler);
|
||||||
} else {
|
} else {
|
||||||
|
globalScope.PDFJS.disableWorker = true;
|
||||||
this.setupFakeWorker();
|
this.setupFakeWorker();
|
||||||
}
|
}
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
|
|
||||||
var testObj = new Uint8Array(1);
|
var testObj = new Uint8Array(1);
|
||||||
|
// Some versions of Opera throw a DATA_CLONE_ERR on
|
||||||
|
// serializing the typed array.
|
||||||
messageHandler.send('test', testObj);
|
messageHandler.send('test', testObj);
|
||||||
} else {
|
return;
|
||||||
|
} catch (e) {
|
||||||
|
warn('The worker has been disabled.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Either workers are disabled, not supported or have thrown an exception.
|
||||||
|
// Thus, we fallback to a faked worker.
|
||||||
|
globalScope.PDFJS.disableWorker = true;
|
||||||
this.setupFakeWorker();
|
this.setupFakeWorker();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
constructor.prototype = {
|
PDFDoc.prototype = {
|
||||||
setupFakeWorker: function() {
|
setupFakeWorker: function PDFDoc_setupFakeWorker() {
|
||||||
// If we don't use a worker, just post/sendMessage to the main thread.
|
// If we don't use a worker, just post/sendMessage to the main thread.
|
||||||
var fakeWorker = {
|
var fakeWorker = {
|
||||||
postMessage: function pdfDocPostMessage(obj) {
|
postMessage: function PDFDoc_postMessage(obj) {
|
||||||
fakeWorker.onmessage({data: obj});
|
fakeWorker.onmessage({data: obj});
|
||||||
},
|
},
|
||||||
terminate: function pdfDocTerminate() {}
|
terminate: function PDFDoc_terminate() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
var messageHandler = new MessageHandler('main', fakeWorker);
|
var messageHandler = new MessageHandler('main', fakeWorker);
|
||||||
|
@ -532,7 +737,7 @@ var PDFDoc = (function pdfDoc() {
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
setupMessageHandler: function(messageHandler) {
|
setupMessageHandler: function PDFDoc_setupMessageHandler(messageHandler) {
|
||||||
this.messageHandler = messageHandler;
|
this.messageHandler = messageHandler;
|
||||||
|
|
||||||
messageHandler.on('page', function pdfDocPage(data) {
|
messageHandler.on('page', function pdfDocPage(data) {
|
||||||
|
@ -540,7 +745,8 @@ var PDFDoc = (function pdfDoc() {
|
||||||
var page = this.pageCache[pageNum];
|
var page = this.pageCache[pageNum];
|
||||||
var depFonts = data.depFonts;
|
var depFonts = data.depFonts;
|
||||||
|
|
||||||
page.startRenderingFromIRQueue(data.IRQueue, depFonts);
|
page.stats.timeEnd('Page Request');
|
||||||
|
page.startRenderingFromOperatorList(data.operatorList, depFonts);
|
||||||
}, this);
|
}, this);
|
||||||
|
|
||||||
messageHandler.on('obj', function pdfDocObj(data) {
|
messageHandler.on('obj', function pdfDocObj(data) {
|
||||||
|
@ -549,8 +755,12 @@ var PDFDoc = (function pdfDoc() {
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'JpegStream':
|
case 'JpegStream':
|
||||||
var IR = data[2];
|
var imageData = data[2];
|
||||||
new JpegImageLoader(id, IR, this.objs);
|
loadJpegStream(id, imageData, this.objs);
|
||||||
|
break;
|
||||||
|
case 'Image':
|
||||||
|
var imageData = data[2];
|
||||||
|
this.objs.resolve(id, imageData);
|
||||||
break;
|
break;
|
||||||
case 'Font':
|
case 'Font':
|
||||||
var name = data[2];
|
var name = data[2];
|
||||||
|
@ -558,46 +768,63 @@ var PDFDoc = (function pdfDoc() {
|
||||||
var properties = data[4];
|
var properties = data[4];
|
||||||
|
|
||||||
if (file) {
|
if (file) {
|
||||||
|
// Rewrap the ArrayBuffer in a stream.
|
||||||
var fontFileDict = new Dict();
|
var fontFileDict = new Dict();
|
||||||
fontFileDict.map = file.dict.map;
|
file = new Stream(file, 0, file.length, fontFileDict);
|
||||||
|
|
||||||
var fontFile = new Stream(file.bytes, file.start,
|
|
||||||
file.end - file.start, fontFileDict);
|
|
||||||
|
|
||||||
// Check if this is a FlateStream. Otherwise just use the created
|
|
||||||
// Stream one. This makes complex_ttf_font.pdf work.
|
|
||||||
var cmf = file.bytes[0];
|
|
||||||
if ((cmf & 0x0f) == 0x08) {
|
|
||||||
file = new FlateStream(fontFile);
|
|
||||||
} else {
|
|
||||||
file = fontFile;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// For now, resolve the font object here direclty. The real font
|
// At this point, only the font object is created but the font is
|
||||||
// object is then created in FontLoader.bind().
|
// not yet attached to the DOM. This is done in `FontLoader.bind`.
|
||||||
this.objs.resolve(id, {
|
var font = new Font(name, file, properties);
|
||||||
name: name,
|
this.objs.resolve(id, font);
|
||||||
file: file,
|
|
||||||
properties: properties
|
|
||||||
});
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw 'Got unkown object type ' + type;
|
error('Got unkown object type ' + type);
|
||||||
}
|
}
|
||||||
}, this);
|
}, this);
|
||||||
|
|
||||||
messageHandler.on('font_ready', function pdfDocFontReady(data) {
|
messageHandler.on('page_error', function pdfDocError(data) {
|
||||||
var id = data[0];
|
var page = this.pageCache[data.pageNum];
|
||||||
var font = new FontShape(data[1]);
|
if (page.displayReadyPromise)
|
||||||
|
page.displayReadyPromise.reject(data.error);
|
||||||
|
else
|
||||||
|
error(data.error);
|
||||||
|
}, this);
|
||||||
|
|
||||||
// If there is no string, then there is nothing to attach to the DOM.
|
messageHandler.on('jpeg_decode', function(data, promise) {
|
||||||
if (!font.str) {
|
var imageData = data[0];
|
||||||
this.objs.resolve(id, font);
|
var components = data[1];
|
||||||
} else {
|
if (components != 3 && components != 1)
|
||||||
this.objs.setData(id, font);
|
error('Only 3 component or 1 component can be returned');
|
||||||
|
|
||||||
|
var img = new Image();
|
||||||
|
img.onload = (function messageHandler_onloadClosure() {
|
||||||
|
var width = img.width;
|
||||||
|
var height = img.height;
|
||||||
|
var size = width * height;
|
||||||
|
var rgbaLength = size * 4;
|
||||||
|
var buf = new Uint8Array(size * components);
|
||||||
|
var tmpCanvas = createScratchCanvas(width, height);
|
||||||
|
var tmpCtx = tmpCanvas.getContext('2d');
|
||||||
|
tmpCtx.drawImage(img, 0, 0);
|
||||||
|
var data = tmpCtx.getImageData(0, 0, width, height).data;
|
||||||
|
|
||||||
|
if (components == 3) {
|
||||||
|
for (var i = 0, j = 0; i < rgbaLength; i += 4, j += 3) {
|
||||||
|
buf[j] = data[i];
|
||||||
|
buf[j + 1] = data[i + 1];
|
||||||
|
buf[j + 2] = data[i + 2];
|
||||||
}
|
}
|
||||||
}.bind(this));
|
} else if (components == 1) {
|
||||||
|
for (var i = 0, j = 0; i < rgbaLength; i += 4, j++) {
|
||||||
|
buf[j] = data[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
promise.resolve({ data: buf, width: width, height: height});
|
||||||
|
}).bind(this);
|
||||||
|
var src = 'data:image/jpeg;base64,' + window.btoa(imageData);
|
||||||
|
img.src = src;
|
||||||
|
});
|
||||||
|
|
||||||
setTimeout(function pdfDocFontReadySetTimeout() {
|
setTimeout(function pdfDocFontReadySetTimeout() {
|
||||||
messageHandler.send('doc', this.data);
|
messageHandler.send('doc', this.data);
|
||||||
|
@ -606,21 +833,22 @@ var PDFDoc = (function pdfDoc() {
|
||||||
},
|
},
|
||||||
|
|
||||||
get numPages() {
|
get numPages() {
|
||||||
return this.pdf.numPages;
|
return this.pdfModel.numPages;
|
||||||
},
|
},
|
||||||
|
|
||||||
startRendering: function pdfDocStartRendering(page) {
|
startRendering: function PDFDoc_startRendering(page) {
|
||||||
// The worker might not be ready to receive the page request yet.
|
// The worker might not be ready to receive the page request yet.
|
||||||
this.workerReadyPromise.then(function pdfDocStartRenderingThen() {
|
this.workerReadyPromise.then(function pdfDocStartRenderingThen() {
|
||||||
|
page.stats.time('Page Request');
|
||||||
this.messageHandler.send('page_request', page.pageNumber + 1);
|
this.messageHandler.send('page_request', page.pageNumber + 1);
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
},
|
},
|
||||||
|
|
||||||
getPage: function pdfDocGetPage(n) {
|
getPage: function PDFDoc_getPage(n) {
|
||||||
if (this.pageCache[n])
|
if (this.pageCache[n])
|
||||||
return this.pageCache[n];
|
return this.pageCache[n];
|
||||||
|
|
||||||
var page = this.pdf.getPage(n);
|
var page = this.pdfModel.getPage(n);
|
||||||
// Add a reference to the objects such that Page can forward the reference
|
// Add a reference to the objects such that Page can forward the reference
|
||||||
// to the CanvasGraphics and so on.
|
// to the CanvasGraphics and so on.
|
||||||
page.objs = this.objs;
|
page.objs = this.objs;
|
||||||
|
@ -628,7 +856,7 @@ var PDFDoc = (function pdfDoc() {
|
||||||
return (this.pageCache[n] = page);
|
return (this.pageCache[n] = page);
|
||||||
},
|
},
|
||||||
|
|
||||||
destroy: function pdfDocDestroy() {
|
destroy: function PDFDoc_destroy() {
|
||||||
if (this.worker)
|
if (this.worker)
|
||||||
this.worker.terminate();
|
this.worker.terminate();
|
||||||
|
|
||||||
|
@ -645,7 +873,7 @@ var PDFDoc = (function pdfDoc() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return constructor;
|
return PDFDoc;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
globalScope.PDFJS.PDFDoc = PDFDoc;
|
globalScope.PDFJS.PDFDoc = PDFDoc;
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var ARCFourCipher = (function arcFourCipher() {
|
var ARCFourCipher = (function ARCFourCipherClosure() {
|
||||||
function constructor(key) {
|
function ARCFourCipher(key) {
|
||||||
this.a = 0;
|
this.a = 0;
|
||||||
this.b = 0;
|
this.b = 0;
|
||||||
var s = new Uint8Array(256);
|
var s = new Uint8Array(256);
|
||||||
|
@ -20,8 +20,8 @@ var ARCFourCipher = (function arcFourCipher() {
|
||||||
this.s = s;
|
this.s = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor.prototype = {
|
ARCFourCipher.prototype = {
|
||||||
encryptBlock: function arcFourCipherEncryptBlock(data) {
|
encryptBlock: function ARCFourCipher_encryptBlock(data) {
|
||||||
var i, n = data.length, tmp, tmp2;
|
var i, n = data.length, tmp, tmp2;
|
||||||
var a = this.a, b = this.b, s = this.s;
|
var a = this.a, b = this.b, s = this.s;
|
||||||
var output = new Uint8Array(n);
|
var output = new Uint8Array(n);
|
||||||
|
@ -39,12 +39,12 @@ var ARCFourCipher = (function arcFourCipher() {
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
constructor.prototype.decryptBlock = constructor.prototype.encryptBlock;
|
ARCFourCipher.prototype.decryptBlock = ARCFourCipher.prototype.encryptBlock;
|
||||||
|
|
||||||
return constructor;
|
return ARCFourCipher;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
var calculateMD5 = (function calculateMD5() {
|
var calculateMD5 = (function calculateMD5Closure() {
|
||||||
var r = new Uint8Array([
|
var r = new Uint8Array([
|
||||||
7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
|
7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
|
||||||
5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
|
5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
|
||||||
|
@ -128,20 +128,20 @@ var calculateMD5 = (function calculateMD5() {
|
||||||
return hash;
|
return hash;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
var NullCipher = (function nullCipher() {
|
var NullCipher = (function NullCipherClosure() {
|
||||||
function constructor() {
|
function NullCipher() {
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor.prototype = {
|
NullCipher.prototype = {
|
||||||
decryptBlock: function nullCipherDecryptBlock(data) {
|
decryptBlock: function NullCipher_decryptBlock(data) {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return constructor;
|
return NullCipher;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
var AES128Cipher = (function aes128Cipher() {
|
var AES128Cipher = (function AES128CipherClosure() {
|
||||||
var rcon = new Uint8Array([
|
var rcon = new Uint8Array([
|
||||||
0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c,
|
0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c,
|
||||||
0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a,
|
0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a,
|
||||||
|
@ -330,7 +330,7 @@ var AES128Cipher = (function aes128Cipher() {
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
function constructor(key) {
|
function AES128Cipher(key) {
|
||||||
this.key = expandKey128(key);
|
this.key = expandKey128(key);
|
||||||
this.buffer = new Uint8Array(16);
|
this.buffer = new Uint8Array(16);
|
||||||
this.bufferPosition = 0;
|
this.bufferPosition = 0;
|
||||||
|
@ -370,8 +370,8 @@ var AES128Cipher = (function aes128Cipher() {
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor.prototype = {
|
AES128Cipher.prototype = {
|
||||||
decryptBlock: function aes128CipherDecryptBlock(data) {
|
decryptBlock: function AES128Cipher_decryptBlock(data) {
|
||||||
var i, sourceLength = data.length;
|
var i, sourceLength = data.length;
|
||||||
var buffer = this.buffer, bufferLength = this.bufferPosition;
|
var buffer = this.buffer, bufferLength = this.bufferPosition;
|
||||||
// waiting for IV values -- they are at the start of the stream
|
// waiting for IV values -- they are at the start of the stream
|
||||||
|
@ -391,16 +391,16 @@ var AES128Cipher = (function aes128Cipher() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return constructor;
|
return AES128Cipher;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
var CipherTransform = (function cipherTransform() {
|
var CipherTransform = (function CipherTransformClosure() {
|
||||||
function constructor(stringCipherConstructor, streamCipherConstructor) {
|
function CipherTransform(stringCipherConstructor, streamCipherConstructor) {
|
||||||
this.stringCipherConstructor = stringCipherConstructor;
|
this.stringCipherConstructor = stringCipherConstructor;
|
||||||
this.streamCipherConstructor = streamCipherConstructor;
|
this.streamCipherConstructor = streamCipherConstructor;
|
||||||
}
|
}
|
||||||
constructor.prototype = {
|
CipherTransform.prototype = {
|
||||||
createStream: function cipherTransformCreateStream(stream) {
|
createStream: function CipherTransform_createStream(stream) {
|
||||||
var cipher = new this.streamCipherConstructor();
|
var cipher = new this.streamCipherConstructor();
|
||||||
return new DecryptStream(stream,
|
return new DecryptStream(stream,
|
||||||
function cipherTransformDecryptStream(data) {
|
function cipherTransformDecryptStream(data) {
|
||||||
|
@ -408,17 +408,17 @@ var CipherTransform = (function cipherTransform() {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
decryptString: function cipherTransformDecryptString(s) {
|
decryptString: function CipherTransform_decryptString(s) {
|
||||||
var cipher = new this.stringCipherConstructor();
|
var cipher = new this.stringCipherConstructor();
|
||||||
var data = stringToBytes(s);
|
var data = stringToBytes(s);
|
||||||
data = cipher.decryptBlock(data);
|
data = cipher.decryptBlock(data);
|
||||||
return bytesToString(data);
|
return bytesToString(data);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return constructor;
|
return CipherTransform;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
var CipherTransformFactory = (function cipherTransformFactory() {
|
var CipherTransformFactory = (function CipherTransformFactoryClosure() {
|
||||||
function prepareKeyData(fileId, password, ownerPassword, userPassword,
|
function prepareKeyData(fileId, password, ownerPassword, userPassword,
|
||||||
flags, revision, keyLength, encryptMetadata) {
|
flags, revision, keyLength, encryptMetadata) {
|
||||||
var defaultPasswordBytes = new Uint8Array([
|
var defaultPasswordBytes = new Uint8Array([
|
||||||
|
@ -490,7 +490,7 @@ var CipherTransformFactory = (function cipherTransformFactory() {
|
||||||
|
|
||||||
var identityName = new Name('Identity');
|
var identityName = new Name('Identity');
|
||||||
|
|
||||||
function constructor(dict, fileId, password) {
|
function CipherTransformFactory(dict, fileId, password) {
|
||||||
var filter = dict.get('Filter');
|
var filter = dict.get('Filter');
|
||||||
if (!isName(filter) || filter.name != 'Standard')
|
if (!isName(filter) || filter.name != 'Standard')
|
||||||
error('unknown encryption method');
|
error('unknown encryption method');
|
||||||
|
@ -570,12 +570,11 @@ var CipherTransformFactory = (function cipherTransformFactory() {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
error('Unknown crypto method');
|
error('Unknown crypto method');
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor.prototype = {
|
CipherTransformFactory.prototype = {
|
||||||
createCipherTransform: function buildCipherCreateCipherTransform(num,
|
createCipherTransform:
|
||||||
gen) {
|
function CipherTransformFactory_createCipherTransform(num, gen) {
|
||||||
if (this.algorithm == 4) {
|
if (this.algorithm == 4) {
|
||||||
return new CipherTransform(
|
return new CipherTransform(
|
||||||
buildCipherConstructor(this.cf, this.stmf,
|
buildCipherConstructor(this.cf, this.stmf,
|
||||||
|
@ -592,6 +591,6 @@ var CipherTransformFactory = (function cipherTransformFactory() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return constructor;
|
return CipherTransformFactory;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var PartialEvaluator = (function partialEvaluator() {
|
var PartialEvaluator = (function PartialEvaluatorClosure() {
|
||||||
function constructor(xref, handler, uniquePrefix) {
|
function PartialEvaluator(xref, handler, uniquePrefix) {
|
||||||
this.state = new EvalState();
|
this.state = new EvalState();
|
||||||
this.stateStack = [];
|
this.stateStack = [];
|
||||||
|
|
||||||
|
@ -111,14 +111,27 @@ var PartialEvaluator = (function partialEvaluator() {
|
||||||
EX: 'endCompat'
|
EX: 'endCompat'
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor.prototype = {
|
function splitCombinedOperations(operations) {
|
||||||
getIRQueue: function partialEvaluatorGetIRQueue(stream, resources,
|
// Two operations can be combined together, trying to find which two
|
||||||
queue, dependency) {
|
// operations were concatenated.
|
||||||
|
for (var i = operations.length - 1; i > 0; i--) {
|
||||||
|
var op1 = operations.substring(0, i), op2 = operations.substring(i);
|
||||||
|
if (op1 in OP_MAP && op2 in OP_MAP)
|
||||||
|
return [op1, op2]; // operations found
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
PartialEvaluator.prototype = {
|
||||||
|
getOperatorList: function PartialEvaluator_getOperatorList(stream,
|
||||||
|
resources,
|
||||||
|
dependency,
|
||||||
|
queue) {
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
var xref = this.xref;
|
var xref = this.xref;
|
||||||
var handler = this.handler;
|
var handler = this.handler;
|
||||||
var uniquePrefix = this.uniquePrefix;
|
var uniquePrefix = this.uniquePrefix || '';
|
||||||
|
|
||||||
function insertDependency(depList) {
|
function insertDependency(depList) {
|
||||||
fnArray.push('dependency');
|
fnArray.push('dependency');
|
||||||
|
@ -131,18 +144,14 @@ var PartialEvaluator = (function partialEvaluator() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleSetFont(fontName, fontRef) {
|
function handleSetFont(fontName, font) {
|
||||||
var loadedName = null;
|
var loadedName = null;
|
||||||
|
|
||||||
var fontRes = resources.get('Font');
|
var fontRes = resources.get('Font');
|
||||||
|
|
||||||
// TODO: TOASK: Is it possible to get here? If so, what does
|
|
||||||
// args[0].name should be like???
|
|
||||||
assert(fontRes, 'fontRes not available');
|
assert(fontRes, 'fontRes not available');
|
||||||
|
|
||||||
fontRes = xref.fetchIfRef(fontRes);
|
font = xref.fetchIfRef(font) || fontRes.get(fontName);
|
||||||
fontRef = fontRef || fontRes.get(fontName);
|
|
||||||
var font = xref.fetchIfRef(fontRef);
|
|
||||||
assertWellFormed(isDict(font));
|
assertWellFormed(isDict(font));
|
||||||
if (!font.translated) {
|
if (!font.translated) {
|
||||||
font.translated = self.translateFont(font, xref, resources,
|
font.translated = self.translateFont(font, xref, resources,
|
||||||
|
@ -155,6 +164,15 @@ var PartialEvaluator = (function partialEvaluator() {
|
||||||
font.loadedName = loadedName;
|
font.loadedName = loadedName;
|
||||||
|
|
||||||
var translated = font.translated;
|
var translated = font.translated;
|
||||||
|
// Convert the file to an ArrayBuffer which will be turned back into
|
||||||
|
// a Stream in the main thread.
|
||||||
|
if (translated.file)
|
||||||
|
translated.file = translated.file.getBytes();
|
||||||
|
if (translated.properties.file) {
|
||||||
|
translated.properties.file =
|
||||||
|
translated.properties.file.getBytes();
|
||||||
|
}
|
||||||
|
|
||||||
handler.send('obj', [
|
handler.send('obj', [
|
||||||
loadedName,
|
loadedName,
|
||||||
'Font',
|
'Font',
|
||||||
|
@ -168,7 +186,7 @@ var PartialEvaluator = (function partialEvaluator() {
|
||||||
|
|
||||||
// Ensure the font is ready before the font is set
|
// Ensure the font is ready before the font is set
|
||||||
// and later on used for drawing.
|
// and later on used for drawing.
|
||||||
// TODO: This should get insert to the IRQueue only once per
|
// OPTIMIZE: This should get insert to the operatorList only once per
|
||||||
// page.
|
// page.
|
||||||
insertDependency([loadedName]);
|
insertDependency([loadedName]);
|
||||||
return loadedName;
|
return loadedName;
|
||||||
|
@ -179,53 +197,13 @@ var PartialEvaluator = (function partialEvaluator() {
|
||||||
var w = dict.get('Width', 'W');
|
var w = dict.get('Width', 'W');
|
||||||
var h = dict.get('Height', 'H');
|
var h = dict.get('Height', 'H');
|
||||||
|
|
||||||
if (image instanceof JpegStream && image.isNative) {
|
|
||||||
var objId = 'img_' + uniquePrefix + (++self.objIdCounter);
|
|
||||||
handler.send('obj', [objId, 'JpegStream', image.getIR()]);
|
|
||||||
|
|
||||||
// Add the dependency on the image object.
|
|
||||||
insertDependency([objId]);
|
|
||||||
|
|
||||||
// The normal fn.
|
|
||||||
fn = 'paintJpegXObject';
|
|
||||||
args = [objId, w, h];
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Needs to be rendered ourself.
|
|
||||||
|
|
||||||
// Figure out if the image has an imageMask.
|
|
||||||
var imageMask = dict.get('ImageMask', 'IM') || false;
|
var imageMask = dict.get('ImageMask', 'IM') || false;
|
||||||
|
if (imageMask) {
|
||||||
// If there is no imageMask, create the PDFImage and a lot
|
|
||||||
// of image processing can be done here.
|
|
||||||
if (!imageMask) {
|
|
||||||
var imageObj = new PDFImage(xref, resources, image, inline);
|
|
||||||
|
|
||||||
if (imageObj.imageMask) {
|
|
||||||
throw 'Can\'t handle this in the web worker :/';
|
|
||||||
}
|
|
||||||
|
|
||||||
var imgData = {
|
|
||||||
width: w,
|
|
||||||
height: h,
|
|
||||||
data: new Uint8Array(w * h * 4)
|
|
||||||
};
|
|
||||||
var pixels = imgData.data;
|
|
||||||
imageObj.fillRgbaBuffer(pixels, imageObj.decode);
|
|
||||||
|
|
||||||
fn = 'paintImageXObject';
|
|
||||||
args = [imgData];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This depends on a tmpCanvas beeing filled with the
|
// This depends on a tmpCanvas beeing filled with the
|
||||||
// current fillStyle, such that processing the pixel
|
// current fillStyle, such that processing the pixel
|
||||||
// data can't be done here. Instead of creating a
|
// data can't be done here. Instead of creating a
|
||||||
// complete PDFImage, only read the information needed
|
// complete PDFImage, only read the information needed
|
||||||
// for later.
|
// for later.
|
||||||
fn = 'paintImageMaskXObject';
|
|
||||||
|
|
||||||
var width = dict.get('Width', 'W');
|
var width = dict.get('Width', 'W');
|
||||||
var height = dict.get('Height', 'H');
|
var height = dict.get('Height', 'H');
|
||||||
|
@ -234,10 +212,45 @@ var PartialEvaluator = (function partialEvaluator() {
|
||||||
var decode = dict.get('Decode', 'D');
|
var decode = dict.get('Decode', 'D');
|
||||||
var inverseDecode = !!decode && decode[0] > 0;
|
var inverseDecode = !!decode && decode[0] > 0;
|
||||||
|
|
||||||
|
fn = 'paintImageMaskXObject';
|
||||||
args = [imgArray, inverseDecode, width, height];
|
args = [imgArray, inverseDecode, width, height];
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uniquePrefix = uniquePrefix || '';
|
// If there is no imageMask, create the PDFImage and a lot
|
||||||
|
// of image processing can be done here.
|
||||||
|
var objId = 'img_' + uniquePrefix + (++self.objIdCounter);
|
||||||
|
insertDependency([objId]);
|
||||||
|
args = [objId, w, h];
|
||||||
|
|
||||||
|
var softMask = dict.get('SMask', 'IM') || false;
|
||||||
|
if (!softMask && image instanceof JpegStream &&
|
||||||
|
image.isNativelySupported(xref, resources)) {
|
||||||
|
// These JPEGs don't need any more processing so we can just send it.
|
||||||
|
fn = 'paintJpegXObject';
|
||||||
|
handler.send('obj', [objId, 'JpegStream', image.getIR()]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn = 'paintImageXObject';
|
||||||
|
|
||||||
|
PDFImage.buildImage(function(imageObj) {
|
||||||
|
var drawWidth = imageObj.drawWidth;
|
||||||
|
var drawHeight = imageObj.drawHeight;
|
||||||
|
var imgData = {
|
||||||
|
width: drawWidth,
|
||||||
|
height: drawHeight,
|
||||||
|
data: new Uint8Array(drawWidth * drawHeight * 4)
|
||||||
|
};
|
||||||
|
var pixels = imgData.data;
|
||||||
|
imageObj.fillRgbaBuffer(pixels, drawWidth, drawHeight);
|
||||||
|
handler.send('obj', [objId, 'Image', imgData]);
|
||||||
|
}, handler, xref, resources, image, inline);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!queue)
|
||||||
|
queue = {};
|
||||||
|
|
||||||
if (!queue.argsArray) {
|
if (!queue.argsArray) {
|
||||||
queue.argsArray = [];
|
queue.argsArray = [];
|
||||||
}
|
}
|
||||||
|
@ -248,45 +261,48 @@ var PartialEvaluator = (function partialEvaluator() {
|
||||||
var fnArray = queue.fnArray, argsArray = queue.argsArray;
|
var fnArray = queue.fnArray, argsArray = queue.argsArray;
|
||||||
var dependencyArray = dependency || [];
|
var dependencyArray = dependency || [];
|
||||||
|
|
||||||
resources = xref.fetchIfRef(resources) || new Dict();
|
resources = resources || new Dict();
|
||||||
var xobjs = xref.fetchIfRef(resources.get('XObject')) || new Dict();
|
var xobjs = resources.get('XObject') || new Dict();
|
||||||
var patterns = xref.fetchIfRef(resources.get('Pattern')) || new Dict();
|
var patterns = resources.get('Pattern') || new Dict();
|
||||||
var parser = new Parser(new Lexer(stream), false);
|
var parser = new Parser(new Lexer(stream), false, xref);
|
||||||
var res = resources;
|
var res = resources;
|
||||||
|
var hasNextObj = false, nextObj;
|
||||||
var args = [], obj;
|
var args = [], obj;
|
||||||
var getObjBt = function getObjBt() {
|
|
||||||
parser = this.oldParser;
|
|
||||||
return { name: 'BT' };
|
|
||||||
};
|
|
||||||
var TILING_PATTERN = 1, SHADING_PATTERN = 2;
|
var TILING_PATTERN = 1, SHADING_PATTERN = 2;
|
||||||
|
|
||||||
while (!isEOF(obj = parser.getObj())) {
|
while (true) {
|
||||||
|
if (hasNextObj) {
|
||||||
|
obj = nextObj;
|
||||||
|
hasNextObj = false;
|
||||||
|
} else {
|
||||||
|
obj = parser.getObj();
|
||||||
|
if (isEOF(obj))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (isCmd(obj)) {
|
if (isCmd(obj)) {
|
||||||
var cmd = obj.cmd;
|
var cmd = obj.cmd;
|
||||||
var fn = OP_MAP[cmd];
|
var fn = OP_MAP[cmd];
|
||||||
if (!fn) {
|
if (!fn) {
|
||||||
// invalid content command, trying to recover
|
// invalid content command, trying to recover
|
||||||
if (cmd.substr(-2) == 'BT') {
|
var cmds = splitCombinedOperations(cmd);
|
||||||
fn = OP_MAP[cmd.substr(0, cmd.length - 2)];
|
if (cmds) {
|
||||||
// feeding 'BT' on next interation
|
cmd = cmds[0];
|
||||||
parser = {
|
fn = OP_MAP[cmd];
|
||||||
getObj: getObjBt,
|
// feeding other command on the next interation
|
||||||
oldParser: parser
|
hasNextObj = true;
|
||||||
};
|
nextObj = Cmd.get(cmds[1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assertWellFormed(fn, 'Unknown command "' + cmd + '"');
|
assertWellFormed(fn, 'Unknown command "' + cmd + '"');
|
||||||
// TODO figure out how to type-check vararg functions
|
// TODO figure out how to type-check vararg functions
|
||||||
|
|
||||||
if ((cmd == 'SCN' || cmd == 'scn') && !args[args.length - 1].code) {
|
if ((cmd == 'SCN' || cmd == 'scn') && !args[args.length - 1].code) {
|
||||||
// Use the IR version for setStroke/FillColorN.
|
|
||||||
fn += '_IR';
|
|
||||||
|
|
||||||
// compile tiling patterns
|
// compile tiling patterns
|
||||||
var patternName = args[args.length - 1];
|
var patternName = args[args.length - 1];
|
||||||
// SCN/scn applies patterns along with normal colors
|
// SCN/scn applies patterns along with normal colors
|
||||||
if (isName(patternName)) {
|
if (isName(patternName)) {
|
||||||
var pattern = xref.fetchIfRef(patterns.get(patternName.name));
|
var pattern = patterns.get(patternName.name);
|
||||||
if (pattern) {
|
if (pattern) {
|
||||||
var dict = isStream(pattern) ? pattern.dict : pattern;
|
var dict = isStream(pattern) ? pattern.dict : pattern;
|
||||||
var typeNum = dict.get('PatternType');
|
var typeNum = dict.get('PatternType');
|
||||||
|
@ -294,21 +310,20 @@ var PartialEvaluator = (function partialEvaluator() {
|
||||||
if (typeNum == TILING_PATTERN) {
|
if (typeNum == TILING_PATTERN) {
|
||||||
// Create an IR of the pattern code.
|
// Create an IR of the pattern code.
|
||||||
var depIdx = dependencyArray.length;
|
var depIdx = dependencyArray.length;
|
||||||
var queueObj = {};
|
var operatorList = this.getOperatorList(pattern,
|
||||||
var codeIR = this.getIRQueue(pattern, dict.get('Resources'),
|
dict.get('Resources') || resources, dependencyArray);
|
||||||
queueObj, dependencyArray);
|
|
||||||
|
|
||||||
// Add the dependencies that are required to execute the
|
// Add the dependencies that are required to execute the
|
||||||
// codeIR.
|
// operatorList.
|
||||||
insertDependency(dependencyArray.slice(depIdx));
|
insertDependency(dependencyArray.slice(depIdx));
|
||||||
|
|
||||||
args = TilingPattern.getIR(codeIR, dict, args);
|
args = TilingPattern.getIR(operatorList, dict, args);
|
||||||
}
|
}
|
||||||
else if (typeNum == SHADING_PATTERN) {
|
else if (typeNum == SHADING_PATTERN) {
|
||||||
var shading = xref.fetchIfRef(dict.get('Shading'));
|
var shading = dict.get('Shading');
|
||||||
var matrix = dict.get('Matrix');
|
var matrix = dict.get('Matrix');
|
||||||
var pattern = Pattern.parseShading(shading, matrix, xref, res,
|
var pattern = Pattern.parseShading(shading, matrix, xref,
|
||||||
null /*ctx*/);
|
res);
|
||||||
args = pattern.getIR();
|
args = pattern.getIR();
|
||||||
} else {
|
} else {
|
||||||
error('Unkown PatternType ' + typeNum);
|
error('Unkown PatternType ' + typeNum);
|
||||||
|
@ -320,7 +335,6 @@ var PartialEvaluator = (function partialEvaluator() {
|
||||||
var name = args[0].name;
|
var name = args[0].name;
|
||||||
var xobj = xobjs.get(name);
|
var xobj = xobjs.get(name);
|
||||||
if (xobj) {
|
if (xobj) {
|
||||||
xobj = xref.fetchIfRef(xobj);
|
|
||||||
assertWellFormed(isStream(xobj), 'XObject should be a stream');
|
assertWellFormed(isStream(xobj), 'XObject should be a stream');
|
||||||
|
|
||||||
var type = xobj.dict.get('Subtype');
|
var type = xobj.dict.get('Subtype');
|
||||||
|
@ -336,14 +350,18 @@ var PartialEvaluator = (function partialEvaluator() {
|
||||||
fnArray.push('paintFormXObjectBegin');
|
fnArray.push('paintFormXObjectBegin');
|
||||||
argsArray.push([matrix, bbox]);
|
argsArray.push([matrix, bbox]);
|
||||||
|
|
||||||
// This adds the IRQueue of the xObj to the current queue.
|
// This adds the operatorList of the xObj to the current queue.
|
||||||
var depIdx = dependencyArray.length;
|
var depIdx = dependencyArray.length;
|
||||||
|
|
||||||
this.getIRQueue(xobj, xobj.dict.get('Resources'), queue,
|
// Pass in the current `queue` object. That means the `fnArray`
|
||||||
dependencyArray);
|
// and the `argsArray` in this scope is reused and new commands
|
||||||
|
// are added to them.
|
||||||
|
this.getOperatorList(xobj,
|
||||||
|
xobj.dict.get('Resources') || resources,
|
||||||
|
dependencyArray, queue);
|
||||||
|
|
||||||
// Add the dependencies that are required to execute the
|
// Add the dependencies that are required to execute the
|
||||||
// codeIR.
|
// operatorList.
|
||||||
insertDependency(dependencyArray.slice(depIdx));
|
insertDependency(dependencyArray.slice(depIdx));
|
||||||
|
|
||||||
fn = 'paintFormXObjectEnd';
|
fn = 'paintFormXObjectEnd';
|
||||||
|
@ -367,28 +385,27 @@ var PartialEvaluator = (function partialEvaluator() {
|
||||||
args = [ColorSpace.parseToIR(args[0], xref, resources)];
|
args = [ColorSpace.parseToIR(args[0], xref, resources)];
|
||||||
break;
|
break;
|
||||||
case 'shadingFill':
|
case 'shadingFill':
|
||||||
var shadingRes = xref.fetchIfRef(res.get('Shading'));
|
var shadingRes = res.get('Shading');
|
||||||
if (!shadingRes)
|
if (!shadingRes)
|
||||||
error('No shading resource found');
|
error('No shading resource found');
|
||||||
|
|
||||||
var shading = xref.fetchIfRef(shadingRes.get(args[0].name));
|
var shading = shadingRes.get(args[0].name);
|
||||||
if (!shading)
|
if (!shading)
|
||||||
error('No shading object found');
|
error('No shading object found');
|
||||||
|
|
||||||
var shadingFill = Pattern.parseShading(shading, null, xref, res,
|
var shadingFill = Pattern.parseShading(shading, null, xref, res);
|
||||||
null);
|
|
||||||
var patternIR = shadingFill.getIR();
|
var patternIR = shadingFill.getIR();
|
||||||
args = [patternIR];
|
args = [patternIR];
|
||||||
fn = 'shadingFill';
|
fn = 'shadingFill';
|
||||||
break;
|
break;
|
||||||
case 'setGState':
|
case 'setGState':
|
||||||
var dictName = args[0];
|
var dictName = args[0];
|
||||||
var extGState = xref.fetchIfRef(resources.get('ExtGState'));
|
var extGState = resources.get('ExtGState');
|
||||||
|
|
||||||
if (!isDict(extGState) || !extGState.has(dictName.name))
|
if (!isDict(extGState) || !extGState.has(dictName.name))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
var gsState = xref.fetchIfRef(extGState.get(dictName.name));
|
var gsState = extGState.get(dictName.name);
|
||||||
|
|
||||||
// This array holds the converted/processed state data.
|
// This array holds the converted/processed state data.
|
||||||
var gsStateObj = [];
|
var gsStateObj = [];
|
||||||
|
@ -453,10 +470,7 @@ var PartialEvaluator = (function partialEvaluator() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return queue;
|
||||||
fnArray: fnArray,
|
|
||||||
argsArray: argsArray
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
|
|
||||||
extractDataStructures: function
|
extractDataStructures: function
|
||||||
|
@ -470,7 +484,7 @@ var PartialEvaluator = (function partialEvaluator() {
|
||||||
|
|
||||||
if (properties.composite) {
|
if (properties.composite) {
|
||||||
// CIDSystemInfo helps to match CID to glyphs
|
// CIDSystemInfo helps to match CID to glyphs
|
||||||
var cidSystemInfo = xref.fetchIfRef(dict.get('CIDSystemInfo'));
|
var cidSystemInfo = dict.get('CIDSystemInfo');
|
||||||
if (isDict(cidSystemInfo)) {
|
if (isDict(cidSystemInfo)) {
|
||||||
properties.cidSystemInfo = {
|
properties.cidSystemInfo = {
|
||||||
registry: cidSystemInfo.get('Registry'),
|
registry: cidSystemInfo.get('Registry'),
|
||||||
|
@ -479,20 +493,24 @@ var PartialEvaluator = (function partialEvaluator() {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
var cidToGidMap = xref.fetchIfRef(dict.get('CIDToGIDMap'));
|
var cidToGidMap = dict.get('CIDToGIDMap');
|
||||||
if (isStream(cidToGidMap))
|
if (isStream(cidToGidMap))
|
||||||
properties.cidToGidMap = this.readCidToGidMap(cidToGidMap);
|
properties.cidToGidMap = this.readCidToGidMap(cidToGidMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var flags = properties.flags;
|
||||||
var differences = [];
|
var differences = [];
|
||||||
var baseEncoding = Encodings.StandardEncoding;
|
var baseEncoding = !!(flags & FontFlags.Symbolic) ?
|
||||||
|
Encodings.symbolsEncoding : Encodings.StandardEncoding;
|
||||||
var hasEncoding = dict.has('Encoding');
|
var hasEncoding = dict.has('Encoding');
|
||||||
if (hasEncoding) {
|
if (hasEncoding) {
|
||||||
var encoding = xref.fetchIfRef(dict.get('Encoding'));
|
var encoding = dict.get('Encoding');
|
||||||
if (isDict(encoding)) {
|
if (isDict(encoding)) {
|
||||||
var baseName = encoding.get('BaseEncoding');
|
var baseName = encoding.get('BaseEncoding');
|
||||||
if (baseName)
|
if (baseName)
|
||||||
baseEncoding = Encodings[baseName.name];
|
baseEncoding = Encodings[baseName.name];
|
||||||
|
else
|
||||||
|
hasEncoding = false; // base encoding was not provided
|
||||||
|
|
||||||
// Load the differences between the base and original
|
// Load the differences between the base and original
|
||||||
if (encoding.has('Differences')) {
|
if (encoding.has('Differences')) {
|
||||||
|
@ -512,14 +530,14 @@ var PartialEvaluator = (function partialEvaluator() {
|
||||||
error('Encoding is not a Name nor a Dict');
|
error('Encoding is not a Name nor a Dict');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
properties.differences = differences;
|
properties.differences = differences;
|
||||||
properties.baseEncoding = baseEncoding;
|
properties.baseEncoding = baseEncoding;
|
||||||
properties.hasEncoding = hasEncoding;
|
properties.hasEncoding = hasEncoding;
|
||||||
},
|
},
|
||||||
|
|
||||||
readToUnicode:
|
readToUnicode: function PartialEvaluator_readToUnicode(toUnicode, xref) {
|
||||||
function partialEvaluatorReadToUnicode(toUnicode, xref) {
|
var cmapObj = toUnicode;
|
||||||
var cmapObj = xref.fetchIfRef(toUnicode);
|
|
||||||
var charToUnicode = [];
|
var charToUnicode = [];
|
||||||
if (isName(cmapObj)) {
|
if (isName(cmapObj)) {
|
||||||
var isIdentityMap = cmapObj.name.substr(0, 9) == 'Identity-';
|
var isIdentityMap = cmapObj.name.substr(0, 9) == 'Identity-';
|
||||||
|
@ -532,9 +550,9 @@ var PartialEvaluator = (function partialEvaluator() {
|
||||||
|
|
||||||
var cmap = cmapObj.getBytes(cmapObj.length);
|
var cmap = cmapObj.getBytes(cmapObj.length);
|
||||||
for (var i = 0, ii = cmap.length; i < ii; i++) {
|
for (var i = 0, ii = cmap.length; i < ii; i++) {
|
||||||
var byte = cmap[i];
|
var octet = cmap[i];
|
||||||
if (byte == 0x20 || byte == 0x0D || byte == 0x0A ||
|
if (octet == 0x20 || octet == 0x0D || octet == 0x0A ||
|
||||||
byte == 0x3C || byte == 0x5B || byte == 0x5D) {
|
octet == 0x3C || octet == 0x5B || octet == 0x5D) {
|
||||||
switch (token) {
|
switch (token) {
|
||||||
case 'usecmap':
|
case 'usecmap':
|
||||||
error('usecmap is not implemented');
|
error('usecmap is not implemented');
|
||||||
|
@ -554,11 +572,23 @@ var PartialEvaluator = (function partialEvaluator() {
|
||||||
var startRange = tokens[j];
|
var startRange = tokens[j];
|
||||||
var endRange = tokens[j + 1];
|
var endRange = tokens[j + 1];
|
||||||
var code = tokens[j + 2];
|
var code = tokens[j + 2];
|
||||||
|
if (code == 0xFFFF) {
|
||||||
|
// CMap is broken, assuming code == startRange
|
||||||
|
code = startRange;
|
||||||
|
}
|
||||||
|
if (isArray(code)) {
|
||||||
|
var codeindex = 0;
|
||||||
|
while (startRange <= endRange) {
|
||||||
|
charToUnicode[startRange] = code[codeindex++];
|
||||||
|
++startRange;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
while (startRange <= endRange) {
|
while (startRange <= endRange) {
|
||||||
charToUnicode[startRange] = code++;
|
charToUnicode[startRange] = code++;
|
||||||
++startRange;
|
++startRange;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'endcidchar':
|
case 'endcidchar':
|
||||||
|
@ -579,7 +609,7 @@ var PartialEvaluator = (function partialEvaluator() {
|
||||||
tokens.push(token);
|
tokens.push(token);
|
||||||
token = '';
|
token = '';
|
||||||
}
|
}
|
||||||
switch (byte) {
|
switch (octet) {
|
||||||
case 0x5B:
|
case 0x5B:
|
||||||
// begin list parsing
|
// begin list parsing
|
||||||
tokens.push(beginArrayToken);
|
tokens.push(beginArrayToken);
|
||||||
|
@ -593,21 +623,39 @@ var PartialEvaluator = (function partialEvaluator() {
|
||||||
tokens.push(items);
|
tokens.push(items);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (byte == 0x3E) {
|
} else if (octet == 0x3E) {
|
||||||
if (token.length) {
|
if (token.length) {
|
||||||
|
if (token.length <= 4) {
|
||||||
// parsing hex number
|
// parsing hex number
|
||||||
tokens.push(parseInt(token, 16));
|
tokens.push(parseInt(token, 16));
|
||||||
token = '';
|
token = '';
|
||||||
|
} else {
|
||||||
|
// parsing hex UTF-16BE numbers
|
||||||
|
var str = [];
|
||||||
|
for (var k = 0, kk = token.length; k < kk; k += 4) {
|
||||||
|
var b = parseInt(token.substr(k, 4), 16);
|
||||||
|
if (b <= 0x10) {
|
||||||
|
k += 4;
|
||||||
|
b = (b << 16) | parseInt(token.substr(k, 4), 16);
|
||||||
|
b -= 0x10000;
|
||||||
|
str.push(0xD800 | (b >> 10));
|
||||||
|
str.push(0xDC00 | (b & 0x3FF));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
str.push(b);
|
||||||
|
}
|
||||||
|
tokens.push(String.fromCharCode.apply(String, str));
|
||||||
|
token = '';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
token += String.fromCharCode(byte);
|
token += String.fromCharCode(octet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return charToUnicode;
|
return charToUnicode;
|
||||||
},
|
},
|
||||||
readCidToGidMap:
|
readCidToGidMap: function PartialEvaluator_readCidToGidMap(cidToGidStream) {
|
||||||
function partialEvaluatorReadCidToGidMap(cidToGidStream) {
|
|
||||||
// Extract the encoding from the CIDToGIDMap
|
// Extract the encoding from the CIDToGIDMap
|
||||||
var glyphsData = cidToGidStream.getBytes();
|
var glyphsData = cidToGidStream.getBytes();
|
||||||
|
|
||||||
|
@ -624,16 +672,16 @@ var PartialEvaluator = (function partialEvaluator() {
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
|
|
||||||
extractWidths: function partialEvaluatorWidths(dict,
|
extractWidths: function PartialEvaluator_extractWidths(dict,
|
||||||
xref,
|
xref,
|
||||||
descriptor,
|
descriptor,
|
||||||
properties) {
|
properties) {
|
||||||
var glyphsWidths = [];
|
var glyphsWidths = [];
|
||||||
var defaultWidth = 0;
|
var defaultWidth = 0;
|
||||||
if (properties.composite) {
|
if (properties.composite) {
|
||||||
defaultWidth = xref.fetchIfRef(dict.get('DW')) || 1000;
|
defaultWidth = dict.get('DW') || 1000;
|
||||||
|
|
||||||
var widths = xref.fetchIfRef(dict.get('W'));
|
var widths = dict.get('W');
|
||||||
if (widths) {
|
if (widths) {
|
||||||
var start = 0, end = 0;
|
var start = 0, end = 0;
|
||||||
for (var i = 0, ii = widths.length; i < ii; i++) {
|
for (var i = 0, ii = widths.length; i < ii; i++) {
|
||||||
|
@ -654,7 +702,7 @@ var PartialEvaluator = (function partialEvaluator() {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var firstChar = properties.firstChar;
|
var firstChar = properties.firstChar;
|
||||||
var widths = xref.fetchIfRef(dict.get('Widths'));
|
var widths = dict.get('Widths');
|
||||||
if (widths) {
|
if (widths) {
|
||||||
var j = firstChar;
|
var j = firstChar;
|
||||||
for (var i = 0, ii = widths.length; i < ii; i++)
|
for (var i = 0, ii = widths.length; i < ii; i++)
|
||||||
|
@ -676,7 +724,7 @@ var PartialEvaluator = (function partialEvaluator() {
|
||||||
properties.widths = glyphsWidths;
|
properties.widths = glyphsWidths;
|
||||||
},
|
},
|
||||||
|
|
||||||
getBaseFontMetrics: function getBaseFontMetrics(name) {
|
getBaseFontMetrics: function PartialEvaluator_getBaseFontMetrics(name) {
|
||||||
var defaultWidth = 0, widths = [];
|
var defaultWidth = 0, widths = [];
|
||||||
var glyphWidths = Metrics[stdFontMap[name] || name];
|
var glyphWidths = Metrics[stdFontMap[name] || name];
|
||||||
if (isNum(glyphWidths)) {
|
if (isNum(glyphWidths)) {
|
||||||
|
@ -691,7 +739,9 @@ var PartialEvaluator = (function partialEvaluator() {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
translateFont: function partialEvaluatorTranslateFont(dict, xref, resources,
|
translateFont: function PartialEvaluator_translateFont(dict,
|
||||||
|
xref,
|
||||||
|
resources,
|
||||||
dependency) {
|
dependency) {
|
||||||
var baseDict = dict;
|
var baseDict = dict;
|
||||||
var type = dict.get('Subtype');
|
var type = dict.get('Subtype');
|
||||||
|
@ -707,10 +757,7 @@ var PartialEvaluator = (function partialEvaluator() {
|
||||||
if (!df)
|
if (!df)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
if (isRef(df))
|
dict = isArray(df) ? xref.fetchIfRef(df[0]) : df;
|
||||||
df = xref.fetch(df);
|
|
||||||
|
|
||||||
dict = xref.fetchIfRef(isRef(df) ? df : df[0]);
|
|
||||||
|
|
||||||
type = dict.get('Subtype');
|
type = dict.get('Subtype');
|
||||||
assertWellFormed(isName(type), 'invalid font Subtype');
|
assertWellFormed(isName(type), 'invalid font Subtype');
|
||||||
|
@ -718,7 +765,7 @@ var PartialEvaluator = (function partialEvaluator() {
|
||||||
}
|
}
|
||||||
var maxCharIndex = composite ? 0xFFFF : 0xFF;
|
var maxCharIndex = composite ? 0xFFFF : 0xFF;
|
||||||
|
|
||||||
var descriptor = xref.fetchIfRef(dict.get('FontDescriptor'));
|
var descriptor = dict.get('FontDescriptor');
|
||||||
if (!descriptor) {
|
if (!descriptor) {
|
||||||
if (type.name == 'Type3') {
|
if (type.name == 'Type3') {
|
||||||
// FontDescriptor is only required for Type3 fonts when the document
|
// FontDescriptor is only required for Type3 fonts when the document
|
||||||
|
@ -737,10 +784,18 @@ var PartialEvaluator = (function partialEvaluator() {
|
||||||
baseFontName = baseFontName.name.replace(/[,_]/g, '-');
|
baseFontName = baseFontName.name.replace(/[,_]/g, '-');
|
||||||
var metrics = this.getBaseFontMetrics(baseFontName);
|
var metrics = this.getBaseFontMetrics(baseFontName);
|
||||||
|
|
||||||
|
// Simulating descriptor flags attribute
|
||||||
|
var fontNameWoStyle = baseFontName.split('-')[0];
|
||||||
|
var flags = (serifFonts[fontNameWoStyle] ||
|
||||||
|
(fontNameWoStyle.search(/serif/gi) != -1) ? FontFlags.Serif : 0) |
|
||||||
|
(symbolsFonts[fontNameWoStyle] ? FontFlags.Symbolic :
|
||||||
|
FontFlags.Nonsymbolic);
|
||||||
|
|
||||||
var properties = {
|
var properties = {
|
||||||
type: type.name,
|
type: type.name,
|
||||||
widths: metrics.widths,
|
widths: metrics.widths,
|
||||||
defaultWidth: metrics.defaultWidth,
|
defaultWidth: metrics.defaultWidth,
|
||||||
|
flags: flags,
|
||||||
firstChar: 0,
|
firstChar: 0,
|
||||||
lastChar: maxCharIndex
|
lastChar: maxCharIndex
|
||||||
};
|
};
|
||||||
|
@ -752,34 +807,31 @@ var PartialEvaluator = (function partialEvaluator() {
|
||||||
properties: properties
|
properties: properties
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// According to the spec if 'FontDescriptor' is declared, 'FirstChar',
|
// According to the spec if 'FontDescriptor' is declared, 'FirstChar',
|
||||||
// 'LastChar' and 'Widths' should exists too, but some PDF encoders seems
|
// 'LastChar' and 'Widths' should exist too, but some PDF encoders seem
|
||||||
// to ignore this rule when a variant of a standart font is used.
|
// to ignore this rule when a variant of a standart font is used.
|
||||||
// TODO Fill the width array depending on which of the base font this is
|
// TODO Fill the width array depending on which of the base font this is
|
||||||
// a variant.
|
// a variant.
|
||||||
var firstChar = xref.fetchIfRef(dict.get('FirstChar')) || 0;
|
var firstChar = dict.get('FirstChar') || 0;
|
||||||
var lastChar = xref.fetchIfRef(dict.get('LastChar')) || maxCharIndex;
|
var lastChar = dict.get('LastChar') || maxCharIndex;
|
||||||
var fontName = xref.fetchIfRef(descriptor.get('FontName'));
|
var fontName = descriptor.get('FontName');
|
||||||
|
// Some bad pdf's have a string as the font name.
|
||||||
|
if (isString(fontName))
|
||||||
|
fontName = new Name(fontName);
|
||||||
assertWellFormed(isName(fontName), 'invalid font name');
|
assertWellFormed(isName(fontName), 'invalid font name');
|
||||||
|
|
||||||
var fontFile = descriptor.get('FontFile', 'FontFile2', 'FontFile3');
|
var fontFile = descriptor.get('FontFile', 'FontFile2', 'FontFile3');
|
||||||
if (fontFile) {
|
if (fontFile) {
|
||||||
fontFile = xref.fetchIfRef(fontFile);
|
|
||||||
if (fontFile.dict) {
|
if (fontFile.dict) {
|
||||||
var subtype = fontFile.dict.get('Subtype');
|
var subtype = fontFile.dict.get('Subtype');
|
||||||
if (subtype)
|
if (subtype)
|
||||||
subtype = subtype.name;
|
subtype = subtype.name;
|
||||||
|
|
||||||
var length1 = fontFile.dict.get('Length1');
|
var length1 = fontFile.dict.get('Length1');
|
||||||
if (!isInt(length1))
|
|
||||||
length1 = xref.fetchIfRef(length1);
|
|
||||||
|
|
||||||
var length2 = fontFile.dict.get('Length2');
|
var length2 = fontFile.dict.get('Length2');
|
||||||
if (!isInt(length2))
|
|
||||||
length2 = xref.fetchIfRef(length2);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -808,15 +860,14 @@ var PartialEvaluator = (function partialEvaluator() {
|
||||||
|
|
||||||
if (type.name === 'Type3') {
|
if (type.name === 'Type3') {
|
||||||
properties.coded = true;
|
properties.coded = true;
|
||||||
var charProcs = xref.fetchIfRef(dict.get('CharProcs'));
|
var charProcs = dict.get('CharProcs').getAll();
|
||||||
var fontResources = xref.fetchIfRef(dict.get('Resources')) || resources;
|
var fontResources = dict.get('Resources') || resources;
|
||||||
properties.resources = fontResources;
|
properties.resources = fontResources;
|
||||||
properties.charProcIRQueues = {};
|
properties.charProcOperatorList = {};
|
||||||
for (var key in charProcs.map) {
|
for (var key in charProcs) {
|
||||||
var glyphStream = xref.fetchIfRef(charProcs.map[key]);
|
var glyphStream = charProcs[key];
|
||||||
var queueObj = {};
|
properties.charProcOperatorList[key] =
|
||||||
properties.charProcIRQueues[key] =
|
this.getOperatorList(glyphStream, fontResources, dependency);
|
||||||
this.getIRQueue(glyphStream, fontResources, queueObj, dependency);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -829,11 +880,11 @@ var PartialEvaluator = (function partialEvaluator() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return constructor;
|
return PartialEvaluator;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
var EvalState = (function evalState() {
|
var EvalState = (function EvalStateClosure() {
|
||||||
function constructor() {
|
function EvalState() {
|
||||||
// Are soft masks and alpha values shapes or opacities?
|
// Are soft masks and alpha values shapes or opacities?
|
||||||
this.alphaIsShape = false;
|
this.alphaIsShape = false;
|
||||||
this.fontSize = 0;
|
this.fontSize = 0;
|
||||||
|
@ -850,8 +901,8 @@ var EvalState = (function evalState() {
|
||||||
this.fillColorSpace = null;
|
this.fillColorSpace = null;
|
||||||
this.strokeColorSpace = null;
|
this.strokeColorSpace = null;
|
||||||
}
|
}
|
||||||
constructor.prototype = {
|
EvalState.prototype = {
|
||||||
};
|
};
|
||||||
return constructor;
|
return EvalState;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
|
|
@ -3,14 +3,14 @@
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var PDFFunction = (function pdfFunction() {
|
var PDFFunction = (function PDFFunctionClosure() {
|
||||||
var CONSTRUCT_SAMPLED = 0;
|
var CONSTRUCT_SAMPLED = 0;
|
||||||
var CONSTRUCT_INTERPOLATED = 2;
|
var CONSTRUCT_INTERPOLATED = 2;
|
||||||
var CONSTRUCT_STICHED = 3;
|
var CONSTRUCT_STICHED = 3;
|
||||||
var CONSTRUCT_POSTSCRIPT = 4;
|
var CONSTRUCT_POSTSCRIPT = 4;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
getSampleArray: function pdfFunctionGetSampleArray(size, outputSize, bps,
|
getSampleArray: function PDFFunction_getSampleArray(size, outputSize, bps,
|
||||||
str) {
|
str) {
|
||||||
var length = 1;
|
var length = 1;
|
||||||
for (var i = 0, ii = size.length; i < ii; i++)
|
for (var i = 0, ii = size.length; i < ii; i++)
|
||||||
|
@ -38,7 +38,7 @@ var PDFFunction = (function pdfFunction() {
|
||||||
return array;
|
return array;
|
||||||
},
|
},
|
||||||
|
|
||||||
getIR: function pdfFunctionGetIR(xref, fn) {
|
getIR: function PDFFunction_getIR(xref, fn) {
|
||||||
var dict = fn.dict;
|
var dict = fn.dict;
|
||||||
if (!dict)
|
if (!dict)
|
||||||
dict = fn;
|
dict = fn;
|
||||||
|
@ -57,7 +57,7 @@ var PDFFunction = (function pdfFunction() {
|
||||||
return typeFn.call(this, fn, dict, xref);
|
return typeFn.call(this, fn, dict, xref);
|
||||||
},
|
},
|
||||||
|
|
||||||
fromIR: function pdfFunctionFromIR(IR) {
|
fromIR: function PDFFunction_fromIR(IR) {
|
||||||
var type = IR[0];
|
var type = IR[0];
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case CONSTRUCT_SAMPLED:
|
case CONSTRUCT_SAMPLED:
|
||||||
|
@ -72,16 +72,16 @@ var PDFFunction = (function pdfFunction() {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
parse: function pdfFunctionParse(xref, fn) {
|
parse: function PDFFunction_parse(xref, fn) {
|
||||||
var IR = this.getIR(xref, fn);
|
var IR = this.getIR(xref, fn);
|
||||||
return this.fromIR(IR);
|
return this.fromIR(IR);
|
||||||
},
|
},
|
||||||
|
|
||||||
constructSampled: function pdfFunctionConstructSampled(str, dict) {
|
constructSampled: function PDFFunction_constructSampled(str, dict) {
|
||||||
function toMultiArray(arr) {
|
function toMultiArray(arr) {
|
||||||
var inputLength = arr.length;
|
var inputLength = arr.length;
|
||||||
var outputLength = arr.length / 2;
|
var outputLength = arr.length / 2;
|
||||||
var out = new Array(outputLength);
|
var out = [];
|
||||||
var index = 0;
|
var index = 0;
|
||||||
for (var i = 0; i < inputLength; i += 2) {
|
for (var i = 0; i < inputLength; i += 2) {
|
||||||
out[index] = [arr[i], arr[i + 1]];
|
out[index] = [arr[i], arr[i + 1]];
|
||||||
|
@ -125,114 +125,104 @@ var PDFFunction = (function pdfFunction() {
|
||||||
else
|
else
|
||||||
decode = toMultiArray(decode);
|
decode = toMultiArray(decode);
|
||||||
|
|
||||||
// Precalc the multipliers
|
|
||||||
var inputMul = new Float64Array(inputSize);
|
|
||||||
for (var i = 0; i < inputSize; ++i) {
|
|
||||||
inputMul[i] = (encode[i][1] - encode[i][0]) /
|
|
||||||
(domain[i][1] - domain[i][0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
var idxMul = new Int32Array(inputSize);
|
|
||||||
idxMul[0] = outputSize;
|
|
||||||
for (i = 1; i < inputSize; ++i) {
|
|
||||||
idxMul[i] = idxMul[i - 1] * size[i - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
var nSamples = outputSize;
|
|
||||||
for (i = 0; i < inputSize; ++i)
|
|
||||||
nSamples *= size[i];
|
|
||||||
|
|
||||||
var samples = this.getSampleArray(size, outputSize, bps, str);
|
var samples = this.getSampleArray(size, outputSize, bps, str);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
CONSTRUCT_SAMPLED, inputSize, domain, encode, decode, samples, size,
|
CONSTRUCT_SAMPLED, inputSize, domain, encode, decode, samples, size,
|
||||||
outputSize, bps, range, inputMul, idxMul, nSamples
|
outputSize, Math.pow(2, bps) - 1, range
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
|
|
||||||
constructSampledFromIR: function pdfFunctionConstructSampledFromIR(IR) {
|
constructSampledFromIR: function PDFFunction_constructSampledFromIR(IR) {
|
||||||
var inputSize = IR[1];
|
// See chapter 3, page 109 of the PDF reference
|
||||||
|
function interpolate(x, xmin, xmax, ymin, ymax) {
|
||||||
|
return ymin + ((x - xmin) * ((ymax - ymin) / (xmax - xmin)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return function constructSampledFromIRResult(args) {
|
||||||
|
// See chapter 3, page 110 of the PDF reference.
|
||||||
|
var m = IR[1];
|
||||||
var domain = IR[2];
|
var domain = IR[2];
|
||||||
var encode = IR[3];
|
var encode = IR[3];
|
||||||
var decode = IR[4];
|
var decode = IR[4];
|
||||||
var samples = IR[5];
|
var samples = IR[5];
|
||||||
var size = IR[6];
|
var size = IR[6];
|
||||||
var outputSize = IR[7];
|
var n = IR[7];
|
||||||
var bps = IR[8];
|
var mask = IR[8];
|
||||||
var range = IR[9];
|
var range = IR[9];
|
||||||
var inputMul = IR[10];
|
|
||||||
var idxMul = IR[11];
|
|
||||||
var nSamples = IR[12];
|
|
||||||
|
|
||||||
return function constructSampledFromIRResult(args) {
|
if (m != args.length)
|
||||||
if (inputSize != args.length)
|
|
||||||
error('Incorrect number of arguments: ' + inputSize + ' != ' +
|
error('Incorrect number of arguments: ' + inputSize + ' != ' +
|
||||||
args.length);
|
args.length);
|
||||||
// Most of the below is a port of Poppler's implementation.
|
|
||||||
// TODO: There's a few other ways to do multilinear interpolation such
|
|
||||||
// as piecewise, which is much faster but an approximation.
|
|
||||||
var out = new Float64Array(outputSize);
|
|
||||||
var x;
|
|
||||||
var e = new Array(inputSize);
|
|
||||||
var efrac0 = new Float64Array(inputSize);
|
|
||||||
var efrac1 = new Float64Array(inputSize);
|
|
||||||
var sBuf = new Float64Array(1 << inputSize);
|
|
||||||
var i, j, k, idx, t;
|
|
||||||
|
|
||||||
// map input values into sample array
|
var x = args;
|
||||||
for (i = 0; i < inputSize; ++i) {
|
|
||||||
x = (args[i] - domain[i][0]) * inputMul[i] + encode[i][0];
|
|
||||||
if (x < 0) {
|
|
||||||
x = 0;
|
|
||||||
} else if (x > size[i] - 1) {
|
|
||||||
x = size[i] - 1;
|
|
||||||
}
|
|
||||||
e[i] = [Math.floor(x), 0];
|
|
||||||
if ((e[i][1] = e[i][0] + 1) >= size[i]) {
|
|
||||||
// this happens if in[i] = domain[i][1]
|
|
||||||
e[i][1] = e[i][0];
|
|
||||||
}
|
|
||||||
efrac1[i] = x - e[i][0];
|
|
||||||
efrac0[i] = 1 - efrac1[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
// for each output, do m-linear interpolation
|
// Building the cube vertices: its part and sample index
|
||||||
for (i = 0; i < outputSize; ++i) {
|
// http://rjwagner49.com/Mathematics/Interpolation.pdf
|
||||||
|
var cubeVertices = 1 << m;
|
||||||
|
var cubeN = new Float64Array(cubeVertices);
|
||||||
|
var cubeVertex = new Uint32Array(cubeVertices);
|
||||||
|
for (var j = 0; j < cubeVertices; j++)
|
||||||
|
cubeN[j] = 1;
|
||||||
|
|
||||||
// pull 2^m values out of the sample array
|
var k = n, pos = 1;
|
||||||
for (j = 0; j < (1 << inputSize); ++j) {
|
// Map x_i to y_j for 0 <= i < m using the sampled function.
|
||||||
idx = i;
|
for (var i = 0; i < m; ++i) {
|
||||||
for (k = 0, t = j; k < inputSize; ++k, t >>= 1) {
|
// x_i' = min(max(x_i, Domain_2i), Domain_2i+1)
|
||||||
idx += idxMul[k] * (e[k][t & 1]);
|
var domain_2i = domain[i][0];
|
||||||
}
|
var domain_2i_1 = domain[i][1];
|
||||||
if (idx >= 0 && idx < nSamples) {
|
var xi = Math.min(Math.max(x[i], domain_2i), domain_2i_1);
|
||||||
sBuf[j] = samples[idx];
|
|
||||||
|
// e_i = Interpolate(x_i', Domain_2i, Domain_2i+1,
|
||||||
|
// Encode_2i, Encode_2i+1)
|
||||||
|
var e = interpolate(xi, domain_2i, domain_2i_1,
|
||||||
|
encode[i][0], encode[i][1]);
|
||||||
|
|
||||||
|
// e_i' = min(max(e_i, 0), Size_i - 1)
|
||||||
|
var size_i = size[i];
|
||||||
|
e = Math.min(Math.max(e, 0), size_i - 1);
|
||||||
|
|
||||||
|
// Adjusting the cube: N and vertex sample index
|
||||||
|
var e0 = e < size_i - 1 ? Math.floor(e) : e - 1; // e1 = e0 + 1;
|
||||||
|
var n0 = e0 + 1 - e; // (e1 - e) / (e1 - e0);
|
||||||
|
var n1 = e - e0; // (e - e0) / (e1 - e0);
|
||||||
|
var offset0 = e0 * k;
|
||||||
|
var offset1 = offset0 + k; // e1 * k
|
||||||
|
for (var j = 0; j < cubeVertices; j++) {
|
||||||
|
if (j & pos) {
|
||||||
|
cubeN[j] *= n1;
|
||||||
|
cubeVertex[j] += offset1;
|
||||||
} else {
|
} else {
|
||||||
sBuf[j] = 0; // TODO Investigate if this is what Adobe does
|
cubeN[j] *= n0;
|
||||||
|
cubeVertex[j] += offset0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// do m sets of interpolations
|
k *= size_i;
|
||||||
for (j = 0, t = (1 << inputSize); j < inputSize; ++j, t >>= 1) {
|
pos <<= 1;
|
||||||
for (k = 0; k < t; k += 2) {
|
|
||||||
sBuf[k >> 1] = efrac0[j] * sBuf[k] + efrac1[j] * sBuf[k + 1];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// map output value to range
|
var y = new Float64Array(n);
|
||||||
out[i] = (sBuf[0] * (decode[i][1] - decode[i][0]) + decode[i][0]);
|
for (var j = 0; j < n; ++j) {
|
||||||
if (out[i] < range[i][0]) {
|
// Sum all cube vertices' samples portions
|
||||||
out[i] = range[i][0];
|
var rj = 0;
|
||||||
} else if (out[i] > range[i][1]) {
|
for (var i = 0; i < cubeVertices; i++)
|
||||||
out[i] = range[i][1];
|
rj += samples[cubeVertex[i] + j] * cubeN[i];
|
||||||
|
|
||||||
|
// r_j' = Interpolate(r_j, 0, 2^BitsPerSample - 1,
|
||||||
|
// Decode_2j, Decode_2j+1)
|
||||||
|
rj = interpolate(rj, 0, 1, decode[j][0], decode[j][1]);
|
||||||
|
|
||||||
|
// y_j = min(max(r_j, range_2j), range_2j+1)
|
||||||
|
y[j] = Math.min(Math.max(rj, range[j][0]), range[j][1]);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return out;
|
return y;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
constructInterpolated:
|
constructInterpolated: function PDFFunction_constructInterpolated(str,
|
||||||
function pdfFunctionConstructInterpolated(str, dict) {
|
dict) {
|
||||||
var c0 = dict.get('C0') || [0];
|
var c0 = dict.get('C0') || [0];
|
||||||
var c1 = dict.get('C1') || [1];
|
var c1 = dict.get('C1') || [1];
|
||||||
var n = dict.get('N');
|
var n = dict.get('N');
|
||||||
|
@ -249,7 +239,7 @@ var PDFFunction = (function pdfFunction() {
|
||||||
},
|
},
|
||||||
|
|
||||||
constructInterpolatedFromIR:
|
constructInterpolatedFromIR:
|
||||||
function pdfFunctionconstructInterpolatedFromIR(IR) {
|
function PDFFunction_constructInterpolatedFromIR(IR) {
|
||||||
var c0 = IR[1];
|
var c0 = IR[1];
|
||||||
var diff = IR[2];
|
var diff = IR[2];
|
||||||
var n = IR[3];
|
var n = IR[3];
|
||||||
|
@ -268,9 +258,8 @@ var PDFFunction = (function pdfFunction() {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
constructStiched: function pdfFunctionConstructStiched(fn, dict, xref) {
|
constructStiched: function PDFFunction_constructStiched(fn, dict, xref) {
|
||||||
var domain = dict.get('Domain');
|
var domain = dict.get('Domain');
|
||||||
var range = dict.get('Range');
|
|
||||||
|
|
||||||
if (!domain)
|
if (!domain)
|
||||||
error('No domain');
|
error('No domain');
|
||||||
|
@ -290,7 +279,7 @@ var PDFFunction = (function pdfFunction() {
|
||||||
return [CONSTRUCT_STICHED, domain, bounds, encode, fns];
|
return [CONSTRUCT_STICHED, domain, bounds, encode, fns];
|
||||||
},
|
},
|
||||||
|
|
||||||
constructStichedFromIR: function pdfFunctionConstructStichedFromIR(IR) {
|
constructStichedFromIR: function PDFFunction_constructStichedFromIR(IR) {
|
||||||
var domain = IR[1];
|
var domain = IR[1];
|
||||||
var bounds = IR[2];
|
var bounds = IR[2];
|
||||||
var encode = IR[3];
|
var encode = IR[3];
|
||||||
|
@ -336,16 +325,550 @@ var PDFFunction = (function pdfFunction() {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
constructPostScript: function pdfFunctionConstructPostScript() {
|
constructPostScript: function PDFFunction_constructPostScript(fn, dict,
|
||||||
return [CONSTRUCT_POSTSCRIPT];
|
xref) {
|
||||||
|
var domain = dict.get('Domain');
|
||||||
|
var range = dict.get('Range');
|
||||||
|
|
||||||
|
if (!domain)
|
||||||
|
error('No domain.');
|
||||||
|
|
||||||
|
if (!range)
|
||||||
|
error('No range.');
|
||||||
|
|
||||||
|
var lexer = new PostScriptLexer(fn);
|
||||||
|
var parser = new PostScriptParser(lexer);
|
||||||
|
var code = parser.parse();
|
||||||
|
|
||||||
|
return [CONSTRUCT_POSTSCRIPT, domain, range, code];
|
||||||
},
|
},
|
||||||
|
|
||||||
constructPostScriptFromIR: function pdfFunctionConstructPostScriptFromIR() {
|
constructPostScriptFromIR: function PDFFunction_constructPostScriptFromIR(
|
||||||
TODO('unhandled type of function');
|
IR) {
|
||||||
return function constructPostScriptFromIRResult() {
|
var domain = IR[1];
|
||||||
return [255, 105, 180];
|
var range = IR[2];
|
||||||
|
var code = IR[3];
|
||||||
|
var numOutputs = range.length / 2;
|
||||||
|
var evaluator = new PostScriptEvaluator(code);
|
||||||
|
// Cache the values for a big speed up, the cache size is limited though
|
||||||
|
// since the number of possible values can be huge from a PS function.
|
||||||
|
var cache = new FunctionCache();
|
||||||
|
return function constructPostScriptFromIRResult(args) {
|
||||||
|
var initialStack = [];
|
||||||
|
for (var i = 0, ii = (domain.length / 2); i < ii; ++i) {
|
||||||
|
initialStack.push(args[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
var key = initialStack.join('_');
|
||||||
|
if (cache.has(key))
|
||||||
|
return cache.get(key);
|
||||||
|
|
||||||
|
var stack = evaluator.execute(initialStack);
|
||||||
|
var transformed = [];
|
||||||
|
for (i = numOutputs - 1; i >= 0; --i) {
|
||||||
|
var out = stack.pop();
|
||||||
|
var rangeIndex = 2 * i;
|
||||||
|
if (out < range[rangeIndex])
|
||||||
|
out = range[rangeIndex];
|
||||||
|
else if (out > range[rangeIndex + 1])
|
||||||
|
out = range[rangeIndex + 1];
|
||||||
|
transformed[i] = out;
|
||||||
|
}
|
||||||
|
cache.set(key, transformed);
|
||||||
|
return transformed;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
var FunctionCache = (function FunctionCacheClosure() {
|
||||||
|
// Of 10 PDF's with type4 functions the maxium number of distinct values seen
|
||||||
|
// was 256. This still may need some tweaking in the future though.
|
||||||
|
var MAX_CACHE_SIZE = 1024;
|
||||||
|
function FunctionCache() {
|
||||||
|
this.cache = {};
|
||||||
|
this.total = 0;
|
||||||
|
}
|
||||||
|
FunctionCache.prototype = {
|
||||||
|
has: function FunctionCache_has(key) {
|
||||||
|
return key in this.cache;
|
||||||
|
},
|
||||||
|
get: function FunctionCache_get(key) {
|
||||||
|
return this.cache[key];
|
||||||
|
},
|
||||||
|
set: function FunctionCache_set(key, value) {
|
||||||
|
if (this.total < MAX_CACHE_SIZE) {
|
||||||
|
this.cache[key] = value;
|
||||||
|
this.total++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return FunctionCache;
|
||||||
|
})();
|
||||||
|
|
||||||
|
var PostScriptStack = (function PostScriptStackClosure() {
|
||||||
|
var MAX_STACK_SIZE = 100;
|
||||||
|
function PostScriptStack(initialStack) {
|
||||||
|
this.stack = initialStack || [];
|
||||||
|
}
|
||||||
|
|
||||||
|
PostScriptStack.prototype = {
|
||||||
|
push: function PostScriptStack_push(value) {
|
||||||
|
if (this.stack.length >= MAX_STACK_SIZE)
|
||||||
|
error('PostScript function stack overflow.');
|
||||||
|
this.stack.push(value);
|
||||||
|
},
|
||||||
|
pop: function PostScriptStack_pop() {
|
||||||
|
if (this.stack.length <= 0)
|
||||||
|
error('PostScript function stack underflow.');
|
||||||
|
return this.stack.pop();
|
||||||
|
},
|
||||||
|
copy: function PostScriptStack_copy(n) {
|
||||||
|
if (this.stack.length + n >= MAX_STACK_SIZE)
|
||||||
|
error('PostScript function stack overflow.');
|
||||||
|
var stack = this.stack;
|
||||||
|
for (var i = stack.length - n, j = n - 1; j >= 0; j--, i++)
|
||||||
|
stack.push(stack[i]);
|
||||||
|
},
|
||||||
|
index: function PostScriptStack_index(n) {
|
||||||
|
this.push(this.stack[this.stack.length - n - 1]);
|
||||||
|
},
|
||||||
|
// rotate the last n stack elements p times
|
||||||
|
roll: function PostScriptStack_roll(n, p) {
|
||||||
|
var stack = this.stack;
|
||||||
|
var l = stack.length - n;
|
||||||
|
var r = stack.length - 1, c = l + (p - Math.floor(p / n) * n), i, j, t;
|
||||||
|
for (i = l, j = r; i < j; i++, j--) {
|
||||||
|
t = stack[i]; stack[i] = stack[j]; stack[j] = t;
|
||||||
|
}
|
||||||
|
for (i = l, j = c - 1; i < j; i++, j--) {
|
||||||
|
t = stack[i]; stack[i] = stack[j]; stack[j] = t;
|
||||||
|
}
|
||||||
|
for (i = c, j = r; i < j; i++, j--) {
|
||||||
|
t = stack[i]; stack[i] = stack[j]; stack[j] = t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return PostScriptStack;
|
||||||
|
})();
|
||||||
|
var PostScriptEvaluator = (function PostScriptEvaluatorClosure() {
|
||||||
|
function PostScriptEvaluator(operators, operands) {
|
||||||
|
this.operators = operators;
|
||||||
|
this.operands = operands;
|
||||||
|
}
|
||||||
|
PostScriptEvaluator.prototype = {
|
||||||
|
execute: function PostScriptEvaluator_execute(initialStack) {
|
||||||
|
var stack = new PostScriptStack(initialStack);
|
||||||
|
var counter = 0;
|
||||||
|
var operators = this.operators;
|
||||||
|
var length = operators.length;
|
||||||
|
var operator, a, b;
|
||||||
|
while (counter < length) {
|
||||||
|
operator = operators[counter++];
|
||||||
|
if (typeof operator == 'number') {
|
||||||
|
// Operator is really an operand and should be pushed to the stack.
|
||||||
|
stack.push(operator);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
switch (operator) {
|
||||||
|
// non standard ps operators
|
||||||
|
case 'jz': // jump if false
|
||||||
|
b = stack.pop();
|
||||||
|
a = stack.pop();
|
||||||
|
if (!a)
|
||||||
|
counter = b;
|
||||||
|
break;
|
||||||
|
case 'j': // jump
|
||||||
|
a = stack.pop();
|
||||||
|
counter = a;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// all ps operators in alphabetical order (excluding if/ifelse)
|
||||||
|
case 'abs':
|
||||||
|
a = stack.pop();
|
||||||
|
stack.push(Math.abs(a));
|
||||||
|
break;
|
||||||
|
case 'add':
|
||||||
|
b = stack.pop();
|
||||||
|
a = stack.pop();
|
||||||
|
stack.push(a + b);
|
||||||
|
break;
|
||||||
|
case 'and':
|
||||||
|
b = stack.pop();
|
||||||
|
a = stack.pop();
|
||||||
|
if (isBool(a) && isBool(b))
|
||||||
|
stack.push(a && b);
|
||||||
|
else
|
||||||
|
stack.push(a & b);
|
||||||
|
break;
|
||||||
|
case 'atan':
|
||||||
|
a = stack.pop();
|
||||||
|
stack.push(Math.atan(a));
|
||||||
|
break;
|
||||||
|
case 'bitshift':
|
||||||
|
b = stack.pop();
|
||||||
|
a = stack.pop();
|
||||||
|
if (a > 0)
|
||||||
|
stack.push(a << b);
|
||||||
|
else
|
||||||
|
stack.push(a >> b);
|
||||||
|
break;
|
||||||
|
case 'ceiling':
|
||||||
|
a = stack.pop();
|
||||||
|
stack.push(Math.ceil(a));
|
||||||
|
break;
|
||||||
|
case 'copy':
|
||||||
|
a = stack.pop();
|
||||||
|
stack.copy(a);
|
||||||
|
break;
|
||||||
|
case 'cos':
|
||||||
|
a = stack.pop();
|
||||||
|
stack.push(Math.cos(a));
|
||||||
|
break;
|
||||||
|
case 'cvi':
|
||||||
|
a = stack.pop() | 0;
|
||||||
|
stack.push(a);
|
||||||
|
break;
|
||||||
|
case 'cvr':
|
||||||
|
// noop
|
||||||
|
break;
|
||||||
|
case 'div':
|
||||||
|
b = stack.pop();
|
||||||
|
a = stack.pop();
|
||||||
|
stack.push(a / b);
|
||||||
|
break;
|
||||||
|
case 'dup':
|
||||||
|
stack.copy(1);
|
||||||
|
break;
|
||||||
|
case 'eq':
|
||||||
|
b = stack.pop();
|
||||||
|
a = stack.pop();
|
||||||
|
stack.push(a == b);
|
||||||
|
break;
|
||||||
|
case 'exch':
|
||||||
|
stack.roll(2, 1);
|
||||||
|
break;
|
||||||
|
case 'exp':
|
||||||
|
b = stack.pop();
|
||||||
|
a = stack.pop();
|
||||||
|
stack.push(Math.pow(a, b));
|
||||||
|
break;
|
||||||
|
case 'false':
|
||||||
|
stack.push(false);
|
||||||
|
break;
|
||||||
|
case 'floor':
|
||||||
|
a = stack.pop();
|
||||||
|
stack.push(Math.floor(a));
|
||||||
|
break;
|
||||||
|
case 'ge':
|
||||||
|
b = stack.pop();
|
||||||
|
a = stack.pop();
|
||||||
|
stack.push(a >= b);
|
||||||
|
break;
|
||||||
|
case 'gt':
|
||||||
|
b = stack.pop();
|
||||||
|
a = stack.pop();
|
||||||
|
stack.push(a > b);
|
||||||
|
break;
|
||||||
|
case 'idiv':
|
||||||
|
b = stack.pop();
|
||||||
|
a = stack.pop();
|
||||||
|
stack.push((a / b) | 0);
|
||||||
|
break;
|
||||||
|
case 'index':
|
||||||
|
a = stack.pop();
|
||||||
|
stack.index(a);
|
||||||
|
break;
|
||||||
|
case 'le':
|
||||||
|
b = stack.pop();
|
||||||
|
a = stack.pop();
|
||||||
|
stack.push(a <= b);
|
||||||
|
break;
|
||||||
|
case 'ln':
|
||||||
|
a = stack.pop();
|
||||||
|
stack.push(Math.log(a));
|
||||||
|
break;
|
||||||
|
case 'log':
|
||||||
|
a = stack.pop();
|
||||||
|
stack.push(Math.log(a) / Math.LN10);
|
||||||
|
break;
|
||||||
|
case 'lt':
|
||||||
|
b = stack.pop();
|
||||||
|
a = stack.pop();
|
||||||
|
stack.push(a < b);
|
||||||
|
break;
|
||||||
|
case 'mod':
|
||||||
|
b = stack.pop();
|
||||||
|
a = stack.pop();
|
||||||
|
stack.push(a % b);
|
||||||
|
break;
|
||||||
|
case 'mul':
|
||||||
|
b = stack.pop();
|
||||||
|
a = stack.pop();
|
||||||
|
stack.push(a * b);
|
||||||
|
break;
|
||||||
|
case 'ne':
|
||||||
|
b = stack.pop();
|
||||||
|
a = stack.pop();
|
||||||
|
stack.push(a != b);
|
||||||
|
break;
|
||||||
|
case 'neg':
|
||||||
|
a = stack.pop();
|
||||||
|
stack.push(-b);
|
||||||
|
break;
|
||||||
|
case 'not':
|
||||||
|
a = stack.pop();
|
||||||
|
if (isBool(a) && isBool(b))
|
||||||
|
stack.push(a && b);
|
||||||
|
else
|
||||||
|
stack.push(a & b);
|
||||||
|
break;
|
||||||
|
case 'or':
|
||||||
|
b = stack.pop();
|
||||||
|
a = stack.pop();
|
||||||
|
if (isBool(a) && isBool(b))
|
||||||
|
stack.push(a || b);
|
||||||
|
else
|
||||||
|
stack.push(a | b);
|
||||||
|
break;
|
||||||
|
case 'pop':
|
||||||
|
stack.pop();
|
||||||
|
break;
|
||||||
|
case 'roll':
|
||||||
|
b = stack.pop();
|
||||||
|
a = stack.pop();
|
||||||
|
stack.roll(a, b);
|
||||||
|
break;
|
||||||
|
case 'round':
|
||||||
|
a = stack.pop();
|
||||||
|
stack.push(Math.round(a));
|
||||||
|
break;
|
||||||
|
case 'sin':
|
||||||
|
a = stack.pop();
|
||||||
|
stack.push(Math.sin(a));
|
||||||
|
break;
|
||||||
|
case 'sqrt':
|
||||||
|
a = stack.pop();
|
||||||
|
stack.push(Math.sqrt(a));
|
||||||
|
break;
|
||||||
|
case 'sub':
|
||||||
|
b = stack.pop();
|
||||||
|
a = stack.pop();
|
||||||
|
stack.push(a - b);
|
||||||
|
break;
|
||||||
|
case 'true':
|
||||||
|
stack.push(true);
|
||||||
|
break;
|
||||||
|
case 'truncate':
|
||||||
|
a = stack.pop();
|
||||||
|
a = a < 0 ? Math.ceil(a) : Math.floor(a);
|
||||||
|
stack.push(a);
|
||||||
|
break;
|
||||||
|
case 'xor':
|
||||||
|
b = stack.pop();
|
||||||
|
a = stack.pop();
|
||||||
|
if (isBool(a) && isBool(b))
|
||||||
|
stack.push(a != b);
|
||||||
|
else
|
||||||
|
stack.push(a ^ b);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error('Unknown operator ' + operator);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return stack.stack;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return PostScriptEvaluator;
|
||||||
|
})();
|
||||||
|
|
||||||
|
var PostScriptParser = (function PostScriptParserClosure() {
|
||||||
|
function PostScriptParser(lexer) {
|
||||||
|
this.lexer = lexer;
|
||||||
|
this.operators = [];
|
||||||
|
this.token;
|
||||||
|
this.prev;
|
||||||
|
}
|
||||||
|
PostScriptParser.prototype = {
|
||||||
|
nextToken: function PostScriptParser_nextToken() {
|
||||||
|
this.prev = this.token;
|
||||||
|
this.token = this.lexer.getToken();
|
||||||
|
},
|
||||||
|
accept: function PostScriptParser_accept(type) {
|
||||||
|
if (this.token.type == type) {
|
||||||
|
this.nextToken();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
expect: function PostScriptParser_expect(type) {
|
||||||
|
if (this.accept(type))
|
||||||
|
return true;
|
||||||
|
error('Unexpected symbol: found ' + this.token.type + ' expected ' +
|
||||||
|
type + '.');
|
||||||
|
},
|
||||||
|
parse: function PostScriptParser_parse() {
|
||||||
|
this.nextToken();
|
||||||
|
this.expect(PostScriptTokenTypes.LBRACE);
|
||||||
|
this.parseBlock();
|
||||||
|
this.expect(PostScriptTokenTypes.RBRACE);
|
||||||
|
return this.operators;
|
||||||
|
},
|
||||||
|
parseBlock: function PostScriptParser_parseBlock() {
|
||||||
|
while (true) {
|
||||||
|
if (this.accept(PostScriptTokenTypes.NUMBER)) {
|
||||||
|
this.operators.push(this.prev.value);
|
||||||
|
} else if (this.accept(PostScriptTokenTypes.OPERATOR)) {
|
||||||
|
this.operators.push(this.prev.value);
|
||||||
|
} else if (this.accept(PostScriptTokenTypes.LBRACE)) {
|
||||||
|
this.parseCondition();
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
parseCondition: function PostScriptParser_parseCondition() {
|
||||||
|
// Add two place holders that will be updated later
|
||||||
|
var conditionLocation = this.operators.length;
|
||||||
|
this.operators.push(null, null);
|
||||||
|
|
||||||
|
this.parseBlock();
|
||||||
|
this.expect(PostScriptTokenTypes.RBRACE);
|
||||||
|
if (this.accept(PostScriptTokenTypes.IF)) {
|
||||||
|
// The true block is right after the 'if' so it just falls through on
|
||||||
|
// true else it jumps and skips the true block.
|
||||||
|
this.operators[conditionLocation] = this.operators.length;
|
||||||
|
this.operators[conditionLocation + 1] = 'jz';
|
||||||
|
} else if (this.accept(PostScriptTokenTypes.LBRACE)) {
|
||||||
|
var jumpLocation = this.operators.length;
|
||||||
|
this.operators.push(null, null);
|
||||||
|
var endOfTrue = this.operators.length;
|
||||||
|
this.parseBlock();
|
||||||
|
this.expect(PostScriptTokenTypes.RBRACE);
|
||||||
|
this.expect(PostScriptTokenTypes.IFELSE);
|
||||||
|
// The jump is added at the end of the true block to skip the false
|
||||||
|
// block.
|
||||||
|
this.operators[jumpLocation] = this.operators.length;
|
||||||
|
this.operators[jumpLocation + 1] = 'j';
|
||||||
|
|
||||||
|
this.operators[conditionLocation] = endOfTrue;
|
||||||
|
this.operators[conditionLocation + 1] = 'jz';
|
||||||
|
} else {
|
||||||
|
error('PS Function: error parsing conditional.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return PostScriptParser;
|
||||||
|
})();
|
||||||
|
|
||||||
|
var PostScriptTokenTypes = {
|
||||||
|
LBRACE: 0,
|
||||||
|
RBRACE: 1,
|
||||||
|
NUMBER: 2,
|
||||||
|
OPERATOR: 3,
|
||||||
|
IF: 4,
|
||||||
|
IFELSE: 5
|
||||||
|
};
|
||||||
|
|
||||||
|
var PostScriptToken = (function PostScriptTokenClosure() {
|
||||||
|
function PostScriptToken(type, value) {
|
||||||
|
this.type = type;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
var opCache = {};
|
||||||
|
|
||||||
|
PostScriptToken.getOperator = function PostScriptToken_getOperator(op) {
|
||||||
|
var opValue = opCache[op];
|
||||||
|
if (opValue)
|
||||||
|
return opValue;
|
||||||
|
|
||||||
|
return opCache[op] = new PostScriptToken(PostScriptTokenTypes.OPERATOR, op);
|
||||||
|
};
|
||||||
|
|
||||||
|
PostScriptToken.LBRACE = new PostScriptToken(PostScriptTokenTypes.LBRACE,
|
||||||
|
'{');
|
||||||
|
PostScriptToken.RBRACE = new PostScriptToken(PostScriptTokenTypes.RBRACE,
|
||||||
|
'}');
|
||||||
|
PostScriptToken.IF = new PostScriptToken(PostScriptTokenTypes.IF, 'IF');
|
||||||
|
PostScriptToken.IFELSE = new PostScriptToken(PostScriptTokenTypes.IFELSE,
|
||||||
|
'IFELSE');
|
||||||
|
return PostScriptToken;
|
||||||
|
})();
|
||||||
|
|
||||||
|
var PostScriptLexer = (function PostScriptLexerClosure() {
|
||||||
|
function PostScriptLexer(stream) {
|
||||||
|
this.stream = stream;
|
||||||
|
}
|
||||||
|
PostScriptLexer.prototype = {
|
||||||
|
getToken: function PostScriptLexer_getToken() {
|
||||||
|
var s = '';
|
||||||
|
var ch;
|
||||||
|
var comment = false;
|
||||||
|
var stream = this.stream;
|
||||||
|
|
||||||
|
// skip comments
|
||||||
|
while (true) {
|
||||||
|
if (!(ch = stream.getChar()))
|
||||||
|
return EOF;
|
||||||
|
|
||||||
|
if (comment) {
|
||||||
|
if (ch == '\x0a' || ch == '\x0d')
|
||||||
|
comment = false;
|
||||||
|
} else if (ch == '%') {
|
||||||
|
comment = true;
|
||||||
|
} else if (!Lexer.isSpace(ch)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch (ch) {
|
||||||
|
case '0': case '1': case '2': case '3': case '4':
|
||||||
|
case '5': case '6': case '7': case '8': case '9':
|
||||||
|
case '+': case '-': case '.':
|
||||||
|
return new PostScriptToken(PostScriptTokenTypes.NUMBER,
|
||||||
|
this.getNumber(ch));
|
||||||
|
case '{':
|
||||||
|
return PostScriptToken.LBRACE;
|
||||||
|
case '}':
|
||||||
|
return PostScriptToken.RBRACE;
|
||||||
|
}
|
||||||
|
// operator
|
||||||
|
var str = ch.toLowerCase();
|
||||||
|
while (true) {
|
||||||
|
ch = stream.lookChar().toLowerCase();
|
||||||
|
if (ch >= 'a' && ch <= 'z')
|
||||||
|
str += ch;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
stream.skip();
|
||||||
|
}
|
||||||
|
switch (str) {
|
||||||
|
case 'if':
|
||||||
|
return PostScriptToken.IF;
|
||||||
|
case 'ifelse':
|
||||||
|
return PostScriptToken.IFELSE;
|
||||||
|
default:
|
||||||
|
return PostScriptToken.getOperator(str);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getNumber: function PostScriptLexer_getNumber(ch) {
|
||||||
|
var str = ch;
|
||||||
|
var stream = this.stream;
|
||||||
|
while (true) {
|
||||||
|
ch = stream.lookChar();
|
||||||
|
if ((ch >= '0' && ch <= '9') || ch == '-' || ch == '.')
|
||||||
|
str += ch;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
stream.skip();
|
||||||
|
}
|
||||||
|
var value = parseFloat(str);
|
||||||
|
if (isNaN(value))
|
||||||
|
error('Invalid floating point number: ' + value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return PostScriptLexer;
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
|
@ -1508,27 +1508,7 @@ var GlyphsUnicode = {
|
||||||
dalet: 0x05D3,
|
dalet: 0x05D3,
|
||||||
daletdagesh: 0xFB33,
|
daletdagesh: 0xFB33,
|
||||||
daletdageshhebrew: 0xFB33,
|
daletdageshhebrew: 0xFB33,
|
||||||
dalethatafpatah: 0x05D305B2,
|
|
||||||
dalethatafpatahhebrew: 0x05D305B2,
|
|
||||||
dalethatafsegol: 0x05D305B1,
|
|
||||||
dalethatafsegolhebrew: 0x05D305B1,
|
|
||||||
dalethebrew: 0x05D3,
|
dalethebrew: 0x05D3,
|
||||||
dalethiriq: 0x05D305B4,
|
|
||||||
dalethiriqhebrew: 0x05D305B4,
|
|
||||||
daletholam: 0x05D305B9,
|
|
||||||
daletholamhebrew: 0x05D305B9,
|
|
||||||
daletpatah: 0x05D305B7,
|
|
||||||
daletpatahhebrew: 0x05D305B7,
|
|
||||||
daletqamats: 0x05D305B8,
|
|
||||||
daletqamatshebrew: 0x05D305B8,
|
|
||||||
daletqubuts: 0x05D305BB,
|
|
||||||
daletqubutshebrew: 0x05D305BB,
|
|
||||||
daletsegol: 0x05D305B6,
|
|
||||||
daletsegolhebrew: 0x05D305B6,
|
|
||||||
daletsheva: 0x05D305B0,
|
|
||||||
daletshevahebrew: 0x05D305B0,
|
|
||||||
dalettsere: 0x05D305B5,
|
|
||||||
dalettserehebrew: 0x05D305B5,
|
|
||||||
dalfinalarabic: 0xFEAA,
|
dalfinalarabic: 0xFEAA,
|
||||||
dammaarabic: 0x064F,
|
dammaarabic: 0x064F,
|
||||||
dammalowarabic: 0x064F,
|
dammalowarabic: 0x064F,
|
||||||
|
@ -1845,10 +1825,6 @@ var GlyphsUnicode = {
|
||||||
finalkafdagesh: 0xFB3A,
|
finalkafdagesh: 0xFB3A,
|
||||||
finalkafdageshhebrew: 0xFB3A,
|
finalkafdageshhebrew: 0xFB3A,
|
||||||
finalkafhebrew: 0x05DA,
|
finalkafhebrew: 0x05DA,
|
||||||
finalkafqamats: 0x05DA05B8,
|
|
||||||
finalkafqamatshebrew: 0x05DA05B8,
|
|
||||||
finalkafsheva: 0x05DA05B0,
|
|
||||||
finalkafshevahebrew: 0x05DA05B0,
|
|
||||||
finalmem: 0x05DD,
|
finalmem: 0x05DD,
|
||||||
finalmemhebrew: 0x05DD,
|
finalmemhebrew: 0x05DD,
|
||||||
finalnun: 0x05DF,
|
finalnun: 0x05DF,
|
||||||
|
@ -2037,14 +2013,7 @@ var GlyphsUnicode = {
|
||||||
hakatakanahalfwidth: 0xFF8A,
|
hakatakanahalfwidth: 0xFF8A,
|
||||||
halantgurmukhi: 0x0A4D,
|
halantgurmukhi: 0x0A4D,
|
||||||
hamzaarabic: 0x0621,
|
hamzaarabic: 0x0621,
|
||||||
hamzadammaarabic: 0x0621064F,
|
|
||||||
hamzadammatanarabic: 0x0621064C,
|
|
||||||
hamzafathaarabic: 0x0621064E,
|
|
||||||
hamzafathatanarabic: 0x0621064B,
|
|
||||||
hamzalowarabic: 0x0621,
|
hamzalowarabic: 0x0621,
|
||||||
hamzalowkasraarabic: 0x06210650,
|
|
||||||
hamzalowkasratanarabic: 0x0621064D,
|
|
||||||
hamzasukunarabic: 0x06210652,
|
|
||||||
hangulfiller: 0x3164,
|
hangulfiller: 0x3164,
|
||||||
hardsigncyrillic: 0x044A,
|
hardsigncyrillic: 0x044A,
|
||||||
harpoonleftbarbup: 0x21BC,
|
harpoonleftbarbup: 0x21BC,
|
||||||
|
@ -2476,10 +2445,6 @@ var GlyphsUnicode = {
|
||||||
lameddagesh: 0xFB3C,
|
lameddagesh: 0xFB3C,
|
||||||
lameddageshhebrew: 0xFB3C,
|
lameddageshhebrew: 0xFB3C,
|
||||||
lamedhebrew: 0x05DC,
|
lamedhebrew: 0x05DC,
|
||||||
lamedholam: 0x05DC05B9,
|
|
||||||
lamedholamdagesh: '05DC 05B9 05BC',
|
|
||||||
lamedholamdageshhebrew: '05DC 05B9 05BC',
|
|
||||||
lamedholamhebrew: 0x05DC05B9,
|
|
||||||
lamfinalarabic: 0xFEDE,
|
lamfinalarabic: 0xFEDE,
|
||||||
lamhahinitialarabic: 0xFCCA,
|
lamhahinitialarabic: 0xFCCA,
|
||||||
laminitialarabic: 0xFEDF,
|
laminitialarabic: 0xFEDF,
|
||||||
|
@ -2489,8 +2454,6 @@ var GlyphsUnicode = {
|
||||||
lammedialarabic: 0xFEE0,
|
lammedialarabic: 0xFEE0,
|
||||||
lammeemhahinitialarabic: 0xFD88,
|
lammeemhahinitialarabic: 0xFD88,
|
||||||
lammeeminitialarabic: 0xFCCC,
|
lammeeminitialarabic: 0xFCCC,
|
||||||
lammeemjeeminitialarabic: 'FEDF FEE4 FEA0',
|
|
||||||
lammeemkhahinitialarabic: 'FEDF FEE4 FEA8',
|
|
||||||
largecircle: 0x25EF,
|
largecircle: 0x25EF,
|
||||||
lbar: 0x019A,
|
lbar: 0x019A,
|
||||||
lbelt: 0x026C,
|
lbelt: 0x026C,
|
||||||
|
@ -2787,7 +2750,6 @@ var GlyphsUnicode = {
|
||||||
noonfinalarabic: 0xFEE6,
|
noonfinalarabic: 0xFEE6,
|
||||||
noonghunnaarabic: 0x06BA,
|
noonghunnaarabic: 0x06BA,
|
||||||
noonghunnafinalarabic: 0xFB9F,
|
noonghunnafinalarabic: 0xFB9F,
|
||||||
noonhehinitialarabic: 0xFEE7FEEC,
|
|
||||||
nooninitialarabic: 0xFEE7,
|
nooninitialarabic: 0xFEE7,
|
||||||
noonjeeminitialarabic: 0xFCD2,
|
noonjeeminitialarabic: 0xFCD2,
|
||||||
noonjeemisolatedarabic: 0xFC4B,
|
noonjeemisolatedarabic: 0xFC4B,
|
||||||
|
@ -3159,27 +3121,7 @@ var GlyphsUnicode = {
|
||||||
qof: 0x05E7,
|
qof: 0x05E7,
|
||||||
qofdagesh: 0xFB47,
|
qofdagesh: 0xFB47,
|
||||||
qofdageshhebrew: 0xFB47,
|
qofdageshhebrew: 0xFB47,
|
||||||
qofhatafpatah: 0x05E705B2,
|
|
||||||
qofhatafpatahhebrew: 0x05E705B2,
|
|
||||||
qofhatafsegol: 0x05E705B1,
|
|
||||||
qofhatafsegolhebrew: 0x05E705B1,
|
|
||||||
qofhebrew: 0x05E7,
|
qofhebrew: 0x05E7,
|
||||||
qofhiriq: 0x05E705B4,
|
|
||||||
qofhiriqhebrew: 0x05E705B4,
|
|
||||||
qofholam: 0x05E705B9,
|
|
||||||
qofholamhebrew: 0x05E705B9,
|
|
||||||
qofpatah: 0x05E705B7,
|
|
||||||
qofpatahhebrew: 0x05E705B7,
|
|
||||||
qofqamats: 0x05E705B8,
|
|
||||||
qofqamatshebrew: 0x05E705B8,
|
|
||||||
qofqubuts: 0x05E705BB,
|
|
||||||
qofqubutshebrew: 0x05E705BB,
|
|
||||||
qofsegol: 0x05E705B6,
|
|
||||||
qofsegolhebrew: 0x05E705B6,
|
|
||||||
qofsheva: 0x05E705B0,
|
|
||||||
qofshevahebrew: 0x05E705B0,
|
|
||||||
qoftsere: 0x05E705B5,
|
|
||||||
qoftserehebrew: 0x05E705B5,
|
|
||||||
qparen: 0x24AC,
|
qparen: 0x24AC,
|
||||||
quarternote: 0x2669,
|
quarternote: 0x2669,
|
||||||
qubuts: 0x05BB,
|
qubuts: 0x05BB,
|
||||||
|
@ -3253,32 +3195,11 @@ var GlyphsUnicode = {
|
||||||
reharmenian: 0x0580,
|
reharmenian: 0x0580,
|
||||||
rehfinalarabic: 0xFEAE,
|
rehfinalarabic: 0xFEAE,
|
||||||
rehiragana: 0x308C,
|
rehiragana: 0x308C,
|
||||||
rehyehaleflamarabic: '0631 FEF3 FE8E 0644',
|
|
||||||
rekatakana: 0x30EC,
|
rekatakana: 0x30EC,
|
||||||
rekatakanahalfwidth: 0xFF9A,
|
rekatakanahalfwidth: 0xFF9A,
|
||||||
resh: 0x05E8,
|
resh: 0x05E8,
|
||||||
reshdageshhebrew: 0xFB48,
|
reshdageshhebrew: 0xFB48,
|
||||||
reshhatafpatah: 0x05E805B2,
|
|
||||||
reshhatafpatahhebrew: 0x05E805B2,
|
|
||||||
reshhatafsegol: 0x05E805B1,
|
|
||||||
reshhatafsegolhebrew: 0x05E805B1,
|
|
||||||
reshhebrew: 0x05E8,
|
reshhebrew: 0x05E8,
|
||||||
reshhiriq: 0x05E805B4,
|
|
||||||
reshhiriqhebrew: 0x05E805B4,
|
|
||||||
reshholam: 0x05E805B9,
|
|
||||||
reshholamhebrew: 0x05E805B9,
|
|
||||||
reshpatah: 0x05E805B7,
|
|
||||||
reshpatahhebrew: 0x05E805B7,
|
|
||||||
reshqamats: 0x05E805B8,
|
|
||||||
reshqamatshebrew: 0x05E805B8,
|
|
||||||
reshqubuts: 0x05E805BB,
|
|
||||||
reshqubutshebrew: 0x05E805BB,
|
|
||||||
reshsegol: 0x05E805B6,
|
|
||||||
reshsegolhebrew: 0x05E805B6,
|
|
||||||
reshsheva: 0x05E805B0,
|
|
||||||
reshshevahebrew: 0x05E805B0,
|
|
||||||
reshtsere: 0x05E805B5,
|
|
||||||
reshtserehebrew: 0x05E805B5,
|
|
||||||
reversedtilde: 0x223D,
|
reversedtilde: 0x223D,
|
||||||
reviahebrew: 0x0597,
|
reviahebrew: 0x0597,
|
||||||
reviamugrashhebrew: 0x0597,
|
reviamugrashhebrew: 0x0597,
|
||||||
|
@ -3477,7 +3398,6 @@ var GlyphsUnicode = {
|
||||||
shaddadammaarabic: 0xFC61,
|
shaddadammaarabic: 0xFC61,
|
||||||
shaddadammatanarabic: 0xFC5E,
|
shaddadammatanarabic: 0xFC5E,
|
||||||
shaddafathaarabic: 0xFC60,
|
shaddafathaarabic: 0xFC60,
|
||||||
shaddafathatanarabic: 0x0651064B,
|
|
||||||
shaddakasraarabic: 0xFC62,
|
shaddakasraarabic: 0xFC62,
|
||||||
shaddakasratanarabic: 0xFC5F,
|
shaddakasratanarabic: 0xFC5F,
|
||||||
shade: 0x2592,
|
shade: 0x2592,
|
||||||
|
@ -3674,7 +3594,6 @@ var GlyphsUnicode = {
|
||||||
tchehfinalarabic: 0xFB7B,
|
tchehfinalarabic: 0xFB7B,
|
||||||
tchehinitialarabic: 0xFB7C,
|
tchehinitialarabic: 0xFB7C,
|
||||||
tchehmedialarabic: 0xFB7D,
|
tchehmedialarabic: 0xFB7D,
|
||||||
tchehmeeminitialarabic: 0xFB7CFEE4,
|
|
||||||
tcircle: 0x24E3,
|
tcircle: 0x24E3,
|
||||||
tcircumflexbelow: 0x1E71,
|
tcircumflexbelow: 0x1E71,
|
||||||
tcommaaccent: 0x0163,
|
tcommaaccent: 0x0163,
|
||||||
|
@ -4287,6 +4206,7 @@ var GlyphsUnicode = {
|
||||||
zretroflexhook: 0x0290,
|
zretroflexhook: 0x0290,
|
||||||
zstroke: 0x01B6,
|
zstroke: 0x01B6,
|
||||||
zuhiragana: 0x305A,
|
zuhiragana: 0x305A,
|
||||||
zukatakana: 0x30BA
|
zukatakana: 0x30BA,
|
||||||
|
'.notdef': 0x0000
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,37 @@
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var PDFImage = (function pdfImage() {
|
var PDFImage = (function PDFImageClosure() {
|
||||||
function constructor(xref, res, image, inline) {
|
/**
|
||||||
|
* Decode the image in the main thread if it supported. Resovles the promise
|
||||||
|
* when the image data is ready.
|
||||||
|
*/
|
||||||
|
function handleImageData(handler, xref, res, image, promise) {
|
||||||
|
if (image instanceof JpegStream && image.isNativelyDecodable(xref, res)) {
|
||||||
|
// For natively supported jpegs send them to the main thread for decoding.
|
||||||
|
var dict = image.dict;
|
||||||
|
var colorSpace = dict.get('ColorSpace', 'CS');
|
||||||
|
colorSpace = ColorSpace.parse(colorSpace, xref, res);
|
||||||
|
var numComps = colorSpace.numComps;
|
||||||
|
handler.send('jpeg_decode', [image.getIR(), numComps], function(message) {
|
||||||
|
var data = message.data;
|
||||||
|
var stream = new Stream(data, 0, data.length, image.dict);
|
||||||
|
promise.resolve(stream);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
promise.resolve(image);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Decode and clamp a value. The formula is different from the spec because we
|
||||||
|
* don't decode to float range [0,1], we decode it in the [0,max] range.
|
||||||
|
*/
|
||||||
|
function decodeAndClamp(value, addend, coefficient, max) {
|
||||||
|
value = addend + value * coefficient;
|
||||||
|
// Clamp the value to the range
|
||||||
|
return value < 0 ? 0 : value > max ? max : value;
|
||||||
|
}
|
||||||
|
function PDFImage(xref, res, image, inline, smask) {
|
||||||
this.image = image;
|
this.image = image;
|
||||||
if (image.getParams) {
|
if (image.getParams) {
|
||||||
// JPX/JPEG2000 streams directly contain bits per component
|
// JPX/JPEG2000 streams directly contain bits per component
|
||||||
|
@ -49,34 +78,143 @@ var PDFImage = (function pdfImage() {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.decode = dict.get('Decode', 'D');
|
this.decode = dict.get('Decode', 'D');
|
||||||
|
this.needsDecode = false;
|
||||||
|
if (this.decode && this.colorSpace &&
|
||||||
|
!this.colorSpace.isDefaultDecode(this.decode)) {
|
||||||
|
this.needsDecode = true;
|
||||||
|
// Do some preprocessing to avoid more math.
|
||||||
|
var max = (1 << bitsPerComponent) - 1;
|
||||||
|
this.decodeCoefficients = [];
|
||||||
|
this.decodeAddends = [];
|
||||||
|
for (var i = 0, j = 0; i < this.decode.length; i += 2, ++j) {
|
||||||
|
var dmin = this.decode[i];
|
||||||
|
var dmax = this.decode[i + 1];
|
||||||
|
this.decodeCoefficients[j] = dmax - dmin;
|
||||||
|
this.decodeAddends[j] = max * dmin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var mask = xref.fetchIfRef(dict.get('Mask'));
|
var mask = dict.get('Mask');
|
||||||
var smask = xref.fetchIfRef(dict.get('SMask'));
|
|
||||||
|
|
||||||
if (mask) {
|
if (mask) {
|
||||||
TODO('masked images');
|
TODO('masked images');
|
||||||
} else if (smask) {
|
} else if (smask) {
|
||||||
this.smask = new PDFImage(xref, res, smask);
|
this.smask = new PDFImage(xref, res, smask, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Handles processing of image data and calls the callback with an argument
|
||||||
|
* of a PDFImage when the image is ready to be used.
|
||||||
|
*/
|
||||||
|
PDFImage.buildImage = function PDFImage_buildImage(callback, handler, xref,
|
||||||
|
res, image, inline) {
|
||||||
|
var imageDataPromise = new Promise();
|
||||||
|
var smaskPromise = new Promise();
|
||||||
|
// The image data and smask data may not be ready yet, wait till both are
|
||||||
|
// resolved.
|
||||||
|
Promise.all([imageDataPromise, smaskPromise]).then(function(results) {
|
||||||
|
var imageData = results[0], smaskData = results[1];
|
||||||
|
var image = new PDFImage(xref, res, imageData, inline, smaskData);
|
||||||
|
callback(image);
|
||||||
|
});
|
||||||
|
|
||||||
constructor.prototype = {
|
handleImageData(handler, xref, res, image, imageDataPromise);
|
||||||
getComponents: function getComponents(buffer, decodeMap) {
|
|
||||||
|
var smask = image.dict.get('SMask');
|
||||||
|
if (smask)
|
||||||
|
handleImageData(handler, xref, res, smask, smaskPromise);
|
||||||
|
else
|
||||||
|
smaskPromise.resolve(null);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resize an image using the nearest neighbor algorithm. Currently only
|
||||||
|
* supports one and three component images.
|
||||||
|
* @param {TypedArray} pixels The original image with one component.
|
||||||
|
* @param {Number} bpc Number of bits per component.
|
||||||
|
* @param {Number} components Number of color components, 1 or 3 is supported.
|
||||||
|
* @param {Number} w1 Original width.
|
||||||
|
* @param {Number} h1 Original height.
|
||||||
|
* @param {Number} w2 New width.
|
||||||
|
* @param {Number} h2 New height.
|
||||||
|
* @return {TypedArray} Resized image data.
|
||||||
|
*/
|
||||||
|
PDFImage.resize = function PDFImage_resize(pixels, bpc, components,
|
||||||
|
w1, h1, w2, h2) {
|
||||||
|
var length = w2 * h2 * components;
|
||||||
|
var temp = bpc <= 8 ? new Uint8Array(length) :
|
||||||
|
bpc <= 16 ? new Uint16Array(length) : new Uint32Array(length);
|
||||||
|
var xRatio = w1 / w2;
|
||||||
|
var yRatio = h1 / h2;
|
||||||
|
var px, py, newIndex, oldIndex;
|
||||||
|
for (var i = 0; i < h2; i++) {
|
||||||
|
for (var j = 0; j < w2; j++) {
|
||||||
|
px = Math.floor(j * xRatio);
|
||||||
|
py = Math.floor(i * yRatio);
|
||||||
|
newIndex = (i * w2) + j;
|
||||||
|
oldIndex = ((py * w1) + px);
|
||||||
|
if (components === 1) {
|
||||||
|
temp[newIndex] = pixels[oldIndex];
|
||||||
|
} else if (components === 3) {
|
||||||
|
newIndex *= 3;
|
||||||
|
oldIndex *= 3;
|
||||||
|
temp[newIndex] = pixels[oldIndex];
|
||||||
|
temp[newIndex + 1] = pixels[oldIndex + 1];
|
||||||
|
temp[newIndex + 2] = pixels[oldIndex + 2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return temp;
|
||||||
|
};
|
||||||
|
|
||||||
|
PDFImage.prototype = {
|
||||||
|
get drawWidth() {
|
||||||
|
if (!this.smask)
|
||||||
|
return this.width;
|
||||||
|
return Math.max(this.width, this.smask.width);
|
||||||
|
},
|
||||||
|
get drawHeight() {
|
||||||
|
if (!this.smask)
|
||||||
|
return this.height;
|
||||||
|
return Math.max(this.height, this.smask.height);
|
||||||
|
},
|
||||||
|
getComponents: function PDFImage_getComponents(buffer) {
|
||||||
var bpc = this.bpc;
|
var bpc = this.bpc;
|
||||||
if (bpc == 8)
|
var needsDecode = this.needsDecode;
|
||||||
|
var decodeMap = this.decode;
|
||||||
|
|
||||||
|
// This image doesn't require any extra work.
|
||||||
|
if (bpc == 8 && !needsDecode)
|
||||||
return buffer;
|
return buffer;
|
||||||
|
|
||||||
|
var bufferLength = buffer.length;
|
||||||
var width = this.width;
|
var width = this.width;
|
||||||
var height = this.height;
|
var height = this.height;
|
||||||
var numComps = this.numComps;
|
var numComps = this.numComps;
|
||||||
|
|
||||||
var length = width * height;
|
var length = width * height * numComps;
|
||||||
var bufferPos = 0;
|
var bufferPos = 0;
|
||||||
var output = bpc <= 8 ? new Uint8Array(length) :
|
var output = bpc <= 8 ? new Uint8Array(length) :
|
||||||
bpc <= 16 ? new Uint16Array(length) : new Uint32Array(length);
|
bpc <= 16 ? new Uint16Array(length) : new Uint32Array(length);
|
||||||
var rowComps = width * numComps;
|
var rowComps = width * numComps;
|
||||||
|
var decodeAddends, decodeCoefficients;
|
||||||
|
if (needsDecode) {
|
||||||
|
decodeAddends = this.decodeAddends;
|
||||||
|
decodeCoefficients = this.decodeCoefficients;
|
||||||
|
}
|
||||||
|
var max = (1 << bpc) - 1;
|
||||||
|
|
||||||
if (bpc == 1) {
|
if (bpc == 8) {
|
||||||
|
// Optimization for reading 8 bpc images that have a decode.
|
||||||
|
for (var i = 0, ii = length; i < ii; ++i) {
|
||||||
|
var compIndex = i % numComps;
|
||||||
|
var value = buffer[i];
|
||||||
|
value = decodeAndClamp(value, decodeAddends[compIndex],
|
||||||
|
decodeCoefficients[compIndex], max);
|
||||||
|
output[i] = value;
|
||||||
|
}
|
||||||
|
} else if (bpc == 1) {
|
||||||
|
// Optimization for reading 1 bpc images.
|
||||||
var valueZero = 0, valueOne = 1;
|
var valueZero = 0, valueOne = 1;
|
||||||
if (decodeMap) {
|
if (decodeMap) {
|
||||||
valueZero = decodeMap[0] ? 1 : 0;
|
valueZero = decodeMap[0] ? 1 : 0;
|
||||||
|
@ -101,8 +239,7 @@ var PDFImage = (function pdfImage() {
|
||||||
output[i] = !(buf & mask) ? valueZero : valueOne;
|
output[i] = !(buf & mask) ? valueZero : valueOne;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (decodeMap != null)
|
// The general case that handles all other bpc values.
|
||||||
TODO('interpolate component values');
|
|
||||||
var bits = 0, buf = 0;
|
var bits = 0, buf = 0;
|
||||||
for (var i = 0, ii = length; i < ii; ++i) {
|
for (var i = 0, ii = length; i < ii; ++i) {
|
||||||
if (i % rowComps == 0) {
|
if (i % rowComps == 0) {
|
||||||
|
@ -116,51 +253,44 @@ var PDFImage = (function pdfImage() {
|
||||||
}
|
}
|
||||||
|
|
||||||
var remainingBits = bits - bpc;
|
var remainingBits = bits - bpc;
|
||||||
output[i] = buf >> remainingBits;
|
var value = buf >> remainingBits;
|
||||||
|
if (needsDecode) {
|
||||||
|
var compIndex = i % numComps;
|
||||||
|
value = decodeAndClamp(value, decodeAddends[compIndex],
|
||||||
|
decodeCoefficients[compIndex], max);
|
||||||
|
}
|
||||||
|
output[i] = value;
|
||||||
buf = buf & ((1 << remainingBits) - 1);
|
buf = buf & ((1 << remainingBits) - 1);
|
||||||
bits = remainingBits;
|
bits = remainingBits;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return output;
|
return output;
|
||||||
},
|
},
|
||||||
getOpacity: function getOpacity() {
|
getOpacity: function PDFImage_getOpacity(width, height) {
|
||||||
var smask = this.smask;
|
var smask = this.smask;
|
||||||
var width = this.width;
|
var originalWidth = this.width;
|
||||||
var height = this.height;
|
var originalHeight = this.height;
|
||||||
var buf = new Uint8Array(width * height);
|
var buf;
|
||||||
|
|
||||||
if (smask) {
|
if (smask) {
|
||||||
if (smask.image.getImage) {
|
|
||||||
// smask is a DOM image
|
|
||||||
var tempCanvas = new ScratchCanvas(width, height);
|
|
||||||
var tempCtx = tempCanvas.getContext('2d');
|
|
||||||
var domImage = smask.image.getImage();
|
|
||||||
tempCtx.drawImage(domImage, 0, 0, domImage.width, domImage.height,
|
|
||||||
0, 0, width, height);
|
|
||||||
var data = tempCtx.getImageData(0, 0, width, height).data;
|
|
||||||
for (var i = 0, j = 0, ii = width * height; i < ii; ++i, j += 4)
|
|
||||||
buf[i] = data[j]; // getting first component value
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
var sw = smask.width;
|
var sw = smask.width;
|
||||||
var sh = smask.height;
|
var sh = smask.height;
|
||||||
if (sw != this.width || sh != this.height)
|
buf = new Uint8Array(sw * sh);
|
||||||
error('smask dimensions do not match image dimensions: ' + sw +
|
|
||||||
' != ' + this.width + ', ' + sh + ' != ' + this.height);
|
|
||||||
|
|
||||||
smask.fillGrayBuffer(buf);
|
smask.fillGrayBuffer(buf);
|
||||||
return buf;
|
if (sw != width || sh != height)
|
||||||
|
buf = PDFImage.resize(buf, smask.bps, 1, sw, sh, width, height);
|
||||||
} else {
|
} else {
|
||||||
|
buf = new Uint8Array(width * height);
|
||||||
for (var i = 0, ii = width * height; i < ii; ++i)
|
for (var i = 0, ii = width * height; i < ii; ++i)
|
||||||
buf[i] = 255;
|
buf[i] = 255;
|
||||||
}
|
}
|
||||||
return buf;
|
return buf;
|
||||||
},
|
},
|
||||||
applyStencilMask: function applyStencilMask(buffer, inverseDecode) {
|
applyStencilMask: function PDFImage_applyStencilMask(buffer,
|
||||||
|
inverseDecode) {
|
||||||
var width = this.width, height = this.height;
|
var width = this.width, height = this.height;
|
||||||
var bitStrideLength = (width + 7) >> 3;
|
var bitStrideLength = (width + 7) >> 3;
|
||||||
this.image.reset();
|
var imgArray = this.getImageBytes(bitStrideLength * height);
|
||||||
var imgArray = this.image.getBytes(bitStrideLength * height);
|
|
||||||
var imgArrayPos = 0;
|
var imgArrayPos = 0;
|
||||||
var i, j, mask, buf;
|
var i, j, mask, buf;
|
||||||
// removing making non-masked pixels transparent
|
// removing making non-masked pixels transparent
|
||||||
|
@ -180,21 +310,23 @@ var PDFImage = (function pdfImage() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
fillRgbaBuffer: function fillRgbaBuffer(buffer, decodeMap) {
|
fillRgbaBuffer: function PDFImage_fillRgbaBuffer(buffer, width, height) {
|
||||||
var numComps = this.numComps;
|
var numComps = this.numComps;
|
||||||
var width = this.width;
|
var originalWidth = this.width;
|
||||||
var height = this.height;
|
var originalHeight = this.height;
|
||||||
var bpc = this.bpc;
|
var bpc = this.bpc;
|
||||||
|
|
||||||
// rows start at byte boundary;
|
// rows start at byte boundary;
|
||||||
var rowBytes = (width * numComps * bpc + 7) >> 3;
|
var rowBytes = (originalWidth * numComps * bpc + 7) >> 3;
|
||||||
this.image.reset();
|
var imgArray = this.getImageBytes(originalHeight * rowBytes);
|
||||||
var imgArray = this.image.getBytes(height * rowBytes);
|
|
||||||
|
|
||||||
var comps = this.colorSpace.getRgbBuffer(
|
var comps = this.colorSpace.getRgbBuffer(
|
||||||
this.getComponents(imgArray, decodeMap), bpc);
|
this.getComponents(imgArray), bpc);
|
||||||
|
if (originalWidth != width || originalHeight != height)
|
||||||
|
comps = PDFImage.resize(comps, this.bpc, 3, originalWidth,
|
||||||
|
originalHeight, width, height);
|
||||||
var compsPos = 0;
|
var compsPos = 0;
|
||||||
var opacity = this.getOpacity();
|
var opacity = this.getOpacity(width, height);
|
||||||
var opacityPos = 0;
|
var opacityPos = 0;
|
||||||
var length = width * height * 4;
|
var length = width * height * 4;
|
||||||
|
|
||||||
|
@ -205,7 +337,7 @@ var PDFImage = (function pdfImage() {
|
||||||
buffer[i + 3] = opacity[opacityPos++];
|
buffer[i + 3] = opacity[opacityPos++];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
fillGrayBuffer: function fillGrayBuffer(buffer) {
|
fillGrayBuffer: function PDFImage_fillGrayBuffer(buffer) {
|
||||||
var numComps = this.numComps;
|
var numComps = this.numComps;
|
||||||
if (numComps != 1)
|
if (numComps != 1)
|
||||||
error('Reading gray scale from a color image: ' + numComps);
|
error('Reading gray scale from a color image: ' + numComps);
|
||||||
|
@ -216,42 +348,28 @@ var PDFImage = (function pdfImage() {
|
||||||
|
|
||||||
// rows start at byte boundary;
|
// rows start at byte boundary;
|
||||||
var rowBytes = (width * numComps * bpc + 7) >> 3;
|
var rowBytes = (width * numComps * bpc + 7) >> 3;
|
||||||
this.image.reset();
|
var imgArray = this.getImageBytes(height * rowBytes);
|
||||||
var imgArray = this.image.getBytes(height * rowBytes);
|
|
||||||
|
|
||||||
var comps = this.getComponents(imgArray);
|
var comps = this.getComponents(imgArray);
|
||||||
var length = width * height;
|
var length = width * height;
|
||||||
|
// we aren't using a colorspace so we need to scale the value
|
||||||
|
var scale = 255 / ((1 << bpc) - 1);
|
||||||
for (var i = 0; i < length; ++i)
|
for (var i = 0; i < length; ++i)
|
||||||
buffer[i] = comps[i];
|
buffer[i] = (scale * comps[i]) | 0;
|
||||||
|
},
|
||||||
|
getImageBytes: function PDFImage_getImageBytes(length) {
|
||||||
|
this.image.reset();
|
||||||
|
return this.image.getBytes(length);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return constructor;
|
return PDFImage;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
var JpegImageLoader = (function jpegImage() {
|
function loadJpegStream(id, imageData, objs) {
|
||||||
function JpegImageLoader(objId, imageData, objs) {
|
|
||||||
var src = 'data:image/jpeg;base64,' + window.btoa(imageData);
|
|
||||||
|
|
||||||
var img = new Image();
|
var img = new Image();
|
||||||
img.onload = (function jpegImageLoaderOnload() {
|
img.onload = (function loadJpegStream_onloadClosure() {
|
||||||
this.loaded = true;
|
objs.resolve(id, img);
|
||||||
|
});
|
||||||
objs.resolve(objId, this);
|
img.src = 'data:image/jpeg;base64,' + window.btoa(imageData);
|
||||||
|
}
|
||||||
if (this.onLoad)
|
|
||||||
this.onLoad();
|
|
||||||
}).bind(this);
|
|
||||||
img.src = src;
|
|
||||||
this.domImage = img;
|
|
||||||
}
|
|
||||||
|
|
||||||
JpegImageLoader.prototype = {
|
|
||||||
getImage: function jpegImageLoaderGetImage() {
|
|
||||||
return this.domImage;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return JpegImageLoader;
|
|
||||||
})();
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var Metadata = PDFJS.Metadata = (function MetadataClosure() {
|
||||||
|
function Metadata(meta) {
|
||||||
|
if (typeof meta === 'string') {
|
||||||
|
var parser = new DOMParser();
|
||||||
|
meta = parser.parseFromString(meta, 'application/xml');
|
||||||
|
} else if (!(meta instanceof Document)) {
|
||||||
|
error('Metadata: Invalid metadata object');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.metaDocument = meta;
|
||||||
|
this.metadata = {};
|
||||||
|
this.parse();
|
||||||
|
}
|
||||||
|
|
||||||
|
Metadata.prototype = {
|
||||||
|
parse: function Metadata_parse() {
|
||||||
|
var doc = this.metaDocument;
|
||||||
|
var rdf = doc.documentElement;
|
||||||
|
|
||||||
|
if (rdf.nodeName.toLowerCase() !== 'rdf:rdf') { // Wrapped in <xmpmeta>
|
||||||
|
rdf = rdf.firstChild;
|
||||||
|
while (rdf && rdf.nodeName.toLowerCase() !== 'rdf:rdf')
|
||||||
|
rdf = rdf.nextSibling;
|
||||||
|
}
|
||||||
|
|
||||||
|
var nodeName = (rdf) ? rdf.nodeName.toLowerCase() : null;
|
||||||
|
if (!rdf || nodeName !== 'rdf:rdf' || !rdf.hasChildNodes())
|
||||||
|
return;
|
||||||
|
|
||||||
|
var childNodes = rdf.childNodes, desc, namespace, entries, entry;
|
||||||
|
|
||||||
|
for (var i = 0, length = childNodes.length; i < length; i++) {
|
||||||
|
desc = childNodes[i];
|
||||||
|
if (desc.nodeName.toLowerCase() !== 'rdf:description')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
entries = [];
|
||||||
|
for (var ii = 0, iLength = desc.childNodes.length; ii < iLength; ii++) {
|
||||||
|
if (desc.childNodes[ii].nodeName.toLowerCase() !== '#text')
|
||||||
|
entries.push(desc.childNodes[ii]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ii = 0, iLength = entries.length; ii < iLength; ii++) {
|
||||||
|
var entry = entries[ii];
|
||||||
|
var name = entry.nodeName.toLowerCase();
|
||||||
|
this.metadata[name] = entry.textContent.trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
get: function Metadata_get(name) {
|
||||||
|
return this.metadata[name] || null;
|
||||||
|
},
|
||||||
|
|
||||||
|
has: function Metadata_has(name) {
|
||||||
|
return typeof this.metadata[name] !== 'undefined';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return Metadata;
|
||||||
|
})();
|
|
@ -3,6 +3,9 @@
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
// The Metrics object contains glyph widths (in glyph space units).
|
||||||
|
// As per PDF spec, for most fonts (Type 3 being an exception) a glyph
|
||||||
|
// space unit corresponds to 1/1000th of text space unit.
|
||||||
var Metrics = {
|
var Metrics = {
|
||||||
'Courier': 600,
|
'Courier': 600,
|
||||||
'Courier-Bold': 600,
|
'Courier-Bold': 600,
|
||||||
|
|
|
@ -3,121 +3,157 @@
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var Name = (function nameName() {
|
var Name = (function NameClosure() {
|
||||||
function constructor(name) {
|
function Name(name) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor.prototype = {
|
Name.prototype = {};
|
||||||
};
|
|
||||||
|
|
||||||
return constructor;
|
return Name;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
var Cmd = (function cmdCmd() {
|
var Cmd = (function CmdClosure() {
|
||||||
function constructor(cmd) {
|
function Cmd(cmd) {
|
||||||
this.cmd = cmd;
|
this.cmd = cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor.prototype = {
|
Cmd.prototype = {};
|
||||||
|
|
||||||
|
var cmdCache = {};
|
||||||
|
|
||||||
|
Cmd.get = function Cmd_get(cmd) {
|
||||||
|
var cmdValue = cmdCache[cmd];
|
||||||
|
if (cmdValue)
|
||||||
|
return cmdValue;
|
||||||
|
|
||||||
|
return cmdCache[cmd] = new Cmd(cmd);
|
||||||
};
|
};
|
||||||
|
|
||||||
return constructor;
|
return Cmd;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
var Dict = (function dictDict() {
|
var Dict = (function DictClosure() {
|
||||||
function constructor() {
|
// xref is optional
|
||||||
|
function Dict(xref) {
|
||||||
|
// Map should only be used internally, use functions below to access.
|
||||||
this.map = Object.create(null);
|
this.map = Object.create(null);
|
||||||
|
this.xref = xref;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor.prototype = {
|
Dict.prototype = {
|
||||||
get: function dictGet(key1, key2, key3) {
|
// automatically dereferences Ref objects
|
||||||
|
get: function Dict_get(key1, key2, key3) {
|
||||||
var value;
|
var value;
|
||||||
|
var xref = this.xref;
|
||||||
if (typeof (value = this.map[key1]) != 'undefined' || key1 in this.map ||
|
if (typeof (value = this.map[key1]) != 'undefined' || key1 in this.map ||
|
||||||
typeof key2 == 'undefined') {
|
typeof key2 == 'undefined') {
|
||||||
return value;
|
return xref ? this.xref.fetchIfRef(value) : value;
|
||||||
}
|
}
|
||||||
if (typeof (value = this.map[key2]) != 'undefined' || key2 in this.map ||
|
if (typeof (value = this.map[key2]) != 'undefined' || key2 in this.map ||
|
||||||
typeof key3 == 'undefined') {
|
typeof key3 == 'undefined') {
|
||||||
return value;
|
return xref ? this.xref.fetchIfRef(value) : value;
|
||||||
}
|
}
|
||||||
|
value = this.map[key3] || null;
|
||||||
return this.map[key3] || null;
|
return xref ? this.xref.fetchIfRef(value) : value;
|
||||||
|
},
|
||||||
|
// no dereferencing
|
||||||
|
getRaw: function Dict_getRaw(key) {
|
||||||
|
return this.map[key];
|
||||||
|
},
|
||||||
|
// creates new map and dereferences all Refs
|
||||||
|
getAll: function Dict_getAll() {
|
||||||
|
var all = {};
|
||||||
|
for (var key in this.map)
|
||||||
|
all[key] = this.get(key);
|
||||||
|
return all;
|
||||||
},
|
},
|
||||||
|
|
||||||
set: function dictSet(key, value) {
|
set: function Dict_set(key, value) {
|
||||||
this.map[key] = value;
|
this.map[key] = value;
|
||||||
},
|
},
|
||||||
|
|
||||||
has: function dictHas(key) {
|
has: function Dict_has(key) {
|
||||||
return key in this.map;
|
return key in this.map;
|
||||||
},
|
},
|
||||||
|
|
||||||
forEach: function dictForEach(callback) {
|
forEach: function Dict_forEach(callback) {
|
||||||
for (var key in this.map) {
|
for (var key in this.map) {
|
||||||
callback(key, this.map[key]);
|
callback(key, this.get(key));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return constructor;
|
return Dict;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
var Ref = (function refRef() {
|
var Ref = (function RefClosure() {
|
||||||
function constructor(num, gen) {
|
function Ref(num, gen) {
|
||||||
this.num = num;
|
this.num = num;
|
||||||
this.gen = gen;
|
this.gen = gen;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor.prototype = {
|
Ref.prototype = {};
|
||||||
};
|
|
||||||
|
|
||||||
return constructor;
|
return Ref;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
// The reference is identified by number and generation,
|
// The reference is identified by number and generation,
|
||||||
// this structure stores only one instance of the reference.
|
// this structure stores only one instance of the reference.
|
||||||
var RefSet = (function refSet() {
|
var RefSet = (function RefSetClosure() {
|
||||||
function constructor() {
|
function RefSet() {
|
||||||
this.dict = {};
|
this.dict = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor.prototype = {
|
RefSet.prototype = {
|
||||||
has: function refSetHas(ref) {
|
has: function RefSet_has(ref) {
|
||||||
return !!this.dict['R' + ref.num + '.' + ref.gen];
|
return !!this.dict['R' + ref.num + '.' + ref.gen];
|
||||||
},
|
},
|
||||||
|
|
||||||
put: function refSetPut(ref) {
|
put: function RefSet_put(ref) {
|
||||||
this.dict['R' + ref.num + '.' + ref.gen] = ref;
|
this.dict['R' + ref.num + '.' + ref.gen] = ref;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return constructor;
|
return RefSet;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
var Catalog = (function catalogCatalog() {
|
var Catalog = (function CatalogClosure() {
|
||||||
function constructor(xref) {
|
function Catalog(xref) {
|
||||||
this.xref = xref;
|
this.xref = xref;
|
||||||
var obj = xref.getCatalogObj();
|
var obj = xref.getCatalogObj();
|
||||||
assertWellFormed(isDict(obj), 'catalog object is not a dictionary');
|
assertWellFormed(isDict(obj), 'catalog object is not a dictionary');
|
||||||
this.catDict = obj;
|
this.catDict = obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor.prototype = {
|
Catalog.prototype = {
|
||||||
|
get metadata() {
|
||||||
|
var stream = this.catDict.get('Metadata');
|
||||||
|
var metadata;
|
||||||
|
if (stream && isDict(stream.dict)) {
|
||||||
|
var type = stream.dict.get('Type');
|
||||||
|
var subtype = stream.dict.get('Subtype');
|
||||||
|
|
||||||
|
if (isName(type) && isName(subtype) &&
|
||||||
|
type.name === 'Metadata' && subtype.name === 'XML') {
|
||||||
|
metadata = stringToPDFString(bytesToString(stream.getBytes()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return shadow(this, 'metadata', metadata);
|
||||||
|
},
|
||||||
get toplevelPagesDict() {
|
get toplevelPagesDict() {
|
||||||
var pagesObj = this.catDict.get('Pages');
|
var pagesObj = this.catDict.get('Pages');
|
||||||
assertWellFormed(isRef(pagesObj), 'invalid top-level pages reference');
|
assertWellFormed(isDict(pagesObj), 'invalid top-level pages dictionary');
|
||||||
var xrefObj = this.xref.fetch(pagesObj);
|
|
||||||
assertWellFormed(isDict(xrefObj), 'invalid top-level pages dictionary');
|
|
||||||
// shadow the prototype getter
|
// shadow the prototype getter
|
||||||
return shadow(this, 'toplevelPagesDict', xrefObj);
|
return shadow(this, 'toplevelPagesDict', pagesObj);
|
||||||
},
|
},
|
||||||
get documentOutline() {
|
get documentOutline() {
|
||||||
var obj = this.catDict.get('Outlines');
|
|
||||||
var xref = this.xref;
|
var xref = this.xref;
|
||||||
|
var obj = this.catDict.get('Outlines');
|
||||||
var root = { items: [] };
|
var root = { items: [] };
|
||||||
if (isRef(obj)) {
|
if (isDict(obj)) {
|
||||||
obj = xref.fetch(obj).get('First');
|
obj = obj.getRaw('First');
|
||||||
var processed = new RefSet();
|
var processed = new RefSet();
|
||||||
if (isRef(obj)) {
|
if (isRef(obj)) {
|
||||||
var queue = [{obj: obj, parent: root}];
|
var queue = [{obj: obj, parent: root}];
|
||||||
|
@ -126,18 +162,20 @@ var Catalog = (function catalogCatalog() {
|
||||||
processed.put(obj);
|
processed.put(obj);
|
||||||
while (queue.length > 0) {
|
while (queue.length > 0) {
|
||||||
var i = queue.shift();
|
var i = queue.shift();
|
||||||
var outlineDict = xref.fetch(i.obj);
|
var outlineDict = xref.fetchIfRef(i.obj);
|
||||||
|
if (outlineDict === null)
|
||||||
|
continue;
|
||||||
if (!outlineDict.has('Title'))
|
if (!outlineDict.has('Title'))
|
||||||
error('Invalid outline item');
|
error('Invalid outline item');
|
||||||
var dest = outlineDict.get('A');
|
var dest = outlineDict.get('A');
|
||||||
if (dest)
|
if (dest)
|
||||||
dest = xref.fetchIfRef(dest).get('D');
|
dest = dest.get('D');
|
||||||
else if (outlineDict.has('Dest')) {
|
else if (outlineDict.has('Dest')) {
|
||||||
dest = outlineDict.get('Dest');
|
dest = outlineDict.getRaw('Dest');
|
||||||
if (isName(dest))
|
if (isName(dest))
|
||||||
dest = dest.name;
|
dest = dest.name;
|
||||||
}
|
}
|
||||||
var title = xref.fetchIfRef(outlineDict.get('Title'));
|
var title = outlineDict.get('Title');
|
||||||
var outlineItem = {
|
var outlineItem = {
|
||||||
dest: dest,
|
dest: dest,
|
||||||
title: stringToPDFString(title),
|
title: stringToPDFString(title),
|
||||||
|
@ -148,12 +186,12 @@ var Catalog = (function catalogCatalog() {
|
||||||
items: []
|
items: []
|
||||||
};
|
};
|
||||||
i.parent.items.push(outlineItem);
|
i.parent.items.push(outlineItem);
|
||||||
obj = outlineDict.get('First');
|
obj = outlineDict.getRaw('First');
|
||||||
if (isRef(obj) && !processed.has(obj)) {
|
if (isRef(obj) && !processed.has(obj)) {
|
||||||
queue.push({obj: obj, parent: outlineItem});
|
queue.push({obj: obj, parent: outlineItem});
|
||||||
processed.put(obj);
|
processed.put(obj);
|
||||||
}
|
}
|
||||||
obj = outlineDict.get('Next');
|
obj = outlineDict.getRaw('Next');
|
||||||
if (isRef(obj) && !processed.has(obj)) {
|
if (isRef(obj) && !processed.has(obj)) {
|
||||||
queue.push({obj: obj, parent: i.parent});
|
queue.push({obj: obj, parent: i.parent});
|
||||||
processed.put(obj);
|
processed.put(obj);
|
||||||
|
@ -173,7 +211,7 @@ var Catalog = (function catalogCatalog() {
|
||||||
// shadow the prototype getter
|
// shadow the prototype getter
|
||||||
return shadow(this, 'num', obj);
|
return shadow(this, 'num', obj);
|
||||||
},
|
},
|
||||||
traverseKids: function catalogTraverseKids(pagesDict) {
|
traverseKids: function Catalog_traverseKids(pagesDict) {
|
||||||
var pageCache = this.pageCache;
|
var pageCache = this.pageCache;
|
||||||
var kids = pagesDict.get('Kids');
|
var kids = pagesDict.get('Kids');
|
||||||
assertWellFormed(isArray(kids),
|
assertWellFormed(isArray(kids),
|
||||||
|
@ -195,8 +233,7 @@ var Catalog = (function catalogCatalog() {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
get destinations() {
|
get destinations() {
|
||||||
function fetchDestination(xref, ref) {
|
function fetchDestination(dest) {
|
||||||
var dest = xref.fetchIfRef(ref);
|
|
||||||
return isDict(dest) ? dest.get('D') : dest;
|
return isDict(dest) ? dest.get('D') : dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,16 +241,16 @@ var Catalog = (function catalogCatalog() {
|
||||||
var dests = {}, nameTreeRef, nameDictionaryRef;
|
var dests = {}, nameTreeRef, nameDictionaryRef;
|
||||||
var obj = this.catDict.get('Names');
|
var obj = this.catDict.get('Names');
|
||||||
if (obj)
|
if (obj)
|
||||||
nameTreeRef = xref.fetchIfRef(obj).get('Dests');
|
nameTreeRef = obj.getRaw('Dests');
|
||||||
else if (this.catDict.has('Dests'))
|
else if (this.catDict.has('Dests'))
|
||||||
nameDictionaryRef = this.catDict.get('Dests');
|
nameDictionaryRef = this.catDict.get('Dests');
|
||||||
|
|
||||||
if (nameDictionaryRef) {
|
if (nameDictionaryRef) {
|
||||||
// reading simple destination dictionary
|
// reading simple destination dictionary
|
||||||
obj = xref.fetchIfRef(nameDictionaryRef);
|
obj = nameDictionaryRef;
|
||||||
obj.forEach(function catalogForEach(key, value) {
|
obj.forEach(function catalogForEach(key, value) {
|
||||||
if (!value) return;
|
if (!value) return;
|
||||||
dests[key] = fetchDestination(xref, value);
|
dests[key] = fetchDestination(value);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (nameTreeRef) {
|
if (nameTreeRef) {
|
||||||
|
@ -237,13 +274,13 @@ var Catalog = (function catalogCatalog() {
|
||||||
}
|
}
|
||||||
var names = obj.get('Names');
|
var names = obj.get('Names');
|
||||||
for (i = 0, n = names.length; i < n; i += 2) {
|
for (i = 0, n = names.length; i < n; i += 2) {
|
||||||
dests[names[i]] = fetchDestination(xref, names[i + 1]);
|
dests[names[i]] = fetchDestination(xref.fetchIfRef(names[i + 1]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return shadow(this, 'destinations', dests);
|
return shadow(this, 'destinations', dests);
|
||||||
},
|
},
|
||||||
getPage: function catalogGetPage(n) {
|
getPage: function Catalog_getPage(n) {
|
||||||
var pageCache = this.pageCache;
|
var pageCache = this.pageCache;
|
||||||
if (!pageCache) {
|
if (!pageCache) {
|
||||||
pageCache = this.pageCache = [];
|
pageCache = this.pageCache = [];
|
||||||
|
@ -253,105 +290,101 @@ var Catalog = (function catalogCatalog() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return constructor;
|
return Catalog;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
var XRef = (function xRefXRef() {
|
var XRef = (function XRefClosure() {
|
||||||
function constructor(stream, startXRef, mainXRefEntriesOffset) {
|
function XRef(stream, startXRef, mainXRefEntriesOffset) {
|
||||||
this.stream = stream;
|
this.stream = stream;
|
||||||
this.entries = [];
|
this.entries = [];
|
||||||
this.xrefstms = {};
|
this.xrefstms = {};
|
||||||
var trailerDict = this.readXRef(startXRef);
|
var trailerDict = this.readXRef(startXRef);
|
||||||
|
trailerDict.xref = this;
|
||||||
|
this.trailer = trailerDict;
|
||||||
// prepare the XRef cache
|
// prepare the XRef cache
|
||||||
this.cache = [];
|
this.cache = [];
|
||||||
|
|
||||||
var encrypt = trailerDict.get('Encrypt');
|
var encrypt = trailerDict.get('Encrypt');
|
||||||
if (encrypt) {
|
if (encrypt) {
|
||||||
var fileId = trailerDict.get('ID');
|
var fileId = trailerDict.get('ID');
|
||||||
this.encrypt = new CipherTransformFactory(this.fetch(encrypt),
|
this.encrypt = new CipherTransformFactory(encrypt,
|
||||||
fileId[0] /*, password */);
|
fileId[0] /*, password */);
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the root dictionary (catalog) object
|
// get the root dictionary (catalog) object
|
||||||
if (!isRef(this.root = trailerDict.get('Root')))
|
if (!(this.root = trailerDict.get('Root')))
|
||||||
error('Invalid root reference');
|
error('Invalid root reference');
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor.prototype = {
|
XRef.prototype = {
|
||||||
readXRefTable: function readXRefTable(parser) {
|
readXRefTable: function XRef_readXRefTable(parser) {
|
||||||
|
// Example of cross-reference table:
|
||||||
|
// xref
|
||||||
|
// 0 1 <-- subsection header (first obj #, obj count)
|
||||||
|
// 0000000000 65535 f <-- actual object (offset, generation #, f/n)
|
||||||
|
// 23 2 <-- subsection header ... and so on ...
|
||||||
|
// 0000025518 00002 n
|
||||||
|
// 0000025635 00000 n
|
||||||
|
// trailer
|
||||||
|
// ...
|
||||||
|
|
||||||
|
// Outer loop is over subsection headers
|
||||||
var obj;
|
var obj;
|
||||||
while (true) {
|
while (!isCmd(obj = parser.getObj(), 'trailer')) {
|
||||||
if (isCmd(obj = parser.getObj(), 'trailer'))
|
var first = obj,
|
||||||
break;
|
count = parser.getObj();
|
||||||
if (!isInt(obj))
|
|
||||||
error('Invalid XRef table');
|
if (!isInt(first) || !isInt(count))
|
||||||
var first = obj;
|
error('Invalid XRef table: wrong types in subsection header');
|
||||||
if (!isInt(obj = parser.getObj()))
|
|
||||||
error('Invalid XRef table');
|
// Inner loop is over objects themselves
|
||||||
var n = obj;
|
for (var i = 0; i < count; i++) {
|
||||||
if (first < 0 || n < 0 || (first + n) != ((first + n) | 0))
|
|
||||||
error('Invalid XRef table: ' + first + ', ' + n);
|
|
||||||
for (var i = first; i < first + n; ++i) {
|
|
||||||
var entry = {};
|
var entry = {};
|
||||||
if (!isInt(obj = parser.getObj()))
|
entry.offset = parser.getObj();
|
||||||
error('Invalid XRef table: ' + first + ', ' + n);
|
entry.gen = parser.getObj();
|
||||||
entry.offset = obj;
|
var type = parser.getObj();
|
||||||
if (!isInt(obj = parser.getObj()))
|
|
||||||
error('Invalid XRef table: ' + first + ', ' + n);
|
if (isCmd(type, 'f'))
|
||||||
entry.gen = obj;
|
|
||||||
obj = parser.getObj();
|
|
||||||
if (isCmd(obj, 'n')) {
|
|
||||||
entry.uncompressed = true;
|
|
||||||
} else if (isCmd(obj, 'f')) {
|
|
||||||
entry.free = true;
|
entry.free = true;
|
||||||
} else {
|
else if (isCmd(type, 'n'))
|
||||||
error('Invalid XRef table: ' + first + ', ' + n);
|
entry.uncompressed = true;
|
||||||
}
|
|
||||||
if (!this.entries[i]) {
|
// Validate entry obj
|
||||||
// In some buggy PDF files the xref table claims to start at 1
|
if (!isInt(entry.offset) || !isInt(entry.gen) ||
|
||||||
// instead of 0.
|
!(entry.free || entry.uncompressed)) {
|
||||||
if (i == 1 && first == 1 &&
|
error('Invalid entry in XRef subsection: ' + first + ', ' + count);
|
||||||
entry.offset == 0 && entry.gen == 65535 && entry.free) {
|
|
||||||
i = first = 0;
|
|
||||||
}
|
|
||||||
this.entries[i] = entry;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!this.entries[i + first])
|
||||||
|
this.entries[i + first] = entry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// read the trailer dictionary
|
// Sanity check: as per spec, first object must have these properties
|
||||||
var dict;
|
if (this.entries[0] &&
|
||||||
if (!isDict(dict = parser.getObj()))
|
!(this.entries[0].gen === 65535 && this.entries[0].free))
|
||||||
error('Invalid XRef table');
|
error('Invalid XRef table: unexpected first object');
|
||||||
|
|
||||||
// get the 'Prev' pointer
|
// Sanity check
|
||||||
var prev;
|
if (!isCmd(obj, 'trailer'))
|
||||||
obj = dict.get('Prev');
|
error('Invalid XRef table: could not find trailer dictionary');
|
||||||
if (isInt(obj)) {
|
|
||||||
prev = obj;
|
|
||||||
} else if (isRef(obj)) {
|
|
||||||
// certain buggy PDF generators generate "/Prev NNN 0 R" instead
|
|
||||||
// of "/Prev NNN"
|
|
||||||
prev = obj.num;
|
|
||||||
}
|
|
||||||
if (prev) {
|
|
||||||
this.readXRef(prev);
|
|
||||||
}
|
|
||||||
|
|
||||||
// check for 'XRefStm' key
|
// Read trailer dictionary, e.g.
|
||||||
if (isInt(obj = dict.get('XRefStm'))) {
|
// trailer
|
||||||
var pos = obj;
|
// << /Size 22
|
||||||
// ignore previously loaded xref streams (possible infinite recursion)
|
// /Root 20R
|
||||||
if (!(pos in this.xrefstms)) {
|
// /Info 10R
|
||||||
this.xrefstms[pos] = 1;
|
// /ID [ <81b14aafa313db63dbd6f981e49f94f4> ]
|
||||||
this.readXRef(pos);
|
// >>
|
||||||
}
|
// The parser goes through the entire stream << ... >> and provides
|
||||||
}
|
// a getter interface for the key-value table
|
||||||
|
var dict = parser.getObj();
|
||||||
|
if (!isDict(dict))
|
||||||
|
error('Invalid XRef table: could not parse trailer dictionary');
|
||||||
|
|
||||||
return dict;
|
return dict;
|
||||||
},
|
},
|
||||||
readXRefStream: function readXRefStream(stream) {
|
readXRefStream: function XRef_readXRefStream(stream) {
|
||||||
var streamParameters = stream.parameters;
|
var streamParameters = stream.parameters;
|
||||||
var byteWidths = streamParameters.get('W');
|
var byteWidths = streamParameters.get('W');
|
||||||
var range = streamParameters.get('Index');
|
var range = streamParameters.get('Index');
|
||||||
|
@ -400,12 +433,9 @@ var XRef = (function xRefXRef() {
|
||||||
}
|
}
|
||||||
range.splice(0, 2);
|
range.splice(0, 2);
|
||||||
}
|
}
|
||||||
var prev = streamParameters.get('Prev');
|
|
||||||
if (isInt(prev))
|
|
||||||
this.readXRef(prev);
|
|
||||||
return streamParameters;
|
return streamParameters;
|
||||||
},
|
},
|
||||||
indexObjects: function indexObjects() {
|
indexObjects: function XRef_indexObjects() {
|
||||||
// Simple scan through the PDF content to find objects,
|
// Simple scan through the PDF content to find objects,
|
||||||
// trailers and XRef streams.
|
// trailers and XRef streams.
|
||||||
function readToken(data, offset) {
|
function readToken(data, offset) {
|
||||||
|
@ -497,7 +527,7 @@ var XRef = (function xRefXRef() {
|
||||||
var dict;
|
var dict;
|
||||||
for (var i = 0, ii = trailers.length; i < ii; ++i) {
|
for (var i = 0, ii = trailers.length; i < ii; ++i) {
|
||||||
stream.pos = trailers[i];
|
stream.pos = trailers[i];
|
||||||
var parser = new Parser(new Lexer(stream), true);
|
var parser = new Parser(new Lexer(stream), true, null);
|
||||||
var obj = parser.getObj();
|
var obj = parser.getObj();
|
||||||
if (!isCmd(obj, 'trailer'))
|
if (!isCmd(obj, 'trailer'))
|
||||||
continue;
|
continue;
|
||||||
|
@ -513,50 +543,88 @@ var XRef = (function xRefXRef() {
|
||||||
return dict;
|
return dict;
|
||||||
// nothing helps
|
// nothing helps
|
||||||
error('Invalid PDF structure');
|
error('Invalid PDF structure');
|
||||||
return null;
|
|
||||||
},
|
},
|
||||||
readXRef: function readXref(startXRef) {
|
readXRef: function XRef_readXRef(startXRef) {
|
||||||
var stream = this.stream;
|
var stream = this.stream;
|
||||||
stream.pos = startXRef;
|
stream.pos = startXRef;
|
||||||
var parser = new Parser(new Lexer(stream), true);
|
|
||||||
|
try {
|
||||||
|
var parser = new Parser(new Lexer(stream), true, null);
|
||||||
var obj = parser.getObj();
|
var obj = parser.getObj();
|
||||||
// parse an old-style xref table
|
var dict;
|
||||||
if (isCmd(obj, 'xref'))
|
|
||||||
return this.readXRefTable(parser);
|
// Get dictionary
|
||||||
// parse an xref stream
|
if (isCmd(obj, 'xref')) {
|
||||||
|
// Parse end-of-file XRef
|
||||||
|
dict = this.readXRefTable(parser);
|
||||||
|
|
||||||
|
// Recursively get other XRefs 'XRefStm', if any
|
||||||
|
obj = dict.get('XRefStm');
|
||||||
if (isInt(obj)) {
|
if (isInt(obj)) {
|
||||||
|
var pos = obj;
|
||||||
|
// ignore previously loaded xref streams
|
||||||
|
// (possible infinite recursion)
|
||||||
|
if (!(pos in this.xrefstms)) {
|
||||||
|
this.xrefstms[pos] = 1;
|
||||||
|
this.readXRef(pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (isInt(obj)) {
|
||||||
|
// Parse in-stream XRef
|
||||||
if (!isInt(parser.getObj()) ||
|
if (!isInt(parser.getObj()) ||
|
||||||
!isCmd(parser.getObj(), 'obj') ||
|
!isCmd(parser.getObj(), 'obj') ||
|
||||||
!isStream(obj = parser.getObj())) {
|
!isStream(obj = parser.getObj())) {
|
||||||
error('Invalid XRef stream');
|
error('Invalid XRef stream');
|
||||||
}
|
}
|
||||||
return this.readXRefStream(obj);
|
dict = this.readXRefStream(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Recursively get previous dictionary, if any
|
||||||
|
obj = dict.get('Prev');
|
||||||
|
if (isInt(obj))
|
||||||
|
this.readXRef(obj);
|
||||||
|
else if (isRef(obj)) {
|
||||||
|
// The spec says Prev must not be a reference, i.e. "/Prev NNN"
|
||||||
|
// This is a fallback for non-compliant PDFs, i.e. "/Prev NNN 0 R"
|
||||||
|
this.readXRef(obj.num);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dict;
|
||||||
|
} catch (e) {
|
||||||
|
log('(while reading XRef): ' + e);
|
||||||
|
}
|
||||||
|
|
||||||
|
warn('Indexing all PDF objects');
|
||||||
return this.indexObjects();
|
return this.indexObjects();
|
||||||
},
|
},
|
||||||
getEntry: function xRefGetEntry(i) {
|
getEntry: function XRef_getEntry(i) {
|
||||||
var e = this.entries[i];
|
var e = this.entries[i];
|
||||||
if (e.free)
|
if (e === null)
|
||||||
error('reading an XRef stream not implemented yet');
|
return null;
|
||||||
return e;
|
return e.free ? null : e; // returns null is the entry is free
|
||||||
},
|
},
|
||||||
fetchIfRef: function xRefFetchIfRef(obj) {
|
fetchIfRef: function XRef_fetchIfRef(obj) {
|
||||||
if (!isRef(obj))
|
if (!isRef(obj))
|
||||||
return obj;
|
return obj;
|
||||||
return this.fetch(obj);
|
return this.fetch(obj);
|
||||||
},
|
},
|
||||||
fetch: function xRefFetch(ref, suppressEncryption) {
|
fetch: function XRef_fetch(ref, suppressEncryption) {
|
||||||
|
assertWellFormed(isRef(ref), 'ref object is not a reference');
|
||||||
var num = ref.num;
|
var num = ref.num;
|
||||||
var e = this.cache[num];
|
if (num in this.cache)
|
||||||
if (e)
|
return this.cache[num];
|
||||||
return e;
|
|
||||||
|
var e = this.getEntry(num);
|
||||||
|
|
||||||
|
// the referenced entry can be free
|
||||||
|
if (e === null)
|
||||||
|
return (this.cache[num] = e);
|
||||||
|
|
||||||
e = this.getEntry(num);
|
|
||||||
var gen = ref.gen;
|
var gen = ref.gen;
|
||||||
var stream, parser;
|
var stream, parser;
|
||||||
if (e.uncompressed) {
|
if (e.uncompressed) {
|
||||||
if (e.gen != gen)
|
if (e.gen != gen)
|
||||||
throw ('inconsistent generation in XRef');
|
error('inconsistent generation in XRef');
|
||||||
stream = this.stream.makeSubStream(e.offset);
|
stream = this.stream.makeSubStream(e.offset);
|
||||||
parser = new Parser(new Lexer(stream), true, this);
|
parser = new Parser(new Lexer(stream), true, this);
|
||||||
var obj1 = parser.getObj();
|
var obj1 = parser.getObj();
|
||||||
|
@ -589,7 +657,7 @@ var XRef = (function xRefXRef() {
|
||||||
e = parser.getObj();
|
e = parser.getObj();
|
||||||
}
|
}
|
||||||
// Don't cache streams since they are mutable (except images).
|
// Don't cache streams since they are mutable (except images).
|
||||||
if (!isStream(e) || e.getImage)
|
if (!isStream(e) || e instanceof JpegStream)
|
||||||
this.cache[num] = e;
|
this.cache[num] = e;
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
@ -603,7 +671,7 @@ var XRef = (function xRefXRef() {
|
||||||
if (!isInt(first) || !isInt(n)) {
|
if (!isInt(first) || !isInt(n)) {
|
||||||
error('invalid first and n parameters for ObjStm stream');
|
error('invalid first and n parameters for ObjStm stream');
|
||||||
}
|
}
|
||||||
parser = new Parser(new Lexer(stream), false);
|
parser = new Parser(new Lexer(stream), false, this);
|
||||||
var i, entries = [], nums = [];
|
var i, entries = [], nums = [];
|
||||||
// read the object numbers to populate cache
|
// read the object numbers to populate cache
|
||||||
for (i = 0; i < n; ++i) {
|
for (i = 0; i < n; ++i) {
|
||||||
|
@ -628,12 +696,12 @@ var XRef = (function xRefXRef() {
|
||||||
}
|
}
|
||||||
return e;
|
return e;
|
||||||
},
|
},
|
||||||
getCatalogObj: function xRefGetCatalogObj() {
|
getCatalogObj: function XRef_getCatalogObj() {
|
||||||
return this.fetch(this.root);
|
return this.root;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return constructor;
|
return XRef;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -642,7 +710,7 @@ var XRef = (function xRefXRef() {
|
||||||
* inside of a worker. The `PDFObjects` implements some basic functions to
|
* inside of a worker. The `PDFObjects` implements some basic functions to
|
||||||
* manage these objects.
|
* manage these objects.
|
||||||
*/
|
*/
|
||||||
var PDFObjects = (function pdfObjects() {
|
var PDFObjects = (function PDFObjectsClosure() {
|
||||||
function PDFObjects() {
|
function PDFObjects() {
|
||||||
this.objs = {};
|
this.objs = {};
|
||||||
}
|
}
|
||||||
|
@ -655,7 +723,7 @@ var PDFObjects = (function pdfObjects() {
|
||||||
* Ensures there is an object defined for `objId`. Stores `data` on the
|
* Ensures there is an object defined for `objId`. Stores `data` on the
|
||||||
* object *if* it is created.
|
* object *if* it is created.
|
||||||
*/
|
*/
|
||||||
ensureObj: function pdfObjectsEnsureObj(objId, data) {
|
ensureObj: function PDFObjects_ensureObj(objId, data) {
|
||||||
if (this.objs[objId])
|
if (this.objs[objId])
|
||||||
return this.objs[objId];
|
return this.objs[objId];
|
||||||
return this.objs[objId] = new Promise(objId, data);
|
return this.objs[objId] = new Promise(objId, data);
|
||||||
|
@ -670,7 +738,7 @@ var PDFObjects = (function pdfObjects() {
|
||||||
* function and the object is already resolved, the callback gets called
|
* function and the object is already resolved, the callback gets called
|
||||||
* right away.
|
* right away.
|
||||||
*/
|
*/
|
||||||
get: function pdfObjectsGet(objId, callback) {
|
get: function PDFObjects_get(objId, callback) {
|
||||||
// If there is a callback, then the get can be async and the object is
|
// If there is a callback, then the get can be async and the object is
|
||||||
// not required to be resolved right now
|
// not required to be resolved right now
|
||||||
if (callback) {
|
if (callback) {
|
||||||
|
@ -684,18 +752,16 @@ var PDFObjects = (function pdfObjects() {
|
||||||
|
|
||||||
// If there isn't an object yet or the object isn't resolved, then the
|
// If there isn't an object yet or the object isn't resolved, then the
|
||||||
// data isn't ready yet!
|
// data isn't ready yet!
|
||||||
if (!obj || !obj.isResolved) {
|
if (!obj || !obj.isResolved)
|
||||||
throw 'Requesting object that isn\'t resolved yet ' + objId;
|
error('Requesting object that isn\'t resolved yet ' + objId);
|
||||||
return null;
|
|
||||||
} else {
|
|
||||||
return obj.data;
|
return obj.data;
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolves the object `objId` with optional `data`.
|
* Resolves the object `objId` with optional `data`.
|
||||||
*/
|
*/
|
||||||
resolve: function pdfObjectsResolve(objId, data) {
|
resolve: function PDFObjects_resolve(objId, data) {
|
||||||
var objs = this.objs;
|
var objs = this.objs;
|
||||||
|
|
||||||
// In case there is a promise already on this object, just resolve it.
|
// In case there is a promise already on this object, just resolve it.
|
||||||
|
@ -706,11 +772,11 @@ var PDFObjects = (function pdfObjects() {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onData: function pdfObjectsOnData(objId, callback) {
|
onData: function PDFObjects_onData(objId, callback) {
|
||||||
this.ensureObj(objId).onData(callback);
|
this.ensureObj(objId).onData(callback);
|
||||||
},
|
},
|
||||||
|
|
||||||
isResolved: function pdfObjectsIsResolved(objId) {
|
isResolved: function PDFObjects_isResolved(objId) {
|
||||||
var objs = this.objs;
|
var objs = this.objs;
|
||||||
if (!objs[objId]) {
|
if (!objs[objId]) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -719,7 +785,7 @@ var PDFObjects = (function pdfObjects() {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
hasData: function pdfObjectsHasData(objId) {
|
hasData: function PDFObjects_hasData(objId) {
|
||||||
var objs = this.objs;
|
var objs = this.objs;
|
||||||
if (!objs[objId]) {
|
if (!objs[objId]) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -731,7 +797,7 @@ var PDFObjects = (function pdfObjects() {
|
||||||
/**
|
/**
|
||||||
* Sets the data of an object but *doesn't* resolve it.
|
* Sets the data of an object but *doesn't* resolve it.
|
||||||
*/
|
*/
|
||||||
setData: function pdfObjectsSetData(objId, data) {
|
setData: function PDFObjects_setData(objId, data) {
|
||||||
// Watchout! If you call `this.ensureObj(objId, data)` you're going to
|
// Watchout! If you call `this.ensureObj(objId, data)` you're going to
|
||||||
// create a *resolved* promise which shouldn't be the case!
|
// create a *resolved* promise which shouldn't be the case!
|
||||||
this.ensureObj(objId).data = data;
|
this.ensureObj(objId).data = data;
|
||||||
|
|
|
@ -9,8 +9,8 @@ function isEOF(v) {
|
||||||
return v == EOF;
|
return v == EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
var Parser = (function parserParser() {
|
var Parser = (function ParserClosure() {
|
||||||
function constructor(lexer, allowStreams, xref) {
|
function Parser(lexer, allowStreams, xref) {
|
||||||
this.lexer = lexer;
|
this.lexer = lexer;
|
||||||
this.allowStreams = allowStreams;
|
this.allowStreams = allowStreams;
|
||||||
this.xref = xref;
|
this.xref = xref;
|
||||||
|
@ -18,12 +18,12 @@ var Parser = (function parserParser() {
|
||||||
this.refill();
|
this.refill();
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor.prototype = {
|
Parser.prototype = {
|
||||||
refill: function parserRefill() {
|
refill: function Parser_refill() {
|
||||||
this.buf1 = this.lexer.getObj();
|
this.buf1 = this.lexer.getObj();
|
||||||
this.buf2 = this.lexer.getObj();
|
this.buf2 = this.lexer.getObj();
|
||||||
},
|
},
|
||||||
shift: function parserShift() {
|
shift: function Parser_shift() {
|
||||||
if (isCmd(this.buf2, 'ID')) {
|
if (isCmd(this.buf2, 'ID')) {
|
||||||
this.buf1 = this.buf2;
|
this.buf1 = this.buf2;
|
||||||
this.buf2 = null;
|
this.buf2 = null;
|
||||||
|
@ -34,7 +34,7 @@ var Parser = (function parserParser() {
|
||||||
this.buf2 = this.lexer.getObj();
|
this.buf2 = this.lexer.getObj();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getObj: function parserGetObj(cipherTransform) {
|
getObj: function Parser_getObj(cipherTransform) {
|
||||||
if (isCmd(this.buf1, 'BI')) { // inline image
|
if (isCmd(this.buf1, 'BI')) { // inline image
|
||||||
this.shift();
|
this.shift();
|
||||||
return this.makeInlineImage(cipherTransform);
|
return this.makeInlineImage(cipherTransform);
|
||||||
|
@ -51,18 +51,17 @@ var Parser = (function parserParser() {
|
||||||
}
|
}
|
||||||
if (isCmd(this.buf1, '<<')) { // dictionary or stream
|
if (isCmd(this.buf1, '<<')) { // dictionary or stream
|
||||||
this.shift();
|
this.shift();
|
||||||
var dict = new Dict();
|
var dict = new Dict(this.xref);
|
||||||
while (!isCmd(this.buf1, '>>') && !isEOF(this.buf1)) {
|
while (!isCmd(this.buf1, '>>') && !isEOF(this.buf1)) {
|
||||||
if (!isName(this.buf1)) {
|
if (!isName(this.buf1))
|
||||||
error('Dictionary key must be a name object');
|
error('Dictionary key must be a name object');
|
||||||
} else {
|
|
||||||
var key = this.buf1.name;
|
var key = this.buf1.name;
|
||||||
this.shift();
|
this.shift();
|
||||||
if (isEOF(this.buf1))
|
if (isEOF(this.buf1))
|
||||||
break;
|
break;
|
||||||
dict.set(key, this.getObj(cipherTransform));
|
dict.set(key, this.getObj(cipherTransform));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (isEOF(this.buf1))
|
if (isEOF(this.buf1))
|
||||||
error('End of file inside dictionary');
|
error('End of file inside dictionary');
|
||||||
|
|
||||||
|
@ -99,38 +98,37 @@ var Parser = (function parserParser() {
|
||||||
this.shift();
|
this.shift();
|
||||||
return obj;
|
return obj;
|
||||||
},
|
},
|
||||||
makeInlineImage: function parserMakeInlineImage(cipherTransform) {
|
makeInlineImage: function Parser_makeInlineImage(cipherTransform) {
|
||||||
var lexer = this.lexer;
|
var lexer = this.lexer;
|
||||||
var stream = lexer.stream;
|
var stream = lexer.stream;
|
||||||
|
|
||||||
// parse dictionary
|
// parse dictionary
|
||||||
var dict = new Dict();
|
var dict = new Dict();
|
||||||
while (!isCmd(this.buf1, 'ID') && !isEOF(this.buf1)) {
|
while (!isCmd(this.buf1, 'ID') && !isEOF(this.buf1)) {
|
||||||
if (!isName(this.buf1)) {
|
if (!isName(this.buf1))
|
||||||
error('Dictionary key must be a name object');
|
error('Dictionary key must be a name object');
|
||||||
} else {
|
|
||||||
var key = this.buf1.name;
|
var key = this.buf1.name;
|
||||||
this.shift();
|
this.shift();
|
||||||
if (isEOF(this.buf1))
|
if (isEOF(this.buf1))
|
||||||
break;
|
break;
|
||||||
dict.set(key, this.getObj(cipherTransform));
|
dict.set(key, this.getObj(cipherTransform));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// parse image stream
|
// parse image stream
|
||||||
var startPos = stream.pos;
|
var startPos = stream.pos;
|
||||||
|
|
||||||
// searching for the /\sEI\s/
|
// searching for the /EI\s/
|
||||||
var state = 0, ch;
|
var state = 0, ch;
|
||||||
while (state != 4 && (ch = stream.getByte()) != null) {
|
while (state != 4 && (ch = stream.getByte()) != null) {
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
case 0x20:
|
case 0x20:
|
||||||
case 0x0D:
|
case 0x0D:
|
||||||
case 0x0A:
|
case 0x0A:
|
||||||
state = state === 3 ? 4 : 1;
|
state = state === 3 ? 4 : 0;
|
||||||
break;
|
break;
|
||||||
case 0x45:
|
case 0x45:
|
||||||
state = state === 1 ? 2 : 0;
|
state = 2;
|
||||||
break;
|
break;
|
||||||
case 0x49:
|
case 0x49:
|
||||||
state = state === 2 ? 3 : 0;
|
state = state === 2 ? 3 : 0;
|
||||||
|
@ -157,12 +155,16 @@ var Parser = (function parserParser() {
|
||||||
imageStream = this.filter(imageStream, dict, length);
|
imageStream = this.filter(imageStream, dict, length);
|
||||||
imageStream.parameters = dict;
|
imageStream.parameters = dict;
|
||||||
|
|
||||||
this.buf2 = new Cmd('EI');
|
this.buf2 = Cmd.get('EI');
|
||||||
this.shift();
|
this.shift();
|
||||||
|
|
||||||
return imageStream;
|
return imageStream;
|
||||||
},
|
},
|
||||||
makeStream: function parserMakeStream(dict, cipherTransform) {
|
fetchIfRef: function Parser_fetchIfRef(obj) {
|
||||||
|
// not relying on the xref.fetchIfRef -- xref might not be set
|
||||||
|
return isRef(obj) ? this.xref.fetch(obj) : obj;
|
||||||
|
},
|
||||||
|
makeStream: function Parser_makeStream(dict, cipherTransform) {
|
||||||
var lexer = this.lexer;
|
var lexer = this.lexer;
|
||||||
var stream = lexer.stream;
|
var stream = lexer.stream;
|
||||||
|
|
||||||
|
@ -171,14 +173,9 @@ var Parser = (function parserParser() {
|
||||||
var pos = stream.pos;
|
var pos = stream.pos;
|
||||||
|
|
||||||
// get length
|
// get length
|
||||||
var length = dict.get('Length');
|
var length = this.fetchIfRef(dict.get('Length'));
|
||||||
var xref = this.xref;
|
if (!isInt(length))
|
||||||
if (xref)
|
|
||||||
length = xref.fetchIfRef(length);
|
|
||||||
if (!isInt(length)) {
|
|
||||||
error('Bad ' + length + ' attribute in stream');
|
error('Bad ' + length + ' attribute in stream');
|
||||||
length = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// skip over the stream data
|
// skip over the stream data
|
||||||
stream.pos = pos + length;
|
stream.pos = pos + length;
|
||||||
|
@ -195,9 +192,9 @@ var Parser = (function parserParser() {
|
||||||
stream.parameters = dict;
|
stream.parameters = dict;
|
||||||
return stream;
|
return stream;
|
||||||
},
|
},
|
||||||
filter: function parserFilter(stream, dict, length) {
|
filter: function Parser_filter(stream, dict, length) {
|
||||||
var filter = dict.get('Filter', 'F');
|
var filter = this.fetchIfRef(dict.get('Filter', 'F'));
|
||||||
var params = dict.get('DecodeParms', 'DP');
|
var params = this.fetchIfRef(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)) {
|
||||||
|
@ -207,7 +204,7 @@ var Parser = (function parserParser() {
|
||||||
filter = filterArray[i];
|
filter = filterArray[i];
|
||||||
if (!isName(filter))
|
if (!isName(filter))
|
||||||
error('Bad filter name: ' + filter);
|
error('Bad filter name: ' + filter);
|
||||||
else {
|
|
||||||
params = null;
|
params = null;
|
||||||
if (isArray(paramsArray) && (i in paramsArray))
|
if (isArray(paramsArray) && (i in paramsArray))
|
||||||
params = paramsArray[i];
|
params = paramsArray[i];
|
||||||
|
@ -216,16 +213,16 @@ var Parser = (function parserParser() {
|
||||||
length = null;
|
length = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return stream;
|
return stream;
|
||||||
},
|
},
|
||||||
makeFilter: function parserMakeFilter(stream, name, length, params) {
|
makeFilter: function Parser_makeFilter(stream, name, length, params) {
|
||||||
if (name == 'FlateDecode' || name == 'Fl') {
|
if (name == 'FlateDecode' || name == 'Fl') {
|
||||||
if (params) {
|
if (params) {
|
||||||
return new PredictorStream(new FlateStream(stream), params);
|
return new PredictorStream(new FlateStream(stream), params);
|
||||||
}
|
}
|
||||||
return new FlateStream(stream);
|
return new FlateStream(stream);
|
||||||
} else if (name == 'LZWDecode' || name == 'LZW') {
|
}
|
||||||
|
if (name == 'LZWDecode' || name == 'LZW') {
|
||||||
var earlyChange = 1;
|
var earlyChange = 1;
|
||||||
if (params) {
|
if (params) {
|
||||||
if (params.has('EarlyChange'))
|
if (params.has('EarlyChange'))
|
||||||
|
@ -234,31 +231,41 @@ var Parser = (function parserParser() {
|
||||||
new LZWStream(stream, earlyChange), params);
|
new LZWStream(stream, earlyChange), params);
|
||||||
}
|
}
|
||||||
return new LZWStream(stream, earlyChange);
|
return new LZWStream(stream, earlyChange);
|
||||||
} else if (name == 'DCTDecode' || name == 'DCT') {
|
}
|
||||||
|
if (name == 'DCTDecode' || name == 'DCT') {
|
||||||
var bytes = stream.getBytes(length);
|
var bytes = stream.getBytes(length);
|
||||||
return new JpegStream(bytes, stream.dict, this.xref);
|
return new JpegStream(bytes, stream.dict, this.xref);
|
||||||
} else if (name == 'ASCII85Decode' || name == 'A85') {
|
|
||||||
return new Ascii85Stream(stream);
|
|
||||||
} else if (name == 'ASCIIHexDecode' || name == 'AHx') {
|
|
||||||
return new AsciiHexStream(stream);
|
|
||||||
} else if (name == 'CCITTFaxDecode' || name == 'CCF') {
|
|
||||||
return new CCITTFaxStream(stream, params);
|
|
||||||
} else {
|
|
||||||
TODO('filter "' + name + '" not supported yet');
|
|
||||||
}
|
}
|
||||||
|
if (name == 'JPXDecode' || name == 'JPX') {
|
||||||
|
var bytes = stream.getBytes(length);
|
||||||
|
return new JpxStream(bytes, stream.dict);
|
||||||
|
}
|
||||||
|
if (name == 'ASCII85Decode' || name == 'A85') {
|
||||||
|
return new Ascii85Stream(stream);
|
||||||
|
}
|
||||||
|
if (name == 'ASCIIHexDecode' || name == 'AHx') {
|
||||||
|
return new AsciiHexStream(stream);
|
||||||
|
}
|
||||||
|
if (name == 'CCITTFaxDecode' || name == 'CCF') {
|
||||||
|
return new CCITTFaxStream(stream, params);
|
||||||
|
}
|
||||||
|
if (name == 'RunLengthDecode') {
|
||||||
|
return new RunLengthStream(stream);
|
||||||
|
}
|
||||||
|
warn('filter "' + name + '" not supported yet');
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return constructor;
|
return Parser;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
var Lexer = (function lexer() {
|
var Lexer = (function LexerClosure() {
|
||||||
function constructor(stream) {
|
function Lexer(stream) {
|
||||||
this.stream = stream;
|
this.stream = stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor.isSpace = function lexerIsSpace(ch) {
|
Lexer.isSpace = function Lexer_isSpace(ch) {
|
||||||
return ch == ' ' || ch == '\t' || ch == '\x0d' || ch == '\x0a';
|
return ch == ' ' || ch == '\t' || ch == '\x0d' || ch == '\x0a';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -292,8 +299,8 @@ var Lexer = (function lexer() {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor.prototype = {
|
Lexer.prototype = {
|
||||||
getNumber: function lexerGetNumber(ch) {
|
getNumber: function Lexer_getNumber(ch) {
|
||||||
var floating = false;
|
var floating = false;
|
||||||
var str = ch;
|
var str = ch;
|
||||||
var stream = this.stream;
|
var stream = this.stream;
|
||||||
|
@ -321,7 +328,7 @@ var Lexer = (function lexer() {
|
||||||
error('Invalid floating point number: ' + value);
|
error('Invalid floating point number: ' + value);
|
||||||
return value;
|
return value;
|
||||||
},
|
},
|
||||||
getString: function lexerGetString() {
|
getString: function Lexer_getString() {
|
||||||
var numParen = 1;
|
var numParen = 1;
|
||||||
var done = false;
|
var done = false;
|
||||||
var str = '';
|
var str = '';
|
||||||
|
@ -405,7 +412,7 @@ var Lexer = (function lexer() {
|
||||||
} while (!done);
|
} while (!done);
|
||||||
return str;
|
return str;
|
||||||
},
|
},
|
||||||
getName: function lexerGetName(ch) {
|
getName: function Lexer_getName(ch) {
|
||||||
var str = '';
|
var str = '';
|
||||||
var stream = this.stream;
|
var stream = this.stream;
|
||||||
while (!!(ch = stream.lookChar()) && !specialChars[ch.charCodeAt(0)]) {
|
while (!!(ch = stream.lookChar()) && !specialChars[ch.charCodeAt(0)]) {
|
||||||
|
@ -432,7 +439,7 @@ var Lexer = (function lexer() {
|
||||||
str.length);
|
str.length);
|
||||||
return new Name(str);
|
return new Name(str);
|
||||||
},
|
},
|
||||||
getHexString: function lexerGetHexString(ch) {
|
getHexString: function Lexer_getHexString(ch) {
|
||||||
var str = '';
|
var str = '';
|
||||||
var stream = this.stream;
|
var stream = this.stream;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
@ -461,7 +468,7 @@ var Lexer = (function lexer() {
|
||||||
}
|
}
|
||||||
return str;
|
return str;
|
||||||
},
|
},
|
||||||
getObj: function lexerGetObj() {
|
getObj: function Lexer_getObj() {
|
||||||
// skip whitespace and comments
|
// skip whitespace and comments
|
||||||
var comment = false;
|
var comment = false;
|
||||||
var stream = this.stream;
|
var stream = this.stream;
|
||||||
|
@ -492,14 +499,14 @@ var Lexer = (function lexer() {
|
||||||
// array punctuation
|
// array punctuation
|
||||||
case '[':
|
case '[':
|
||||||
case ']':
|
case ']':
|
||||||
return new Cmd(ch);
|
return Cmd.get(ch);
|
||||||
// hex string or dict punctuation
|
// hex string or dict punctuation
|
||||||
case '<':
|
case '<':
|
||||||
ch = stream.lookChar();
|
ch = stream.lookChar();
|
||||||
if (ch == '<') {
|
if (ch == '<') {
|
||||||
// dict punctuation
|
// dict punctuation
|
||||||
stream.skip();
|
stream.skip();
|
||||||
return new Cmd('<<');
|
return Cmd.get('<<');
|
||||||
}
|
}
|
||||||
return this.getHexString(ch);
|
return this.getHexString(ch);
|
||||||
// dict punctuation
|
// dict punctuation
|
||||||
|
@ -507,25 +514,23 @@ var Lexer = (function lexer() {
|
||||||
ch = stream.lookChar();
|
ch = stream.lookChar();
|
||||||
if (ch == '>') {
|
if (ch == '>') {
|
||||||
stream.skip();
|
stream.skip();
|
||||||
return new Cmd('>>');
|
return Cmd.get('>>');
|
||||||
}
|
}
|
||||||
case '{':
|
case '{':
|
||||||
case '}':
|
case '}':
|
||||||
return new Cmd(ch);
|
return Cmd.get(ch);
|
||||||
// fall through
|
// fall through
|
||||||
case ')':
|
case ')':
|
||||||
error('Illegal character: ' + ch);
|
error('Illegal character: ' + ch);
|
||||||
return Error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// command
|
// command
|
||||||
var str = ch;
|
var str = ch;
|
||||||
while (!!(ch = stream.lookChar()) && !specialChars[ch.charCodeAt(0)]) {
|
while (!!(ch = stream.lookChar()) && !specialChars[ch.charCodeAt(0)]) {
|
||||||
stream.skip();
|
stream.skip();
|
||||||
if (str.length == 128) {
|
if (str.length == 128)
|
||||||
error('Command token too long: ' + str.length);
|
error('Command token too long: ' + str.length);
|
||||||
break;
|
|
||||||
}
|
|
||||||
str += ch;
|
str += ch;
|
||||||
}
|
}
|
||||||
if (str == 'true')
|
if (str == 'true')
|
||||||
|
@ -534,9 +539,9 @@ var Lexer = (function lexer() {
|
||||||
return false;
|
return false;
|
||||||
if (str == 'null')
|
if (str == 'null')
|
||||||
return null;
|
return null;
|
||||||
return new Cmd(str);
|
return Cmd.get(str);
|
||||||
},
|
},
|
||||||
skipToNextLine: function lexerSkipToNextLine() {
|
skipToNextLine: function Lexer_skipToNextLine() {
|
||||||
var stream = this.stream;
|
var stream = this.stream;
|
||||||
while (true) {
|
while (true) {
|
||||||
var ch = stream.getChar();
|
var ch = stream.getChar();
|
||||||
|
@ -549,17 +554,17 @@ var Lexer = (function lexer() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
skip: function lexerSkip() {
|
skip: function Lexer_skip() {
|
||||||
this.stream.skip();
|
this.stream.skip();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return constructor;
|
return Lexer;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
var Linearization = (function linearizationLinearization() {
|
var Linearization = (function LinearizationClosure() {
|
||||||
function constructor(stream) {
|
function Linearization(stream) {
|
||||||
this.parser = new Parser(new Lexer(stream), false);
|
this.parser = new Parser(new Lexer(stream), false, null);
|
||||||
var obj1 = this.parser.getObj();
|
var obj1 = this.parser.getObj();
|
||||||
var obj2 = this.parser.getObj();
|
var obj2 = this.parser.getObj();
|
||||||
var obj3 = this.parser.getObj();
|
var obj3 = this.parser.getObj();
|
||||||
|
@ -572,8 +577,8 @@ var Linearization = (function linearizationLinearization() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor.prototype = {
|
Linearization.prototype = {
|
||||||
getInt: function linearizationGetInt(name) {
|
getInt: function Linearization_getInt(name) {
|
||||||
var linDict = this.linDict;
|
var linDict = this.linDict;
|
||||||
var obj;
|
var obj;
|
||||||
if (isDict(linDict) &&
|
if (isDict(linDict) &&
|
||||||
|
@ -582,9 +587,8 @@ var Linearization = (function linearizationLinearization() {
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
error('"' + name + '" field in linearization table is invalid');
|
error('"' + name + '" field in linearization table is invalid');
|
||||||
return 0;
|
|
||||||
},
|
},
|
||||||
getHint: function linearizationGetHint(index) {
|
getHint: function Linearization_getHint(index) {
|
||||||
var linDict = this.linDict;
|
var linDict = this.linDict;
|
||||||
var obj1, obj2;
|
var obj1, obj2;
|
||||||
if (isDict(linDict) &&
|
if (isDict(linDict) &&
|
||||||
|
@ -595,7 +599,6 @@ var Linearization = (function linearizationLinearization() {
|
||||||
return obj2;
|
return obj2;
|
||||||
}
|
}
|
||||||
error('Hints table in linearization table is invalid: ' + index);
|
error('Hints table in linearization table is invalid: ' + index);
|
||||||
return 0;
|
|
||||||
},
|
},
|
||||||
get length() {
|
get length() {
|
||||||
if (!isDict(this.linDict))
|
if (!isDict(this.linDict))
|
||||||
|
@ -631,6 +634,6 @@ var Linearization = (function linearizationLinearization() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return constructor;
|
return Linearization;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
|
|
@ -3,48 +3,53 @@
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var Pattern = (function patternPattern() {
|
var PatternType = {
|
||||||
|
AXIAL: 2,
|
||||||
|
RADIAL: 3
|
||||||
|
};
|
||||||
|
|
||||||
|
var Pattern = (function PatternClosure() {
|
||||||
// Constructor should define this.getPattern
|
// Constructor should define this.getPattern
|
||||||
function constructor() {
|
function Pattern() {
|
||||||
error('should not call Pattern constructor');
|
error('should not call Pattern constructor');
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor.prototype = {
|
Pattern.prototype = {
|
||||||
// Input: current Canvas context
|
// Input: current Canvas context
|
||||||
// Output: the appropriate fillStyle or strokeStyle
|
// Output: the appropriate fillStyle or strokeStyle
|
||||||
getPattern: function pattern_getStyle(ctx) {
|
getPattern: function Pattern_getPattern(ctx) {
|
||||||
error('Should not call Pattern.getStyle: ' + ctx);
|
error('Should not call Pattern.getStyle: ' + ctx);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor.shadingFromIR = function pattern_shadingFromIR(ctx, raw) {
|
Pattern.shadingFromIR = function Pattern_shadingFromIR(raw) {
|
||||||
return Shadings[raw[0]].fromIR(ctx, raw);
|
return Shadings[raw[0]].fromIR(raw);
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor.parseShading = function pattern_shading(shading, matrix, xref,
|
Pattern.parseShading = function Pattern_parseShading(shading, matrix, xref,
|
||||||
res, ctx) {
|
res) {
|
||||||
|
|
||||||
var dict = isStream(shading) ? shading.dict : shading;
|
var dict = isStream(shading) ? shading.dict : shading;
|
||||||
var type = dict.get('ShadingType');
|
var type = dict.get('ShadingType');
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 2:
|
case PatternType.AXIAL:
|
||||||
case 3:
|
case PatternType.RADIAL:
|
||||||
// both radial and axial shadings are handled by RadialAxial shading
|
// Both radial and axial shadings are handled by RadialAxial shading.
|
||||||
return new Shadings.RadialAxial(dict, matrix, xref, res, ctx);
|
return new Shadings.RadialAxial(dict, matrix, xref, res);
|
||||||
default:
|
default:
|
||||||
return new Shadings.Dummy();
|
return new Shadings.Dummy();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return constructor;
|
return Pattern;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
var Shadings = {};
|
var Shadings = {};
|
||||||
|
|
||||||
// Radial and axial shading have very similar implementations
|
// Radial and axial shading have very similar implementations
|
||||||
// If needed, the implementations can be broken into two classes
|
// If needed, the implementations can be broken into two classes
|
||||||
Shadings.RadialAxial = (function radialAxialShading() {
|
Shadings.RadialAxial = (function RadialAxialClosure() {
|
||||||
function constructor(dict, matrix, xref, res, ctx) {
|
function RadialAxial(dict, matrix, xref, res, ctx) {
|
||||||
this.matrix = matrix;
|
this.matrix = matrix;
|
||||||
this.coordsArr = dict.get('Coords');
|
this.coordsArr = dict.get('Coords');
|
||||||
this.shadingType = dict.get('ShadingType');
|
this.shadingType = dict.get('ShadingType');
|
||||||
|
@ -74,10 +79,9 @@ Shadings.RadialAxial = (function radialAxialShading() {
|
||||||
this.extendEnd = extendEnd;
|
this.extendEnd = extendEnd;
|
||||||
|
|
||||||
var fnObj = dict.get('Function');
|
var fnObj = dict.get('Function');
|
||||||
fnObj = xref.fetchIfRef(fnObj);
|
|
||||||
if (isArray(fnObj))
|
if (isArray(fnObj))
|
||||||
error('No support for array of functions');
|
error('No support for array of functions');
|
||||||
else if (!isPDFFunction(fnObj))
|
if (!isPDFFunction(fnObj))
|
||||||
error('Invalid function');
|
error('Invalid function');
|
||||||
var fn = PDFFunction.parse(xref, fnObj);
|
var fn = PDFFunction.parse(xref, fnObj);
|
||||||
|
|
||||||
|
@ -89,22 +93,24 @@ Shadings.RadialAxial = (function radialAxialShading() {
|
||||||
|
|
||||||
var colorStops = [];
|
var colorStops = [];
|
||||||
for (var i = t0; i <= t1; i += step) {
|
for (var i = t0; i <= t1; i += step) {
|
||||||
var color = fn([i]);
|
var rgbColor = cs.getRgb(fn([i]));
|
||||||
var rgbColor = Util.makeCssRgb.apply(this, cs.getRgb(color));
|
var cssColor = Util.makeCssRgb(rgbColor[0], rgbColor[1], rgbColor[2]);
|
||||||
colorStops.push([(i - t0) / diff, rgbColor]);
|
colorStops.push([(i - t0) / diff, cssColor]);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.colorStops = colorStops;
|
this.colorStops = colorStops;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor.fromIR = function radialAxialShadingGetIR(ctx, raw) {
|
RadialAxial.fromIR = function RadialAxial_fromIR(raw) {
|
||||||
var type = raw[1];
|
var type = raw[1];
|
||||||
var colorStops = raw[2];
|
var colorStops = raw[2];
|
||||||
var p0 = raw[3];
|
var p0 = raw[3];
|
||||||
var p1 = raw[4];
|
var p1 = raw[4];
|
||||||
var r0 = raw[5];
|
var r0 = raw[5];
|
||||||
var r1 = raw[6];
|
var r1 = raw[6];
|
||||||
|
return {
|
||||||
|
type: 'Pattern',
|
||||||
|
getPattern: function(ctx) {
|
||||||
var curMatrix = ctx.mozCurrentTransform;
|
var curMatrix = ctx.mozCurrentTransform;
|
||||||
if (curMatrix) {
|
if (curMatrix) {
|
||||||
var userMatrix = ctx.mozCurrentTransformInverse;
|
var userMatrix = ctx.mozCurrentTransformInverse;
|
||||||
|
@ -117,9 +123,9 @@ Shadings.RadialAxial = (function radialAxialShading() {
|
||||||
}
|
}
|
||||||
|
|
||||||
var grad;
|
var grad;
|
||||||
if (type == 2)
|
if (type == PatternType.AXIAL)
|
||||||
grad = ctx.createLinearGradient(p0[0], p0[1], p1[0], p1[1]);
|
grad = ctx.createLinearGradient(p0[0], p0[1], p1[0], p1[1]);
|
||||||
else if (type == 3)
|
else if (type == PatternType.RADIAL)
|
||||||
grad = ctx.createRadialGradient(p0[0], p0[1], r0, p1[0], p1[1], r1);
|
grad = ctx.createRadialGradient(p0[0], p0[1], r0, p1[0], p1[1], r1);
|
||||||
|
|
||||||
for (var i = 0, ii = colorStops.length; i < ii; ++i) {
|
for (var i = 0, ii = colorStops.length; i < ii; ++i) {
|
||||||
|
@ -127,18 +133,20 @@ Shadings.RadialAxial = (function radialAxialShading() {
|
||||||
grad.addColorStop(c[0], c[1]);
|
grad.addColorStop(c[0], c[1]);
|
||||||
}
|
}
|
||||||
return grad;
|
return grad;
|
||||||
|
}
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor.prototype = {
|
RadialAxial.prototype = {
|
||||||
getIR: function radialAxialShadingGetIR() {
|
getIR: function RadialAxial_getIR() {
|
||||||
var coordsArr = this.coordsArr;
|
var coordsArr = this.coordsArr;
|
||||||
var type = this.shadingType;
|
var type = this.shadingType;
|
||||||
if (type == 2) {
|
if (type == PatternType.AXIAL) {
|
||||||
var p0 = [coordsArr[0], coordsArr[1]];
|
var p0 = [coordsArr[0], coordsArr[1]];
|
||||||
var p1 = [coordsArr[2], coordsArr[3]];
|
var p1 = [coordsArr[2], coordsArr[3]];
|
||||||
var r0 = null;
|
var r0 = null;
|
||||||
var r1 = null;
|
var r1 = null;
|
||||||
} else if (type == 3) {
|
} else if (type == PatternType.RADIAL) {
|
||||||
var p0 = [coordsArr[0], coordsArr[1]];
|
var p0 = [coordsArr[0], coordsArr[1]];
|
||||||
var p1 = [coordsArr[3], coordsArr[4]];
|
var p1 = [coordsArr[3], coordsArr[4]];
|
||||||
var r0 = coordsArr[2];
|
var r0 = coordsArr[2];
|
||||||
|
@ -157,31 +165,35 @@ Shadings.RadialAxial = (function radialAxialShading() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return constructor;
|
return RadialAxial;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
Shadings.Dummy = (function dummyShading() {
|
Shadings.Dummy = (function DummyClosure() {
|
||||||
function constructor() {
|
function Dummy() {
|
||||||
this.type = 'Pattern';
|
this.type = 'Pattern';
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor.fromIR = function dummyShadingFromIR() {
|
Dummy.fromIR = function Dummy_fromIR() {
|
||||||
return 'hotpink';
|
return 'hotpink';
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor.prototype = {
|
Dummy.prototype = {
|
||||||
getIR: function dummyShadingGetIR() {
|
getIR: function Dummy_getIR() {
|
||||||
return ['Dummy'];
|
return ['Dummy'];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return constructor;
|
return Dummy;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
var TilingPattern = (function tilingPattern() {
|
var TilingPattern = (function TilingPatternClosure() {
|
||||||
var PAINT_TYPE_COLORED = 1, PAINT_TYPE_UNCOLORED = 2;
|
var PaintType = {
|
||||||
|
COLORED: 1,
|
||||||
|
UNCOLORED: 2
|
||||||
|
};
|
||||||
|
var MAX_PATTERN_SIZE = 512;
|
||||||
|
|
||||||
function TilingPattern(IR, color, ctx, objs) {
|
function TilingPattern(IR, color, ctx, objs) {
|
||||||
var IRQueue = IR[2];
|
var operatorList = IR[2];
|
||||||
this.matrix = IR[3];
|
this.matrix = IR[3];
|
||||||
var bbox = IR[4];
|
var bbox = IR[4];
|
||||||
var xstep = IR[5];
|
var xstep = IR[5];
|
||||||
|
@ -204,30 +216,30 @@ var TilingPattern = (function tilingPattern() {
|
||||||
var width = botRight[0] - topLeft[0];
|
var width = botRight[0] - topLeft[0];
|
||||||
var height = botRight[1] - topLeft[1];
|
var height = botRight[1] - topLeft[1];
|
||||||
|
|
||||||
// TODO: hack to avoid OOM, we would idealy compute the tiling
|
// TODO: hack to avoid OOM, we would ideally compute the tiling
|
||||||
// pattern to be only as large as the acual size in device space
|
// pattern to be only as large as the acual size in device space
|
||||||
// This could be computed with .mozCurrentTransform, but still
|
// This could be computed with .mozCurrentTransform, but still
|
||||||
// needs to be implemented
|
// needs to be implemented
|
||||||
while (Math.abs(width) > 512 || Math.abs(height) > 512) {
|
while (Math.abs(width) > MAX_PATTERN_SIZE ||
|
||||||
width = 512;
|
Math.abs(height) > MAX_PATTERN_SIZE) {
|
||||||
height = 512;
|
width = height = MAX_PATTERN_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
var tmpCanvas = new ScratchCanvas(width, height);
|
var tmpCanvas = createScratchCanvas(width, height);
|
||||||
|
|
||||||
// set the new canvas element context as the graphics context
|
// set the new canvas element context as the graphics context
|
||||||
var tmpCtx = tmpCanvas.getContext('2d');
|
var tmpCtx = tmpCanvas.getContext('2d');
|
||||||
var graphics = new CanvasGraphics(tmpCtx, objs);
|
var graphics = new CanvasGraphics(tmpCtx, objs);
|
||||||
|
|
||||||
switch (paintType) {
|
switch (paintType) {
|
||||||
case PAINT_TYPE_COLORED:
|
case PaintType.COLORED:
|
||||||
tmpCtx.fillStyle = ctx.fillStyle;
|
tmpCtx.fillStyle = ctx.fillStyle;
|
||||||
tmpCtx.strokeStyle = ctx.strokeStyle;
|
tmpCtx.strokeStyle = ctx.strokeStyle;
|
||||||
break;
|
break;
|
||||||
case PAINT_TYPE_UNCOLORED:
|
case PaintType.UNCOLORED:
|
||||||
color = Util.makeCssRgb.apply(this, color);
|
var cssColor = Util.makeCssRgb(this, color[0], color[1], color[2]);
|
||||||
tmpCtx.fillStyle = color;
|
tmpCtx.fillStyle = cssColor;
|
||||||
tmpCtx.strokeStyle = color;
|
tmpCtx.strokeStyle = cssColor;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
error('Unsupported paint type: ' + paintType);
|
error('Unsupported paint type: ' + paintType);
|
||||||
|
@ -250,12 +262,12 @@ var TilingPattern = (function tilingPattern() {
|
||||||
graphics.endPath();
|
graphics.endPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
graphics.executeIRQueue(IRQueue);
|
graphics.executeOperatorList(operatorList);
|
||||||
|
|
||||||
this.canvas = tmpCanvas;
|
this.canvas = tmpCanvas;
|
||||||
}
|
}
|
||||||
|
|
||||||
TilingPattern.getIR = function tiling_getIR(codeIR, dict, args) {
|
TilingPattern.getIR = function TilingPattern_getIR(operatorList, dict, args) {
|
||||||
var matrix = dict.get('Matrix');
|
var matrix = dict.get('Matrix');
|
||||||
var bbox = dict.get('BBox');
|
var bbox = dict.get('BBox');
|
||||||
var xstep = dict.get('XStep');
|
var xstep = dict.get('XStep');
|
||||||
|
@ -263,12 +275,12 @@ var TilingPattern = (function tilingPattern() {
|
||||||
var paintType = dict.get('PaintType');
|
var paintType = dict.get('PaintType');
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'TilingPattern', args, codeIR, matrix, bbox, xstep, ystep, paintType
|
'TilingPattern', args, operatorList, matrix, bbox, xstep, ystep, paintType
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
TilingPattern.prototype = {
|
TilingPattern.prototype = {
|
||||||
getPattern: function tiling_getPattern() {
|
getPattern: function TilingPattern_getPattern() {
|
||||||
var matrix = this.matrix;
|
var matrix = this.matrix;
|
||||||
var curMatrix = this.curMatrix;
|
var curMatrix = this.curMatrix;
|
||||||
var ctx = this.ctx;
|
var ctx = this.ctx;
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var Stream = (function streamStream() {
|
var Stream = (function StreamClosure() {
|
||||||
function constructor(arrayBuffer, start, length, dict) {
|
function Stream(arrayBuffer, start, length, dict) {
|
||||||
this.bytes = new Uint8Array(arrayBuffer);
|
this.bytes = new Uint8Array(arrayBuffer);
|
||||||
this.start = start || 0;
|
this.start = start || 0;
|
||||||
this.pos = this.start;
|
this.pos = this.start;
|
||||||
|
@ -14,18 +14,18 @@ var Stream = (function streamStream() {
|
||||||
|
|
||||||
// required methods for a stream. if a particular stream does not
|
// required methods for a stream. if a particular stream does not
|
||||||
// implement these, an error should be thrown
|
// implement these, an error should be thrown
|
||||||
constructor.prototype = {
|
Stream.prototype = {
|
||||||
get length() {
|
get length() {
|
||||||
return this.end - this.start;
|
return this.end - this.start;
|
||||||
},
|
},
|
||||||
getByte: function stream_getByte() {
|
getByte: function Stream_getByte() {
|
||||||
if (this.pos >= this.end)
|
if (this.pos >= this.end)
|
||||||
return null;
|
return null;
|
||||||
return this.bytes[this.pos++];
|
return this.bytes[this.pos++];
|
||||||
},
|
},
|
||||||
// returns subarray of original buffer
|
// returns subarray of original buffer
|
||||||
// should only be read
|
// should only be read
|
||||||
getBytes: function stream_getBytes(length) {
|
getBytes: function Stream_getBytes(length) {
|
||||||
var bytes = this.bytes;
|
var bytes = this.bytes;
|
||||||
var pos = this.pos;
|
var pos = this.pos;
|
||||||
var strEnd = this.end;
|
var strEnd = this.end;
|
||||||
|
@ -40,38 +40,38 @@ var Stream = (function streamStream() {
|
||||||
this.pos = end;
|
this.pos = end;
|
||||||
return bytes.subarray(pos, end);
|
return bytes.subarray(pos, end);
|
||||||
},
|
},
|
||||||
lookChar: function stream_lookChar() {
|
lookChar: function Stream_lookChar() {
|
||||||
if (this.pos >= this.end)
|
if (this.pos >= this.end)
|
||||||
return null;
|
return null;
|
||||||
return String.fromCharCode(this.bytes[this.pos]);
|
return String.fromCharCode(this.bytes[this.pos]);
|
||||||
},
|
},
|
||||||
getChar: function stream_getChar() {
|
getChar: function Stream_getChar() {
|
||||||
if (this.pos >= this.end)
|
if (this.pos >= this.end)
|
||||||
return null;
|
return null;
|
||||||
return String.fromCharCode(this.bytes[this.pos++]);
|
return String.fromCharCode(this.bytes[this.pos++]);
|
||||||
},
|
},
|
||||||
skip: function stream_skip(n) {
|
skip: function Stream_skip(n) {
|
||||||
if (!n)
|
if (!n)
|
||||||
n = 1;
|
n = 1;
|
||||||
this.pos += n;
|
this.pos += n;
|
||||||
},
|
},
|
||||||
reset: function stream_reset() {
|
reset: function Stream_reset() {
|
||||||
this.pos = this.start;
|
this.pos = this.start;
|
||||||
},
|
},
|
||||||
moveStart: function stream_moveStart() {
|
moveStart: function Stream_moveStart() {
|
||||||
this.start = this.pos;
|
this.start = this.pos;
|
||||||
},
|
},
|
||||||
makeSubStream: function stream_makeSubstream(start, length, dict) {
|
makeSubStream: function Stream_makeSubStream(start, length, dict) {
|
||||||
return new Stream(this.bytes.buffer, start, length, dict);
|
return new Stream(this.bytes.buffer, start, length, dict);
|
||||||
},
|
},
|
||||||
isStream: true
|
isStream: true
|
||||||
};
|
};
|
||||||
|
|
||||||
return constructor;
|
return Stream;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
var StringStream = (function stringStream() {
|
var StringStream = (function StringStreamClosure() {
|
||||||
function constructor(str) {
|
function StringStream(str) {
|
||||||
var length = str.length;
|
var length = str.length;
|
||||||
var bytes = new Uint8Array(length);
|
var bytes = new Uint8Array(length);
|
||||||
for (var n = 0; n < length; ++n)
|
for (var n = 0; n < length; ++n)
|
||||||
|
@ -79,22 +79,22 @@ var StringStream = (function stringStream() {
|
||||||
Stream.call(this, bytes);
|
Stream.call(this, bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor.prototype = Stream.prototype;
|
StringStream.prototype = Stream.prototype;
|
||||||
|
|
||||||
return constructor;
|
return StringStream;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
// super class for the decoding streams
|
// super class for the decoding streams
|
||||||
var DecodeStream = (function decodeStream() {
|
var DecodeStream = (function DecodeStreamClosure() {
|
||||||
function constructor() {
|
function DecodeStream() {
|
||||||
this.pos = 0;
|
this.pos = 0;
|
||||||
this.bufferLength = 0;
|
this.bufferLength = 0;
|
||||||
this.eof = false;
|
this.eof = false;
|
||||||
this.buffer = null;
|
this.buffer = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor.prototype = {
|
DecodeStream.prototype = {
|
||||||
ensureBuffer: function decodestream_ensureBuffer(requested) {
|
ensureBuffer: function DecodeStream_ensureBuffer(requested) {
|
||||||
var buffer = this.buffer;
|
var buffer = this.buffer;
|
||||||
var current = buffer ? buffer.byteLength : 0;
|
var current = buffer ? buffer.byteLength : 0;
|
||||||
if (requested < current)
|
if (requested < current)
|
||||||
|
@ -107,7 +107,7 @@ var DecodeStream = (function decodeStream() {
|
||||||
buffer2[i] = buffer[i];
|
buffer2[i] = buffer[i];
|
||||||
return (this.buffer = buffer2);
|
return (this.buffer = buffer2);
|
||||||
},
|
},
|
||||||
getByte: function decodestream_getByte() {
|
getByte: function DecodeStream_getByte() {
|
||||||
var pos = this.pos;
|
var pos = this.pos;
|
||||||
while (this.bufferLength <= pos) {
|
while (this.bufferLength <= pos) {
|
||||||
if (this.eof)
|
if (this.eof)
|
||||||
|
@ -116,7 +116,7 @@ var DecodeStream = (function decodeStream() {
|
||||||
}
|
}
|
||||||
return this.buffer[this.pos++];
|
return this.buffer[this.pos++];
|
||||||
},
|
},
|
||||||
getBytes: function decodestream_getBytes(length) {
|
getBytes: function DecodeStream_getBytes(length) {
|
||||||
var end, pos = this.pos;
|
var end, pos = this.pos;
|
||||||
|
|
||||||
if (length) {
|
if (length) {
|
||||||
|
@ -144,7 +144,7 @@ var DecodeStream = (function decodeStream() {
|
||||||
this.pos = end;
|
this.pos = end;
|
||||||
return this.buffer.subarray(pos, end);
|
return this.buffer.subarray(pos, end);
|
||||||
},
|
},
|
||||||
lookChar: function decodestream_lookChar() {
|
lookChar: function DecodeStream_lookChar() {
|
||||||
var pos = this.pos;
|
var pos = this.pos;
|
||||||
while (this.bufferLength <= pos) {
|
while (this.bufferLength <= pos) {
|
||||||
if (this.eof)
|
if (this.eof)
|
||||||
|
@ -153,7 +153,7 @@ var DecodeStream = (function decodeStream() {
|
||||||
}
|
}
|
||||||
return String.fromCharCode(this.buffer[this.pos]);
|
return String.fromCharCode(this.buffer[this.pos]);
|
||||||
},
|
},
|
||||||
getChar: function decodestream_getChar() {
|
getChar: function DecodeStream_getChar() {
|
||||||
var pos = this.pos;
|
var pos = this.pos;
|
||||||
while (this.bufferLength <= pos) {
|
while (this.bufferLength <= pos) {
|
||||||
if (this.eof)
|
if (this.eof)
|
||||||
|
@ -162,40 +162,40 @@ var DecodeStream = (function decodeStream() {
|
||||||
}
|
}
|
||||||
return String.fromCharCode(this.buffer[this.pos++]);
|
return String.fromCharCode(this.buffer[this.pos++]);
|
||||||
},
|
},
|
||||||
makeSubStream: function decodestream_makeSubstream(start, length, dict) {
|
makeSubStream: function DecodeStream_makeSubStream(start, length, dict) {
|
||||||
var end = start + length;
|
var end = start + length;
|
||||||
while (this.bufferLength <= end && !this.eof)
|
while (this.bufferLength <= end && !this.eof)
|
||||||
this.readBlock();
|
this.readBlock();
|
||||||
return new Stream(this.buffer, start, length, dict);
|
return new Stream(this.buffer, start, length, dict);
|
||||||
},
|
},
|
||||||
skip: function decodestream_skip(n) {
|
skip: function DecodeStream_skip(n) {
|
||||||
if (!n)
|
if (!n)
|
||||||
n = 1;
|
n = 1;
|
||||||
this.pos += n;
|
this.pos += n;
|
||||||
},
|
},
|
||||||
reset: function decodestream_reset() {
|
reset: function DecodeStream_reset() {
|
||||||
this.pos = 0;
|
this.pos = 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return constructor;
|
return DecodeStream;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
var FakeStream = (function fakeStream() {
|
var FakeStream = (function FakeStreamClosure() {
|
||||||
function constructor(stream) {
|
function FakeStream(stream) {
|
||||||
this.dict = stream.dict;
|
this.dict = stream.dict;
|
||||||
DecodeStream.call(this);
|
DecodeStream.call(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor.prototype = Object.create(DecodeStream.prototype);
|
FakeStream.prototype = Object.create(DecodeStream.prototype);
|
||||||
constructor.prototype.readBlock = function fakeStreamReadBlock() {
|
FakeStream.prototype.readBlock = function FakeStream_readBlock() {
|
||||||
var bufferLength = this.bufferLength;
|
var bufferLength = this.bufferLength;
|
||||||
bufferLength += 1024;
|
bufferLength += 1024;
|
||||||
var buffer = this.ensureBuffer(bufferLength);
|
var buffer = this.ensureBuffer(bufferLength);
|
||||||
this.bufferLength = bufferLength;
|
this.bufferLength = bufferLength;
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor.prototype.getBytes = function fakeStreamGetBytes(length) {
|
FakeStream.prototype.getBytes = function FakeStream_getBytes(length) {
|
||||||
var end, pos = this.pos;
|
var end, pos = this.pos;
|
||||||
|
|
||||||
if (length) {
|
if (length) {
|
||||||
|
@ -217,18 +217,20 @@ var FakeStream = (function fakeStream() {
|
||||||
return this.buffer.subarray(pos, end);
|
return this.buffer.subarray(pos, end);
|
||||||
};
|
};
|
||||||
|
|
||||||
return constructor;
|
return FakeStream;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
var StreamsSequenceStream = (function streamSequenceStream() {
|
var StreamsSequenceStream = (function StreamsSequenceStreamClosure() {
|
||||||
function constructor(streams) {
|
function StreamsSequenceStream(streams) {
|
||||||
this.streams = streams;
|
this.streams = streams;
|
||||||
DecodeStream.call(this);
|
DecodeStream.call(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor.prototype = Object.create(DecodeStream.prototype);
|
StreamsSequenceStream.prototype = Object.create(DecodeStream.prototype);
|
||||||
|
|
||||||
|
StreamsSequenceStream.prototype.readBlock =
|
||||||
|
function streamSequenceStreamReadBlock() {
|
||||||
|
|
||||||
constructor.prototype.readBlock = function streamSequenceStreamReadBlock() {
|
|
||||||
var streams = this.streams;
|
var streams = this.streams;
|
||||||
if (streams.length == 0) {
|
if (streams.length == 0) {
|
||||||
this.eof = true;
|
this.eof = true;
|
||||||
|
@ -243,10 +245,10 @@ var StreamsSequenceStream = (function streamSequenceStream() {
|
||||||
this.bufferLength = newLength;
|
this.bufferLength = newLength;
|
||||||
};
|
};
|
||||||
|
|
||||||
return constructor;
|
return StreamsSequenceStream;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
var FlateStream = (function flateStream() {
|
var FlateStream = (function FlateStreamClosure() {
|
||||||
var codeLenCodeMap = new Uint32Array([
|
var codeLenCodeMap = new Uint32Array([
|
||||||
16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
|
16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
|
||||||
]);
|
]);
|
||||||
|
@ -339,7 +341,7 @@ var FlateStream = (function flateStream() {
|
||||||
0x50003, 0x50013, 0x5000b, 0x5001b, 0x50007, 0x50017, 0x5000f, 0x00000
|
0x50003, 0x50013, 0x5000b, 0x5001b, 0x50007, 0x50017, 0x5000f, 0x00000
|
||||||
]), 5];
|
]), 5];
|
||||||
|
|
||||||
function constructor(stream) {
|
function FlateStream(stream) {
|
||||||
var bytes = stream.getBytes();
|
var bytes = stream.getBytes();
|
||||||
var bytesPos = 0;
|
var bytesPos = 0;
|
||||||
|
|
||||||
|
@ -364,9 +366,9 @@ var FlateStream = (function flateStream() {
|
||||||
DecodeStream.call(this);
|
DecodeStream.call(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor.prototype = Object.create(DecodeStream.prototype);
|
FlateStream.prototype = Object.create(DecodeStream.prototype);
|
||||||
|
|
||||||
constructor.prototype.getBits = function flateStreamGetBits(bits) {
|
FlateStream.prototype.getBits = function FlateStream_getBits(bits) {
|
||||||
var codeSize = this.codeSize;
|
var codeSize = this.codeSize;
|
||||||
var codeBuf = this.codeBuf;
|
var codeBuf = this.codeBuf;
|
||||||
var bytes = this.bytes;
|
var bytes = this.bytes;
|
||||||
|
@ -386,7 +388,7 @@ var FlateStream = (function flateStream() {
|
||||||
return b;
|
return b;
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor.prototype.getCode = function flateStreamGetCode(table) {
|
FlateStream.prototype.getCode = function FlateStream_getCode(table) {
|
||||||
var codes = table[0];
|
var codes = table[0];
|
||||||
var maxLen = table[1];
|
var maxLen = table[1];
|
||||||
var codeSize = this.codeSize;
|
var codeSize = this.codeSize;
|
||||||
|
@ -412,7 +414,7 @@ var FlateStream = (function flateStream() {
|
||||||
return codeVal;
|
return codeVal;
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor.prototype.generateHuffmanTable =
|
FlateStream.prototype.generateHuffmanTable =
|
||||||
function flateStreamGenerateHuffmanTable(lengths) {
|
function flateStreamGenerateHuffmanTable(lengths) {
|
||||||
var n = lengths.length;
|
var n = lengths.length;
|
||||||
|
|
||||||
|
@ -451,7 +453,7 @@ var FlateStream = (function flateStream() {
|
||||||
return [codes, maxLen];
|
return [codes, maxLen];
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor.prototype.readBlock = function flateStreamReadBlock() {
|
FlateStream.prototype.readBlock = function FlateStream_readBlock() {
|
||||||
// read block header
|
// read block header
|
||||||
var hdr = this.getBits(3);
|
var hdr = this.getBits(3);
|
||||||
if (hdr & 1)
|
if (hdr & 1)
|
||||||
|
@ -582,11 +584,11 @@ var FlateStream = (function flateStream() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return constructor;
|
return FlateStream;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
var PredictorStream = (function predictorStream() {
|
var PredictorStream = (function PredictorStreamClosure() {
|
||||||
function constructor(stream, params) {
|
function PredictorStream(stream, params) {
|
||||||
var predictor = this.predictor = params.get('Predictor') || 1;
|
var predictor = this.predictor = params.get('Predictor') || 1;
|
||||||
|
|
||||||
if (predictor <= 1)
|
if (predictor <= 1)
|
||||||
|
@ -613,15 +615,14 @@ var PredictorStream = (function predictorStream() {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor.prototype = Object.create(DecodeStream.prototype);
|
PredictorStream.prototype = Object.create(DecodeStream.prototype);
|
||||||
|
|
||||||
constructor.prototype.readBlockTiff =
|
PredictorStream.prototype.readBlockTiff =
|
||||||
function predictorStreamReadBlockTiff() {
|
function predictorStreamReadBlockTiff() {
|
||||||
var rowBytes = this.rowBytes;
|
var rowBytes = this.rowBytes;
|
||||||
|
|
||||||
var bufferLength = this.bufferLength;
|
var bufferLength = this.bufferLength;
|
||||||
var buffer = this.ensureBuffer(bufferLength + rowBytes);
|
var buffer = this.ensureBuffer(bufferLength + rowBytes);
|
||||||
var currentRow = buffer.subarray(bufferLength, bufferLength + rowBytes);
|
|
||||||
|
|
||||||
var bits = this.bits;
|
var bits = this.bits;
|
||||||
var colors = this.colors;
|
var colors = this.colors;
|
||||||
|
@ -630,6 +631,7 @@ var PredictorStream = (function predictorStream() {
|
||||||
|
|
||||||
var inbuf = 0, outbuf = 0;
|
var inbuf = 0, outbuf = 0;
|
||||||
var inbits = 0, outbits = 0;
|
var inbits = 0, outbits = 0;
|
||||||
|
var pos = bufferLength;
|
||||||
|
|
||||||
if (bits === 1) {
|
if (bits === 1) {
|
||||||
for (var i = 0; i < rowBytes; ++i) {
|
for (var i = 0; i < rowBytes; ++i) {
|
||||||
|
@ -637,19 +639,21 @@ var PredictorStream = (function predictorStream() {
|
||||||
inbuf = (inbuf << 8) | c;
|
inbuf = (inbuf << 8) | c;
|
||||||
// bitwise addition is exclusive or
|
// bitwise addition is exclusive or
|
||||||
// first shift inbuf and then add
|
// first shift inbuf and then add
|
||||||
currentRow[i] = (c ^ (inbuf >> colors)) & 0xFF;
|
buffer[pos++] = (c ^ (inbuf >> colors)) & 0xFF;
|
||||||
// truncate inbuf (assumes colors < 16)
|
// truncate inbuf (assumes colors < 16)
|
||||||
inbuf &= 0xFFFF;
|
inbuf &= 0xFFFF;
|
||||||
}
|
}
|
||||||
} else if (bits === 8) {
|
} else if (bits === 8) {
|
||||||
for (var i = 0; i < colors; ++i)
|
for (var i = 0; i < colors; ++i)
|
||||||
currentRow[i] = rawBytes[i];
|
buffer[pos++] = rawBytes[i];
|
||||||
for (; i < rowBytes; ++i)
|
for (; i < rowBytes; ++i) {
|
||||||
currentRow[i] = currentRow[i - colors] + rawBytes[i];
|
buffer[pos] = buffer[pos - colors] + rawBytes[i];
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
var compArray = new Uint8Array(colors + 1);
|
var compArray = new Uint8Array(colors + 1);
|
||||||
var bitMask = (1 << bits) - 1;
|
var bitMask = (1 << bits) - 1;
|
||||||
var j = 0, k = 0;
|
var j = 0, k = bufferLength;
|
||||||
var columns = this.columns;
|
var columns = this.columns;
|
||||||
for (var i = 0; i < columns; ++i) {
|
for (var i = 0; i < columns; ++i) {
|
||||||
for (var kk = 0; kk < colors; ++kk) {
|
for (var kk = 0; kk < colors; ++kk) {
|
||||||
|
@ -663,20 +667,22 @@ var PredictorStream = (function predictorStream() {
|
||||||
outbuf = (outbuf << bits) | compArray[kk];
|
outbuf = (outbuf << bits) | compArray[kk];
|
||||||
outbits += bits;
|
outbits += bits;
|
||||||
if (outbits >= 8) {
|
if (outbits >= 8) {
|
||||||
currentRow[k++] = (outbuf >> (outbits - 8)) & 0xFF;
|
buffer[k++] = (outbuf >> (outbits - 8)) & 0xFF;
|
||||||
outbits -= 8;
|
outbits -= 8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (outbits > 0) {
|
if (outbits > 0) {
|
||||||
currentRow[k++] = (outbuf << (8 - outbits)) +
|
buffer[k++] = (outbuf << (8 - outbits)) +
|
||||||
(inbuf & ((1 << (8 - outbits)) - 1));
|
(inbuf & ((1 << (8 - outbits)) - 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.bufferLength += rowBytes;
|
this.bufferLength += rowBytes;
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor.prototype.readBlockPng = function predictorStreamReadBlockPng() {
|
PredictorStream.prototype.readBlockPng =
|
||||||
|
function predictorStreamReadBlockPng() {
|
||||||
|
|
||||||
var rowBytes = this.rowBytes;
|
var rowBytes = this.rowBytes;
|
||||||
var pixBytes = this.pixBytes;
|
var pixBytes = this.pixBytes;
|
||||||
|
|
||||||
|
@ -686,32 +692,35 @@ var PredictorStream = (function predictorStream() {
|
||||||
var bufferLength = this.bufferLength;
|
var bufferLength = this.bufferLength;
|
||||||
var buffer = this.ensureBuffer(bufferLength + rowBytes);
|
var buffer = this.ensureBuffer(bufferLength + rowBytes);
|
||||||
|
|
||||||
var currentRow = buffer.subarray(bufferLength, bufferLength + rowBytes);
|
|
||||||
var prevRow = buffer.subarray(bufferLength - rowBytes, bufferLength);
|
var prevRow = buffer.subarray(bufferLength - rowBytes, bufferLength);
|
||||||
if (prevRow.length == 0)
|
if (prevRow.length == 0)
|
||||||
prevRow = new Uint8Array(rowBytes);
|
prevRow = new Uint8Array(rowBytes);
|
||||||
|
|
||||||
|
var j = bufferLength;
|
||||||
switch (predictor) {
|
switch (predictor) {
|
||||||
case 0:
|
case 0:
|
||||||
for (var i = 0; i < rowBytes; ++i)
|
for (var i = 0; i < rowBytes; ++i)
|
||||||
currentRow[i] = rawBytes[i];
|
buffer[j++] = rawBytes[i];
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
for (var i = 0; i < pixBytes; ++i)
|
for (var i = 0; i < pixBytes; ++i)
|
||||||
currentRow[i] = rawBytes[i];
|
buffer[j++] = rawBytes[i];
|
||||||
for (; i < rowBytes; ++i)
|
for (; i < rowBytes; ++i) {
|
||||||
currentRow[i] = (currentRow[i - pixBytes] + rawBytes[i]) & 0xFF;
|
buffer[j] = (buffer[j - pixBytes] + rawBytes[i]) & 0xFF;
|
||||||
|
j++;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
for (var i = 0; i < rowBytes; ++i)
|
for (var i = 0; i < rowBytes; ++i)
|
||||||
currentRow[i] = (prevRow[i] + rawBytes[i]) & 0xFF;
|
buffer[j++] = (prevRow[i] + rawBytes[i]) & 0xFF;
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
for (var i = 0; i < pixBytes; ++i)
|
for (var i = 0; i < pixBytes; ++i)
|
||||||
currentRow[i] = (prevRow[i] >> 1) + rawBytes[i];
|
buffer[j++] = (prevRow[i] >> 1) + rawBytes[i];
|
||||||
for (; i < rowBytes; ++i) {
|
for (; i < rowBytes; ++i) {
|
||||||
currentRow[i] = (((prevRow[i] + currentRow[i - pixBytes]) >> 1) +
|
buffer[j] = (((prevRow[i] + buffer[j - pixBytes]) >> 1) +
|
||||||
rawBytes[i]) & 0xFF;
|
rawBytes[i]) & 0xFF;
|
||||||
|
j++;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
|
@ -720,12 +729,12 @@ var PredictorStream = (function predictorStream() {
|
||||||
for (var i = 0; i < pixBytes; ++i) {
|
for (var i = 0; i < pixBytes; ++i) {
|
||||||
var up = prevRow[i];
|
var up = prevRow[i];
|
||||||
var c = rawBytes[i];
|
var c = rawBytes[i];
|
||||||
currentRow[i] = up + c;
|
buffer[j++] = up + c;
|
||||||
}
|
}
|
||||||
for (; i < rowBytes; ++i) {
|
for (; i < rowBytes; ++i) {
|
||||||
var up = prevRow[i];
|
var up = prevRow[i];
|
||||||
var upLeft = prevRow[i - pixBytes];
|
var upLeft = prevRow[i - pixBytes];
|
||||||
var left = currentRow[i - pixBytes];
|
var left = buffer[j - pixBytes];
|
||||||
var p = left + up - upLeft;
|
var p = left + up - upLeft;
|
||||||
|
|
||||||
var pa = p - left;
|
var pa = p - left;
|
||||||
|
@ -740,11 +749,11 @@ var PredictorStream = (function predictorStream() {
|
||||||
|
|
||||||
var c = rawBytes[i];
|
var c = rawBytes[i];
|
||||||
if (pa <= pb && pa <= pc)
|
if (pa <= pb && pa <= pc)
|
||||||
currentRow[i] = left + c;
|
buffer[j++] = left + c;
|
||||||
else if (pb <= pc)
|
else if (pb <= pc)
|
||||||
currentRow[i] = up + c;
|
buffer[j++] = up + c;
|
||||||
else
|
else
|
||||||
currentRow[i] = upLeft + c;
|
buffer[j++] = upLeft + c;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -753,7 +762,7 @@ var PredictorStream = (function predictorStream() {
|
||||||
this.bufferLength += rowBytes;
|
this.bufferLength += rowBytes;
|
||||||
};
|
};
|
||||||
|
|
||||||
return constructor;
|
return PredictorStream;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -763,7 +772,7 @@ var PredictorStream = (function predictorStream() {
|
||||||
* a library to decode these images and the stream behaves like all the other
|
* a library to decode these images and the stream behaves like all the other
|
||||||
* DecodeStreams.
|
* DecodeStreams.
|
||||||
*/
|
*/
|
||||||
var JpegStream = (function jpegStream() {
|
var JpegStream = (function JpegStreamClosure() {
|
||||||
function isAdobeImage(bytes) {
|
function isAdobeImage(bytes) {
|
||||||
var maxBytesScanned = Math.max(bytes.length - 16, 1024);
|
var maxBytesScanned = Math.max(bytes.length - 16, 1024);
|
||||||
// Looking for APP14, 'Adobe'
|
// Looking for APP14, 'Adobe'
|
||||||
|
@ -794,43 +803,32 @@ var JpegStream = (function jpegStream() {
|
||||||
return newBytes;
|
return newBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
function constructor(bytes, dict, xref) {
|
function JpegStream(bytes, dict, xref) {
|
||||||
// TODO: per poppler, some images may have 'junk' before that
|
// TODO: per poppler, some images may have 'junk' before that
|
||||||
// need to be removed
|
// need to be removed
|
||||||
this.dict = dict;
|
this.dict = dict;
|
||||||
|
|
||||||
// Flag indicating wether the image can be natively loaded.
|
this.isAdobeImage = false;
|
||||||
this.isNative = true;
|
this.colorTransform = dict.get('ColorTransform') || -1;
|
||||||
|
|
||||||
this.colorTransform = -1;
|
|
||||||
|
|
||||||
if (isAdobeImage(bytes)) {
|
if (isAdobeImage(bytes)) {
|
||||||
// when bug 674619 land, let's check if browser can do
|
this.isAdobeImage = true;
|
||||||
// normal cmyk and then we won't have to the following
|
|
||||||
var cs = xref.fetchIfRef(dict.get('ColorSpace'));
|
|
||||||
|
|
||||||
// DeviceRGB and DeviceGray are the only Adobe images that work natively
|
|
||||||
if (isName(cs) && (cs.name === 'DeviceRGB' || cs.name === 'DeviceGray')) {
|
|
||||||
bytes = fixAdobeImage(bytes);
|
bytes = fixAdobeImage(bytes);
|
||||||
this.src = bytesToString(bytes);
|
}
|
||||||
} else {
|
|
||||||
this.colorTransform = dict.get('ColorTransform');
|
|
||||||
this.isNative = false;
|
|
||||||
this.bytes = bytes;
|
this.bytes = bytes;
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.src = bytesToString(bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
DecodeStream.call(this);
|
DecodeStream.call(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor.prototype = Object.create(DecodeStream.prototype);
|
JpegStream.prototype = Object.create(DecodeStream.prototype);
|
||||||
|
|
||||||
constructor.prototype.ensureBuffer = function jpegStreamEnsureBuffer(req) {
|
JpegStream.prototype.ensureBuffer = function JpegStream_ensureBuffer(req) {
|
||||||
if (this.bufferLength)
|
if (this.bufferLength)
|
||||||
return;
|
return;
|
||||||
|
try {
|
||||||
var jpegImage = new JpegImage();
|
var jpegImage = new JpegImage();
|
||||||
|
if (this.colorTransform != -1)
|
||||||
jpegImage.colorTransform = this.colorTransform;
|
jpegImage.colorTransform = this.colorTransform;
|
||||||
jpegImage.parse(this.bytes);
|
jpegImage.parse(this.bytes);
|
||||||
var width = jpegImage.width;
|
var width = jpegImage.width;
|
||||||
|
@ -838,19 +836,151 @@ var JpegStream = (function jpegStream() {
|
||||||
var data = jpegImage.getData(width, height);
|
var data = jpegImage.getData(width, height);
|
||||||
this.buffer = data;
|
this.buffer = data;
|
||||||
this.bufferLength = data.length;
|
this.bufferLength = data.length;
|
||||||
|
} catch (e) {
|
||||||
|
error('JPEG error: ' + e);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
constructor.prototype.getIR = function jpegStreamGetIR() {
|
JpegStream.prototype.getIR = function JpegStream_getIR() {
|
||||||
return this.src;
|
return bytesToString(this.bytes);
|
||||||
};
|
};
|
||||||
constructor.prototype.getChar = function jpegStreamGetChar() {
|
JpegStream.prototype.getChar = function JpegStream_getChar() {
|
||||||
error('internal error: getChar is not valid on JpegStream');
|
error('internal error: getChar is not valid on JpegStream');
|
||||||
};
|
};
|
||||||
|
/**
|
||||||
|
* Checks if the image can be decoded and displayed by the browser without any
|
||||||
|
* further processing such as color space conversions.
|
||||||
|
*/
|
||||||
|
JpegStream.prototype.isNativelySupported =
|
||||||
|
function JpegStream_isNativelySupported(xref, res) {
|
||||||
|
var cs = ColorSpace.parse(this.dict.get('ColorSpace'), xref, res);
|
||||||
|
// when bug 674619 lands, let's check if browser can do
|
||||||
|
// normal cmyk and then we won't need to decode in JS
|
||||||
|
if (cs.name === 'DeviceGray' || cs.name === 'DeviceRGB')
|
||||||
|
return true;
|
||||||
|
if (cs.name === 'DeviceCMYK' && !this.isAdobeImage &&
|
||||||
|
this.colorTransform < 1)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Checks if the image can be decoded by the browser.
|
||||||
|
*/
|
||||||
|
JpegStream.prototype.isNativelyDecodable =
|
||||||
|
function JpegStream_isNativelyDecodable(xref, res) {
|
||||||
|
var cs = ColorSpace.parse(this.dict.get('ColorSpace'), xref, res);
|
||||||
|
var numComps = cs.numComps;
|
||||||
|
if (numComps == 1 || numComps == 3)
|
||||||
|
return true;
|
||||||
|
|
||||||
return constructor;
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
return JpegStream;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
var DecryptStream = (function decryptStream() {
|
/**
|
||||||
function constructor(str, decrypt) {
|
* For JPEG 2000's we use a library to decode these images and
|
||||||
|
* the stream behaves like all the other DecodeStreams.
|
||||||
|
*/
|
||||||
|
var JpxStream = (function JpxStreamClosure() {
|
||||||
|
function JpxStream(bytes, dict) {
|
||||||
|
this.dict = dict;
|
||||||
|
this.bytes = bytes;
|
||||||
|
|
||||||
|
DecodeStream.call(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
JpxStream.prototype = Object.create(DecodeStream.prototype);
|
||||||
|
|
||||||
|
JpxStream.prototype.ensureBuffer = function JpxStream_ensureBuffer(req) {
|
||||||
|
if (this.bufferLength)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var jpxImage = new JpxImage();
|
||||||
|
jpxImage.parse(this.bytes);
|
||||||
|
|
||||||
|
var width = jpxImage.width;
|
||||||
|
var height = jpxImage.height;
|
||||||
|
var componentsCount = jpxImage.componentsCount;
|
||||||
|
if (componentsCount != 1 && componentsCount != 3 && componentsCount != 4)
|
||||||
|
error('JPX with ' + componentsCount + ' components is not supported');
|
||||||
|
|
||||||
|
var data = new Uint8Array(width * height * componentsCount);
|
||||||
|
|
||||||
|
for (var k = 0, kk = jpxImage.tiles.length; k < kk; k++) {
|
||||||
|
var tileCompoments = jpxImage.tiles[k];
|
||||||
|
var tileWidth = tileCompoments[0].width;
|
||||||
|
var tileHeight = tileCompoments[0].height;
|
||||||
|
var tileLeft = tileCompoments[0].left;
|
||||||
|
var tileTop = tileCompoments[0].top;
|
||||||
|
|
||||||
|
var dataPosition, sourcePosition, data0, data1, data2, data3, rowFeed;
|
||||||
|
switch (componentsCount) {
|
||||||
|
case 1:
|
||||||
|
data0 = tileCompoments[0].items;
|
||||||
|
|
||||||
|
dataPosition = width * tileTop + tileLeft;
|
||||||
|
rowFeed = width - tileWidth;
|
||||||
|
sourcePosition = 0;
|
||||||
|
for (var j = 0; j < tileHeight; j++) {
|
||||||
|
for (var i = 0; i < tileWidth; i++)
|
||||||
|
data[dataPosition++] = data0[sourcePosition++];
|
||||||
|
dataPosition += rowFeed;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
data0 = tileCompoments[0].items;
|
||||||
|
data1 = tileCompoments[1].items;
|
||||||
|
data2 = tileCompoments[2].items;
|
||||||
|
|
||||||
|
dataPosition = (width * tileTop + tileLeft) * 3;
|
||||||
|
rowFeed = (width - tileWidth) * 3;
|
||||||
|
sourcePosition = 0;
|
||||||
|
for (var j = 0; j < tileHeight; j++) {
|
||||||
|
for (var i = 0; i < tileWidth; i++) {
|
||||||
|
data[dataPosition++] = data0[sourcePosition];
|
||||||
|
data[dataPosition++] = data1[sourcePosition];
|
||||||
|
data[dataPosition++] = data2[sourcePosition];
|
||||||
|
sourcePosition++;
|
||||||
|
}
|
||||||
|
dataPosition += rowFeed;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
data0 = tileCompoments[0].items;
|
||||||
|
data1 = tileCompoments[1].items;
|
||||||
|
data2 = tileCompoments[2].items;
|
||||||
|
data3 = tileCompoments[3].items;
|
||||||
|
|
||||||
|
dataPosition = (width * tileTop + tileLeft) * 4;
|
||||||
|
rowFeed = (width - tileWidth) * 4;
|
||||||
|
sourcePosition = 0;
|
||||||
|
for (var j = 0; j < tileHeight; j++) {
|
||||||
|
for (var i = 0; i < tileWidth; i++) {
|
||||||
|
data[dataPosition++] = data0[sourcePosition];
|
||||||
|
data[dataPosition++] = data1[sourcePosition];
|
||||||
|
data[dataPosition++] = data2[sourcePosition];
|
||||||
|
data[dataPosition++] = data3[sourcePosition];
|
||||||
|
sourcePosition++;
|
||||||
|
}
|
||||||
|
dataPosition += rowFeed;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.buffer = data;
|
||||||
|
this.bufferLength = data.length;
|
||||||
|
};
|
||||||
|
JpxStream.prototype.getChar = function JpxStream_getChar() {
|
||||||
|
error('internal error: getChar is not valid on JpxStream');
|
||||||
|
};
|
||||||
|
|
||||||
|
return JpxStream;
|
||||||
|
})();
|
||||||
|
|
||||||
|
var DecryptStream = (function DecryptStreamClosure() {
|
||||||
|
function DecryptStream(str, decrypt) {
|
||||||
this.str = str;
|
this.str = str;
|
||||||
this.dict = str.dict;
|
this.dict = str.dict;
|
||||||
this.decrypt = decrypt;
|
this.decrypt = decrypt;
|
||||||
|
@ -860,9 +990,9 @@ var DecryptStream = (function decryptStream() {
|
||||||
|
|
||||||
var chunkSize = 512;
|
var chunkSize = 512;
|
||||||
|
|
||||||
constructor.prototype = Object.create(DecodeStream.prototype);
|
DecryptStream.prototype = Object.create(DecodeStream.prototype);
|
||||||
|
|
||||||
constructor.prototype.readBlock = function decryptStreamReadBlock() {
|
DecryptStream.prototype.readBlock = function DecryptStream_readBlock() {
|
||||||
var chunk = this.str.getBytes(chunkSize);
|
var chunk = this.str.getBytes(chunkSize);
|
||||||
if (!chunk || chunk.length == 0) {
|
if (!chunk || chunk.length == 0) {
|
||||||
this.eof = true;
|
this.eof = true;
|
||||||
|
@ -879,11 +1009,11 @@ var DecryptStream = (function decryptStream() {
|
||||||
this.bufferLength = bufferLength;
|
this.bufferLength = bufferLength;
|
||||||
};
|
};
|
||||||
|
|
||||||
return constructor;
|
return DecryptStream;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
var Ascii85Stream = (function ascii85Stream() {
|
var Ascii85Stream = (function Ascii85StreamClosure() {
|
||||||
function constructor(str) {
|
function Ascii85Stream(str) {
|
||||||
this.str = str;
|
this.str = str;
|
||||||
this.dict = str.dict;
|
this.dict = str.dict;
|
||||||
this.input = new Uint8Array(5);
|
this.input = new Uint8Array(5);
|
||||||
|
@ -891,9 +1021,9 @@ var Ascii85Stream = (function ascii85Stream() {
|
||||||
DecodeStream.call(this);
|
DecodeStream.call(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor.prototype = Object.create(DecodeStream.prototype);
|
Ascii85Stream.prototype = Object.create(DecodeStream.prototype);
|
||||||
|
|
||||||
constructor.prototype.readBlock = function ascii85StreamReadBlock() {
|
Ascii85Stream.prototype.readBlock = function Ascii85Stream_readBlock() {
|
||||||
var tildaCode = '~'.charCodeAt(0);
|
var tildaCode = '~'.charCodeAt(0);
|
||||||
var zCode = 'z'.charCodeAt(0);
|
var zCode = 'z'.charCodeAt(0);
|
||||||
var str = this.str;
|
var str = this.str;
|
||||||
|
@ -948,11 +1078,11 @@ var Ascii85Stream = (function ascii85Stream() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return constructor;
|
return Ascii85Stream;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
var AsciiHexStream = (function asciiHexStream() {
|
var AsciiHexStream = (function AsciiHexStreamClosure() {
|
||||||
function constructor(str) {
|
function AsciiHexStream(str) {
|
||||||
this.str = str;
|
this.str = str;
|
||||||
this.dict = str.dict;
|
this.dict = str.dict;
|
||||||
|
|
||||||
|
@ -986,9 +1116,9 @@ var AsciiHexStream = (function asciiHexStream() {
|
||||||
102: 15
|
102: 15
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor.prototype = Object.create(DecodeStream.prototype);
|
AsciiHexStream.prototype = Object.create(DecodeStream.prototype);
|
||||||
|
|
||||||
constructor.prototype.readBlock = function asciiHexStreamReadBlock() {
|
AsciiHexStream.prototype.readBlock = function AsciiHexStream_readBlock() {
|
||||||
var gtCode = '>'.charCodeAt(0), bytes = this.str.getBytes(), c, n,
|
var gtCode = '>'.charCodeAt(0), bytes = this.str.getBytes(), c, n,
|
||||||
decodeLength, buffer, bufferLength, i, length;
|
decodeLength, buffer, bufferLength, i, length;
|
||||||
|
|
||||||
|
@ -1018,10 +1148,55 @@ var AsciiHexStream = (function asciiHexStream() {
|
||||||
this.eof = true;
|
this.eof = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
return constructor;
|
return AsciiHexStream;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
var CCITTFaxStream = (function ccittFaxStream() {
|
var RunLengthStream = (function RunLengthStreamClosure() {
|
||||||
|
function RunLengthStream(str) {
|
||||||
|
this.str = str;
|
||||||
|
this.dict = str.dict;
|
||||||
|
|
||||||
|
DecodeStream.call(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
RunLengthStream.prototype = Object.create(DecodeStream.prototype);
|
||||||
|
|
||||||
|
RunLengthStream.prototype.readBlock = function RunLengthStream_readBlock() {
|
||||||
|
// The repeatHeader has following format. The first byte defines type of run
|
||||||
|
// and amount of bytes to repeat/copy: n = 0 through 127 - copy next n bytes
|
||||||
|
// (in addition to the second byte from the header), n = 129 through 255 -
|
||||||
|
// duplicate the second byte from the header (257 - n) times, n = 128 - end.
|
||||||
|
var repeatHeader = this.str.getBytes(2);
|
||||||
|
if (!repeatHeader || repeatHeader.length < 2 || repeatHeader[0] == 128) {
|
||||||
|
this.eof = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var bufferLength = this.bufferLength;
|
||||||
|
var n = repeatHeader[0];
|
||||||
|
if (n < 128) {
|
||||||
|
// copy n bytes
|
||||||
|
var buffer = this.ensureBuffer(bufferLength + n + 1);
|
||||||
|
buffer[bufferLength++] = repeatHeader[1];
|
||||||
|
if (n > 0) {
|
||||||
|
var source = this.str.getBytes(n);
|
||||||
|
buffer.set(source, bufferLength);
|
||||||
|
bufferLength += n;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
n = 257 - n;
|
||||||
|
var b = repeatHeader[1];
|
||||||
|
var buffer = this.ensureBuffer(bufferLength + n + 1);
|
||||||
|
for (var i = 0; i < n; i++)
|
||||||
|
buffer[bufferLength++] = b;
|
||||||
|
}
|
||||||
|
this.bufferLength = bufferLength;
|
||||||
|
};
|
||||||
|
|
||||||
|
return RunLengthStream;
|
||||||
|
})();
|
||||||
|
|
||||||
|
var CCITTFaxStream = (function CCITTFaxStreamClosure() {
|
||||||
|
|
||||||
var ccittEOL = -2;
|
var ccittEOL = -2;
|
||||||
var twoDimPass = 0;
|
var twoDimPass = 0;
|
||||||
|
@ -1449,7 +1624,7 @@ var CCITTFaxStream = (function ccittFaxStream() {
|
||||||
[2, 2], [2, 2], [2, 2], [2, 2]
|
[2, 2], [2, 2], [2, 2], [2, 2]
|
||||||
];
|
];
|
||||||
|
|
||||||
function constructor(str, params) {
|
function CCITTFaxStream(str, params) {
|
||||||
this.str = str;
|
this.str = str;
|
||||||
this.dict = str.dict;
|
this.dict = str.dict;
|
||||||
|
|
||||||
|
@ -1494,9 +1669,9 @@ var CCITTFaxStream = (function ccittFaxStream() {
|
||||||
DecodeStream.call(this);
|
DecodeStream.call(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor.prototype = Object.create(DecodeStream.prototype);
|
CCITTFaxStream.prototype = Object.create(DecodeStream.prototype);
|
||||||
|
|
||||||
constructor.prototype.readBlock = function ccittFaxStreamReadBlock() {
|
CCITTFaxStream.prototype.readBlock = function CCITTFaxStream_readBlock() {
|
||||||
while (!this.eof) {
|
while (!this.eof) {
|
||||||
var c = this.lookChar();
|
var c = this.lookChar();
|
||||||
this.buf = EOF;
|
this.buf = EOF;
|
||||||
|
@ -1505,7 +1680,7 @@ var CCITTFaxStream = (function ccittFaxStream() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor.prototype.addPixels =
|
CCITTFaxStream.prototype.addPixels =
|
||||||
function ccittFaxStreamAddPixels(a1, blackPixels) {
|
function ccittFaxStreamAddPixels(a1, blackPixels) {
|
||||||
var codingLine = this.codingLine;
|
var codingLine = this.codingLine;
|
||||||
var codingPos = this.codingPos;
|
var codingPos = this.codingPos;
|
||||||
|
@ -1525,7 +1700,7 @@ var CCITTFaxStream = (function ccittFaxStream() {
|
||||||
this.codingPos = codingPos;
|
this.codingPos = codingPos;
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor.prototype.addPixelsNeg =
|
CCITTFaxStream.prototype.addPixelsNeg =
|
||||||
function ccittFaxStreamAddPixelsNeg(a1, blackPixels) {
|
function ccittFaxStreamAddPixelsNeg(a1, blackPixels) {
|
||||||
var codingLine = this.codingLine;
|
var codingLine = this.codingLine;
|
||||||
var codingPos = this.codingPos;
|
var codingPos = this.codingPos;
|
||||||
|
@ -1554,7 +1729,7 @@ var CCITTFaxStream = (function ccittFaxStream() {
|
||||||
this.codingPos = codingPos;
|
this.codingPos = codingPos;
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor.prototype.lookChar = function ccittFaxStreamLookChar() {
|
CCITTFaxStream.prototype.lookChar = function CCITTFaxStream_lookChar() {
|
||||||
if (this.buf != EOF)
|
if (this.buf != EOF)
|
||||||
return this.buf;
|
return this.buf;
|
||||||
|
|
||||||
|
@ -1852,10 +2027,10 @@ var CCITTFaxStream = (function ccittFaxStream() {
|
||||||
// values. The first array element indicates whether a valid code is being
|
// values. The first array element indicates whether a valid code is being
|
||||||
// returned. The second array element is the actual code. The third array
|
// returned. The second array element is the actual code. The third array
|
||||||
// element indicates whether EOF was reached.
|
// element indicates whether EOF was reached.
|
||||||
var findTableCode = function ccittFaxStreamFindTableCode(start, end, table,
|
CCITTFaxStream.prototype.findTableCode =
|
||||||
limit) {
|
function ccittFaxStreamFindTableCode(start, end, table, limit) {
|
||||||
var limitValue = limit || 0;
|
|
||||||
|
|
||||||
|
var limitValue = limit || 0;
|
||||||
for (var i = start; i <= end; ++i) {
|
for (var i = start; i <= end; ++i) {
|
||||||
var code = this.lookBits(i);
|
var code = this.lookBits(i);
|
||||||
if (code == EOF)
|
if (code == EOF)
|
||||||
|
@ -1873,18 +2048,20 @@ var CCITTFaxStream = (function ccittFaxStream() {
|
||||||
return [false, 0, false];
|
return [false, 0, false];
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor.prototype.getTwoDimCode = function ccittFaxStreamGetTwoDimCode() {
|
CCITTFaxStream.prototype.getTwoDimCode =
|
||||||
|
function ccittFaxStreamGetTwoDimCode() {
|
||||||
|
|
||||||
var code = 0;
|
var code = 0;
|
||||||
var p;
|
var p;
|
||||||
if (this.eoblock) {
|
if (this.eoblock) {
|
||||||
code = this.lookBits(7);
|
code = this.lookBits(7);
|
||||||
p = twoDimTable[code];
|
p = twoDimTable[code];
|
||||||
if (p[0] > 0) {
|
if (p && p[0] > 0) {
|
||||||
this.eatBits(p[0]);
|
this.eatBits(p[0]);
|
||||||
return p[1];
|
return p[1];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var result = findTableCode(1, 7, twoDimTable);
|
var result = this.findTableCode(1, 7, twoDimTable);
|
||||||
if (result[0] && result[2])
|
if (result[0] && result[2])
|
||||||
return result[1];
|
return result[1];
|
||||||
}
|
}
|
||||||
|
@ -1892,7 +2069,9 @@ var CCITTFaxStream = (function ccittFaxStream() {
|
||||||
return EOF;
|
return EOF;
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor.prototype.getWhiteCode = function ccittFaxStreamGetWhiteCode() {
|
CCITTFaxStream.prototype.getWhiteCode =
|
||||||
|
function ccittFaxStreamGetWhiteCode() {
|
||||||
|
|
||||||
var code = 0;
|
var code = 0;
|
||||||
var p;
|
var p;
|
||||||
var n;
|
var n;
|
||||||
|
@ -1911,11 +2090,11 @@ var CCITTFaxStream = (function ccittFaxStream() {
|
||||||
return p[1];
|
return p[1];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var result = findTableCode(1, 9, whiteTable2);
|
var result = this.findTableCode(1, 9, whiteTable2);
|
||||||
if (result[0])
|
if (result[0])
|
||||||
return result[1];
|
return result[1];
|
||||||
|
|
||||||
result = findTableCode(11, 12, whiteTable1);
|
result = this.findTableCode(11, 12, whiteTable1);
|
||||||
if (result[0])
|
if (result[0])
|
||||||
return result[1];
|
return result[1];
|
||||||
}
|
}
|
||||||
|
@ -1924,7 +2103,9 @@ var CCITTFaxStream = (function ccittFaxStream() {
|
||||||
return 1;
|
return 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor.prototype.getBlackCode = function ccittFaxStreamGetBlackCode() {
|
CCITTFaxStream.prototype.getBlackCode =
|
||||||
|
function ccittFaxStreamGetBlackCode() {
|
||||||
|
|
||||||
var code, p;
|
var code, p;
|
||||||
if (this.eoblock) {
|
if (this.eoblock) {
|
||||||
code = this.lookBits(13);
|
code = this.lookBits(13);
|
||||||
|
@ -1942,15 +2123,15 @@ var CCITTFaxStream = (function ccittFaxStream() {
|
||||||
return p[1];
|
return p[1];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var result = findTableCode(2, 6, blackTable3);
|
var result = this.findTableCode(2, 6, blackTable3);
|
||||||
if (result[0])
|
if (result[0])
|
||||||
return result[1];
|
return result[1];
|
||||||
|
|
||||||
result = findTableCode(7, 12, blackTable2, 64);
|
result = this.findTableCode(7, 12, blackTable2, 64);
|
||||||
if (result[0])
|
if (result[0])
|
||||||
return result[1];
|
return result[1];
|
||||||
|
|
||||||
result = findTableCode(10, 13, blackTable1);
|
result = this.findTableCode(10, 13, blackTable1);
|
||||||
if (result[0])
|
if (result[0])
|
||||||
return result[1];
|
return result[1];
|
||||||
}
|
}
|
||||||
|
@ -1959,7 +2140,7 @@ var CCITTFaxStream = (function ccittFaxStream() {
|
||||||
return 1;
|
return 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor.prototype.lookBits = function ccittFaxStreamLookBits(n) {
|
CCITTFaxStream.prototype.lookBits = function CCITTFaxStream_lookBits(n) {
|
||||||
var c;
|
var c;
|
||||||
while (this.inputBits < n) {
|
while (this.inputBits < n) {
|
||||||
if ((c = this.str.getByte()) == null) {
|
if ((c = this.str.getByte()) == null) {
|
||||||
|
@ -1974,16 +2155,16 @@ var CCITTFaxStream = (function ccittFaxStream() {
|
||||||
return (this.inputBuf >> (this.inputBits - n)) & (0xFFFF >> (16 - n));
|
return (this.inputBuf >> (this.inputBits - n)) & (0xFFFF >> (16 - n));
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor.prototype.eatBits = function ccittFaxStreamEatBits(n) {
|
CCITTFaxStream.prototype.eatBits = function CCITTFaxStream_eatBits(n) {
|
||||||
if ((this.inputBits -= n) < 0)
|
if ((this.inputBits -= n) < 0)
|
||||||
this.inputBits = 0;
|
this.inputBits = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
return constructor;
|
return CCITTFaxStream;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
var LZWStream = (function lzwStream() {
|
var LZWStream = (function LZWStreamClosure() {
|
||||||
function constructor(str, earlyChange) {
|
function LZWStream(str, earlyChange) {
|
||||||
this.str = str;
|
this.str = str;
|
||||||
this.dict = str.dict;
|
this.dict = str.dict;
|
||||||
this.cachedData = 0;
|
this.cachedData = 0;
|
||||||
|
@ -2009,9 +2190,9 @@ var LZWStream = (function lzwStream() {
|
||||||
DecodeStream.call(this);
|
DecodeStream.call(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor.prototype = Object.create(DecodeStream.prototype);
|
LZWStream.prototype = Object.create(DecodeStream.prototype);
|
||||||
|
|
||||||
constructor.prototype.readBits = function lzwStreamReadBits(n) {
|
LZWStream.prototype.readBits = function LZWStream_readBits(n) {
|
||||||
var bitsCached = this.bitsCached;
|
var bitsCached = this.bitsCached;
|
||||||
var cachedData = this.cachedData;
|
var cachedData = this.cachedData;
|
||||||
while (bitsCached < n) {
|
while (bitsCached < n) {
|
||||||
|
@ -2029,7 +2210,7 @@ var LZWStream = (function lzwStream() {
|
||||||
return (cachedData >>> bitsCached) & ((1 << n) - 1);
|
return (cachedData >>> bitsCached) & ((1 << n) - 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor.prototype.readBlock = function lzwStreamReadBlock() {
|
LZWStream.prototype.readBlock = function LZWStream_readBlock() {
|
||||||
var blockSize = 512;
|
var blockSize = 512;
|
||||||
var estimatedDecodedSize = blockSize * 2, decodedSizeDelta = blockSize;
|
var estimatedDecodedSize = blockSize * 2, decodedSizeDelta = blockSize;
|
||||||
var i, j, q;
|
var i, j, q;
|
||||||
|
@ -2108,6 +2289,6 @@ var LZWStream = (function lzwStream() {
|
||||||
this.bufferLength = currentBufferLength;
|
this.bufferLength = currentBufferLength;
|
||||||
};
|
};
|
||||||
|
|
||||||
return constructor;
|
return LZWStream;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
|
|
@ -76,24 +76,102 @@ function stringToBytes(str) {
|
||||||
|
|
||||||
var IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0];
|
var IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0];
|
||||||
|
|
||||||
var Util = (function utilUtil() {
|
var Util = (function UtilClosure() {
|
||||||
function constructor() {}
|
function Util() {}
|
||||||
constructor.makeCssRgb = function makergb(r, g, b) {
|
|
||||||
|
Util.makeCssRgb = function Util_makeCssRgb(r, g, b) {
|
||||||
var ri = (255 * r) | 0, gi = (255 * g) | 0, bi = (255 * b) | 0;
|
var ri = (255 * r) | 0, gi = (255 * g) | 0, bi = (255 * b) | 0;
|
||||||
return 'rgb(' + ri + ',' + gi + ',' + bi + ')';
|
return 'rgb(' + ri + ',' + gi + ',' + bi + ')';
|
||||||
};
|
};
|
||||||
constructor.makeCssCmyk = function makecmyk(c, m, y, k) {
|
|
||||||
|
Util.makeCssCmyk = function Util_makeCssCmyk(c, m, y, k) {
|
||||||
c = (new DeviceCmykCS()).getRgb([c, m, y, k]);
|
c = (new DeviceCmykCS()).getRgb([c, m, y, k]);
|
||||||
var ri = (255 * c[0]) | 0, gi = (255 * c[1]) | 0, bi = (255 * c[2]) | 0;
|
var ri = (255 * c[0]) | 0, gi = (255 * c[1]) | 0, bi = (255 * c[2]) | 0;
|
||||||
return 'rgb(' + ri + ',' + gi + ',' + bi + ')';
|
return 'rgb(' + ri + ',' + gi + ',' + bi + ')';
|
||||||
};
|
};
|
||||||
constructor.applyTransform = function apply(p, m) {
|
|
||||||
|
// For 2d affine transforms
|
||||||
|
Util.applyTransform = function Util_applyTransform(p, m) {
|
||||||
var xt = p[0] * m[0] + p[1] * m[2] + m[4];
|
var xt = p[0] * m[0] + p[1] * m[2] + m[4];
|
||||||
var yt = p[0] * m[1] + p[1] * m[3] + m[5];
|
var yt = p[0] * m[1] + p[1] * m[3] + m[5];
|
||||||
return [xt, yt];
|
return [xt, yt];
|
||||||
};
|
};
|
||||||
|
|
||||||
return constructor;
|
// Apply a generic 3d matrix M on a 3-vector v:
|
||||||
|
// | a b c | | X |
|
||||||
|
// | d e f | x | Y |
|
||||||
|
// | g h i | | Z |
|
||||||
|
// M is assumed to be serialized as [a,b,c,d,e,f,g,h,i],
|
||||||
|
// with v as [X,Y,Z]
|
||||||
|
Util.apply3dTransform = function Util_apply3dTransform(m, v) {
|
||||||
|
return [
|
||||||
|
m[0] * v[0] + m[1] * v[1] + m[2] * v[2],
|
||||||
|
m[3] * v[0] + m[4] * v[1] + m[5] * v[2],
|
||||||
|
m[6] * v[0] + m[7] * v[1] + m[8] * v[2]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalize rectangle rect=[x1, y1, x2, y2] so that (x1,y1) < (x2,y2)
|
||||||
|
// For coordinate systems whose origin lies in the bottom-left, this
|
||||||
|
// means normalization to (BL,TR) ordering. For systems with origin in the
|
||||||
|
// top-left, this means (TL,BR) ordering.
|
||||||
|
Util.normalizeRect = function Util_normalizeRect(rect) {
|
||||||
|
var r = rect.slice(0); // clone rect
|
||||||
|
if (rect[0] > rect[2]) {
|
||||||
|
r[0] = rect[2];
|
||||||
|
r[2] = rect[0];
|
||||||
|
}
|
||||||
|
if (rect[1] > rect[3]) {
|
||||||
|
r[1] = rect[3];
|
||||||
|
r[3] = rect[1];
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a rectangle [x1, y1, x2, y2] corresponding to the
|
||||||
|
// intersection of rect1 and rect2. If no intersection, returns 'false'
|
||||||
|
// The rectangle coordinates of rect1, rect2 should be [x1, y1, x2, y2]
|
||||||
|
Util.intersect = function Util_intersect(rect1, rect2) {
|
||||||
|
function compare(a, b) {
|
||||||
|
return a - b;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Order points along the axes
|
||||||
|
var orderedX = [rect1[0], rect1[2], rect2[0], rect2[2]].sort(compare),
|
||||||
|
orderedY = [rect1[1], rect1[3], rect2[1], rect2[3]].sort(compare),
|
||||||
|
result = [];
|
||||||
|
|
||||||
|
rect1 = Util.normalizeRect(rect1);
|
||||||
|
rect2 = Util.normalizeRect(rect2);
|
||||||
|
|
||||||
|
// X: first and second points belong to different rectangles?
|
||||||
|
if ((orderedX[0] === rect1[0] && orderedX[1] === rect2[0]) ||
|
||||||
|
(orderedX[0] === rect2[0] && orderedX[1] === rect1[0])) {
|
||||||
|
// Intersection must be between second and third points
|
||||||
|
result[0] = orderedX[1];
|
||||||
|
result[2] = orderedX[2];
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Y: first and second points belong to different rectangles?
|
||||||
|
if ((orderedY[0] === rect1[1] && orderedY[1] === rect2[1]) ||
|
||||||
|
(orderedY[0] === rect2[1] && orderedY[1] === rect1[1])) {
|
||||||
|
// Intersection must be between second and third points
|
||||||
|
result[1] = orderedY[1];
|
||||||
|
result[3] = orderedY[2];
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Util.sign = function Util_sign(num) {
|
||||||
|
return num < 0 ? -1 : 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
return Util;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
var PDFStringTranslateTable = [
|
var PDFStringTranslateTable = [
|
||||||
|
@ -197,7 +275,7 @@ function isPDFFunction(v) {
|
||||||
* can be set. If any of these happens twice or the data is required before
|
* can be set. If any of these happens twice or the data is required before
|
||||||
* it was set, an exception is throw.
|
* it was set, an exception is throw.
|
||||||
*/
|
*/
|
||||||
var Promise = (function promise() {
|
var Promise = (function PromiseClosure() {
|
||||||
var EMPTY_PROMISE = {};
|
var EMPTY_PROMISE = {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -206,6 +284,8 @@ var Promise = (function promise() {
|
||||||
*/
|
*/
|
||||||
function Promise(name, data) {
|
function Promise(name, data) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
this.isRejected = false;
|
||||||
|
this.error = null;
|
||||||
// If you build a promise and pass in some data it's already resolved.
|
// If you build a promise and pass in some data it's already resolved.
|
||||||
if (data != null) {
|
if (data != null) {
|
||||||
this.isResolved = true;
|
this.isResolved = true;
|
||||||
|
@ -216,8 +296,35 @@ var Promise = (function promise() {
|
||||||
this._data = EMPTY_PROMISE;
|
this._data = EMPTY_PROMISE;
|
||||||
}
|
}
|
||||||
this.callbacks = [];
|
this.callbacks = [];
|
||||||
|
this.errbacks = [];
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Builds a promise that is resolved when all the passed in promises are
|
||||||
|
* resolved.
|
||||||
|
* @param {Promise[]} promises Array of promises to wait for.
|
||||||
|
* @return {Promise} New dependant promise.
|
||||||
|
*/
|
||||||
|
Promise.all = function Promise_all(promises) {
|
||||||
|
var deferred = new Promise();
|
||||||
|
var unresolved = promises.length;
|
||||||
|
var results = [];
|
||||||
|
if (unresolved === 0) {
|
||||||
|
deferred.resolve(results);
|
||||||
|
return deferred;
|
||||||
|
}
|
||||||
|
for (var i = 0; i < unresolved; ++i) {
|
||||||
|
var promise = promises[i];
|
||||||
|
promise.then((function(i) {
|
||||||
|
return function(value) {
|
||||||
|
results[i] = value;
|
||||||
|
unresolved--;
|
||||||
|
if (unresolved === 0)
|
||||||
|
deferred.resolve(results);
|
||||||
|
};
|
||||||
|
})(i));
|
||||||
|
}
|
||||||
|
return deferred;
|
||||||
};
|
};
|
||||||
|
|
||||||
Promise.prototype = {
|
Promise.prototype = {
|
||||||
hasData: false,
|
hasData: false,
|
||||||
|
|
||||||
|
@ -226,8 +333,8 @@ var Promise = (function promise() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this._data !== EMPTY_PROMISE) {
|
if (this._data !== EMPTY_PROMISE) {
|
||||||
throw 'Promise ' + this.name +
|
error('Promise ' + this.name +
|
||||||
': Cannot set the data of a promise twice';
|
': Cannot set the data of a promise twice');
|
||||||
}
|
}
|
||||||
this._data = value;
|
this._data = value;
|
||||||
this.hasData = true;
|
this.hasData = true;
|
||||||
|
@ -239,12 +346,12 @@ var Promise = (function promise() {
|
||||||
|
|
||||||
get data() {
|
get data() {
|
||||||
if (this._data === EMPTY_PROMISE) {
|
if (this._data === EMPTY_PROMISE) {
|
||||||
throw 'Promise ' + this.name + ': Cannot get data that isn\'t set';
|
error('Promise ' + this.name + ': Cannot get data that isn\'t set');
|
||||||
}
|
}
|
||||||
return this._data;
|
return this._data;
|
||||||
},
|
},
|
||||||
|
|
||||||
onData: function promiseOnData(callback) {
|
onData: function Promise_onData(callback) {
|
||||||
if (this._data !== EMPTY_PROMISE) {
|
if (this._data !== EMPTY_PROMISE) {
|
||||||
callback(this._data);
|
callback(this._data);
|
||||||
} else {
|
} else {
|
||||||
|
@ -252,13 +359,16 @@ var Promise = (function promise() {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
resolve: function promiseResolve(data) {
|
resolve: function Promise_resolve(data) {
|
||||||
if (this.isResolved) {
|
if (this.isResolved) {
|
||||||
throw 'A Promise can be resolved only once ' + this.name;
|
error('A Promise can be resolved only once ' + this.name);
|
||||||
|
}
|
||||||
|
if (this.isRejected) {
|
||||||
|
error('The Promise was already rejected ' + this.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.isResolved = true;
|
this.isResolved = true;
|
||||||
this.data = data;
|
this.data = data || null;
|
||||||
var callbacks = this.callbacks;
|
var callbacks = this.callbacks;
|
||||||
|
|
||||||
for (var i = 0, ii = callbacks.length; i < ii; i++) {
|
for (var i = 0, ii = callbacks.length; i < ii; i++) {
|
||||||
|
@ -266,17 +376,39 @@ var Promise = (function promise() {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
then: function promiseThen(callback) {
|
reject: function Promise_reject(reason) {
|
||||||
|
if (this.isRejected) {
|
||||||
|
error('A Promise can be rejected only once ' + this.name);
|
||||||
|
}
|
||||||
|
if (this.isResolved) {
|
||||||
|
error('The Promise was already resolved ' + this.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isRejected = true;
|
||||||
|
this.error = reason || null;
|
||||||
|
var errbacks = this.errbacks;
|
||||||
|
|
||||||
|
for (var i = 0, ii = errbacks.length; i < ii; i++) {
|
||||||
|
errbacks[i].call(null, reason);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
then: function Promise_then(callback, errback) {
|
||||||
if (!callback) {
|
if (!callback) {
|
||||||
throw 'Requiring callback' + this.name;
|
error('Requiring callback' + this.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the promise is already resolved, call the callback directly.
|
// If the promise is already resolved, call the callback directly.
|
||||||
if (this.isResolved) {
|
if (this.isResolved) {
|
||||||
var data = this.data;
|
var data = this.data;
|
||||||
callback.call(null, data);
|
callback.call(null, data);
|
||||||
|
} else if (this.isRejected && errback) {
|
||||||
|
var error = this.error;
|
||||||
|
errback.call(null, error);
|
||||||
} else {
|
} else {
|
||||||
this.callbacks.push(callback);
|
this.callbacks.push(callback);
|
||||||
|
if (errback)
|
||||||
|
this.errbacks.push(errback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -284,3 +416,55 @@ var Promise = (function promise() {
|
||||||
return Promise;
|
return Promise;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
var StatTimer = (function StatTimerClosure() {
|
||||||
|
function rpad(str, pad, length) {
|
||||||
|
while (str.length < length)
|
||||||
|
str += pad;
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
function StatTimer() {
|
||||||
|
this.started = {};
|
||||||
|
this.times = [];
|
||||||
|
this.enabled = true;
|
||||||
|
}
|
||||||
|
StatTimer.prototype = {
|
||||||
|
time: function StatTimer_time(name) {
|
||||||
|
if (!this.enabled)
|
||||||
|
return;
|
||||||
|
if (name in this.started)
|
||||||
|
throw 'Timer is already running for ' + name;
|
||||||
|
this.started[name] = Date.now();
|
||||||
|
},
|
||||||
|
timeEnd: function StatTimer_timeEnd(name) {
|
||||||
|
if (!this.enabled)
|
||||||
|
return;
|
||||||
|
if (!(name in this.started))
|
||||||
|
throw 'Timer has not been started for ' + name;
|
||||||
|
this.times.push({
|
||||||
|
'name': name,
|
||||||
|
'start': this.started[name],
|
||||||
|
'end': Date.now()
|
||||||
|
});
|
||||||
|
// Remove timer from started so it can be called again.
|
||||||
|
delete this.started[name];
|
||||||
|
},
|
||||||
|
toString: function StatTimer_toString() {
|
||||||
|
var times = this.times;
|
||||||
|
var out = '';
|
||||||
|
// Find the longest name for padding purposes.
|
||||||
|
var longest = 0;
|
||||||
|
for (var i = 0, ii = times.length; i < ii; ++i) {
|
||||||
|
var name = times[i]['name'];
|
||||||
|
if (name.length > longest)
|
||||||
|
longest = name.length;
|
||||||
|
}
|
||||||
|
for (var i = 0, ii = times.length; i < ii; ++i) {
|
||||||
|
var span = times[i];
|
||||||
|
var duration = span.end - span.start;
|
||||||
|
out += rpad(span['name'], ' ', longest) + ' ' + duration + 'ms\n';
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return StatTimer;
|
||||||
|
})();
|
||||||
|
|
|
@ -122,9 +122,9 @@ function readFontDictData(aString, aMap) {
|
||||||
token = '';
|
token = '';
|
||||||
var parsed = false;
|
var parsed = false;
|
||||||
while (!parsed) {
|
while (!parsed) {
|
||||||
var byte = aString[i++];
|
var octet = aString[i++];
|
||||||
|
|
||||||
var nibbles = [parseInt(byte / 16, 10), parseInt(byte % 16, 10)];
|
var nibbles = [parseInt(octet / 16, 10), parseInt(octet % 16, 10)];
|
||||||
for (var j = 0; j < nibbles.length; j++) {
|
for (var j = 0; j < nibbles.length; j++) {
|
||||||
var nibble = nibbles[j];
|
var nibble = nibbles[j];
|
||||||
switch (nibble) {
|
switch (nibble) {
|
||||||
|
@ -336,7 +336,7 @@ var Type2Parser = function type2Parser(aFilePath) {
|
||||||
var privateDict = [];
|
var privateDict = [];
|
||||||
for (var i = 0; i < priv.size; i++)
|
for (var i = 0; i < priv.size; i++)
|
||||||
privateDict.push(aStream.getByte());
|
privateDict.push(aStream.getByte());
|
||||||
dump('private:' + privateDict);
|
dump('privateData:' + privateDict);
|
||||||
parseAsToken(privateDict, CFFDictPrivateDataMap);
|
parseAsToken(privateDict, CFFDictPrivateDataMap);
|
||||||
|
|
||||||
for (var p in font.map)
|
for (var p in font.map)
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
function MessageHandler(name, comObj) {
|
function MessageHandler(name, comObj) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.comObj = comObj;
|
this.comObj = comObj;
|
||||||
|
this.callbackIndex = 1;
|
||||||
|
var callbacks = this.callbacks = {};
|
||||||
var ah = this.actionHandler = {};
|
var ah = this.actionHandler = {};
|
||||||
|
|
||||||
ah['console_log'] = [function ahConsoleLog(data) {
|
ah['console_log'] = [function ahConsoleLog(data) {
|
||||||
|
@ -17,11 +19,32 @@ function MessageHandler(name, comObj) {
|
||||||
|
|
||||||
comObj.onmessage = function messageHandlerComObjOnMessage(event) {
|
comObj.onmessage = function messageHandlerComObjOnMessage(event) {
|
||||||
var data = event.data;
|
var data = event.data;
|
||||||
if (data.action in ah) {
|
if (data.isReply) {
|
||||||
var action = ah[data.action];
|
var callbackId = data.callbackId;
|
||||||
action[0].call(action[1], data.data);
|
if (data.callbackId in callbacks) {
|
||||||
|
var callback = callbacks[callbackId];
|
||||||
|
delete callbacks[callbackId];
|
||||||
|
callback(data.data);
|
||||||
} else {
|
} else {
|
||||||
throw 'Unkown action from worker: ' + data.action;
|
error('Cannot resolve callback ' + callbackId);
|
||||||
|
}
|
||||||
|
} else if (data.action in ah) {
|
||||||
|
var action = ah[data.action];
|
||||||
|
if (data.callbackId) {
|
||||||
|
var promise = new Promise();
|
||||||
|
promise.then(function(resolvedData) {
|
||||||
|
comObj.postMessage({
|
||||||
|
isReply: true,
|
||||||
|
callbackId: data.callbackId,
|
||||||
|
data: resolvedData
|
||||||
|
});
|
||||||
|
});
|
||||||
|
action[0].call(action[1], data.data, promise);
|
||||||
|
} else {
|
||||||
|
action[0].call(action[1], data.data);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error('Unkown action from worker: ' + data.action);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -30,44 +53,47 @@ MessageHandler.prototype = {
|
||||||
on: function messageHandlerOn(actionName, handler, scope) {
|
on: function messageHandlerOn(actionName, handler, scope) {
|
||||||
var ah = this.actionHandler;
|
var ah = this.actionHandler;
|
||||||
if (ah[actionName]) {
|
if (ah[actionName]) {
|
||||||
throw 'There is already an actionName called "' + actionName + '"';
|
error('There is already an actionName called "' + actionName + '"');
|
||||||
}
|
}
|
||||||
ah[actionName] = [handler, scope];
|
ah[actionName] = [handler, scope];
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
send: function messageHandlerSend(actionName, data) {
|
* Sends a message to the comObj to invoke the action with the supplied data.
|
||||||
this.comObj.postMessage({
|
* @param {String} actionName Action to call.
|
||||||
|
* @param {JSON} data JSON data to send.
|
||||||
|
* @param {function} [callback] Optional callback that will handle a reply.
|
||||||
|
*/
|
||||||
|
send: function messageHandlerSend(actionName, data, callback) {
|
||||||
|
var message = {
|
||||||
action: actionName,
|
action: actionName,
|
||||||
data: data
|
data: data
|
||||||
});
|
};
|
||||||
|
if (callback) {
|
||||||
|
var callbackId = this.callbackIndex++;
|
||||||
|
this.callbacks[callbackId] = callback;
|
||||||
|
message.callbackId = callbackId;
|
||||||
|
}
|
||||||
|
this.comObj.postMessage(message);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var WorkerMessageHandler = {
|
var WorkerMessageHandler = {
|
||||||
setup: function wphSetup(handler) {
|
setup: function wphSetup(handler) {
|
||||||
var pdfDoc = null;
|
var pdfModel = null;
|
||||||
|
|
||||||
handler.on('test', function wphSetupTest(data) {
|
handler.on('test', function wphSetupTest(data) {
|
||||||
handler.send('test', data instanceof Uint8Array);
|
handler.send('test', data instanceof Uint8Array);
|
||||||
});
|
});
|
||||||
|
|
||||||
handler.on('workerSrc', function wphSetupWorkerSrc(data) {
|
|
||||||
// In development, the `workerSrc` message is handled in the
|
|
||||||
// `worker_loader.js` file. In production the workerProcessHandler is
|
|
||||||
// called for this. This servers as a dummy to prevent calling an
|
|
||||||
// undefined action `workerSrc`.
|
|
||||||
});
|
|
||||||
|
|
||||||
handler.on('doc', function wphSetupDoc(data) {
|
handler.on('doc', function wphSetupDoc(data) {
|
||||||
// Create only the model of the PDFDoc, which is enough for
|
// Create only the model of the PDFDoc, which is enough for
|
||||||
// processing the content of the pdf.
|
// processing the content of the pdf.
|
||||||
pdfDoc = new PDFDocModel(new Stream(data));
|
pdfModel = new PDFDocModel(new Stream(data));
|
||||||
});
|
});
|
||||||
|
|
||||||
handler.on('page_request', function wphSetupPageRequest(pageNum) {
|
handler.on('page_request', function wphSetupPageRequest(pageNum) {
|
||||||
pageNum = parseInt(pageNum);
|
pageNum = parseInt(pageNum);
|
||||||
|
|
||||||
var page = pdfDoc.getPage(pageNum);
|
|
||||||
|
|
||||||
// The following code does quite the same as
|
// The following code does quite the same as
|
||||||
// Page.prototype.startRendering, but stops at one point and sends the
|
// Page.prototype.startRendering, but stops at one point and sends the
|
||||||
|
@ -77,12 +103,42 @@ var WorkerMessageHandler = {
|
||||||
var start = Date.now();
|
var start = Date.now();
|
||||||
|
|
||||||
var dependency = [];
|
var dependency = [];
|
||||||
|
var operatorList = null;
|
||||||
|
try {
|
||||||
|
var page = pdfModel.getPage(pageNum);
|
||||||
// Pre compile the pdf page and fetch the fonts/images.
|
// Pre compile the pdf page and fetch the fonts/images.
|
||||||
var IRQueue = page.getIRQueue(handler, dependency);
|
operatorList = page.getOperatorList(handler, dependency);
|
||||||
|
} catch (e) {
|
||||||
|
var minimumStackMessage =
|
||||||
|
'worker.js: while trying to getPage() and getOperatorList()';
|
||||||
|
|
||||||
console.log('page=%d - getIRQueue: time=%dms, len=%d', pageNum,
|
// Turn the error into an obj that can be serialized
|
||||||
Date.now() - start, IRQueue.fnArray.length);
|
if (typeof e === 'string') {
|
||||||
|
e = {
|
||||||
|
message: e,
|
||||||
|
stack: minimumStackMessage
|
||||||
|
};
|
||||||
|
} else if (typeof e === 'object') {
|
||||||
|
e = {
|
||||||
|
message: e.message || e.toString(),
|
||||||
|
stack: e.stack || minimumStackMessage
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
e = {
|
||||||
|
message: 'Unknown exception type: ' + (typeof e),
|
||||||
|
stack: minimumStackMessage
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
handler.send('page_error', {
|
||||||
|
pageNum: pageNum,
|
||||||
|
error: e
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('page=%d - getOperatorList: time=%dms, len=%d', pageNum,
|
||||||
|
Date.now() - start, operatorList.fnArray.length);
|
||||||
|
|
||||||
// Filter the dependecies for fonts.
|
// Filter the dependecies for fonts.
|
||||||
var fonts = {};
|
var fonts = {};
|
||||||
|
@ -95,59 +151,10 @@ var WorkerMessageHandler = {
|
||||||
|
|
||||||
handler.send('page', {
|
handler.send('page', {
|
||||||
pageNum: pageNum,
|
pageNum: pageNum,
|
||||||
IRQueue: IRQueue,
|
operatorList: operatorList,
|
||||||
depFonts: Object.keys(fonts)
|
depFonts: Object.keys(fonts)
|
||||||
});
|
});
|
||||||
}, this);
|
}, this);
|
||||||
|
|
||||||
handler.on('font', function wphSetupFont(data) {
|
|
||||||
var objId = data[0];
|
|
||||||
var name = data[1];
|
|
||||||
var file = data[2];
|
|
||||||
var properties = data[3];
|
|
||||||
|
|
||||||
var font = {
|
|
||||||
name: name,
|
|
||||||
file: file,
|
|
||||||
properties: properties
|
|
||||||
};
|
|
||||||
|
|
||||||
// Some fonts don't have a file, e.g. the build in ones like Arial.
|
|
||||||
if (file) {
|
|
||||||
var fontFileDict = new Dict();
|
|
||||||
fontFileDict.map = file.dict.map;
|
|
||||||
|
|
||||||
var fontFile = new Stream(file.bytes, file.start,
|
|
||||||
file.end - file.start, fontFileDict);
|
|
||||||
|
|
||||||
// Check if this is a FlateStream. Otherwise just use the created
|
|
||||||
// Stream one. This makes complex_ttf_font.pdf work.
|
|
||||||
var cmf = file.bytes[0];
|
|
||||||
if ((cmf & 0x0f) == 0x08) {
|
|
||||||
font.file = new FlateStream(fontFile);
|
|
||||||
} else {
|
|
||||||
font.file = fontFile;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var obj = new Font(font.name, font.file, font.properties);
|
|
||||||
|
|
||||||
var str = '';
|
|
||||||
var objData = obj.data;
|
|
||||||
if (objData) {
|
|
||||||
var length = objData.length;
|
|
||||||
for (var j = 0; j < length; ++j)
|
|
||||||
str += String.fromCharCode(objData[j]);
|
|
||||||
}
|
|
||||||
|
|
||||||
obj.str = str;
|
|
||||||
|
|
||||||
// Remove the data array form the font object, as it's not needed
|
|
||||||
// anymore as we sent over the ready str.
|
|
||||||
delete obj.data;
|
|
||||||
|
|
||||||
handler.send('font_ready', [objId, obj]);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -168,6 +175,7 @@ var workerConsole = {
|
||||||
action: 'console_error',
|
action: 'console_error',
|
||||||
data: args
|
data: args
|
||||||
});
|
});
|
||||||
|
throw 'pdf.js execution error';
|
||||||
},
|
},
|
||||||
|
|
||||||
time: function time(name) {
|
time: function time(name) {
|
||||||
|
@ -177,7 +185,7 @@ var workerConsole = {
|
||||||
timeEnd: function timeEnd(name) {
|
timeEnd: function timeEnd(name) {
|
||||||
var time = consoleTimer[name];
|
var time = consoleTimer[name];
|
||||||
if (time == null) {
|
if (time == null) {
|
||||||
throw 'Unkown timer name ' + name;
|
error('Unkown timer name ' + name);
|
||||||
}
|
}
|
||||||
this.log('Timer:', name, Date.now() - time);
|
this.log('Timer:', name, Date.now() - time);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,26 +3,8 @@
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
function onMessageLoader(evt) {
|
// List of files to include;
|
||||||
// Reset the `onmessage` function as it was only set to call
|
var files = [
|
||||||
// this function the first time a message is passed to the worker
|
|
||||||
// but shouldn't get called anytime afterwards.
|
|
||||||
this.onmessage = null;
|
|
||||||
|
|
||||||
if (evt.data.action !== 'workerSrc') {
|
|
||||||
throw 'Worker expects first message to be `workerSrc`';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Content of `PDFJS.workerSrc` as defined on the main thread.
|
|
||||||
var workerSrc = evt.data.data;
|
|
||||||
|
|
||||||
// Extract the directory that contains the source files to load.
|
|
||||||
// Assuming the source files have the same relative possition as the
|
|
||||||
// `workerSrc` file.
|
|
||||||
var dir = workerSrc.substring(0, workerSrc.lastIndexOf('/') + 1);
|
|
||||||
|
|
||||||
// List of files to include;
|
|
||||||
var files = [
|
|
||||||
'core.js',
|
'core.js',
|
||||||
'util.js',
|
'util.js',
|
||||||
'canvas.js',
|
'canvas.js',
|
||||||
|
@ -41,13 +23,12 @@ function onMessageLoader(evt) {
|
||||||
'pattern.js',
|
'pattern.js',
|
||||||
'stream.js',
|
'stream.js',
|
||||||
'worker.js',
|
'worker.js',
|
||||||
'../external/jpgjs/jpg.js'
|
'../external/jpgjs/jpg.js',
|
||||||
];
|
'jpx.js',
|
||||||
|
'bidi.js'
|
||||||
|
];
|
||||||
|
|
||||||
// Load all the files.
|
// Load all the files.
|
||||||
for (var i = 0; i < files.length; i++) {
|
for (var i = 0; i < files.length; i++) {
|
||||||
importScripts(dir + files[i]);
|
importScripts(files[i]);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.onmessage = onMessageLoader;
|
|
||||||
|
|
|
@ -20,7 +20,8 @@
|
||||||
height="48.000000px"
|
height="48.000000px"
|
||||||
width="48.000000px"
|
width="48.000000px"
|
||||||
inkscape:output_extension="org.inkscape.output.svg.inkscape"
|
inkscape:output_extension="org.inkscape.output.svg.inkscape"
|
||||||
version="1.1">
|
version="1.1"
|
||||||
|
viewbox="0 0 48 48">
|
||||||
<defs
|
<defs
|
||||||
id="defs3">
|
id="defs3">
|
||||||
<inkscape:perspective
|
<inkscape:perspective
|
||||||
|
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
|
@ -0,0 +1,3 @@
|
||||||
|
<svg height="40" width="40" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M2.379,14.729 5.208,11.899 12.958,19.648 25.877,6.733 28.707,9.561 12.958,25.308z" fill="#333333"></path>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 188 B |
|
@ -0,0 +1,3 @@
|
||||||
|
<svg height="40" width="40" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M16,5.333c-7.732,0-14,4.701-14,10.5c0,1.982,0.741,3.833,2.016,5.414L2,25.667l5.613-1.441c2.339,1.317,5.237,2.107,8.387,2.107c7.732,0,14-4.701,14-10.5C30,10.034,23.732,5.333,16,5.333z" fill="#333333"></path>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 289 B |
|
@ -16,7 +16,8 @@
|
||||||
id="svg2994"
|
id="svg2994"
|
||||||
height="48px"
|
height="48px"
|
||||||
width="48px"
|
width="48px"
|
||||||
inkscape:output_extension="org.inkscape.output.svg.inkscape">
|
inkscape:output_extension="org.inkscape.output.svg.inkscape"
|
||||||
|
viewbox="0 0 48 48">
|
||||||
<defs
|
<defs
|
||||||
id="defs3">
|
id="defs3">
|
||||||
<inkscape:perspective
|
<inkscape:perspective
|
||||||
|
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
|
@ -16,7 +16,8 @@
|
||||||
id="svg2913"
|
id="svg2913"
|
||||||
height="48px"
|
height="48px"
|
||||||
width="48px"
|
width="48px"
|
||||||
inkscape:output_extension="org.inkscape.output.svg.inkscape">
|
inkscape:output_extension="org.inkscape.output.svg.inkscape"
|
||||||
|
viewbox="0 0 48 48">
|
||||||
<defs
|
<defs
|
||||||
id="defs3">
|
id="defs3">
|
||||||
<inkscape:perspective
|
<inkscape:perspective
|
||||||
|
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
|
@ -19,7 +19,8 @@
|
||||||
inkscape:export-filename="/home/jimmac/Desktop/wi-fi.png"
|
inkscape:export-filename="/home/jimmac/Desktop/wi-fi.png"
|
||||||
inkscape:export-xdpi="90.000000"
|
inkscape:export-xdpi="90.000000"
|
||||||
inkscape:export-ydpi="90.000000"
|
inkscape:export-ydpi="90.000000"
|
||||||
inkscape:output_extension="org.inkscape.output.svg.inkscape">
|
inkscape:output_extension="org.inkscape.output.svg.inkscape"
|
||||||
|
viewbox="0 0 48 48">
|
||||||
<defs
|
<defs
|
||||||
id="defs3">
|
id="defs3">
|
||||||
<inkscape:perspective
|
<inkscape:perspective
|
||||||
|
|
Before Width: | Height: | Size: 8.1 KiB After Width: | Height: | Size: 8.2 KiB |
|
@ -19,7 +19,8 @@
|
||||||
inkscape:export-filename="/home/jimmac/Desktop/wi-fi.png"
|
inkscape:export-filename="/home/jimmac/Desktop/wi-fi.png"
|
||||||
inkscape:export-xdpi="90.000000"
|
inkscape:export-xdpi="90.000000"
|
||||||
inkscape:export-ydpi="90.000000"
|
inkscape:export-ydpi="90.000000"
|
||||||
inkscape:output_extension="org.inkscape.output.svg.inkscape">
|
inkscape:output_extension="org.inkscape.output.svg.inkscape"
|
||||||
|
viewbox="0 0 48 48">
|
||||||
<defs
|
<defs
|
||||||
id="defs3">
|
id="defs3">
|
||||||
<inkscape:perspective
|
<inkscape:perspective
|
||||||
|
|
Before Width: | Height: | Size: 8.0 KiB After Width: | Height: | Size: 8.0 KiB |
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.3 KiB |
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 7.6 KiB |
|
@ -0,0 +1,297 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="48"
|
||||||
|
height="48"
|
||||||
|
id="svg3075"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.48.1 r9760"
|
||||||
|
sodipodi:docname="pin-down.svg"
|
||||||
|
viewPort="0 0 48 48">
|
||||||
|
<defs
|
||||||
|
id="defs3077">
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
id="linearGradient3804">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#000000;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop3806" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#000000;stop-opacity:0;"
|
||||||
|
offset="1"
|
||||||
|
id="stop3808" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient3965">
|
||||||
|
<stop
|
||||||
|
id="stop3967"
|
||||||
|
offset="0"
|
||||||
|
style="stop-color:#ffffff;stop-opacity:1;" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#ffffff;stop-opacity:0"
|
||||||
|
offset="1"
|
||||||
|
id="stop3969" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient3885">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#a8b5e9;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop3889" />
|
||||||
|
<stop
|
||||||
|
id="stop3891"
|
||||||
|
offset="1"
|
||||||
|
style="stop-color:#1d4488;stop-opacity:1;" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient3865">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#0e0ec3;stop-opacity:0"
|
||||||
|
offset="0"
|
||||||
|
id="stop3867" />
|
||||||
|
<stop
|
||||||
|
id="stop3883"
|
||||||
|
offset="0.5"
|
||||||
|
style="stop-color:#95b1e4;stop-opacity:1;" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#0d29c0;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop3869" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient3853">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#717171;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop3855" />
|
||||||
|
<stop
|
||||||
|
id="stop3861"
|
||||||
|
offset="0.5"
|
||||||
|
style="stop-color:#ffffff;stop-opacity:1;" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#818181;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop3857" />
|
||||||
|
</linearGradient>
|
||||||
|
<radialGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient3885"
|
||||||
|
id="radialGradient3792"
|
||||||
|
cx="13.508819"
|
||||||
|
cy="30.521608"
|
||||||
|
fx="13.508819"
|
||||||
|
fy="30.521608"
|
||||||
|
r="13.254341"
|
||||||
|
gradientTransform="matrix(1,0,0,1.045977,0,-1.4434017)"
|
||||||
|
gradientUnits="userSpaceOnUse" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient3885"
|
||||||
|
id="linearGradient3802"
|
||||||
|
x1="15.306904"
|
||||||
|
y1="13.407407"
|
||||||
|
x2="29.35461"
|
||||||
|
y2="30.15519"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(1.2304178,0,0,1.1235308,-2.1158755,998.83747)" />
|
||||||
|
<radialGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient3804"
|
||||||
|
id="radialGradient3812"
|
||||||
|
cx="20.111172"
|
||||||
|
cy="28.238274"
|
||||||
|
fx="20.111172"
|
||||||
|
fy="28.238274"
|
||||||
|
r="7.6291947"
|
||||||
|
gradientTransform="matrix(1.2304178,0,0,1.1452771,-2.1158755,998.22337)"
|
||||||
|
gradientUnits="userSpaceOnUse" />
|
||||||
|
<radialGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient3885"
|
||||||
|
id="radialGradient3822"
|
||||||
|
cx="23.985939"
|
||||||
|
cy="24.847366"
|
||||||
|
fx="23.985939"
|
||||||
|
fy="24.847366"
|
||||||
|
r="10.593476"
|
||||||
|
gradientTransform="matrix(0.63682384,0.44303926,-1.1714282,1.6838088,35.523491,-26.055439)"
|
||||||
|
gradientUnits="userSpaceOnUse" />
|
||||||
|
<filter
|
||||||
|
inkscape:collect="always"
|
||||||
|
id="filter3856"
|
||||||
|
x="-0.30370581"
|
||||||
|
width="1.6074116"
|
||||||
|
y="-0.32771564"
|
||||||
|
height="1.6554313">
|
||||||
|
<feGaussianBlur
|
||||||
|
inkscape:collect="always"
|
||||||
|
stdDeviation="4.7808869"
|
||||||
|
id="feGaussianBlur3858" />
|
||||||
|
</filter>
|
||||||
|
<radialGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient3885"
|
||||||
|
id="radialGradient3865"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(1,0,0,1.045977,0,-1.4434017)"
|
||||||
|
cx="13.508819"
|
||||||
|
cy="30.521608"
|
||||||
|
fx="13.508819"
|
||||||
|
fy="30.521608"
|
||||||
|
r="13.254341" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient3885"
|
||||||
|
id="linearGradient3867"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(1.2304178,0,0,1.1235308,-2.1158755,998.83747)"
|
||||||
|
x1="15.306904"
|
||||||
|
y1="13.407407"
|
||||||
|
x2="29.35461"
|
||||||
|
y2="30.15519" />
|
||||||
|
<radialGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient3804"
|
||||||
|
id="radialGradient3869"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(1.2304178,0,0,1.1452771,-2.1158755,998.22337)"
|
||||||
|
cx="20.111172"
|
||||||
|
cy="28.238274"
|
||||||
|
fx="20.111172"
|
||||||
|
fy="28.238274"
|
||||||
|
r="7.6291947" />
|
||||||
|
<radialGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient3885"
|
||||||
|
id="radialGradient3871"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(0.63682384,0.44303926,-1.1714282,1.6838088,35.523491,-26.055439)"
|
||||||
|
cx="23.985939"
|
||||||
|
cy="24.847366"
|
||||||
|
fx="23.985939"
|
||||||
|
fy="24.847366"
|
||||||
|
r="10.593476" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient3885"
|
||||||
|
id="linearGradient3875"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(0.98683814,0,0,0.9524914,3.4991888,1004.1467)"
|
||||||
|
x1="15.306904"
|
||||||
|
y1="13.407407"
|
||||||
|
x2="29.35461"
|
||||||
|
y2="30.15519" />
|
||||||
|
<radialGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient3804"
|
||||||
|
id="radialGradient3877"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(1.195641,0.23932984,-0.18533175,0.95255553,4.5333676,999.33159)"
|
||||||
|
cx="20.111172"
|
||||||
|
cy="28.238274"
|
||||||
|
fx="20.111172"
|
||||||
|
fy="28.238274"
|
||||||
|
r="7.6291947" />
|
||||||
|
<radialGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient3885"
|
||||||
|
id="radialGradient3880"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(1.5847553,0.52693722,-0.99805104,2.7064773,14.11088,-45.304477)"
|
||||||
|
cx="18.133854"
|
||||||
|
cy="19.778509"
|
||||||
|
fx="18.133854"
|
||||||
|
fy="19.778509"
|
||||||
|
r="10.593476" />
|
||||||
|
<radialGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient3885"
|
||||||
|
id="radialGradient3882"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(1,0,0,1.045977,0,-1.4434017)"
|
||||||
|
cx="13.508819"
|
||||||
|
cy="30.521608"
|
||||||
|
fx="13.508819"
|
||||||
|
fy="30.521608"
|
||||||
|
r="13.254341" />
|
||||||
|
</defs>
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="4.9558805"
|
||||||
|
inkscape:cx="3.0237013"
|
||||||
|
inkscape:cy="17.287267"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:window-width="1291"
|
||||||
|
inkscape:window-height="776"
|
||||||
|
inkscape:window-x="16"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="0" />
|
||||||
|
<metadata
|
||||||
|
id="metadata3080">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-1004.3622)">
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:none;filter:url(#filter3856)"
|
||||||
|
d="m 14.326415,1019.2702 c -8.3327876,4.0675 -9.8235436,10.8833 -8.8783416,15.1336 4.6840646,7.9754 8.3608166,13.8165 24.0118786,12.9139 9.657617,-3.7312 12.9762,-9.3269 13.519293,-15.7389 -0.547269,-4.3839 -1.957958,-9.3396 -5.649854,-14.9317 -3.965534,-2.471 -6.300859,-4.4246 -10.290805,-4.2374 -8.25193,0.5026 -8.752485,4.4502 -12.712171,6.8605 z"
|
||||||
|
id="path3826"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccccc"
|
||||||
|
transform="matrix(0.69099294,0,0,0.75978808,7.3427938,249.11025)" />
|
||||||
|
<path
|
||||||
|
sodipodi:type="arc"
|
||||||
|
style="fill:url(#radialGradient3882);fill-opacity:1;stroke:none"
|
||||||
|
id="path3011"
|
||||||
|
sodipodi:cx="21.176477"
|
||||||
|
sodipodi:cy="31.393986"
|
||||||
|
sodipodi:rx="13.254341"
|
||||||
|
sodipodi:ry="13.863736"
|
||||||
|
d="m 34.430819,31.393986 a 13.254341,13.863736 0 1 1 -26.5086827,0 13.254341,13.863736 0 1 1 26.5086827,0 z"
|
||||||
|
transform="matrix(0.98683814,0,0,0.83062636,2.696034,1005.3655)" />
|
||||||
|
<path
|
||||||
|
style="fill:url(#linearGradient3875);fill-opacity:1;stroke:url(#radialGradient3877);stroke-width:0.9695127;stroke-opacity:1"
|
||||||
|
d="m 17.246758,1026.7905 c -1.7156,4.5052 -2.482464,10.6205 8.726963,10.7476 4.849099,-1.8941 3.522783,-5.3561 6.021544,-11.8282 l -10.973104,-1.5977 z"
|
||||||
|
id="path3794"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccc" />
|
||||||
|
<path
|
||||||
|
sodipodi:type="arc"
|
||||||
|
style="fill:url(#radialGradient3880);fill-opacity:1;stroke:none"
|
||||||
|
id="path3814"
|
||||||
|
sodipodi:cx="24.718111"
|
||||||
|
sodipodi:cy="23.38278"
|
||||||
|
sodipodi:rx="10.593476"
|
||||||
|
sodipodi:ry="9.6854639"
|
||||||
|
d="m 35.311587,23.38278 a 10.593476,9.6854639 0 1 1 -21.186952,0 10.593476,9.6854639 0 1 1 21.186952,0 z"
|
||||||
|
transform="matrix(0.85425691,0,0,0.84187503,3.9779774,1006.7561)" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 9.6 KiB |
|
@ -0,0 +1,230 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="48"
|
||||||
|
height="48"
|
||||||
|
id="svg3075"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.48.1 r9760"
|
||||||
|
sodipodi:docname="pin-up.svg"
|
||||||
|
viewPort="0 0 48 48">
|
||||||
|
<defs
|
||||||
|
id="defs3077">
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient3965">
|
||||||
|
<stop
|
||||||
|
id="stop3967"
|
||||||
|
offset="0"
|
||||||
|
style="stop-color:#ffffff;stop-opacity:1;" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#ffffff;stop-opacity:0"
|
||||||
|
offset="1"
|
||||||
|
id="stop3969" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient3885">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#a8b5e9;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop3889" />
|
||||||
|
<stop
|
||||||
|
id="stop3891"
|
||||||
|
offset="1"
|
||||||
|
style="stop-color:#1d4488;stop-opacity:1;" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient3865">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#0e0ec3;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop3867" />
|
||||||
|
<stop
|
||||||
|
id="stop3883"
|
||||||
|
offset="0.5"
|
||||||
|
style="stop-color:#95b1e4;stop-opacity:1;" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#0d29c0;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop3869" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient3853">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#717171;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop3855" />
|
||||||
|
<stop
|
||||||
|
id="stop3861"
|
||||||
|
offset="0.5"
|
||||||
|
style="stop-color:#ffffff;stop-opacity:1;" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#818181;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop3857" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient3853"
|
||||||
|
id="linearGradient3859"
|
||||||
|
x1="7.7696066"
|
||||||
|
y1="34.979828"
|
||||||
|
x2="11.854106"
|
||||||
|
y2="39.107044"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="translate(4.8388015,1001.6582)" />
|
||||||
|
<radialGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient3885"
|
||||||
|
id="radialGradient3871"
|
||||||
|
cx="14.801222"
|
||||||
|
cy="1030.6609"
|
||||||
|
fx="14.801222"
|
||||||
|
fy="1030.6609"
|
||||||
|
r="10.177785"
|
||||||
|
gradientTransform="matrix(1,0,0,1.0108042,4.8388015,-13.880529)"
|
||||||
|
gradientUnits="userSpaceOnUse" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient3865"
|
||||||
|
id="linearGradient3881"
|
||||||
|
x1="15.012629"
|
||||||
|
y1="11.922465"
|
||||||
|
x2="31.098303"
|
||||||
|
y2="28.858271"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(1,0,0,0.97315436,4.8388015,1002.4769)" />
|
||||||
|
<radialGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient3885"
|
||||||
|
id="radialGradient3909"
|
||||||
|
cx="16.437693"
|
||||||
|
cy="22.596292"
|
||||||
|
fx="16.437693"
|
||||||
|
fy="22.596292"
|
||||||
|
r="1.7789712"
|
||||||
|
gradientTransform="matrix(1,0,0,8.3599999,0,-166.30871)"
|
||||||
|
gradientUnits="userSpaceOnUse" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient3865"
|
||||||
|
id="linearGradient3927"
|
||||||
|
x1="26.47109"
|
||||||
|
y1="1010.7343"
|
||||||
|
x2="35.294788"
|
||||||
|
y2="1019.8425"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="translate(4.5541661,-2.1347654)" />
|
||||||
|
<radialGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient3965"
|
||||||
|
id="radialGradient3995"
|
||||||
|
cx="23.189369"
|
||||||
|
cy="25.704245"
|
||||||
|
fx="23.189369"
|
||||||
|
fy="25.704245"
|
||||||
|
r="37.336674"
|
||||||
|
gradientTransform="matrix(1,0,0,1.0332422,0,-0.85446479)"
|
||||||
|
gradientUnits="userSpaceOnUse" />
|
||||||
|
<filter
|
||||||
|
inkscape:collect="always"
|
||||||
|
id="filter4009"
|
||||||
|
x="-0.19299152"
|
||||||
|
width="1.385983"
|
||||||
|
y="-0.18351803"
|
||||||
|
height="1.3670361">
|
||||||
|
<feGaussianBlur
|
||||||
|
inkscape:collect="always"
|
||||||
|
stdDeviation="3.8667902"
|
||||||
|
id="feGaussianBlur4011" />
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="3.2819435"
|
||||||
|
inkscape:cx="18.697469"
|
||||||
|
inkscape:cy="17.287267"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:window-width="970"
|
||||||
|
inkscape:window-height="778"
|
||||||
|
inkscape:window-x="284"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="0" />
|
||||||
|
<metadata
|
||||||
|
id="metadata3080">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-1004.3622)">
|
||||||
|
<path
|
||||||
|
style="fill:url(#radialGradient3995);stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1.0;filter:url(#filter4009)"
|
||||||
|
d="M -0.85390618,50.988672 14.231769,27.790888 C 12.21393,25.133052 9.5514307,24.605255 9.9622384,18.824874 13.947134,14.236899 17.362759,16.258973 21.347654,16.54779 l 8.966014,-8.6813789 c 1.467204,-2.4778468 -1.023584,-4.6422045 0.569271,-7.25820222 4.802307,-0.84764718 6.662499,1.15219542 11.527733,6.26197842 4.061691,4.1873637 5.648882,7.0611607 4.411848,9.5352857 -1.075122,2.776443 -4.518349,-0.692782 -5.835025,0.56927 l -9.108332,10.104556 c -0.418785,3.74872 2.078647,7.861968 -1.280859,11.243098 -4.132171,0.818036 -6.734336,-1.933944 -9.819921,-3.557942 z"
|
||||||
|
id="path3955"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
transform="translate(0,1004.3622)"
|
||||||
|
sodipodi:nodetypes="ccccccccccccc" />
|
||||||
|
<g
|
||||||
|
id="g3929">
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="cccc"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path3083"
|
||||||
|
d="m 3.2884874,1051.0662 c 3.1862139,-6.2911 11.3693156,-15.19 15.4471616,-20.0327 l 2.86533,3.0086 c -3.476851,3.6575 -10.192375,10.8664 -18.3124916,17.0241 z"
|
||||||
|
style="fill:url(#linearGradient3859);fill-opacity:1;stroke:#a5a5a5;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="ccccc"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path3863"
|
||||||
|
d="m 11.10078,1023.3294 c 5.038264,10.1095 11.83652,14.8875 18.358981,18.2167 1.196291,-2.5422 1.454996,-5.6203 0,-9.6776 l -8.539061,-8.6814 c -3.704654,-1.8936 -6.871076,-1.3652 -9.81992,0.1423 z"
|
||||||
|
style="fill:url(#radialGradient3871);fill-opacity:1;stroke:none" />
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="ccccc"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path3873"
|
||||||
|
d="m 33.729292,1011.5171 -13.235545,11.4952 c 2.869602,4.2703 6.221839,7.4544 9.108332,9.1408 l 11.385416,-13.0187 z"
|
||||||
|
style="fill:url(#linearGradient3881);fill-opacity:1;stroke:none" />
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="ccccc"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path3893"
|
||||||
|
d="m 33.228885,1011.6148 c 1.843189,2.7806 3.431654,5.6597 7.19852,7.6953 l 5.398891,1.7423 c -7.6738,-4.7914 -10.989683,-9.5828 -13.947133,-14.3741 z"
|
||||||
|
style="fill:url(#linearGradient3927);fill-opacity:1;stroke:none" />
|
||||||
|
<path
|
||||||
|
transform="matrix(0.68275275,-0.5590416,0.45791123,0.47036287,17.42507,1012.2127)"
|
||||||
|
d="m 18.216664,22.596292 a 1.7789712,14.872199 0 1 1 -3.557943,0 1.7789712,14.872199 0 1 1 3.557943,0 z"
|
||||||
|
sodipodi:ry="14.872199"
|
||||||
|
sodipodi:rx="1.7789712"
|
||||||
|
sodipodi:cy="22.596292"
|
||||||
|
sodipodi:cx="16.437693"
|
||||||
|
id="path3901"
|
||||||
|
style="fill:url(#radialGradient3909);fill-opacity:1;stroke:none"
|
||||||
|
sodipodi:type="arc" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 8.1 KiB |
|
@ -16,7 +16,8 @@
|
||||||
inkscape:version="0.46"
|
inkscape:version="0.46"
|
||||||
sodipodi:docbase="/home/jimmac/src/cvs/tango-icon-theme/scalable/actions"
|
sodipodi:docbase="/home/jimmac/src/cvs/tango-icon-theme/scalable/actions"
|
||||||
sodipodi:docname="list-add.svg"
|
sodipodi:docname="list-add.svg"
|
||||||
inkscape:output_extension="org.inkscape.output.svg.inkscape">
|
inkscape:output_extension="org.inkscape.output.svg.inkscape"
|
||||||
|
viewbox="0 0 48 48">
|
||||||
<defs
|
<defs
|
||||||
id="defs6433">
|
id="defs6433">
|
||||||
<inkscape:perspective
|
<inkscape:perspective
|
||||||
|
@ -418,12 +419,12 @@
|
||||||
d="M 33.278212 34.94062 A 10.31934 2.320194 0 1 1 12.639532,34.94062 A 10.31934 2.320194 0 1 1 33.278212 34.94062 z"
|
d="M 33.278212 34.94062 A 10.31934 2.320194 0 1 1 12.639532,34.94062 A 10.31934 2.320194 0 1 1 33.278212 34.94062 z"
|
||||||
transform="matrix(1.550487,0,0,1.978714,-12.4813,-32.49103)" />
|
transform="matrix(1.550487,0,0,1.978714,-12.4813,-32.49103)" />
|
||||||
<path
|
<path
|
||||||
style="font-size:59.901077px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125.00000%;writing-mode:lr-tb;text-anchor:start;fill:#75a1d0;fill-opacity:1.0000000;stroke:#3465a4;stroke-width:1.0000004px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
|
style="fill:#75a1d0;fill-opacity:1.0000000;stroke:#3465a4;stroke-width:1.0000004px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000"
|
||||||
d="M 27.514356,37.542682 L 27.514356,28.515722 L 37.492820,28.475543 L 37.492820,21.480219 L 27.523285,21.480219 L 27.514356,11.520049 L 20.498082,11.531210 L 20.502546,21.462362 L 10.512920,21.536022 L 10.477206,28.504561 L 20.511475,28.475543 L 20.518171,37.515896 L 27.514356,37.542682 z "
|
d="M 27.514356,37.542682 L 27.514356,28.515722 L 37.492820,28.475543 L 37.492820,21.480219 L 27.523285,21.480219 L 27.514356,11.520049 L 20.498082,11.531210 L 20.502546,21.462362 L 10.512920,21.536022 L 10.477206,28.504561 L 20.511475,28.475543 L 20.518171,37.515896 L 27.514356,37.542682 z "
|
||||||
id="text1314"
|
id="text1314"
|
||||||
sodipodi:nodetypes="ccccccccccccc" />
|
sodipodi:nodetypes="ccccccccccccc" />
|
||||||
<path
|
<path
|
||||||
style="font-size:59.901077px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125.00000%;writing-mode:lr-tb;text-anchor:start;opacity:0.40860215;fill:url(#linearGradient4975);fill-opacity:1.0000000;stroke:url(#linearGradient7922);stroke-width:1.0000006px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
|
style="opacity:0.40860215;fill:url(#linearGradient4975);fill-opacity:1.0000000;stroke:url(#linearGradient7922);stroke-width:1.0000006px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000"
|
||||||
d="M 26.498702,36.533920 L 26.498702,27.499738 L 36.501304,27.499738 L 36.494607,22.475309 L 26.507630,22.475309 L 26.507630,12.480335 L 21.512796,12.498193 L 21.521725,22.475309 L 11.495536,22.493166 L 11.468750,27.466256 L 21.533143,27.475185 L 21.519750,36.502670 L 26.498702,36.533920 z "
|
d="M 26.498702,36.533920 L 26.498702,27.499738 L 36.501304,27.499738 L 36.494607,22.475309 L 26.507630,22.475309 L 26.507630,12.480335 L 21.512796,12.498193 L 21.521725,22.475309 L 11.495536,22.493166 L 11.468750,27.466256 L 21.533143,27.475185 L 21.519750,36.502670 L 26.498702,36.533920 z "
|
||||||
id="path7076"
|
id="path7076"
|
||||||
sodipodi:nodetypes="ccccccccccccc" />
|
sodipodi:nodetypes="ccccccccccccc" />
|
||||||
|
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
@ -16,7 +16,8 @@
|
||||||
inkscape:version="0.46"
|
inkscape:version="0.46"
|
||||||
sodipodi:docbase="/home/jimmac/src/cvs/tango-icon-theme/scalable/actions"
|
sodipodi:docbase="/home/jimmac/src/cvs/tango-icon-theme/scalable/actions"
|
||||||
sodipodi:docname="list-remove.svg"
|
sodipodi:docname="list-remove.svg"
|
||||||
inkscape:output_extension="org.inkscape.output.svg.inkscape">
|
inkscape:output_extension="org.inkscape.output.svg.inkscape"
|
||||||
|
viewbox="0 0 48 48">
|
||||||
<defs
|
<defs
|
||||||
id="defs6433">
|
id="defs6433">
|
||||||
<inkscape:perspective
|
<inkscape:perspective
|
||||||
|
@ -406,12 +407,12 @@
|
||||||
inkscape:label="Layer 1"
|
inkscape:label="Layer 1"
|
||||||
inkscape:groupmode="layer">
|
inkscape:groupmode="layer">
|
||||||
<path
|
<path
|
||||||
style="font-size:59.901077px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125.00000%;writing-mode:lr-tb;text-anchor:start;fill:#75a1d0;fill-opacity:1.0000000;stroke:#3465a4;stroke-width:1.0000004px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
|
style="fill:#75a1d0;fill-opacity:1.0000000;stroke:#3465a4;stroke-width:1.0000004px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000"
|
||||||
d="M 27.514356,28.359472 L 39.633445,28.475543 L 39.633445,21.480219 L 27.523285,21.480219 L 20.502546,21.462362 L 8.5441705,21.489147 L 8.5084565,28.457686 L 20.511475,28.475543 L 27.514356,28.359472 z "
|
d="M 27.514356,28.359472 L 39.633445,28.475543 L 39.633445,21.480219 L 27.523285,21.480219 L 20.502546,21.462362 L 8.5441705,21.489147 L 8.5084565,28.457686 L 20.511475,28.475543 L 27.514356,28.359472 z "
|
||||||
id="text1314"
|
id="text1314"
|
||||||
sodipodi:nodetypes="ccccccccc" />
|
sodipodi:nodetypes="ccccccccc" />
|
||||||
<path
|
<path
|
||||||
style="font-size:59.901077px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125.00000%;writing-mode:lr-tb;text-anchor:start;opacity:0.40860215;fill:url(#linearGradient4975);fill-opacity:1.0000000;stroke:url(#linearGradient7922);stroke-width:1.0000006px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
|
style="opacity:0.40860215;fill:url(#linearGradient4975);fill-opacity:1.0000000;stroke:url(#linearGradient7922);stroke-width:1.0000006px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000"
|
||||||
d="M 38.579429,27.484113 L 38.588357,22.475309 L 9.5267863,22.493166 L 9.5000003,27.466256 L 38.579429,27.484113 z "
|
d="M 38.579429,27.484113 L 38.588357,22.475309 L 9.5267863,22.493166 L 9.5000003,27.466256 L 38.579429,27.484113 z "
|
||||||
id="path7076"
|
id="path7076"
|
||||||
sodipodi:nodetypes="ccccc" />
|
sodipodi:nodetypes="ccccc" />
|
||||||
|
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 13 KiB |