Merge upstream.
This commit is contained in:
commit
a5d9ff8568
66 changed files with 6462 additions and 1424 deletions
|
@ -23,6 +23,7 @@ var CanvasExtraState = (function CanvasExtraStateClosure() {
|
|||
this.alphaIsShape = false;
|
||||
this.fontSize = 0;
|
||||
this.textMatrix = IDENTITY_MATRIX;
|
||||
this.fontMatrix = IDENTITY_MATRIX;
|
||||
this.leading = 0;
|
||||
// Current point (in user coordinates)
|
||||
this.x = 0;
|
||||
|
@ -48,6 +49,7 @@ var CanvasExtraState = (function CanvasExtraStateClosure() {
|
|||
// Note: fill alpha applies to all non-stroking operations
|
||||
this.fillAlpha = 1;
|
||||
this.strokeAlpha = 1;
|
||||
this.lineWidth = 1;
|
||||
|
||||
this.old = old;
|
||||
}
|
||||
|
@ -329,6 +331,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||
|
||||
// Graphics state
|
||||
setLineWidth: function canvasGraphicsSetLineWidth(width) {
|
||||
this.current.lineWidth = width;
|
||||
this.ctx.lineWidth = width;
|
||||
},
|
||||
setLineCap: function canvasGraphicsSetLineCap(style) {
|
||||
|
@ -442,6 +445,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||
consumePath = typeof consumePath !== 'undefined' ? consumePath : true;
|
||||
var ctx = this.ctx;
|
||||
var strokeColor = this.current.strokeColor;
|
||||
if (this.current.lineWidth === 0)
|
||||
ctx.lineWidth = this.getSinglePixelWidth();
|
||||
// For stroke we want to temporarily change the global alpha to the
|
||||
// stroking alpha.
|
||||
ctx.globalAlpha = this.current.strokeAlpha;
|
||||
|
@ -542,12 +547,32 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||
},
|
||||
setFont: function canvasGraphicsSetFont(fontRefName, size) {
|
||||
var fontObj = this.objs.get(fontRefName).fontObj;
|
||||
var current = this.current;
|
||||
|
||||
if (!fontObj) {
|
||||
throw 'Can\'t find font for ' + fontRefName;
|
||||
if (!fontObj)
|
||||
error('Can\'t find font for ' + fontRefName);
|
||||
|
||||
// Slice-clone matrix so we can manipulate it without affecting original
|
||||
if (fontObj.fontMatrix)
|
||||
current.fontMatrix = fontObj.fontMatrix.slice(0);
|
||||
else
|
||||
current.fontMatrix = IDENTITY_MATRIX.slice(0);
|
||||
|
||||
// A valid matrix needs all main diagonal elements to be non-zero
|
||||
// This also ensures we bypass FF bugzilla bug #719844.
|
||||
if (current.fontMatrix[0] === 0 ||
|
||||
current.fontMatrix[3] === 0) {
|
||||
warn('Invalid font matrix for font ' + fontRefName);
|
||||
}
|
||||
|
||||
var name = fontObj.loadedName || 'sans-serif';
|
||||
// The spec for Tf (setFont) says that 'size' specifies the font 'scale',
|
||||
// and in some docs this can be negative (inverted x-y axes).
|
||||
// We implement this condition with fontMatrix.
|
||||
if (size < 0) {
|
||||
size = -size;
|
||||
current.fontMatrix[0] *= -1;
|
||||
current.fontMatrix[3] *= -1;
|
||||
}
|
||||
|
||||
this.current.font = fontObj;
|
||||
this.current.fontSize = size;
|
||||
|
@ -557,7 +582,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||
(fontObj.bold ? 'bold' : 'normal');
|
||||
|
||||
var italic = fontObj.italic ? 'italic' : 'normal';
|
||||
var serif = fontObj.serif ? 'serif' : 'sans-serif';
|
||||
var serif = fontObj.isSerifFont ? 'serif' : 'sans-serif';
|
||||
var typeface = '"' + name + '", ' + serif;
|
||||
var rule = italic + ' ' + bold + ' ' + size + 'px ' + typeface;
|
||||
this.ctx.font = rule;
|
||||
|
@ -591,7 +616,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||
var ctx = this.ctx;
|
||||
var current = this.current;
|
||||
var textHScale = current.textHScale;
|
||||
var fontMatrix = current.font.fontMatrix || IDENTITY_MATRIX;
|
||||
var fontMatrix = current.fontMatrix || IDENTITY_MATRIX;
|
||||
|
||||
ctx.transform.apply(ctx, current.textMatrix);
|
||||
ctx.scale(1, -1);
|
||||
|
@ -625,7 +650,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||
var charSpacing = current.charSpacing;
|
||||
var wordSpacing = current.wordSpacing;
|
||||
var textHScale = current.textHScale;
|
||||
var fontMatrix = font.fontMatrix || IDENTITY_MATRIX;
|
||||
var fontMatrix = current.fontMatrix || IDENTITY_MATRIX;
|
||||
var textHScale2 = textHScale * fontMatrix[0];
|
||||
var glyphsLength = glyphs.length;
|
||||
var textLayer = this.textLayer;
|
||||
|
@ -640,7 +665,6 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||
ctx.translate(current.x, current.y);
|
||||
|
||||
ctx.scale(textHScale, 1);
|
||||
ctx.lineWidth /= current.textMatrix[0];
|
||||
|
||||
if (textSelection) {
|
||||
this.save();
|
||||
|
@ -664,7 +688,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||
this.restore();
|
||||
|
||||
var transformed = Util.applyTransform([glyph.width, 0], fontMatrix);
|
||||
var width = transformed[0] * fontSize + charSpacing;
|
||||
var width = transformed[0] * fontSize +
|
||||
Util.sign(current.fontMatrix[0]) * charSpacing;
|
||||
|
||||
ctx.translate(width, 0);
|
||||
current.x += width * textHScale;
|
||||
|
@ -677,49 +702,58 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||
} else {
|
||||
ctx.save();
|
||||
this.applyTextTransforms();
|
||||
ctx.lineWidth /= current.textMatrix[0] * fontMatrix[0];
|
||||
|
||||
var lineWidth = current.lineWidth;
|
||||
var scale = Math.abs(current.textMatrix[0] * fontMatrix[0]);
|
||||
if (scale == 0 || lineWidth == 0)
|
||||
lineWidth = this.getSinglePixelWidth();
|
||||
else
|
||||
lineWidth /= scale;
|
||||
|
||||
ctx.lineWidth = lineWidth;
|
||||
|
||||
if (textSelection)
|
||||
text.geom = this.getTextGeometry();
|
||||
|
||||
var width = 0;
|
||||
var x = 0;
|
||||
for (var i = 0; i < glyphsLength; ++i) {
|
||||
var glyph = glyphs[i];
|
||||
if (glyph === null) {
|
||||
// word break
|
||||
width += wordSpacing;
|
||||
x += Util.sign(current.fontMatrix[0]) * wordSpacing;
|
||||
continue;
|
||||
}
|
||||
|
||||
var char = glyph.fontChar;
|
||||
var charWidth = glyph.width * fontSize * 0.001 + charSpacing;
|
||||
var charWidth = glyph.width * fontSize * 0.001 +
|
||||
Util.sign(current.fontMatrix[0]) * charSpacing;
|
||||
|
||||
switch (textRenderingMode) {
|
||||
default: // other unsupported rendering modes
|
||||
case TextRenderingMode.FILL:
|
||||
case TextRenderingMode.FILL_ADD_TO_PATH:
|
||||
ctx.fillText(char, width, 0);
|
||||
ctx.fillText(char, x, 0);
|
||||
break;
|
||||
case TextRenderingMode.STROKE:
|
||||
case TextRenderingMode.STROKE_ADD_TO_PATH:
|
||||
ctx.strokeText(char, width, 0);
|
||||
ctx.strokeText(char, x, 0);
|
||||
break;
|
||||
case TextRenderingMode.FILL_STROKE:
|
||||
case TextRenderingMode.FILL_STROKE_ADD_TO_PATH:
|
||||
ctx.fillText(char, width, 0);
|
||||
ctx.strokeText(char, width, 0);
|
||||
ctx.fillText(char, x, 0);
|
||||
ctx.strokeText(char, x, 0);
|
||||
break;
|
||||
case TextRenderingMode.INVISIBLE:
|
||||
break;
|
||||
}
|
||||
|
||||
width += charWidth;
|
||||
x += charWidth;
|
||||
|
||||
text.str += glyph.unicode === ' ' ? '\u00A0' : glyph.unicode;
|
||||
text.length++;
|
||||
text.canvasWidth += charWidth;
|
||||
}
|
||||
current.x += width * textHScale2;
|
||||
current.x += x * textHScale2;
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
|
@ -735,7 +769,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||
var fontSize = current.fontSize;
|
||||
var textHScale = current.textHScale;
|
||||
if (!font.coded)
|
||||
textHScale *= (font.fontMatrix || IDENTITY_MATRIX)[0];
|
||||
textHScale *= (current.fontMatrix || IDENTITY_MATRIX)[0];
|
||||
var arrLength = arr.length;
|
||||
var textLayer = this.textLayer;
|
||||
var text = {str: '', length: 0, canvasWidth: 0, geom: {}};
|
||||
|
@ -832,8 +866,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||
},
|
||||
setStrokeColor: function canvasGraphicsSetStrokeColor(/*...*/) {
|
||||
var cs = this.current.strokeColorSpace;
|
||||
var color = cs.getRgb(arguments);
|
||||
var color = Util.makeCssRgb.apply(null, cs.getRgb(arguments));
|
||||
var rgbColor = cs.getRgb(arguments);
|
||||
var color = Util.makeCssRgb(rgbColor[0], rgbColor[1], rgbColor[2]);
|
||||
this.ctx.strokeStyle = color;
|
||||
this.current.strokeColor = color;
|
||||
},
|
||||
|
@ -855,7 +889,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||
} else if (IR[0] == 'RadialAxial' || IR[0] == 'Dummy') {
|
||||
var pattern = Pattern.shadingFromIR(this.ctx, IR);
|
||||
} else {
|
||||
throw 'Unkown IR type';
|
||||
error('Unkown IR type ' + IR[0]);
|
||||
}
|
||||
return pattern;
|
||||
},
|
||||
|
@ -870,7 +904,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||
},
|
||||
setFillColor: function canvasGraphicsSetFillColor(/*...*/) {
|
||||
var cs = this.current.fillColorSpace;
|
||||
var color = Util.makeCssRgb.apply(null, cs.getRgb(arguments));
|
||||
var rgbColor = cs.getRgb(arguments);
|
||||
var color = Util.makeCssRgb(rgbColor[0], rgbColor[1], rgbColor[2]);
|
||||
this.ctx.fillStyle = color;
|
||||
this.current.fillColor = color;
|
||||
},
|
||||
|
@ -1141,6 +1176,10 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||
},
|
||||
restoreFillRule: function canvasGraphicsRestoreFillRule(rule) {
|
||||
this.ctx.mozFillRule = rule;
|
||||
},
|
||||
getSinglePixelWidth: function getSinglePixelWidth(scale) {
|
||||
var inverse = this.ctx.mozCurrentTransformInverse;
|
||||
return Math.abs(inverse[0] + inverse[2]);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -57,6 +57,11 @@ var ColorSpace = (function ColorSpaceClosure() {
|
|||
|
||||
return new AlternateCS(numComps, ColorSpace.fromIR(alt),
|
||||
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:
|
||||
error('Unkown name ' + name);
|
||||
}
|
||||
|
@ -146,6 +151,8 @@ var ColorSpace = (function ColorSpaceClosure() {
|
|||
var tintFnIR = PDFFunction.getIR(xref, xref.fetchIfRef(cs[3]));
|
||||
return ['AlternateCS', numComps, alt, tintFnIR];
|
||||
case 'Lab':
|
||||
var params = cs[1].map;
|
||||
return ['LabCS', params];
|
||||
default:
|
||||
error('unimplemented color space object "' + mode + '"');
|
||||
}
|
||||
|
@ -369,55 +376,16 @@ var DeviceCmykCS = (function DeviceCmykCSClosure() {
|
|||
DeviceCmykCS.prototype = {
|
||||
getRgb: function cmykcs_getRgb(color) {
|
||||
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;
|
||||
// this is a matrix multiplication, unrolled for performance
|
||||
// code is taken from the poppler implementation
|
||||
x = c1 * m1 * y1 * k1; // 0 0 0 0
|
||||
r = g = b = x;
|
||||
x = c1 * m1 * y1 * k; // 0 0 0 1
|
||||
r += 0.1373 * x;
|
||||
g += 0.1216 * x;
|
||||
b += 0.1255 * x;
|
||||
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;
|
||||
// CMYK -> CMY: http://www.easyrgb.com/index.php?X=MATH&H=14#text14
|
||||
c = (c * (1 - k) + k);
|
||||
m = (m * (1 - k) + k);
|
||||
y = (y * (1 - k) + k);
|
||||
|
||||
// CMY -> RGB: http://www.easyrgb.com/index.php?X=MATH&H=12#text12
|
||||
var r = (1 - c);
|
||||
var g = (1 - m);
|
||||
var b = (1 - y);
|
||||
|
||||
return [r, g, b];
|
||||
},
|
||||
|
@ -448,3 +416,116 @@ var DeviceCmykCS = (function DeviceCmykCSClosure() {
|
|||
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;
|
||||
})();
|
||||
|
|
40
src/core.js
40
src/core.js
|
@ -33,7 +33,9 @@ function getPdf(arg, callback) {
|
|||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', params.url);
|
||||
xhr.mozResponseType = xhr.responseType = 'arraybuffer';
|
||||
xhr.expected = (params.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)
|
||||
xhr.onprogress = params.progress || undefined;
|
||||
|
@ -193,6 +195,9 @@ var Page = (function PageClosure() {
|
|||
for (i = 0; i < n; ++i)
|
||||
content[i] = xref.fetchIfRef(content[i]);
|
||||
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(
|
||||
|
@ -409,14 +414,14 @@ var Page = (function PageClosure() {
|
|||
if (callback)
|
||||
callback(e);
|
||||
else
|
||||
throw e;
|
||||
error(e);
|
||||
}
|
||||
}.bind(this),
|
||||
function pageDisplayReadPromiseError(reason) {
|
||||
if (callback)
|
||||
callback(reason);
|
||||
else
|
||||
throw reason;
|
||||
error(reason);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -619,17 +624,26 @@ var PDFDoc = (function PDFDocClosure() {
|
|||
if (!globalScope.PDFJS.disableWorker && typeof Worker !== 'undefined') {
|
||||
var workerSrc = PDFJS.workerSrc;
|
||||
if (typeof workerSrc === 'undefined') {
|
||||
throw 'No PDFJS.workerSrc specified';
|
||||
error('No PDFJS.workerSrc specified');
|
||||
}
|
||||
|
||||
try {
|
||||
// Some versions of FF can't create a worker on localhost, see:
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=683280
|
||||
var worker = new Worker(workerSrc);
|
||||
var worker;
|
||||
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:
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=683280
|
||||
worker = new Worker(workerSrc);
|
||||
}
|
||||
|
||||
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) {
|
||||
if (supportTypedArray) {
|
||||
this.worker = worker;
|
||||
|
@ -645,7 +659,9 @@ var PDFDoc = (function PDFDocClosure() {
|
|||
// serializing the typed array.
|
||||
messageHandler.send('test', testObj);
|
||||
return;
|
||||
} catch (e) {}
|
||||
} 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.
|
||||
|
@ -716,7 +732,7 @@ var PDFDoc = (function PDFDocClosure() {
|
|||
});
|
||||
break;
|
||||
default:
|
||||
throw 'Got unkown object type ' + type;
|
||||
error('Got unkown object type ' + type);
|
||||
}
|
||||
}, this);
|
||||
|
||||
|
@ -737,7 +753,7 @@ var PDFDoc = (function PDFDocClosure() {
|
|||
if (page.displayReadyPromise)
|
||||
page.displayReadyPromise.reject(data.error);
|
||||
else
|
||||
throw data.error;
|
||||
error(data.error);
|
||||
}, this);
|
||||
|
||||
messageHandler.on('jpeg_decode', function(data, promise) {
|
||||
|
|
|
@ -159,6 +159,10 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||
// 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', [
|
||||
loadedName,
|
||||
|
@ -292,8 +296,8 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||
// Create an IR of the pattern code.
|
||||
var depIdx = dependencyArray.length;
|
||||
var queueObj = {};
|
||||
var codeIR = this.getIRQueue(pattern, dict.get('Resources'),
|
||||
queueObj, dependencyArray);
|
||||
var codeIR = this.getIRQueue(pattern, dict.get('Resources') ||
|
||||
resources, queueObj, dependencyArray);
|
||||
|
||||
// Add the dependencies that are required to execute the
|
||||
// codeIR.
|
||||
|
@ -336,8 +340,8 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||
// This adds the IRQueue of the xObj to the current queue.
|
||||
var depIdx = dependencyArray.length;
|
||||
|
||||
this.getIRQueue(xobj, xobj.dict.get('Resources'), queue,
|
||||
dependencyArray);
|
||||
this.getIRQueue(xobj, xobj.dict.get('Resources') || resources,
|
||||
queue, dependencyArray);
|
||||
|
||||
// Add the dependencies that are required to execute the
|
||||
// codeIR.
|
||||
|
@ -481,8 +485,10 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||
properties.cidToGidMap = this.readCidToGidMap(cidToGidMap);
|
||||
}
|
||||
|
||||
var flags = properties.flags;
|
||||
var differences = [];
|
||||
var baseEncoding = Encodings.StandardEncoding;
|
||||
var baseEncoding = !!(flags & FontFlags.Symbolic) ?
|
||||
Encodings.symbolsEncoding : Encodings.StandardEncoding;
|
||||
var hasEncoding = dict.has('Encoding');
|
||||
if (hasEncoding) {
|
||||
var encoding = xref.fetchIfRef(dict.get('Encoding'));
|
||||
|
@ -758,10 +764,18 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||
baseFontName = baseFontName.name.replace(/[,_]/g, '-');
|
||||
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 = {
|
||||
type: type.name,
|
||||
widths: metrics.widths,
|
||||
defaultWidth: metrics.defaultWidth,
|
||||
flags: flags,
|
||||
firstChar: 0,
|
||||
lastChar: maxCharIndex
|
||||
};
|
||||
|
@ -773,11 +787,10 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||
properties: properties
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 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.
|
||||
// TODO Fill the width array depending on which of the base font this is
|
||||
// a variant.
|
||||
|
|
155
src/fonts.js
155
src/fonts.js
|
@ -19,6 +19,18 @@ var kPDFGlyphSpaceUnits = 1000;
|
|||
// Until hinting is fully supported this constant can be used
|
||||
var kHintingEnabled = false;
|
||||
|
||||
var FontFlags = {
|
||||
FixedPitch: 1,
|
||||
Serif: 2,
|
||||
Symbolic: 4,
|
||||
Script: 8,
|
||||
Nonsymbolic: 32,
|
||||
Italic: 64,
|
||||
AllCap: 65536,
|
||||
SmallCap: 131072,
|
||||
ForceBold: 262144
|
||||
};
|
||||
|
||||
var Encodings = {
|
||||
get ExpertEncoding() {
|
||||
return shadow(this, 'ExpertEncoding', ['', '', '', '', '', '', '', '', '',
|
||||
|
@ -160,19 +172,20 @@ var Encodings = {
|
|||
'bracketleft', 'backslash', 'bracketright', 'asciicircum', 'underscore',
|
||||
'quoteleft', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
|
||||
'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
|
||||
'braceleft', 'bar', 'braceright', 'asciitilde', '', '', 'exclamdown',
|
||||
'cent', 'sterling', 'fraction', 'yen', 'florin', 'section', 'currency',
|
||||
'quotesingle', 'quotedblleft', 'guillemotleft', 'guilsinglleft',
|
||||
'guilsinglright', 'fi', 'fl', '', 'endash', 'dagger', 'daggerdbl',
|
||||
'periodcentered', '', 'paragraph', 'bullet', 'quotesinglbase',
|
||||
'quotedblbase', 'quotedblright', 'guillemotright', 'ellipsis',
|
||||
'perthousand', '', 'questiondown', '', 'grave', 'acute', 'circumflex',
|
||||
'tilde', 'macron', 'breve', 'dotaccent', 'dieresis', '', 'ring',
|
||||
'cedilla', '', 'hungarumlaut', 'ogonek', 'caron', 'emdash', '', '', '',
|
||||
'', '', '', '', '', '', '', '', '', '', '', '', '', 'AE', '',
|
||||
'ordfeminine', '', '', '', '', 'Lslash', 'Oslash', 'OE', 'ordmasculine',
|
||||
'', '', '', '', '', 'ae', '', '', '', 'dotlessi', '', '', 'lslash',
|
||||
'oslash', 'oe', 'germandbls'
|
||||
'braceleft', 'bar', 'braceright', 'asciitilde', '', '', '', '', '', '',
|
||||
'', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
|
||||
'', '', '', '', '', '', '', '', '', '', 'exclamdown', 'cent', 'sterling',
|
||||
'fraction', 'yen', 'florin', 'section', 'currency', 'quotesingle',
|
||||
'quotedblleft', 'guillemotleft', 'guilsinglleft', 'guilsinglright', 'fi',
|
||||
'fl', '', 'endash', 'dagger', 'daggerdbl', 'periodcentered', '',
|
||||
'paragraph', 'bullet', 'quotesinglbase', 'quotedblbase', 'quotedblright',
|
||||
'guillemotright', 'ellipsis', 'perthousand', '', 'questiondown', '',
|
||||
'grave', 'acute', 'circumflex', 'tilde', 'macron', 'breve', 'dotaccent',
|
||||
'dieresis', '', 'ring', 'cedilla', '', 'hungarumlaut', 'ogonek', 'caron',
|
||||
'emdash', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
|
||||
'AE', '', 'ordfeminine', '', '', '', '', 'Lslash', 'Oslash', 'OE',
|
||||
'ordmasculine', '', '', '', '', '', 'ae', '', '', '', 'dotlessi', '', '',
|
||||
'lslash', 'oslash', 'oe', 'germandbls'
|
||||
]);
|
||||
},
|
||||
get WinAnsiEncoding() {
|
||||
|
@ -339,6 +352,21 @@ var stdFontMap = {
|
|||
'TimesNewRomanPSMT-Italic': 'Times-Italic'
|
||||
};
|
||||
|
||||
/**
|
||||
* Holds the map of the non-standard fonts that might be included as a standard
|
||||
* fonts without glyph data.
|
||||
*/
|
||||
var nonStdFontMap = {
|
||||
'ComicSansMS': 'Comic Sans MS',
|
||||
'ComicSansMS-Bold': 'Comic Sans MS-Bold',
|
||||
'ComicSansMS-BoldItalic': 'Comic Sans MS-BoldItalic',
|
||||
'ComicSansMS-Italic': 'Comic Sans MS-Italic',
|
||||
'LucidaConsole': 'Courier',
|
||||
'LucidaConsole-Bold': 'Courier-Bold',
|
||||
'LucidaConsole-BoldItalic': 'Courier-BoldOblique',
|
||||
'LucidaConsole-Italic': 'Courier-Oblique'
|
||||
};
|
||||
|
||||
var serifFonts = {
|
||||
'Adobe Jenson': true, 'Adobe Text': true, 'Albertus': true,
|
||||
'Aldus': true, 'Alexandria': true, 'Algerian': true,
|
||||
|
@ -386,6 +414,23 @@ var serifFonts = {
|
|||
'Wide Latin': true, 'Windsor': true, 'XITS': true
|
||||
};
|
||||
|
||||
var symbolsFonts = {
|
||||
'Dingbats': true, 'Symbol': true, 'ZapfDingbats': true
|
||||
};
|
||||
|
||||
// Some characters, e.g. copyrightserif, mapped to the private use area and
|
||||
// might not be displayed using standard fonts. Mapping/hacking well-known chars
|
||||
// to the similar equivalents in the normal characters range.
|
||||
function mapPrivateUseChars(code) {
|
||||
switch (code) {
|
||||
case 0xF8E9: // copyrightsans
|
||||
case 0xF6D9: // copyrightserif
|
||||
return 0x00A9; // copyright
|
||||
default:
|
||||
return code;
|
||||
}
|
||||
}
|
||||
|
||||
var FontLoader = {
|
||||
listeningForFontLoad: false,
|
||||
|
||||
|
@ -528,7 +573,8 @@ var FontLoader = {
|
|||
src += ' window.onload = function fontLoaderOnload() {\n';
|
||||
src += ' parent.postMessage(JSON.stringify(fontNames), "*");\n';
|
||||
src += ' }';
|
||||
src += '</script></head><body>';
|
||||
// Hack so the end script tag isn't counted if this is inline JS.
|
||||
src += '</scr' + 'ipt></head><body>';
|
||||
for (var i = 0, ii = names.length; i < ii; ++i) {
|
||||
src += '<p style="font-family:\'' + names[i] + '\'">Hi</p>';
|
||||
}
|
||||
|
@ -742,7 +788,8 @@ var Font = (function FontClosure() {
|
|||
var names = name.split('+');
|
||||
names = names.length > 1 ? names[1] : names[0];
|
||||
names = names.split(/[-,_]/g)[0];
|
||||
this.serif = serifFonts[names] || (name.search(/serif/gi) != -1);
|
||||
this.isSerifFont = !!(properties.flags & FontFlags.Serif);
|
||||
this.isSymbolicFont = !!(properties.flags & FontFlags.Symbolic);
|
||||
|
||||
var type = properties.type;
|
||||
this.type = type;
|
||||
|
@ -750,7 +797,7 @@ var Font = (function FontClosure() {
|
|||
// If the font is to be ignored, register it like an already loaded font
|
||||
// to avoid the cost of waiting for it be be loaded by the platform.
|
||||
if (properties.ignore) {
|
||||
this.loadedName = this.serif ? 'serif' : 'sans-serif';
|
||||
this.loadedName = this.isSerifFont ? 'serif' : 'sans-serif';
|
||||
this.loading = false;
|
||||
return;
|
||||
}
|
||||
|
@ -780,7 +827,7 @@ var Font = (function FontClosure() {
|
|||
// The file data is not specified. Trying to fix the font name
|
||||
// to be used with the canvas.font.
|
||||
var fontName = name.replace(/[,_]/g, '-');
|
||||
fontName = stdFontMap[fontName] || fontName;
|
||||
fontName = stdFontMap[fontName] || nonStdFontMap[fontName] || fontName;
|
||||
|
||||
this.bold = (fontName.search(/bold/gi) != -1);
|
||||
this.italic = (fontName.search(/oblique/gi) != -1) ||
|
||||
|
@ -830,7 +877,6 @@ var Font = (function FontClosure() {
|
|||
this.widthMultiplier = !properties.fontMatrix ? 1.0 :
|
||||
1.0 / properties.fontMatrix[0];
|
||||
this.encoding = properties.baseEncoding;
|
||||
this.hasShortCmap = properties.hasShortCmap;
|
||||
this.loadedName = getUniqueName();
|
||||
this.loading = true;
|
||||
};
|
||||
|
@ -1800,7 +1846,32 @@ var Font = (function FontClosure() {
|
|||
this.useToUnicode = true;
|
||||
}
|
||||
}
|
||||
properties.hasShortCmap = hasShortCmap;
|
||||
|
||||
if (hasShortCmap && this.hasEncoding && !this.isSymbolicFont) {
|
||||
// Re-encode short map encoding to unicode -- that simplifies the
|
||||
// resolution of MacRoman encoded glyphs logic for TrueType fonts:
|
||||
// copying all characters to private use area, all mapping all known
|
||||
// glyphs to the unicodes. The glyphs and ids arrays will grow.
|
||||
var usedUnicodes = [];
|
||||
for (var i = 0, ii = glyphs.length; i < ii; i++) {
|
||||
var code = glyphs[i].unicode;
|
||||
glyphs[i].unicode += kCmapGlyphOffset;
|
||||
|
||||
var glyphName = properties.baseEncoding[code];
|
||||
if (glyphName in GlyphsUnicode) {
|
||||
var unicode = GlyphsUnicode[glyphName];
|
||||
if (unicode in usedUnicodes)
|
||||
continue;
|
||||
|
||||
usedUnicodes[unicode] = true;
|
||||
glyphs.push({
|
||||
unicode: unicode,
|
||||
code: glyphs[i].code
|
||||
});
|
||||
ids.push(ids[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove glyph references outside range of avaialable glyphs
|
||||
for (var i = 0, ii = ids.length; i < ii; i++) {
|
||||
|
@ -2092,10 +2163,11 @@ var Font = (function FontClosure() {
|
|||
window.btoa(data) + ');');
|
||||
var rule = "@font-face { font-family:'" + fontName + "';src:" + url + '}';
|
||||
|
||||
var styleElement = document.createElement('style');
|
||||
document.documentElement.getElementsByTagName('head')[0].appendChild(
|
||||
document.createElement('style'));
|
||||
styleElement);
|
||||
|
||||
var styleSheet = document.styleSheets[document.styleSheets.length - 1];
|
||||
var styleSheet = styleElement.sheet;
|
||||
styleSheet.insertRule(rule, styleSheet.cssRules.length);
|
||||
|
||||
return rule;
|
||||
|
@ -2141,7 +2213,7 @@ var Font = (function FontClosure() {
|
|||
case 'CIDFontType0':
|
||||
if (this.noUnicodeAdaptation) {
|
||||
width = this.widths[this.unicodeToCID[charcode] || charcode];
|
||||
unicode = charcode;
|
||||
unicode = mapPrivateUseChars(charcode);
|
||||
break;
|
||||
}
|
||||
unicode = this.toUnicode[charcode] || charcode;
|
||||
|
@ -2149,7 +2221,7 @@ var Font = (function FontClosure() {
|
|||
case 'CIDFontType2':
|
||||
if (this.noUnicodeAdaptation) {
|
||||
width = this.widths[this.unicodeToCID[charcode] || charcode];
|
||||
unicode = charcode;
|
||||
unicode = mapPrivateUseChars(charcode);
|
||||
break;
|
||||
}
|
||||
unicode = this.toUnicode[charcode] || charcode;
|
||||
|
@ -2159,7 +2231,7 @@ var Font = (function FontClosure() {
|
|||
if (!isNum(width))
|
||||
width = this.widths[glyphName];
|
||||
if (this.noUnicodeAdaptation) {
|
||||
unicode = GlyphsUnicode[glyphName] || charcode;
|
||||
unicode = mapPrivateUseChars(GlyphsUnicode[glyphName] || charcode);
|
||||
break;
|
||||
}
|
||||
unicode = this.glyphNameMap[glyphName] ||
|
||||
|
@ -2184,19 +2256,14 @@ var Font = (function FontClosure() {
|
|||
unicode = GlyphsUnicode[glyphName] || charcode;
|
||||
break;
|
||||
}
|
||||
if (!this.hasEncoding) {
|
||||
if (!this.hasEncoding || this.isSymbolicFont) {
|
||||
unicode = this.useToUnicode ? this.toUnicode[charcode] : charcode;
|
||||
break;
|
||||
}
|
||||
if (this.hasShortCmap && false) {
|
||||
var j = Encodings.MacRomanEncoding.indexOf(glyphName);
|
||||
unicode = j >= 0 ? j :
|
||||
this.glyphNameMap[glyphName];
|
||||
} else {
|
||||
unicode = glyphName in GlyphsUnicode ?
|
||||
GlyphsUnicode[glyphName] :
|
||||
this.glyphNameMap[glyphName];
|
||||
}
|
||||
|
||||
// MacRoman encoding address by re-encoding the cmap table
|
||||
unicode = glyphName in this.glyphNameMap ?
|
||||
this.glyphNameMap[glyphName] : GlyphsUnicode[glyphName];
|
||||
break;
|
||||
default:
|
||||
warn('Unsupported font type: ' + this.type);
|
||||
|
@ -2553,7 +2620,13 @@ var Type1Parser = function type1Parser() {
|
|||
while (str[index++] != ']')
|
||||
count++;
|
||||
|
||||
var array = str.substr(start, count).split(' ');
|
||||
str = str.substr(start, count);
|
||||
|
||||
str = str.trim();
|
||||
// Remove adjacent spaces
|
||||
str = str.replace(/\s+/g, ' ');
|
||||
|
||||
var array = str.split(' ');
|
||||
for (var i = 0, ii = array.length; i < ii; i++)
|
||||
array[i] = parseFloat(array[i] || 0);
|
||||
return array;
|
||||
|
@ -3299,15 +3372,9 @@ var Type2CFF = (function Type2CFFClosure() {
|
|||
inverseEncoding[encoding[charcode]] = charcode | 0;
|
||||
for (var i = 0, ii = charsets.length; i < ii; i++) {
|
||||
var glyph = charsets[i];
|
||||
if (glyph == '.notdef') {
|
||||
charstrings.push({
|
||||
unicode: 0,
|
||||
code: 0,
|
||||
gid: i,
|
||||
glyph: glyph
|
||||
});
|
||||
if (glyph == '.notdef')
|
||||
continue;
|
||||
}
|
||||
|
||||
var code = inverseEncoding[i];
|
||||
if (!code || isSpecialUnicode(code)) {
|
||||
unassignedUnicodeItems.push(i);
|
||||
|
@ -3560,7 +3627,7 @@ var Type2CFF = (function Type2CFFClosure() {
|
|||
dict['cidOperatorPresent'] = true;
|
||||
break;
|
||||
default:
|
||||
TODO('interpret top dict key');
|
||||
TODO('interpret top dict key: ' + key);
|
||||
}
|
||||
}
|
||||
return dict;
|
||||
|
|
156
src/function.js
156
src/function.js
|
@ -125,109 +125,99 @@ var PDFFunction = (function PDFFunctionClosure() {
|
|||
else
|
||||
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);
|
||||
|
||||
return [
|
||||
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) {
|
||||
var inputSize = IR[1];
|
||||
var domain = IR[2];
|
||||
var encode = IR[3];
|
||||
var decode = IR[4];
|
||||
var samples = IR[5];
|
||||
var size = IR[6];
|
||||
var outputSize = IR[7];
|
||||
var bps = IR[8];
|
||||
var range = IR[9];
|
||||
var inputMul = IR[10];
|
||||
var idxMul = IR[11];
|
||||
var nSamples = IR[12];
|
||||
// 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) {
|
||||
if (inputSize != args.length)
|
||||
// See chapter 3, page 110 of the PDF reference.
|
||||
var m = IR[1];
|
||||
var domain = IR[2];
|
||||
var encode = IR[3];
|
||||
var decode = IR[4];
|
||||
var samples = IR[5];
|
||||
var size = IR[6];
|
||||
var n = IR[7];
|
||||
var mask = IR[8];
|
||||
var range = IR[9];
|
||||
|
||||
if (m != args.length)
|
||||
error('Incorrect number of arguments: ' + inputSize + ' != ' +
|
||||
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
|
||||
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];
|
||||
}
|
||||
var x = args;
|
||||
|
||||
// for each output, do m-linear interpolation
|
||||
for (i = 0; i < outputSize; ++i) {
|
||||
// Building the cube vertices: its part and sample index
|
||||
// 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
|
||||
for (j = 0; j < (1 << inputSize); ++j) {
|
||||
idx = i;
|
||||
for (k = 0, t = j; k < inputSize; ++k, t >>= 1) {
|
||||
idx += idxMul[k] * (e[k][t & 1]);
|
||||
}
|
||||
if (idx >= 0 && idx < nSamples) {
|
||||
sBuf[j] = samples[idx];
|
||||
var k = n, pos = 1;
|
||||
// Map x_i to y_j for 0 <= i < m using the sampled function.
|
||||
for (var i = 0; i < m; ++i) {
|
||||
// x_i' = min(max(x_i, Domain_2i), Domain_2i+1)
|
||||
var domain_2i = domain[i][0];
|
||||
var domain_2i_1 = domain[i][1];
|
||||
var xi = Math.min(Math.max(x[i], domain_2i), domain_2i_1);
|
||||
|
||||
// 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 {
|
||||
sBuf[j] = 0; // TODO Investigate if this is what Adobe does
|
||||
cubeN[j] *= n0;
|
||||
cubeVertex[j] += offset0;
|
||||
}
|
||||
}
|
||||
|
||||
// do m sets of interpolations
|
||||
for (j = 0, t = (1 << inputSize); j < inputSize; ++j, t >>= 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
|
||||
out[i] = (sBuf[0] * (decode[i][1] - decode[i][0]) + decode[i][0]);
|
||||
if (out[i] < range[i][0]) {
|
||||
out[i] = range[i][0];
|
||||
} else if (out[i] > range[i][1]) {
|
||||
out[i] = range[i][1];
|
||||
}
|
||||
k *= size_i;
|
||||
pos <<= 1;
|
||||
}
|
||||
return out;
|
||||
|
||||
var y = new Float64Array(n);
|
||||
for (var j = 0; j < n; ++j) {
|
||||
// Sum all cube vertices' samples portions
|
||||
var rj = 0;
|
||||
for (var i = 0; i < cubeVertices; i++)
|
||||
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 y;
|
||||
}
|
||||
},
|
||||
|
||||
|
|
1854
src/jpx.js
Normal file
1854
src/jpx.js
Normal file
File diff suppressed because it is too large
Load diff
159
src/obj.js
159
src/obj.js
|
@ -287,74 +287,69 @@ var XRef = (function XRefClosure() {
|
|||
|
||||
XRef.prototype = {
|
||||
readXRefTable: function 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;
|
||||
while (true) {
|
||||
if (isCmd(obj = parser.getObj(), 'trailer'))
|
||||
break;
|
||||
if (!isInt(obj))
|
||||
error('Invalid XRef table');
|
||||
var first = obj;
|
||||
if (!isInt(obj = parser.getObj()))
|
||||
error('Invalid XRef table');
|
||||
var n = obj;
|
||||
if (first < 0 || n < 0 || (first + n) != ((first + n) | 0))
|
||||
error('Invalid XRef table: ' + first + ', ' + n);
|
||||
for (var i = first; i < first + n; ++i) {
|
||||
while (!isCmd(obj = parser.getObj(), 'trailer')) {
|
||||
var first = obj,
|
||||
count = parser.getObj();
|
||||
|
||||
if (!isInt(first) || !isInt(count))
|
||||
error('Invalid XRef table: wrong types in subsection header');
|
||||
|
||||
// Inner loop is over objects themselves
|
||||
for (var i = 0; i < count; i++) {
|
||||
var entry = {};
|
||||
if (!isInt(obj = parser.getObj()))
|
||||
error('Invalid XRef table: ' + first + ', ' + n);
|
||||
entry.offset = obj;
|
||||
if (!isInt(obj = parser.getObj()))
|
||||
error('Invalid XRef table: ' + first + ', ' + n);
|
||||
entry.gen = obj;
|
||||
obj = parser.getObj();
|
||||
if (isCmd(obj, 'n')) {
|
||||
entry.uncompressed = true;
|
||||
} else if (isCmd(obj, 'f')) {
|
||||
entry.offset = parser.getObj();
|
||||
entry.gen = parser.getObj();
|
||||
var type = parser.getObj();
|
||||
|
||||
if (isCmd(type, 'f'))
|
||||
entry.free = true;
|
||||
} else {
|
||||
error('Invalid XRef table: ' + first + ', ' + n);
|
||||
}
|
||||
if (!this.entries[i]) {
|
||||
// In some buggy PDF files the xref table claims to start at 1
|
||||
// instead of 0.
|
||||
if (i == 1 && first == 1 &&
|
||||
entry.offset == 0 && entry.gen == 65535 && entry.free) {
|
||||
i = first = 0;
|
||||
}
|
||||
this.entries[i] = entry;
|
||||
else if (isCmd(type, 'n'))
|
||||
entry.uncompressed = true;
|
||||
|
||||
// Validate entry obj
|
||||
if (!isInt(entry.offset) || !isInt(entry.gen) ||
|
||||
!(entry.free || entry.uncompressed)) {
|
||||
error('Invalid entry in XRef subsection: ' + first + ', ' + count);
|
||||
}
|
||||
|
||||
if (!this.entries[i + first])
|
||||
this.entries[i + first] = entry;
|
||||
}
|
||||
}
|
||||
|
||||
// read the trailer dictionary
|
||||
var dict;
|
||||
if (!isDict(dict = parser.getObj()))
|
||||
error('Invalid XRef table');
|
||||
// Sanity check: as per spec, first object must have these properties
|
||||
if (this.entries[0] &&
|
||||
!(this.entries[0].gen === 65535 && this.entries[0].free))
|
||||
error('Invalid XRef table: unexpected first object');
|
||||
|
||||
// get the 'Prev' pointer
|
||||
var prev;
|
||||
obj = dict.get('Prev');
|
||||
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);
|
||||
}
|
||||
// Sanity check
|
||||
if (!isCmd(obj, 'trailer'))
|
||||
error('Invalid XRef table: could not find trailer dictionary');
|
||||
|
||||
// check for 'XRefStm' key
|
||||
if (isInt(obj = dict.get('XRefStm'))) {
|
||||
var pos = obj;
|
||||
// ignore previously loaded xref streams (possible infinite recursion)
|
||||
if (!(pos in this.xrefstms)) {
|
||||
this.xrefstms[pos] = 1;
|
||||
this.readXRef(pos);
|
||||
}
|
||||
}
|
||||
// Read trailer dictionary, e.g.
|
||||
// trailer
|
||||
// << /Size 22
|
||||
// /Root 20R
|
||||
// /Info 10R
|
||||
// /ID [ <81b14aafa313db63dbd6f981e49f94f4> ]
|
||||
// >>
|
||||
// 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;
|
||||
},
|
||||
|
@ -407,9 +402,6 @@ var XRef = (function XRefClosure() {
|
|||
}
|
||||
range.splice(0, 2);
|
||||
}
|
||||
var prev = streamParameters.get('Prev');
|
||||
if (isInt(prev))
|
||||
this.readXRef(prev);
|
||||
return streamParameters;
|
||||
},
|
||||
indexObjects: function indexObjects() {
|
||||
|
@ -529,22 +521,47 @@ var XRef = (function XRefClosure() {
|
|||
try {
|
||||
var parser = new Parser(new Lexer(stream), true);
|
||||
var obj = parser.getObj();
|
||||
var dict;
|
||||
|
||||
// parse an old-style xref table
|
||||
if (isCmd(obj, 'xref'))
|
||||
return this.readXRefTable(parser);
|
||||
// Get dictionary
|
||||
if (isCmd(obj, 'xref')) {
|
||||
// Parse end-of-file XRef
|
||||
dict = this.readXRefTable(parser);
|
||||
|
||||
// parse an xref stream
|
||||
if (isInt(obj)) {
|
||||
// Recursively get other XRefs 'XRefStm', if any
|
||||
obj = dict.get('XRefStm');
|
||||
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()) ||
|
||||
!isCmd(parser.getObj(), 'obj') ||
|
||||
!isStream(obj = parser.getObj())) {
|
||||
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('Reading of the xref table/stream failed: ' + e);
|
||||
log('(while reading XRef): ' + e);
|
||||
}
|
||||
|
||||
warn('Indexing all PDF objects');
|
||||
|
@ -574,7 +591,7 @@ var XRef = (function XRefClosure() {
|
|||
var stream, parser;
|
||||
if (e.uncompressed) {
|
||||
if (e.gen != gen)
|
||||
throw ('inconsistent generation in XRef');
|
||||
error('inconsistent generation in XRef');
|
||||
stream = this.stream.makeSubStream(e.offset);
|
||||
parser = new Parser(new Lexer(stream), true, this);
|
||||
var obj1 = parser.getObj();
|
||||
|
@ -703,7 +720,7 @@ var PDFObjects = (function PDFObjectsClosure() {
|
|||
// If there isn't an object yet or the object isn't resolved, then the
|
||||
// data isn't ready yet!
|
||||
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;
|
||||
|
|
|
@ -240,6 +240,10 @@ var Parser = (function ParserClosure() {
|
|||
var bytes = stream.getBytes(length);
|
||||
return new JpegStream(bytes, stream.dict, this.xref);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
@ -249,6 +253,9 @@ var Parser = (function ParserClosure() {
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -94,9 +94,9 @@ Shadings.RadialAxial = (function RadialAxialClosure() {
|
|||
|
||||
var colorStops = [];
|
||||
for (var i = t0; i <= t1; i += step) {
|
||||
var color = fn([i]);
|
||||
var rgbColor = Util.makeCssRgb.apply(this, cs.getRgb(color));
|
||||
colorStops.push([(i - t0) / diff, rgbColor]);
|
||||
var rgbColor = cs.getRgb(fn([i]));
|
||||
var cssColor = Util.makeCssRgb(rgbColor[0], rgbColor[1], rgbColor[2]);
|
||||
colorStops.push([(i - t0) / diff, cssColor]);
|
||||
}
|
||||
|
||||
this.colorStops = colorStops;
|
||||
|
@ -234,9 +234,9 @@ var TilingPattern = (function TilingPatternClosure() {
|
|||
tmpCtx.strokeStyle = ctx.strokeStyle;
|
||||
break;
|
||||
case PaintType.UNCOLORED:
|
||||
color = Util.makeCssRgb.apply(this, color);
|
||||
tmpCtx.fillStyle = color;
|
||||
tmpCtx.strokeStyle = color;
|
||||
var cssColor = Util.makeCssRgb(this, color[0], color[1], color[2]);
|
||||
tmpCtx.fillStyle = cssColor;
|
||||
tmpCtx.strokeStyle = cssColor;
|
||||
break;
|
||||
default:
|
||||
error('Unsupported paint type: ' + paintType);
|
||||
|
|
170
src/stream.js
170
src/stream.js
|
@ -821,21 +821,25 @@ var JpegStream = (function JpegStreamClosure() {
|
|||
JpegStream.prototype.ensureBuffer = function jpegStreamEnsureBuffer(req) {
|
||||
if (this.bufferLength)
|
||||
return;
|
||||
var jpegImage = new JpegImage();
|
||||
if (this.colorTransform != -1)
|
||||
jpegImage.colorTransform = this.colorTransform;
|
||||
jpegImage.parse(this.bytes);
|
||||
var width = jpegImage.width;
|
||||
var height = jpegImage.height;
|
||||
var data = jpegImage.getData(width, height);
|
||||
this.buffer = data;
|
||||
this.bufferLength = data.length;
|
||||
try {
|
||||
var jpegImage = new JpegImage();
|
||||
if (this.colorTransform != -1)
|
||||
jpegImage.colorTransform = this.colorTransform;
|
||||
jpegImage.parse(this.bytes);
|
||||
var width = jpegImage.width;
|
||||
var height = jpegImage.height;
|
||||
var data = jpegImage.getData(width, height);
|
||||
this.buffer = data;
|
||||
this.bufferLength = data.length;
|
||||
} catch (e) {
|
||||
error('JPEG error: ' + e);
|
||||
}
|
||||
};
|
||||
JpegStream.prototype.getIR = function jpegStreamGetIR() {
|
||||
return bytesToString(this.bytes);
|
||||
};
|
||||
JpegStream.prototype.getChar = function jpegStreamGetChar() {
|
||||
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
|
||||
|
@ -869,6 +873,107 @@ var JpegStream = (function JpegStreamClosure() {
|
|||
return JpegStream;
|
||||
})();
|
||||
|
||||
/**
|
||||
* 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 jpxStreamEnsureBuffer(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 jpxStreamGetChar() {
|
||||
error('internal error: getChar is not valid on JpxStream');
|
||||
};
|
||||
|
||||
return JpxStream;
|
||||
})();
|
||||
|
||||
var DecryptStream = (function DecryptStreamClosure() {
|
||||
function DecryptStream(str, decrypt) {
|
||||
this.str = str;
|
||||
|
@ -1041,6 +1146,51 @@ var AsciiHexStream = (function AsciiHexStreamClosure() {
|
|||
return AsciiHexStream;
|
||||
})();
|
||||
|
||||
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 runLengthStreamReadBlock() {
|
||||
// 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;
|
||||
|
|
38
src/util.js
38
src/util.js
|
@ -78,21 +78,43 @@ var IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0];
|
|||
|
||||
var Util = (function UtilClosure() {
|
||||
function Util() {}
|
||||
|
||||
Util.makeCssRgb = function makergb(r, g, b) {
|
||||
var ri = (255 * r) | 0, gi = (255 * g) | 0, bi = (255 * b) | 0;
|
||||
return 'rgb(' + ri + ',' + gi + ',' + bi + ')';
|
||||
};
|
||||
|
||||
Util.makeCssCmyk = function makecmyk(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;
|
||||
return 'rgb(' + ri + ',' + gi + ',' + bi + ')';
|
||||
};
|
||||
|
||||
// For 2d affine transforms
|
||||
Util.applyTransform = function apply(p, m) {
|
||||
var xt = p[0] * m[0] + p[1] * m[2] + m[4];
|
||||
var yt = p[0] * m[1] + p[1] * m[3] + m[5];
|
||||
return [xt, yt];
|
||||
};
|
||||
|
||||
// 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 apply3d(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]
|
||||
];
|
||||
}
|
||||
|
||||
Util.sign = function sign(num) {
|
||||
return num < 0 ? -1 : 1;
|
||||
};
|
||||
|
||||
return Util;
|
||||
})();
|
||||
|
||||
|
@ -255,8 +277,8 @@ var Promise = (function PromiseClosure() {
|
|||
return;
|
||||
}
|
||||
if (this._data !== EMPTY_PROMISE) {
|
||||
throw 'Promise ' + this.name +
|
||||
': Cannot set the data of a promise twice';
|
||||
error('Promise ' + this.name +
|
||||
': Cannot set the data of a promise twice');
|
||||
}
|
||||
this._data = value;
|
||||
this.hasData = true;
|
||||
|
@ -268,7 +290,7 @@ var Promise = (function PromiseClosure() {
|
|||
|
||||
get data() {
|
||||
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;
|
||||
},
|
||||
|
@ -283,10 +305,10 @@ var Promise = (function PromiseClosure() {
|
|||
|
||||
resolve: function promiseResolve(data) {
|
||||
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) {
|
||||
throw 'The Promise was already rejected ' + this.name;
|
||||
error('The Promise was already rejected ' + this.name);
|
||||
}
|
||||
|
||||
this.isResolved = true;
|
||||
|
@ -300,10 +322,10 @@ var Promise = (function PromiseClosure() {
|
|||
|
||||
reject: function proimseReject(reason) {
|
||||
if (this.isRejected) {
|
||||
throw 'A Promise can be rejected only once ' + this.name;
|
||||
error('A Promise can be rejected only once ' + this.name);
|
||||
}
|
||||
if (this.isResolved) {
|
||||
throw 'The Promise was already resolved ' + this.name;
|
||||
error('The Promise was already resolved ' + this.name);
|
||||
}
|
||||
|
||||
this.isRejected = true;
|
||||
|
@ -317,7 +339,7 @@ var Promise = (function PromiseClosure() {
|
|||
|
||||
then: function promiseThen(callback, errback) {
|
||||
if (!callback) {
|
||||
throw 'Requiring callback' + this.name;
|
||||
error('Requiring callback' + this.name);
|
||||
}
|
||||
|
||||
// If the promise is already resolved, call the callback directly.
|
||||
|
|
|
@ -26,7 +26,7 @@ function MessageHandler(name, comObj) {
|
|||
delete callbacks[callbackId];
|
||||
callback(data.data);
|
||||
} else {
|
||||
throw 'Cannot resolve callback ' + callbackId;
|
||||
error('Cannot resolve callback ' + callbackId);
|
||||
}
|
||||
} else if (data.action in ah) {
|
||||
var action = ah[data.action];
|
||||
|
@ -44,7 +44,7 @@ function MessageHandler(name, comObj) {
|
|||
action[0].call(action[1], data.data);
|
||||
}
|
||||
} else {
|
||||
throw 'Unkown action from worker: ' + data.action;
|
||||
error('Unkown action from worker: ' + data.action);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ MessageHandler.prototype = {
|
|||
on: function messageHandlerOn(actionName, handler, scope) {
|
||||
var ah = this.actionHandler;
|
||||
if (ah[actionName]) {
|
||||
throw 'There is already an actionName called "' + actionName + '"';
|
||||
error('There is already an actionName called "' + actionName + '"');
|
||||
}
|
||||
ah[actionName] = [handler, scope];
|
||||
},
|
||||
|
@ -85,13 +85,6 @@ var WorkerMessageHandler = {
|
|||
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) {
|
||||
// Create only the model of the PDFDoc, which is enough for
|
||||
// processing the content of the pdf.
|
||||
|
@ -116,11 +109,27 @@ var WorkerMessageHandler = {
|
|||
// Pre compile the pdf page and fetch the fonts/images.
|
||||
IRQueue = page.getIRQueue(handler, dependency);
|
||||
} catch (e) {
|
||||
var minimumStackMessage =
|
||||
'worker.js: while trying to getPage() and getIRQueue()';
|
||||
|
||||
// Turn the error into an obj that can be serialized
|
||||
e = {
|
||||
message: typeof e === 'object' ? e.message : e,
|
||||
stack: typeof e === 'object' ? e.stack : null
|
||||
};
|
||||
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
|
||||
|
@ -215,6 +224,7 @@ var workerConsole = {
|
|||
action: 'console_error',
|
||||
data: args
|
||||
});
|
||||
throw 'pdf.js execution error';
|
||||
},
|
||||
|
||||
time: function time(name) {
|
||||
|
@ -224,7 +234,7 @@ var workerConsole = {
|
|||
timeEnd: function timeEnd(name) {
|
||||
var time = consoleTimer[name];
|
||||
if (time == null) {
|
||||
throw 'Unkown timer name ' + name;
|
||||
error('Unkown timer name ' + name);
|
||||
}
|
||||
this.log('Timer:', name, Date.now() - time);
|
||||
}
|
||||
|
|
|
@ -3,51 +3,31 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
function onMessageLoader(evt) {
|
||||
// Reset the `onmessage` function as it was only set to call
|
||||
// this function the first time a message is passed to the worker
|
||||
// but shouldn't get called anytime afterwards.
|
||||
this.onmessage = null;
|
||||
// List of files to include;
|
||||
var files = [
|
||||
'core.js',
|
||||
'util.js',
|
||||
'canvas.js',
|
||||
'obj.js',
|
||||
'function.js',
|
||||
'charsets.js',
|
||||
'cidmaps.js',
|
||||
'colorspace.js',
|
||||
'crypto.js',
|
||||
'evaluator.js',
|
||||
'fonts.js',
|
||||
'glyphlist.js',
|
||||
'image.js',
|
||||
'metrics.js',
|
||||
'parser.js',
|
||||
'pattern.js',
|
||||
'stream.js',
|
||||
'worker.js',
|
||||
'../external/jpgjs/jpg.js',
|
||||
'jpx.js'
|
||||
];
|
||||
|
||||
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',
|
||||
'util.js',
|
||||
'canvas.js',
|
||||
'obj.js',
|
||||
'function.js',
|
||||
'charsets.js',
|
||||
'cidmaps.js',
|
||||
'colorspace.js',
|
||||
'crypto.js',
|
||||
'evaluator.js',
|
||||
'fonts.js',
|
||||
'glyphlist.js',
|
||||
'image.js',
|
||||
'metrics.js',
|
||||
'parser.js',
|
||||
'pattern.js',
|
||||
'stream.js',
|
||||
'worker.js',
|
||||
'../external/jpgjs/jpg.js'
|
||||
];
|
||||
|
||||
// Load all the files.
|
||||
for (var i = 0; i < files.length; i++) {
|
||||
importScripts(dir + files[i]);
|
||||
}
|
||||
// Load all the files.
|
||||
for (var i = 0; i < files.length; i++) {
|
||||
importScripts(files[i]);
|
||||
}
|
||||
|
||||
this.onmessage = onMessageLoader;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue