summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorschneefux <schneefux+commit@schneefux.xyz>2014-06-10 15:24:45 +0200
committerschneefux <schneefux+commit@schneefux.xyz>2016-08-15 20:02:41 +0200
commit83b02062f91d616a01a5daa035fbca7d097adc05 (patch)
tree63008394cba75f43404066d25a63dd392585a227
parent46cf469a0dfa9088aaf059b2d051ecf9951beea7 (diff)
downloadwvs-vplan-83b02062f91d616a01a5daa035fbca7d097adc05.tar.gz
wvs-vplan-83b02062f91d616a01a5daa035fbca7d097adc05.zip
aktualisiere PDF.js
-rw-r--r--index.html1
-rw-r--r--js/index.js8
-rw-r--r--js/pdf.js3914
-rw-r--r--js/pdf.worker.js13355
4 files changed, 8993 insertions, 8285 deletions
diff --git a/index.html b/index.html
index 05ca5a6..d611028 100644
--- a/index.html
+++ b/index.html
@@ -129,6 +129,7 @@
<script type="text/javascript" src="js/jqm-themehack.js"></script>
<script type="text/javascript" src="js/jquery.mobile-1.4.2.min.js"></script>
<script type="text/javascript" src="cordova.js"></script>
+ <script type="text/javascript" src="js/compatibility.js"></script> <!-- sonst gibt es Probleme mit PDF.js, weil Android zu schlecht ist -->
<script type="text/javascript" src="js/pdf.js"></script>
<script type="text/javascript" src="js/moment-with-langs.min.js"></script>
<script type="text/javascript" src="js/piwik.js"></script>
diff --git a/js/index.js b/js/index.js
index a22e96b..ddedc8f 100644
--- a/js/index.js
+++ b/js/index.js
@@ -598,12 +598,12 @@ function renderPage($div, pdf, pageNumber, callback){
var pageText = "";
var lastBlock = null;
- for(j = 0; j < textContent.length; j++){
- var block = textContent[j];
+ for(j = 0; j < textContent.items.length; j++){
+ var block = textContent.items[j];
if(lastBlock !== null && lastBlock.str[lastBlock.str.length - 1] !== ' '){
- if(block.x < lastBlock.x){
+ if(block.transform[4] < lastBlock.transform[4]){
pageText += '\n';
- }else if(lastBlock.y !== block.y && (lastBlock.str.match(/^(\s?[a-zA-Z])$|^(.+\s[a-zA-Z])$/) === null )){
+ }else if(lastBlock.transform[5] !== block.transform[5] && (lastBlock.str.match(/^(\s?[a-zA-Z])$|^(.+\s[a-zA-Z])$/) === null )){
pageText += '\n';
}
}
diff --git a/js/pdf.js b/js/pdf.js
index 421c29a..6d7416f 100644
--- a/js/pdf.js
+++ b/js/pdf.js
@@ -21,8 +21,8 @@ if (typeof PDFJS === 'undefined') {
(typeof window !== 'undefined' ? window : this).PDFJS = {};
}
-PDFJS.version = '0.8.1239';
-PDFJS.build = '1a6e103';
+PDFJS.version = '1.0.276';
+PDFJS.build = 'a09aecb';
(function pdfjsWrapper() {
// Use strict in our context only - users might not want it
@@ -181,7 +181,9 @@ var OPS = PDFJS.OPS = {
paintInlineImageXObject: 86,
paintInlineImageXObjectGroup: 87,
paintImageXObjectRepeat: 88,
- paintImageMaskXObjectRepeat: 89
+ paintImageMaskXObjectRepeat: 89,
+ paintSolidColorImageMask: 90,
+ constructPath: 91
};
// A notice for devs. These are good for things that are helpful to devs, such
@@ -266,9 +268,10 @@ function combineUrl(baseUrl, url) {
if (/^[a-z][a-z0-9+\-.]*:/i.test(url)) {
return url;
}
+ var i;
if (url.charAt(0) == '/') {
// absolute path
- var i = baseUrl.indexOf('://');
+ i = baseUrl.indexOf('://');
if (url.charAt(1) === '/') {
++i;
} else {
@@ -277,7 +280,7 @@ function combineUrl(baseUrl, url) {
return baseUrl.substring(0, i) + url;
} else {
// relative path
- var pathLength = baseUrl.length, i;
+ var pathLength = baseUrl.length;
i = baseUrl.lastIndexOf('#');
pathLength = i >= 0 ? i : pathLength;
i = baseUrl.lastIndexOf('?', pathLength);
@@ -311,14 +314,6 @@ function isValidUrl(url, allowRelative) {
}
PDFJS.isValidUrl = isValidUrl;
-// In a well-formed PDF, |cond| holds. If it doesn't, subsequent
-// behavior is undefined.
-function assertWellFormed(cond, msg) {
- if (!cond) {
- error(msg);
- }
-}
-
function shadow(obj, prop, value) {
Object.defineProperty(obj, prop, { value: value,
enumerable: true,
@@ -422,23 +417,137 @@ var XRefParseException = (function XRefParseExceptionClosure() {
function bytesToString(bytes) {
- var strBuf = [];
var length = bytes.length;
- for (var n = 0; n < length; ++n) {
- strBuf.push(String.fromCharCode(bytes[n]));
+ var MAX_ARGUMENT_COUNT = 8192;
+ if (length < MAX_ARGUMENT_COUNT) {
+ return String.fromCharCode.apply(null, bytes);
+ }
+ var strBuf = [];
+ for (var i = 0; i < length; i += MAX_ARGUMENT_COUNT) {
+ var chunkEnd = Math.min(i + MAX_ARGUMENT_COUNT, length);
+ var chunk = bytes.subarray(i, chunkEnd);
+ strBuf.push(String.fromCharCode.apply(null, chunk));
}
return strBuf.join('');
}
+function stringToArray(str) {
+ var length = str.length;
+ var array = [];
+ for (var i = 0; i < length; ++i) {
+ array[i] = str.charCodeAt(i);
+ }
+ return array;
+}
+
function stringToBytes(str) {
var length = str.length;
var bytes = new Uint8Array(length);
- for (var n = 0; n < length; ++n) {
- bytes[n] = str.charCodeAt(n) & 0xFF;
+ for (var i = 0; i < length; ++i) {
+ bytes[i] = str.charCodeAt(i) & 0xFF;
}
return bytes;
}
+function string32(value) {
+ return String.fromCharCode((value >> 24) & 0xff, (value >> 16) & 0xff,
+ (value >> 8) & 0xff, value & 0xff);
+}
+
+function log2(x) {
+ var n = 1, i = 0;
+ while (x > n) {
+ n <<= 1;
+ i++;
+ }
+ return i;
+}
+
+function readInt8(data, start) {
+ return (data[start] << 24) >> 24;
+}
+
+function readUint16(data, offset) {
+ return (data[offset] << 8) | data[offset + 1];
+}
+
+function readUint32(data, offset) {
+ return ((data[offset] << 24) | (data[offset + 1] << 16) |
+ (data[offset + 2] << 8) | data[offset + 3]) >>> 0;
+}
+
+// Lazy test the endianness of the platform
+// NOTE: This will be 'true' for simulated TypedArrays
+function isLittleEndian() {
+ var buffer8 = new Uint8Array(2);
+ buffer8[0] = 1;
+ var buffer16 = new Uint16Array(buffer8.buffer);
+ return (buffer16[0] === 1);
+}
+
+Object.defineProperty(PDFJS, 'isLittleEndian', {
+ configurable: true,
+ get: function PDFJS_isLittleEndian() {
+ return shadow(PDFJS, 'isLittleEndian', isLittleEndian());
+ }
+});
+
+ // Lazy test if the userAgant support CanvasTypedArrays
+function hasCanvasTypedArrays() {
+ var canvas = document.createElement('canvas');
+ canvas.width = canvas.height = 1;
+ var ctx = canvas.getContext('2d');
+ var imageData = ctx.createImageData(1, 1);
+ return (typeof imageData.data.buffer !== 'undefined');
+}
+
+Object.defineProperty(PDFJS, 'hasCanvasTypedArrays', {
+ configurable: true,
+ get: function PDFJS_hasCanvasTypedArrays() {
+ return shadow(PDFJS, 'hasCanvasTypedArrays', hasCanvasTypedArrays());
+ }
+});
+
+var Uint32ArrayView = (function Uint32ArrayViewClosure() {
+
+ function Uint32ArrayView(buffer, length) {
+ this.buffer = buffer;
+ this.byteLength = buffer.length;
+ this.length = length === undefined ? (this.byteLength >> 2) : length;
+ ensureUint32ArrayViewProps(this.length);
+ }
+ Uint32ArrayView.prototype = Object.create(null);
+
+ var uint32ArrayViewSetters = 0;
+ function createUint32ArrayProp(index) {
+ return {
+ get: function () {
+ var buffer = this.buffer, offset = index << 2;
+ return (buffer[offset] | (buffer[offset + 1] << 8) |
+ (buffer[offset + 2] << 16) | (buffer[offset + 3] << 24)) >>> 0;
+ },
+ set: function (value) {
+ var buffer = this.buffer, offset = index << 2;
+ buffer[offset] = value & 255;
+ buffer[offset + 1] = (value >> 8) & 255;
+ buffer[offset + 2] = (value >> 16) & 255;
+ buffer[offset + 3] = (value >>> 24) & 255;
+ }
+ };
+ }
+
+ function ensureUint32ArrayViewProps(length) {
+ while (uint32ArrayViewSetters < length) {
+ Object.defineProperty(Uint32ArrayView.prototype,
+ uint32ArrayViewSetters,
+ createUint32ArrayProp(uint32ArrayViewSetters));
+ uint32ArrayViewSetters++;
+ }
+ }
+
+ return Uint32ArrayView;
+})();
+
var IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0];
var Util = PDFJS.Util = (function UtilClosure() {
@@ -448,11 +557,6 @@ var Util = PDFJS.Util = (function UtilClosure() {
return 'rgb(' + rgb[0] + ',' + rgb[1] + ',' + rgb[2] + ')';
};
- Util.makeCssCmyk = function Util_makeCssCmyk(cmyk) {
- var rgb = ColorSpace.singletons.cmyk.getRgb(cmyk, 0);
- return Util.makeCssRgb(rgb);
- };
-
// Concatenates two transformation matrices together and returns the result.
Util.transform = function Util_transform(m1, m2) {
return [
@@ -652,7 +756,22 @@ var Util = PDFJS.Util = (function UtilClosure() {
return Util;
})();
+/**
+ * PDF page viewport created based on scale, rotation and offset.
+ * @class
+ * @alias PDFJS.PageViewport
+ */
var PageViewport = PDFJS.PageViewport = (function PageViewportClosure() {
+ /**
+ * @constructor
+ * @private
+ * @param viewBox {Array} xMin, yMin, xMax and yMax coordinates.
+ * @param scale {number} scale of the viewport.
+ * @param rotation {number} rotations of the viewport in degrees.
+ * @param offsetX {number} offset X
+ * @param offsetY {number} offset Y
+ * @param dontFlip {boolean} if true, axis Y will not be flipped.
+ */
function PageViewport(viewBox, scale, rotation, offsetX, offsetY, dontFlip) {
this.viewBox = viewBox;
this.scale = scale;
@@ -716,7 +835,14 @@ var PageViewport = PDFJS.PageViewport = (function PageViewportClosure() {
this.height = height;
this.fontScale = scale;
}
- PageViewport.prototype = {
+ PageViewport.prototype = /** @lends PDFJS.PageViewport.prototype */ {
+ /**
+ * Clones viewport with additional properties.
+ * @param args {Object} (optional) If specified, may contain the 'scale' or
+ * 'rotation' properties to override the corresponding properties in
+ * the cloned viewport.
+ * @returns {PDFJS.PageViewport} Cloned viewport.
+ */
clone: function PageViewPort_clone(args) {
args = args || {};
var scale = 'scale' in args ? args.scale : this.scale;
@@ -724,15 +850,41 @@ var PageViewport = PDFJS.PageViewport = (function PageViewportClosure() {
return new PageViewport(this.viewBox.slice(), scale, rotation,
this.offsetX, this.offsetY, args.dontFlip);
},
+ /**
+ * Converts PDF point to the viewport coordinates. For examples, useful for
+ * converting PDF location into canvas pixel coordinates.
+ * @param x {number} X coordinate.
+ * @param y {number} Y coordinate.
+ * @returns {Object} Object that contains 'x' and 'y' properties of the
+ * point in the viewport coordinate space.
+ * @see {@link convertToPdfPoint}
+ * @see {@link convertToViewportRectangle}
+ */
convertToViewportPoint: function PageViewport_convertToViewportPoint(x, y) {
return Util.applyTransform([x, y], this.transform);
},
+ /**
+ * Converts PDF rectangle to the viewport coordinates.
+ * @param rect {Array} xMin, yMin, xMax and yMax coordinates.
+ * @returns {Array} Contains corresponding coordinates of the rectangle
+ * in the viewport coordinate space.
+ * @see {@link convertToViewportPoint}
+ */
convertToViewportRectangle:
function PageViewport_convertToViewportRectangle(rect) {
var tl = Util.applyTransform([rect[0], rect[1]], this.transform);
var br = Util.applyTransform([rect[2], rect[3]], this.transform);
return [tl[0], tl[1], br[0], br[1]];
},
+ /**
+ * Converts viewport coordinates to the PDF location. For examples, useful
+ * for converting canvas pixel location into PDF one.
+ * @param x {number} X coordinate.
+ * @param y {number} Y coordinate.
+ * @returns {Object} Object that contains 'x' and 'y' properties of the
+ * point in the PDF coordinate space.
+ * @see {@link convertToViewportPoint}
+ */
convertToPdfPoint: function PageViewport_convertToPdfPoint(x, y) {
return Util.applyInverseTransform([x, y], this.transform);
}
@@ -837,40 +989,36 @@ function isRef(v) {
return v instanceof Ref;
}
-function isPDFFunction(v) {
- var fnDict;
- if (typeof v != 'object') {
- return false;
- } else if (isDict(v)) {
- fnDict = v;
- } else if (isStream(v)) {
- fnDict = v.dict;
- } else {
- return false;
- }
- return fnDict.has('FunctionType');
-}
+/**
+ * Promise Capability object.
+ *
+ * @typedef {Object} PromiseCapability
+ * @property {Promise} promise - A promise object.
+ * @property {function} resolve - Fullfills the promise.
+ * @property {function} reject - Rejects the promise.
+ */
/**
- * Legacy support for PDFJS Promise implementation.
- * TODO remove eventually
+ * Creates a promise capability object.
+ * @alias PDFJS.createPromiseCapability
+ *
+ * @return {PromiseCapability} A capability object contains:
+ * - a Promise, resolve and reject methods.
*/
-var LegacyPromise = PDFJS.LegacyPromise = (function LegacyPromiseClosure() {
- return function LegacyPromise() {
- var resolve, reject;
- var promise = new Promise(function (resolve_, reject_) {
- resolve = resolve_;
- reject = reject_;
- });
- promise.resolve = resolve;
- promise.reject = reject;
- return promise;
- };
-})();
+function createPromiseCapability() {
+ var capability = {};
+ capability.promise = new Promise(function (resolve, reject) {
+ capability.resolve = resolve;
+ capability.reject = reject;
+ });
+ return capability;
+}
+
+PDFJS.createPromiseCapability = createPromiseCapability;
/**
* Polyfill for Promises:
- * The following promise implementation tries to generally implment the
+ * The following promise implementation tries to generally implement the
* Promise/A+ spec. Some notable differences from other promise libaries are:
* - There currently isn't a seperate deferred and promise object.
* - Unhandled rejections eventually show an error if they aren't handled.
@@ -905,8 +1053,20 @@ var LegacyPromise = PDFJS.LegacyPromise = (function LegacyPromiseClosure() {
};
}
if (typeof globalScope.Promise.resolve !== 'function') {
- globalScope.Promise.resolve = function (x) {
- return new globalScope.Promise(function (resolve) { resolve(x); });
+ globalScope.Promise.resolve = function (value) {
+ return new globalScope.Promise(function (resolve) { resolve(value); });
+ };
+ }
+ if (typeof globalScope.Promise.reject !== 'function') {
+ globalScope.Promise.reject = function (reason) {
+ return new globalScope.Promise(function (resolve, reject) {
+ reject(reason);
+ });
+ };
+ }
+ if (typeof globalScope.Promise.prototype.catch !== 'function') {
+ globalScope.Promise.prototype.catch = function (onReject) {
+ return globalScope.Promise.prototype.then(undefined, onReject);
};
}
return;
@@ -1031,7 +1191,11 @@ var LegacyPromise = PDFJS.LegacyPromise = (function LegacyPromiseClosure() {
function Promise(resolver) {
this._status = STATUS_PENDING;
this._handlers = [];
- resolver.call(this, this._resolve.bind(this), this._reject.bind(this));
+ try {
+ resolver.call(this, this._resolve.bind(this), this._reject.bind(this));
+ } catch (e) {
+ this._reject(e);
+ }
}
/**
* Builds a promise that is resolved when all the passed in promises are
@@ -1083,18 +1247,28 @@ var LegacyPromise = PDFJS.LegacyPromise = (function LegacyPromiseClosure() {
/**
* Checks if the value is likely a promise (has a 'then' function).
- * @return {boolean} true if x is thenable
+ * @return {boolean} true if value is thenable
*/
Promise.isPromise = function Promise_isPromise(value) {
return value && typeof value.then === 'function';
};
+
/**
* Creates resolved promise
- * @param x resolve value
+ * @param value resolve value
* @returns {Promise}
*/
- Promise.resolve = function Promise_resolve(x) {
- return new Promise(function (resolve) { resolve(x); });
+ Promise.resolve = function Promise_resolve(value) {
+ return new Promise(function (resolve) { resolve(value); });
+ };
+
+ /**
+ * Creates rejected promise
+ * @param reason rejection value
+ * @returns {Promise}
+ */
+ Promise.reject = function Promise_reject(reason) {
+ return new Promise(function (resolve, reject) { reject(reason); });
};
Promise.prototype = {
@@ -1148,6 +1322,10 @@ var LegacyPromise = PDFJS.LegacyPromise = (function LegacyPromiseClosure() {
});
HandlerManager.scheduleHandlers(this);
return nextPromise;
+ },
+
+ catch: function Promise_catch(onReject) {
+ return this.then(undefined, onReject);
}
};
@@ -1192,17 +1370,18 @@ var StatTimer = (function StatTimerClosure() {
delete this.started[name];
},
toString: function StatTimer_toString() {
+ var i, ii;
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) {
+ for (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) {
+ for (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';
@@ -1254,7 +1433,7 @@ function MessageHandler(name, comObj) {
this.comObj = comObj;
this.callbackIndex = 1;
this.postMessageTransfers = true;
- var callbacks = this.callbacks = {};
+ var callbacksCapabilities = this.callbacksCapabilities = {};
var ah = this.actionHandler = {};
ah['console_log'] = [function ahConsoleLog(data) {
@@ -1271,35 +1450,40 @@ function MessageHandler(name, comObj) {
var data = event.data;
if (data.isReply) {
var callbackId = data.callbackId;
- if (data.callbackId in callbacks) {
- var callback = callbacks[callbackId];
- delete callbacks[callbackId];
- callback(data.data);
+ if (data.callbackId in callbacksCapabilities) {
+ var callback = callbacksCapabilities[callbackId];
+ delete callbacksCapabilities[callbackId];
+ if ('error' in data) {
+ callback.reject(data.error);
+ } else {
+ callback.resolve(data.data);
+ }
} else {
error('Cannot resolve callback ' + callbackId);
}
} else if (data.action in ah) {
var action = ah[data.action];
if (data.callbackId) {
- var deferred = {};
- var promise = new Promise(function (resolve, reject) {
- deferred.resolve = resolve;
- deferred.reject = reject;
- });
- deferred.promise = promise;
- promise.then(function(resolvedData) {
+ Promise.resolve().then(function () {
+ return action[0].call(action[1], data.data);
+ }).then(function (result) {
+ comObj.postMessage({
+ isReply: true,
+ callbackId: data.callbackId,
+ data: result
+ });
+ }, function (reason) {
comObj.postMessage({
isReply: true,
callbackId: data.callbackId,
- data: resolvedData
+ error: reason
});
});
- action[0].call(action[1], data.data, deferred);
} else {
action[0].call(action[1], data.data);
}
} else {
- error('Unkown action from worker: ' + data.action);
+ error('Unknown action from worker: ' + data.action);
}
};
}
@@ -1316,19 +1500,47 @@ MessageHandler.prototype = {
* Sends a message to the comObj to invoke the action with the supplied data.
* @param {String} actionName Action to call.
* @param {JSON} data JSON data to send.
- * @param {function} [callback] Optional callback that will handle a reply.
* @param {Array} [transfers] Optional list of transfers/ArrayBuffers
*/
- send: function messageHandlerSend(actionName, data, callback, transfers) {
+ send: function messageHandlerSend(actionName, data, transfers) {
var message = {
action: actionName,
data: data
};
- if (callback) {
- var callbackId = this.callbackIndex++;
- this.callbacks[callbackId] = callback;
- message.callbackId = callbackId;
+ this.postMessage(message, transfers);
+ },
+ /**
+ * Sends a message to the comObj to invoke the action with the supplied data.
+ * Expects that other side will callback with the response.
+ * @param {String} actionName Action to call.
+ * @param {JSON} data JSON data to send.
+ * @param {Array} [transfers] Optional list of transfers/ArrayBuffers.
+ * @returns {Promise} Promise to be resolved with response data.
+ */
+ sendWithPromise:
+ function messageHandlerSendWithPromise(actionName, data, transfers) {
+ var callbackId = this.callbackIndex++;
+ var message = {
+ action: actionName,
+ data: data,
+ callbackId: callbackId
+ };
+ var capability = createPromiseCapability();
+ this.callbacksCapabilities[callbackId] = capability;
+ try {
+ this.postMessage(message, transfers);
+ } catch (e) {
+ capability.reject(e);
}
+ return capability.promise;
+ },
+ /**
+ * Sends raw message to the comObj.
+ * @private
+ * @param message {Object} Raw message.
+ * @param transfers List of transfers/ArrayBuffers, or undefined.
+ */
+ postMessage: function (message, transfers) {
if (transfers && this.postMessageTransfers) {
this.comObj.postMessage(message, transfers);
} else {
@@ -1346,1635 +1558,7 @@ function loadJpegStream(id, imageUrl, objs) {
}
-var ColorSpace = (function ColorSpaceClosure() {
- // Constructor should define this.numComps, this.defaultColor, this.name
- function ColorSpace() {
- error('should not call ColorSpace constructor');
- }
-
- ColorSpace.prototype = {
- /**
- * Converts the color value to the RGB color. The color components are
- * located in the src array starting from the srcOffset. Returns the array
- * of the rgb components, each value ranging from [0,255].
- */
- getRgb: function ColorSpace_getRgb(src, srcOffset) {
- var rgb = new Uint8Array(3);
- this.getRgbItem(src, srcOffset, rgb, 0);
- return rgb;
- },
- /**
- * Converts the color value to the RGB color, similar to the getRgb method.
- * The result placed into the dest array starting from the destOffset.
- */
- getRgbItem: function ColorSpace_getRgbItem(src, srcOffset,
- dest, destOffset) {
- error('Should not call ColorSpace.getRgbItem');
- },
- /**
- * Converts the specified number of the color values to the RGB colors.
- * The colors are located in the src array starting from the srcOffset.
- * The result is placed into the dest array starting from the destOffset.
- * The src array items shall be in [0,2^bits) range, the dest array items
- * will be in [0,255] range. alpha01 indicates how many alpha components
- * there are in the dest array; it will be either 0 (RGB array) or 1 (RGBA
- * array).
- */
- getRgbBuffer: function ColorSpace_getRgbBuffer(src, srcOffset, count,
- dest, destOffset, bits,
- alpha01) {
- error('Should not call ColorSpace.getRgbBuffer');
- },
- /**
- * Determines the number of bytes required to store the result of the
- * conversion done by the getRgbBuffer method. As in getRgbBuffer,
- * |alpha01| is either 0 (RGB output) or 1 (RGBA output).
- */
- getOutputLength: function ColorSpace_getOutputLength(inputLength,
- alpha01) {
- error('Should not call ColorSpace.getOutputLength');
- },
- /**
- * Returns true if source data will be equal the result/output data.
- */
- isPassthrough: function ColorSpace_isPassthrough(bits) {
- return false;
- },
- /**
- * Fills in the RGB colors in the destination buffer. alpha01 indicates
- * how many alpha components there are in the dest array; it will be either
- * 0 (RGB array) or 1 (RGBA array).
- */
- fillRgb: function ColorSpace_fillRgb(dest, originalWidth,
- originalHeight, width, height,
- actualHeight, bpc, comps, alpha01) {
- var count = originalWidth * originalHeight;
- var rgbBuf = null;
- var numComponentColors = 1 << bpc;
- var needsResizing = originalHeight != height || originalWidth != width;
-
- if (this.isPassthrough(bpc)) {
- rgbBuf = comps;
-
- } else if (this.numComps === 1 && count > numComponentColors &&
- this.name !== 'DeviceGray' && this.name !== 'DeviceRGB') {
- // Optimization: create a color map when there is just one component and
- // we are converting more colors than the size of the color map. We
- // don't build the map if the colorspace is gray or rgb since those
- // methods are faster than building a map. This mainly offers big speed
- // ups for indexed and alternate colorspaces.
- //
- // TODO it may be worth while to cache the color map. While running
- // testing I never hit a cache so I will leave that out for now (perhaps
- // we are reparsing colorspaces too much?).
- var allColors = bpc <= 8 ? new Uint8Array(numComponentColors) :
- new Uint16Array(numComponentColors);
- for (var i = 0; i < numComponentColors; i++) {
- allColors[i] = i;
- }
- var colorMap = new Uint8Array(numComponentColors * 3);
- this.getRgbBuffer(allColors, 0, numComponentColors, colorMap, 0, bpc,
- /* alpha01 = */ 0);
-
- if (!needsResizing) {
- // Fill in the RGB values directly into |dest|.
- var destPos = 0;
- for (var i = 0; i < count; ++i) {
- var key = comps[i] * 3;
- dest[destPos++] = colorMap[key];
- dest[destPos++] = colorMap[key + 1];
- dest[destPos++] = colorMap[key + 2];
- destPos += alpha01;
- }
- } else {
- rgbBuf = new Uint8Array(count * 3);
- var rgbPos = 0;
- for (var i = 0; i < count; ++i) {
- var key = comps[i] * 3;
- rgbBuf[rgbPos++] = colorMap[key];
- rgbBuf[rgbPos++] = colorMap[key + 1];
- rgbBuf[rgbPos++] = colorMap[key + 2];
- }
- }
- } else {
- if (!needsResizing) {
- // Fill in the RGB values directly into |dest|.
- this.getRgbBuffer(comps, 0, width * actualHeight, dest, 0, bpc,
- alpha01);
- } else {
- rgbBuf = new Uint8Array(count * 3);
- this.getRgbBuffer(comps, 0, count, rgbBuf, 0, bpc,
- /* alpha01 = */ 0);
- }
- }
-
- if (rgbBuf) {
- if (needsResizing) {
- rgbBuf = PDFImage.resize(rgbBuf, bpc, 3, originalWidth,
- originalHeight, width, height);
- }
- var rgbPos = 0;
- var destPos = 0;
- for (var i = 0, ii = width * actualHeight; i < ii; i++) {
- dest[destPos++] = rgbBuf[rgbPos++];
- dest[destPos++] = rgbBuf[rgbPos++];
- dest[destPos++] = rgbBuf[rgbPos++];
- destPos += alpha01;
- }
- }
- },
- /**
- * True if the colorspace has components in the default range of [0, 1].
- * This should be true for all colorspaces except for lab color spaces
- * which are [0,100], [-128, 127], [-128, 127].
- */
- usesZeroToOneRange: true
- };
-
- ColorSpace.parse = function ColorSpace_parse(cs, xref, res) {
- var IR = ColorSpace.parseToIR(cs, xref, res);
- if (IR instanceof AlternateCS) {
- return IR;
- }
- return ColorSpace.fromIR(IR);
- };
-
- ColorSpace.fromIR = function ColorSpace_fromIR(IR) {
- var name = isArray(IR) ? IR[0] : IR;
-
- switch (name) {
- case 'DeviceGrayCS':
- return this.singletons.gray;
- case 'DeviceRgbCS':
- return this.singletons.rgb;
- case 'DeviceCmykCS':
- return this.singletons.cmyk;
- case 'CalGrayCS':
- var whitePoint = IR[1].WhitePoint;
- var blackPoint = IR[1].BlackPoint;
- var gamma = IR[1].Gamma;
- return new CalGrayCS(whitePoint, blackPoint, gamma);
- case 'PatternCS':
- var basePatternCS = IR[1];
- if (basePatternCS) {
- basePatternCS = ColorSpace.fromIR(basePatternCS);
- }
- return new PatternCS(basePatternCS);
- case 'IndexedCS':
- var baseIndexedCS = IR[1];
- var hiVal = IR[2];
- var lookup = IR[3];
- return new IndexedCS(ColorSpace.fromIR(baseIndexedCS), hiVal, lookup);
- case 'AlternateCS':
- var numComps = IR[1];
- var alt = IR[2];
- var tintFnIR = IR[3];
-
- 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);
- }
- return null;
- };
-
- ColorSpace.parseToIR = function ColorSpace_parseToIR(cs, xref, res) {
- if (isName(cs)) {
- var colorSpaces = res.get('ColorSpace');
- if (isDict(colorSpaces)) {
- var refcs = colorSpaces.get(cs.name);
- if (refcs) {
- cs = refcs;
- }
- }
- }
-
- cs = xref.fetchIfRef(cs);
- var mode;
-
- if (isName(cs)) {
- mode = cs.name;
- this.mode = mode;
-
- switch (mode) {
- case 'DeviceGray':
- case 'G':
- return 'DeviceGrayCS';
- case 'DeviceRGB':
- case 'RGB':
- return 'DeviceRgbCS';
- case 'DeviceCMYK':
- case 'CMYK':
- return 'DeviceCmykCS';
- case 'Pattern':
- return ['PatternCS', null];
- default:
- error('unrecognized colorspace ' + mode);
- }
- } else if (isArray(cs)) {
- mode = cs[0].name;
- this.mode = mode;
-
- switch (mode) {
- case 'DeviceGray':
- case 'G':
- return 'DeviceGrayCS';
- case 'DeviceRGB':
- case 'RGB':
- return 'DeviceRgbCS';
- case 'DeviceCMYK':
- case 'CMYK':
- return 'DeviceCmykCS';
- case 'CalGray':
- var params = cs[1].getAll();
- return ['CalGrayCS', params];
- case 'CalRGB':
- return 'DeviceRgbCS';
- case 'ICCBased':
- var stream = xref.fetchIfRef(cs[1]);
- var dict = stream.dict;
- var numComps = dict.get('N');
- if (numComps == 1) {
- return 'DeviceGrayCS';
- } else if (numComps == 3) {
- return 'DeviceRgbCS';
- } else if (numComps == 4) {
- return 'DeviceCmykCS';
- }
- break;
- case 'Pattern':
- var basePatternCS = cs[1];
- if (basePatternCS) {
- basePatternCS = ColorSpace.parseToIR(basePatternCS, xref, res);
- }
- return ['PatternCS', basePatternCS];
- case 'Indexed':
- case 'I':
- var baseIndexedCS = ColorSpace.parseToIR(cs[1], xref, res);
- var hiVal = cs[2] + 1;
- var lookup = xref.fetchIfRef(cs[3]);
- if (isStream(lookup)) {
- lookup = lookup.getBytes();
- }
- return ['IndexedCS', baseIndexedCS, hiVal, lookup];
- case 'Separation':
- case 'DeviceN':
- var name = cs[1];
- var numComps = 1;
- if (isName(name)) {
- numComps = 1;
- } else if (isArray(name)) {
- numComps = name.length;
- }
- var alt = ColorSpace.parseToIR(cs[2], xref, res);
- var tintFnIR = PDFFunction.getIR(xref, xref.fetchIfRef(cs[3]));
- return ['AlternateCS', numComps, alt, tintFnIR];
- case 'Lab':
- var params = cs[1].getAll();
- return ['LabCS', params];
- default:
- error('unimplemented color space object "' + mode + '"');
- }
- } else {
- error('unrecognized color space object: "' + cs + '"');
- }
- 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;
- }
-
- if (n * 2 !== decode.length) {
- warn('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;
- };
-
- ColorSpace.singletons = {
- get gray() {
- return shadow(this, 'gray', new DeviceGrayCS());
- },
- get rgb() {
- return shadow(this, 'rgb', new DeviceRgbCS());
- },
- get cmyk() {
- return shadow(this, 'cmyk', new DeviceCmykCS());
- }
- };
-
- return ColorSpace;
-})();
-
-/**
- * Alternate color space handles both Separation and DeviceN color spaces. A
- * Separation color space is actually just a DeviceN with one color component.
- * Both color spaces use a tinting function to convert colors to a base color
- * space.
- */
-var AlternateCS = (function AlternateCSClosure() {
- function AlternateCS(numComps, base, tintFn) {
- this.name = 'Alternate';
- this.numComps = numComps;
- this.defaultColor = new Float32Array(numComps);
- for (var i = 0; i < numComps; ++i) {
- this.defaultColor[i] = 1;
- }
- this.base = base;
- this.tintFn = tintFn;
- }
-
- AlternateCS.prototype = {
- getRgb: ColorSpace.prototype.getRgb,
- getRgbItem: function AlternateCS_getRgbItem(src, srcOffset,
- dest, destOffset) {
- var baseNumComps = this.base.numComps;
- var input = 'subarray' in src ?
- src.subarray(srcOffset, srcOffset + this.numComps) :
- Array.prototype.slice.call(src, srcOffset, srcOffset + this.numComps);
- var tinted = this.tintFn(input);
- this.base.getRgbItem(tinted, 0, dest, destOffset);
- },
- getRgbBuffer: function AlternateCS_getRgbBuffer(src, srcOffset, count,
- dest, destOffset, bits,
- alpha01) {
- var tintFn = this.tintFn;
- var base = this.base;
- var scale = 1 / ((1 << bits) - 1);
- var baseNumComps = base.numComps;
- var usesZeroToOneRange = base.usesZeroToOneRange;
- var isPassthrough = (base.isPassthrough(8) || !usesZeroToOneRange) &&
- alpha01 === 0;
- var pos = isPassthrough ? destOffset : 0;
- var baseBuf = isPassthrough ? dest : new Uint8Array(baseNumComps * count);
- var numComps = this.numComps;
-
- var scaled = new Float32Array(numComps);
- for (var i = 0; i < count; i++) {
- for (var j = 0; j < numComps; j++) {
- scaled[j] = src[srcOffset++] * scale;
- }
- var tinted = tintFn(scaled);
- if (usesZeroToOneRange) {
- for (var j = 0; j < baseNumComps; j++) {
- baseBuf[pos++] = tinted[j] * 255;
- }
- } else {
- base.getRgbItem(tinted, 0, baseBuf, pos);
- pos += baseNumComps;
- }
- }
- if (!isPassthrough) {
- base.getRgbBuffer(baseBuf, 0, count, dest, destOffset, 8, alpha01);
- }
- },
- getOutputLength: function AlternateCS_getOutputLength(inputLength,
- alpha01) {
- return this.base.getOutputLength(inputLength *
- this.base.numComps / this.numComps,
- alpha01);
- },
- isPassthrough: ColorSpace.prototype.isPassthrough,
- fillRgb: ColorSpace.prototype.fillRgb,
- isDefaultDecode: function AlternateCS_isDefaultDecode(decodeMap) {
- return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
- },
- usesZeroToOneRange: true
- };
-
- return AlternateCS;
-})();
-
-var PatternCS = (function PatternCSClosure() {
- function PatternCS(baseCS) {
- this.name = 'Pattern';
- this.base = baseCS;
- }
- PatternCS.prototype = {};
-
- return PatternCS;
-})();
-
-var IndexedCS = (function IndexedCSClosure() {
- function IndexedCS(base, highVal, lookup) {
- this.name = 'Indexed';
- this.numComps = 1;
- this.defaultColor = new Uint8Array([0]);
- this.base = base;
- this.highVal = highVal;
-
- var baseNumComps = base.numComps;
- var length = baseNumComps * highVal;
- var lookupArray;
-
- if (isStream(lookup)) {
- lookupArray = new Uint8Array(length);
- var bytes = lookup.getBytes(length);
- lookupArray.set(bytes);
- } else if (isString(lookup)) {
- lookupArray = new Uint8Array(length);
- for (var i = 0; i < length; ++i) {
- lookupArray[i] = lookup.charCodeAt(i);
- }
- } else if (lookup instanceof Uint8Array || lookup instanceof Array) {
- lookupArray = lookup;
- } else {
- error('Unrecognized lookup table: ' + lookup);
- }
- this.lookup = lookupArray;
- }
-
- IndexedCS.prototype = {
- getRgb: ColorSpace.prototype.getRgb,
- getRgbItem: function IndexedCS_getRgbItem(src, srcOffset,
- dest, destOffset) {
- var numComps = this.base.numComps;
- var start = src[srcOffset] * numComps;
- this.base.getRgbItem(this.lookup, start, dest, destOffset);
- },
- getRgbBuffer: function IndexedCS_getRgbBuffer(src, srcOffset, count,
- dest, destOffset, bits,
- alpha01) {
- var base = this.base;
- var numComps = base.numComps;
- var outputDelta = base.getOutputLength(numComps, alpha01);
- var lookup = this.lookup;
-
- for (var i = 0; i < count; ++i) {
- var lookupPos = src[srcOffset++] * numComps;
- base.getRgbBuffer(lookup, lookupPos, 1, dest, destOffset, 8, alpha01);
- destOffset += outputDelta;
- }
- },
- getOutputLength: function IndexedCS_getOutputLength(inputLength, alpha01) {
- return this.base.getOutputLength(inputLength * this.base.numComps,
- alpha01);
- },
- isPassthrough: ColorSpace.prototype.isPassthrough,
- fillRgb: ColorSpace.prototype.fillRgb,
- isDefaultDecode: function IndexedCS_isDefaultDecode(decodeMap) {
- // indexed color maps shouldn't be changed
- return true;
- },
- usesZeroToOneRange: true
- };
- return IndexedCS;
-})();
-
-var DeviceGrayCS = (function DeviceGrayCSClosure() {
- function DeviceGrayCS() {
- this.name = 'DeviceGray';
- this.numComps = 1;
- this.defaultColor = new Float32Array([0]);
- }
-
- DeviceGrayCS.prototype = {
- getRgb: ColorSpace.prototype.getRgb,
- getRgbItem: function DeviceGrayCS_getRgbItem(src, srcOffset,
- dest, destOffset) {
- var c = (src[srcOffset] * 255) | 0;
- c = c < 0 ? 0 : c > 255 ? 255 : c;
- dest[destOffset] = dest[destOffset + 1] = dest[destOffset + 2] = c;
- },
- getRgbBuffer: function DeviceGrayCS_getRgbBuffer(src, srcOffset, count,
- dest, destOffset, bits,
- alpha01) {
- var scale = 255 / ((1 << bits) - 1);
- var j = srcOffset, q = destOffset;
- for (var i = 0; i < count; ++i) {
- var c = (scale * src[j++]) | 0;
- dest[q++] = c;
- dest[q++] = c;
- dest[q++] = c;
- q += alpha01;
- }
- },
- getOutputLength: function DeviceGrayCS_getOutputLength(inputLength,
- alpha01) {
- return inputLength * (3 + alpha01);
- },
- isPassthrough: ColorSpace.prototype.isPassthrough,
- fillRgb: ColorSpace.prototype.fillRgb,
- isDefaultDecode: function DeviceGrayCS_isDefaultDecode(decodeMap) {
- return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
- },
- usesZeroToOneRange: true
- };
- return DeviceGrayCS;
-})();
-
-var DeviceRgbCS = (function DeviceRgbCSClosure() {
- function DeviceRgbCS() {
- this.name = 'DeviceRGB';
- this.numComps = 3;
- this.defaultColor = new Float32Array([0, 0, 0]);
- }
- DeviceRgbCS.prototype = {
- getRgb: ColorSpace.prototype.getRgb,
- getRgbItem: function DeviceRgbCS_getRgbItem(src, srcOffset,
- dest, destOffset) {
- var r = (src[srcOffset] * 255) | 0;
- var g = (src[srcOffset + 1] * 255) | 0;
- var b = (src[srcOffset + 2] * 255) | 0;
- dest[destOffset] = r < 0 ? 0 : r > 255 ? 255 : r;
- dest[destOffset + 1] = g < 0 ? 0 : g > 255 ? 255 : g;
- dest[destOffset + 2] = b < 0 ? 0 : b > 255 ? 255 : b;
- },
- getRgbBuffer: function DeviceRgbCS_getRgbBuffer(src, srcOffset, count,
- dest, destOffset, bits,
- alpha01) {
- if (bits === 8 && alpha01 === 0) {
- dest.set(src.subarray(srcOffset, srcOffset + count * 3), destOffset);
- return;
- }
- var scale = 255 / ((1 << bits) - 1);
- var j = srcOffset, q = destOffset;
- for (var i = 0; i < count; ++i) {
- dest[q++] = (scale * src[j++]) | 0;
- dest[q++] = (scale * src[j++]) | 0;
- dest[q++] = (scale * src[j++]) | 0;
- q += alpha01;
- }
- },
- getOutputLength: function DeviceRgbCS_getOutputLength(inputLength,
- alpha01) {
- return (inputLength * (3 + alpha01) / 3) | 0;
- },
- isPassthrough: function DeviceRgbCS_isPassthrough(bits) {
- return bits == 8;
- },
- fillRgb: ColorSpace.prototype.fillRgb,
- isDefaultDecode: function DeviceRgbCS_isDefaultDecode(decodeMap) {
- return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
- },
- usesZeroToOneRange: true
- };
- return DeviceRgbCS;
-})();
-
-var DeviceCmykCS = (function DeviceCmykCSClosure() {
- // The coefficients below was found using numerical analysis: the method of
- // steepest descent for the sum((f_i - color_value_i)^2) for r/g/b colors,
- // where color_value is the tabular value from the table of sampled RGB colors
- // from CMYK US Web Coated (SWOP) colorspace, and f_i is the corresponding
- // CMYK color conversion using the estimation below:
- // f(A, B,.. N) = Acc+Bcm+Ccy+Dck+c+Fmm+Gmy+Hmk+Im+Jyy+Kyk+Ly+Mkk+Nk+255
- function convertToRgb(src, srcOffset, srcScale, dest, destOffset) {
- var c = src[srcOffset + 0] * srcScale;
- var m = src[srcOffset + 1] * srcScale;
- var y = src[srcOffset + 2] * srcScale;
- var k = src[srcOffset + 3] * srcScale;
-
- var r =
- c * (-4.387332384609988 * c + 54.48615194189176 * m +
- 18.82290502165302 * y + 212.25662451639585 * k +
- -285.2331026137004) +
- m * (1.7149763477362134 * m - 5.6096736904047315 * y +
- -17.873870861415444 * k - 5.497006427196366) +
- y * (-2.5217340131683033 * y - 21.248923337353073 * k +
- 17.5119270841813) +
- k * (-21.86122147463605 * k - 189.48180835922747) + 255;
- var g =
- c * (8.841041422036149 * c + 60.118027045597366 * m +
- 6.871425592049007 * y + 31.159100130055922 * k +
- -79.2970844816548) +
- m * (-15.310361306967817 * m + 17.575251261109482 * y +
- 131.35250912493976 * k - 190.9453302588951) +
- y * (4.444339102852739 * y + 9.8632861493405 * k - 24.86741582555878) +
- k * (-20.737325471181034 * k - 187.80453709719578) + 255;
- var b =
- c * (0.8842522430003296 * c + 8.078677503112928 * m +
- 30.89978309703729 * y - 0.23883238689178934 * k +
- -14.183576799673286) +
- m * (10.49593273432072 * m + 63.02378494754052 * y +
- 50.606957656360734 * k - 112.23884253719248) +
- y * (0.03296041114873217 * y + 115.60384449646641 * k +
- -193.58209356861505) +
- k * (-22.33816807309886 * k - 180.12613974708367) + 255;
-
- dest[destOffset] = r > 255 ? 255 : r < 0 ? 0 : r;
- dest[destOffset + 1] = g > 255 ? 255 : g < 0 ? 0 : g;
- dest[destOffset + 2] = b > 255 ? 255 : b < 0 ? 0 : b;
- }
-
- function DeviceCmykCS() {
- this.name = 'DeviceCMYK';
- this.numComps = 4;
- this.defaultColor = new Float32Array([0, 0, 0, 1]);
- }
- DeviceCmykCS.prototype = {
- getRgb: ColorSpace.prototype.getRgb,
- getRgbItem: function DeviceCmykCS_getRgbItem(src, srcOffset,
- dest, destOffset) {
- convertToRgb(src, srcOffset, 1, dest, destOffset);
- },
- getRgbBuffer: function DeviceCmykCS_getRgbBuffer(src, srcOffset, count,
- dest, destOffset, bits,
- alpha01) {
- var scale = 1 / ((1 << bits) - 1);
- for (var i = 0; i < count; i++) {
- convertToRgb(src, srcOffset, scale, dest, destOffset);
- srcOffset += 4;
- destOffset += 3 + alpha01;
- }
- },
- getOutputLength: function DeviceCmykCS_getOutputLength(inputLength,
- alpha01) {
- return (inputLength / 4 * (3 + alpha01)) | 0;
- },
- isPassthrough: ColorSpace.prototype.isPassthrough,
- fillRgb: ColorSpace.prototype.fillRgb,
- isDefaultDecode: function DeviceCmykCS_isDefaultDecode(decodeMap) {
- return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
- },
- usesZeroToOneRange: true
- };
-
- return DeviceCmykCS;
-})();
-
-//
-// CalGrayCS: Based on "PDF Reference, Sixth Ed", p.245
-//
-var CalGrayCS = (function CalGrayCSClosure() {
- function CalGrayCS(whitePoint, blackPoint, gamma) {
- this.name = 'CalGray';
- this.numComps = 1;
- this.defaultColor = new Float32Array([0]);
-
- if (!whitePoint) {
- error('WhitePoint missing - required for color space CalGray');
- }
- blackPoint = blackPoint || [0, 0, 0];
- gamma = gamma || 1;
-
- // Translate arguments to spec variables.
- this.XW = whitePoint[0];
- this.YW = whitePoint[1];
- this.ZW = whitePoint[2];
-
- this.XB = blackPoint[0];
- this.YB = blackPoint[1];
- this.ZB = blackPoint[2];
-
- this.G = gamma;
-
- // Validate variables as per spec.
- if (this.XW < 0 || this.ZW < 0 || this.YW !== 1) {
- error('Invalid WhitePoint components for ' + this.name +
- ', no fallback available');
- }
-
- if (this.XB < 0 || this.YB < 0 || this.ZB < 0) {
- info('Invalid BlackPoint for ' + this.name + ', falling back to default');
- this.XB = this.YB = this.ZB = 0;
- }
-
- if (this.XB !== 0 || this.YB !== 0 || this.ZB !== 0) {
- warn(this.name + ', BlackPoint: XB: ' + this.XB + ', YB: ' + this.YB +
- ', ZB: ' + this.ZB + ', only default values are supported.');
- }
-
- if (this.G < 1) {
- info('Invalid Gamma: ' + this.G + ' for ' + this.name +
- ', falling back to default');
- this.G = 1;
- }
- }
-
- function convertToRgb(cs, src, srcOffset, dest, destOffset, scale) {
- // A represents a gray component of a calibrated gray space.
- // A <---> AG in the spec
- var A = src[srcOffset] * scale;
- var AG = Math.pow(A, cs.G);
-
- // Computes intermediate variables M, L, N as per spec.
- // Except if other than default BlackPoint values are used.
- var M = cs.XW * AG;
- var L = cs.YW * AG;
- var N = cs.ZW * AG;
-
- // Decode XYZ, as per spec.
- var X = M;
- var Y = L;
- var Z = N;
-
- // http://www.poynton.com/notes/colour_and_gamma/ColorFAQ.html, Ch 4.
- // This yields values in range [0, 100].
- var Lstar = Math.max(116 * Math.pow(Y, 1 / 3) - 16, 0);
-
- // Convert values to rgb range [0, 255].
- dest[destOffset] = Lstar * 255 / 100;
- dest[destOffset + 1] = Lstar * 255 / 100;
- dest[destOffset + 2] = Lstar * 255 / 100;
- }
-
- CalGrayCS.prototype = {
- getRgb: ColorSpace.prototype.getRgb,
- getRgbItem: function CalGrayCS_getRgbItem(src, srcOffset,
- dest, destOffset) {
- convertToRgb(this, src, srcOffset, dest, destOffset, 1);
- },
- getRgbBuffer: function CalGrayCS_getRgbBuffer(src, srcOffset, count,
- dest, destOffset, bits,
- alpha01) {
- var scale = 1 / ((1 << bits) - 1);
-
- for (var i = 0; i < count; ++i) {
- convertToRgb(this, src, srcOffset, dest, destOffset, scale);
- srcOffset += 1;
- destOffset += 3 + alpha01;
- }
- },
- getOutputLength: function CalGrayCS_getOutputLength(inputLength, alpha01) {
- return inputLength * (3 + alpha01);
- },
- isPassthrough: ColorSpace.prototype.isPassthrough,
- fillRgb: ColorSpace.prototype.fillRgb,
- isDefaultDecode: function CalGrayCS_isDefaultDecode(decodeMap) {
- return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
- },
- usesZeroToOneRange: true
- };
- return CalGrayCS;
-})();
-
-//
-// 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 = new Float32Array([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) {
- info('Invalid BlackPoint, falling back to default');
- this.XB = this.YB = this.ZB = 0;
- }
-
- if (this.amin > this.amax || this.bmin > this.bmax) {
- info('Invalid Range, falling back to defaults');
- this.amin = -100;
- this.amax = 100;
- this.bmin = -100;
- this.bmax = 100;
- }
- }
-
- // Function g(x) from spec
- function fn_g(x) {
- if (x >= 6 / 29) {
- return x * x * x;
- } else {
- return (108 / 841) * (x - 4 / 29);
- }
- }
-
- function decode(value, high1, low2, high2) {
- return low2 + (value) * (high2 - low2) / (high1);
- }
-
- // If decoding is needed maxVal should be 2^bits per component - 1.
- function convertToRgb(cs, src, srcOffset, maxVal, dest, destOffset) {
- // XXX: Lab input is in the range of [0, 100], [amin, amax], [bmin, bmax]
- // not the usual [0, 1]. If a command like setFillColor is used the src
- // values will already be within the correct range. However, if we are
- // converting an image we have to map the values to the correct range given
- // above.
- // Ls,as,bs <---> L*,a*,b* in the spec
- var Ls = src[srcOffset];
- var as = src[srcOffset + 1];
- var bs = src[srcOffset + 2];
- if (maxVal !== false) {
- Ls = decode(Ls, maxVal, 0, 100);
- as = decode(as, maxVal, cs.amin, cs.amax);
- bs = decode(bs, maxVal, cs.bmin, cs.bmax);
- }
-
- // Adjust limits of 'as' and 'bs'
- as = as > cs.amax ? cs.amax : as < cs.amin ? cs.amin : as;
- bs = bs > cs.bmax ? cs.bmax : bs < cs.bmin ? cs.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 = cs.XW * fn_g(L);
- var Y = cs.YW * fn_g(M);
- var Z = cs.ZW * fn_g(N);
-
- var r, g, b;
- // Using different conversions for D50 and D65 white points,
- // per http://www.color.org/srgb.pdf
- if (cs.ZW < 1) {
- // Assuming D50 (X=0.9642, Y=1.00, Z=0.8249)
- r = X * 3.1339 + Y * -1.6170 + Z * -0.4906;
- g = X * -0.9785 + Y * 1.9160 + Z * 0.0333;
- b = X * 0.0720 + Y * -0.2290 + Z * 1.4057;
- } else {
- // Assuming D65 (X=0.9505, Y=1.00, Z=1.0888)
- r = X * 3.2406 + Y * -1.5372 + Z * -0.4986;
- g = X * -0.9689 + Y * 1.8758 + Z * 0.0415;
- b = X * 0.0557 + Y * -0.2040 + Z * 1.0570;
- }
- // clamp color values to [0,1] range then convert to [0,255] range.
- dest[destOffset] = r <= 0 ? 0 : r >= 1 ? 255 : Math.sqrt(r) * 255 | 0;
- dest[destOffset + 1] = g <= 0 ? 0 : g >= 1 ? 255 : Math.sqrt(g) * 255 | 0;
- dest[destOffset + 2] = b <= 0 ? 0 : b >= 1 ? 255 : Math.sqrt(b) * 255 | 0;
- }
-
- LabCS.prototype = {
- getRgb: ColorSpace.prototype.getRgb,
- getRgbItem: function LabCS_getRgbItem(src, srcOffset, dest, destOffset) {
- convertToRgb(this, src, srcOffset, false, dest, destOffset);
- },
- getRgbBuffer: function LabCS_getRgbBuffer(src, srcOffset, count,
- dest, destOffset, bits,
- alpha01) {
- var maxVal = (1 << bits) - 1;
- for (var i = 0; i < count; i++) {
- convertToRgb(this, src, srcOffset, maxVal, dest, destOffset);
- srcOffset += 3;
- destOffset += 3 + alpha01;
- }
- },
- getOutputLength: function LabCS_getOutputLength(inputLength, alpha01) {
- return (inputLength * (3 + alpha01) / 3) | 0;
- },
- isPassthrough: ColorSpace.prototype.isPassthrough,
- isDefaultDecode: function LabCS_isDefaultDecode(decodeMap) {
- // XXX: Decoding is handled with the lab conversion because of the strange
- // ranges that are used.
- return true;
- },
- usesZeroToOneRange: false
- };
- return LabCS;
-})();
-
-
-
-var PDFFunction = (function PDFFunctionClosure() {
- var CONSTRUCT_SAMPLED = 0;
- var CONSTRUCT_INTERPOLATED = 2;
- var CONSTRUCT_STICHED = 3;
- var CONSTRUCT_POSTSCRIPT = 4;
-
- return {
- getSampleArray: function PDFFunction_getSampleArray(size, outputSize, bps,
- str) {
- var length = 1;
- for (var i = 0, ii = size.length; i < ii; i++) {
- length *= size[i];
- }
- length *= outputSize;
-
- var array = [];
- var codeSize = 0;
- var codeBuf = 0;
- // 32 is a valid bps so shifting won't work
- var sampleMul = 1.0 / (Math.pow(2.0, bps) - 1);
-
- var strBytes = str.getBytes((length * bps + 7) / 8);
- var strIdx = 0;
- for (var i = 0; i < length; i++) {
- while (codeSize < bps) {
- codeBuf <<= 8;
- codeBuf |= strBytes[strIdx++];
- codeSize += 8;
- }
- codeSize -= bps;
- array.push((codeBuf >> codeSize) * sampleMul);
- codeBuf &= (1 << codeSize) - 1;
- }
- return array;
- },
-
- getIR: function PDFFunction_getIR(xref, fn) {
- var dict = fn.dict;
- if (!dict) {
- dict = fn;
- }
-
- var types = [this.constructSampled,
- null,
- this.constructInterpolated,
- this.constructStiched,
- this.constructPostScript];
-
- var typeNum = dict.get('FunctionType');
- var typeFn = types[typeNum];
- if (!typeFn) {
- error('Unknown type of function');
- }
-
- return typeFn.call(this, fn, dict, xref);
- },
-
- fromIR: function PDFFunction_fromIR(IR) {
- var type = IR[0];
- switch (type) {
- case CONSTRUCT_SAMPLED:
- return this.constructSampledFromIR(IR);
- case CONSTRUCT_INTERPOLATED:
- return this.constructInterpolatedFromIR(IR);
- case CONSTRUCT_STICHED:
- return this.constructStichedFromIR(IR);
- //case CONSTRUCT_POSTSCRIPT:
- default:
- return this.constructPostScriptFromIR(IR);
- }
- },
-
- parse: function PDFFunction_parse(xref, fn) {
- var IR = this.getIR(xref, fn);
- return this.fromIR(IR);
- },
-
- constructSampled: function PDFFunction_constructSampled(str, dict) {
- function toMultiArray(arr) {
- var inputLength = arr.length;
- var outputLength = arr.length / 2;
- var out = [];
- var index = 0;
- for (var i = 0; i < inputLength; i += 2) {
- out[index] = [arr[i], arr[i + 1]];
- ++index;
- }
- return out;
- }
- var domain = dict.get('Domain');
- var range = dict.get('Range');
-
- if (!domain || !range) {
- error('No domain or range');
- }
-
- var inputSize = domain.length / 2;
- var outputSize = range.length / 2;
-
- domain = toMultiArray(domain);
- range = toMultiArray(range);
-
- var size = dict.get('Size');
- var bps = dict.get('BitsPerSample');
- var order = dict.get('Order') || 1;
- if (order !== 1) {
- // No description how cubic spline interpolation works in PDF32000:2008
- // As in poppler, ignoring order, linear interpolation may work as good
- info('No support for cubic spline interpolation: ' + order);
- }
-
- var encode = dict.get('Encode');
- if (!encode) {
- encode = [];
- for (var i = 0; i < inputSize; ++i) {
- encode.push(0);
- encode.push(size[i] - 1);
- }
- }
- encode = toMultiArray(encode);
-
- var decode = dict.get('Decode');
- if (!decode) {
- decode = range;
- } else {
- decode = toMultiArray(decode);
- }
-
- var samples = this.getSampleArray(size, outputSize, bps, str);
-
- return [
- CONSTRUCT_SAMPLED, inputSize, domain, encode, decode, samples, size,
- outputSize, Math.pow(2, bps) - 1, range
- ];
- },
-
- constructSampledFromIR: function PDFFunction_constructSampledFromIR(IR) {
- // 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 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: ' + m + ' != ' +
- args.length);
- }
-
- var x = args;
-
- // 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;
- }
-
- 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 {
- cubeN[j] *= n0;
- cubeVertex[j] += offset0;
- }
- }
-
- k *= size_i;
- pos <<= 1;
- }
-
- 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;
- };
- },
-
- constructInterpolated: function PDFFunction_constructInterpolated(str,
- dict) {
- var c0 = dict.get('C0') || [0];
- var c1 = dict.get('C1') || [1];
- var n = dict.get('N');
-
- if (!isArray(c0) || !isArray(c1)) {
- error('Illegal dictionary for interpolated function');
- }
-
- var length = c0.length;
- var diff = [];
- for (var i = 0; i < length; ++i) {
- diff.push(c1[i] - c0[i]);
- }
-
- return [CONSTRUCT_INTERPOLATED, c0, diff, n];
- },
-
- constructInterpolatedFromIR:
- function PDFFunction_constructInterpolatedFromIR(IR) {
- var c0 = IR[1];
- var diff = IR[2];
- var n = IR[3];
-
- var length = diff.length;
-
- return function constructInterpolatedFromIRResult(args) {
- var x = n == 1 ? args[0] : Math.pow(args[0], n);
-
- var out = [];
- for (var j = 0; j < length; ++j) {
- out.push(c0[j] + (x * diff[j]));
- }
-
- return out;
-
- };
- },
-
- constructStiched: function PDFFunction_constructStiched(fn, dict, xref) {
- var domain = dict.get('Domain');
-
- if (!domain) {
- error('No domain');
- }
-
- var inputSize = domain.length / 2;
- if (inputSize != 1) {
- error('Bad domain for stiched function');
- }
-
- var fnRefs = dict.get('Functions');
- var fns = [];
- for (var i = 0, ii = fnRefs.length; i < ii; ++i) {
- fns.push(PDFFunction.getIR(xref, xref.fetchIfRef(fnRefs[i])));
- }
-
- var bounds = dict.get('Bounds');
- var encode = dict.get('Encode');
-
- return [CONSTRUCT_STICHED, domain, bounds, encode, fns];
- },
-
- constructStichedFromIR: function PDFFunction_constructStichedFromIR(IR) {
- var domain = IR[1];
- var bounds = IR[2];
- var encode = IR[3];
- var fnsIR = IR[4];
- var fns = [];
-
- for (var i = 0, ii = fnsIR.length; i < ii; i++) {
- fns.push(PDFFunction.fromIR(fnsIR[i]));
- }
-
- return function constructStichedFromIRResult(args) {
- var clip = function constructStichedFromIRClip(v, min, max) {
- if (v > max) {
- v = max;
- } else if (v < min) {
- v = min;
- }
- return v;
- };
-
- // clip to domain
- var v = clip(args[0], domain[0], domain[1]);
- // calulate which bound the value is in
- for (var i = 0, ii = bounds.length; i < ii; ++i) {
- if (v < bounds[i]) {
- break;
- }
- }
-
- // encode value into domain of function
- var dmin = domain[0];
- if (i > 0) {
- dmin = bounds[i - 1];
- }
- var dmax = domain[1];
- if (i < bounds.length) {
- dmax = bounds[i];
- }
-
- var rmin = encode[2 * i];
- var rmax = encode[2 * i + 1];
-
- var v2 = rmin + (v - dmin) * (rmax - rmin) / (dmax - dmin);
-
- // call the appropriate function
- return fns[i]([v2]);
- };
- },
-
- constructPostScript: function PDFFunction_constructPostScript(fn, dict,
- 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 PDFFunction_constructPostScriptFromIR(
- IR) {
- var domain = IR[1];
- 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) {
- this.operators = operators;
- }
- 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 DEFAULT_ICON_SIZE = 22; // px
var HIGHLIGHT_OFFSET = 4; // px
var SUPPORTED_TYPES = ['Link', 'Text', 'Widget'];
@@ -3034,7 +1618,7 @@ var Annotation = (function AnnotationClosure() {
var data = this.data = {};
data.subtype = dict.get('Subtype').name;
- var rect = dict.get('Rect');
+ var rect = dict.get('Rect') || [0, 0, 0, 0];
data.rect = Util.normalizeRect(rect);
data.annotationFlags = dict.get('F');
@@ -3058,23 +1642,30 @@ var Annotation = (function AnnotationClosure() {
// TODO: implement proper support for annotations with line dash patterns.
var dashArray = borderArray[3];
- if (data.borderWidth > 0 && dashArray && isArray(dashArray)) {
- var dashArrayLength = dashArray.length;
- if (dashArrayLength > 0) {
- // According to the PDF specification: the elements in a dashArray
- // shall be numbers that are nonnegative and not all equal to zero.
- var isInvalid = false;
- var numPositive = 0;
- for (var i = 0; i < dashArrayLength; i++) {
- if (!(+dashArray[i] >= 0)) {
- isInvalid = true;
- break;
- } else if (dashArray[i] > 0) {
- numPositive++;
+ if (data.borderWidth > 0 && dashArray) {
+ if (!isArray(dashArray)) {
+ // Ignore the border if dashArray is not actually an array,
+ // this is consistent with the behaviour in Adobe Reader.
+ data.borderWidth = 0;
+ } else {
+ var dashArrayLength = dashArray.length;
+ if (dashArrayLength > 0) {
+ // According to the PDF specification: the elements in a dashArray
+ // shall be numbers that are nonnegative and not all equal to zero.
+ var isInvalid = false;
+ var numPositive = 0;
+ for (var i = 0; i < dashArrayLength; i++) {
+ var validNumber = (+dashArray[i] >= 0);
+ if (!validNumber) {
+ isInvalid = true;
+ break;
+ } else if (dashArray[i] > 0) {
+ numPositive++;
+ }
+ }
+ if (isInvalid || numPositive === 0) {
+ data.borderWidth = 0;
}
- }
- if (isInvalid || numPositive === 0) {
- data.borderWidth = 0;
}
}
}
@@ -3082,6 +1673,7 @@ var Annotation = (function AnnotationClosure() {
this.appearance = getDefaultAppearance(dict);
data.hasAppearance = !!this.appearance;
+ data.id = params.ref.num;
}
Annotation.prototype = {
@@ -3146,31 +1738,27 @@ var Annotation = (function AnnotationClosure() {
data.rect); // rectangle is nessessary
},
- loadResources: function(keys) {
- var promise = new LegacyPromise();
- this.appearance.dict.getAsync('Resources').then(function(resources) {
- if (!resources) {
- promise.resolve();
- return;
- }
- var objectLoader = new ObjectLoader(resources.map,
- keys,
- resources.xref);
- objectLoader.load().then(function() {
- promise.resolve(resources);
- });
+ loadResources: function Annotation_loadResources(keys) {
+ return new Promise(function (resolve, reject) {
+ this.appearance.dict.getAsync('Resources').then(function (resources) {
+ if (!resources) {
+ resolve();
+ return;
+ }
+ var objectLoader = new ObjectLoader(resources.map,
+ keys,
+ resources.xref);
+ objectLoader.load().then(function() {
+ resolve(resources);
+ }, reject);
+ }, reject);
}.bind(this));
-
- return promise;
},
getOperatorList: function Annotation_getOperatorList(evaluator) {
- var promise = new LegacyPromise();
-
if (!this.appearance) {
- promise.resolve(new OperatorList());
- return promise;
+ return Promise.resolve(new OperatorList());
}
var data = this.data;
@@ -3189,20 +1777,18 @@ var Annotation = (function AnnotationClosure() {
var bbox = appearanceDict.get('BBox') || [0, 0, 1, 1];
var matrix = appearanceDict.get('Matrix') || [1, 0, 0, 1, 0 ,0];
var transform = getTransformMatrix(data.rect, bbox, matrix);
+ var self = this;
- var border = data.border;
-
- resourcesPromise.then(function(resources) {
- var opList = new OperatorList();
- opList.addOp(OPS.beginAnnotation, [data.rect, transform, matrix]);
- evaluator.getOperatorList(this.appearance, resources, opList);
- opList.addOp(OPS.endAnnotation, []);
- promise.resolve(opList);
-
- this.appearance.reset();
- }.bind(this));
-
- return promise;
+ return resourcesPromise.then(function(resources) {
+ var opList = new OperatorList();
+ opList.addOp(OPS.beginAnnotation, [data.rect, transform, matrix]);
+ return evaluator.getOperatorList(self.appearance, resources, opList).
+ then(function () {
+ opList.addOp(OPS.endAnnotation, []);
+ self.appearance.reset();
+ return opList;
+ });
+ });
}
};
@@ -3282,10 +1868,10 @@ var Annotation = (function AnnotationClosure() {
annotations, opList, pdfManager, partialEvaluator, intent) {
function reject(e) {
- annotationsReadyPromise.reject(e);
+ annotationsReadyCapability.reject(e);
}
- var annotationsReadyPromise = new LegacyPromise();
+ var annotationsReadyCapability = createPromiseCapability();
var annotationPromises = [];
for (var i = 0, n = annotations.length; i < n; ++i) {
@@ -3302,10 +1888,10 @@ var Annotation = (function AnnotationClosure() {
opList.addOpList(annotOpList);
}
opList.addOp(OPS.endAnnotations, []);
- annotationsReadyPromise.resolve();
+ annotationsReadyCapability.resolve();
}, reject);
- return annotationsReadyPromise;
+ return annotationsReadyCapability.promise;
};
return Annotation;
@@ -3332,7 +1918,7 @@ var WidgetAnnotation = (function WidgetAnnotationClosure() {
var fieldType = Util.getInheritableProperty(dict, 'FT');
data.fieldType = isName(fieldType) ? fieldType.name : '';
data.fieldFlags = Util.getInheritableProperty(dict, 'Ff') || 0;
- this.fieldResources = Util.getInheritableProperty(dict, 'DR') || new Dict();
+ this.fieldResources = Util.getInheritableProperty(dict, 'DR') || Dict.empty;
// Building the full field name by collecting the field and
// its ancestors 'T' data and joining them using '.'.
@@ -3417,7 +2003,6 @@ var TextWidgetAnnotation = (function TextWidgetAnnotationClosure() {
}
- var parent = WidgetAnnotation.prototype;
Util.inherit(TextWidgetAnnotation, WidgetAnnotation, {
hasHtml: function TextWidgetAnnotation_hasHtml() {
return !this.data.hasAppearance && !!this.data.fieldValue;
@@ -3440,7 +2025,7 @@ var TextWidgetAnnotation = (function TextWidgetAnnotationClosure() {
var fontObj = item.fontRefName ?
commonObjs.getData(item.fontRefName) : null;
- var cssRules = setTextStyles(content, item, fontObj);
+ setTextStyles(content, item, fontObj);
element.appendChild(content);
@@ -3452,54 +2037,20 @@ var TextWidgetAnnotation = (function TextWidgetAnnotationClosure() {
return Annotation.prototype.getOperatorList.call(this, evaluator);
}
- var promise = new LegacyPromise();
var opList = new OperatorList();
var data = this.data;
// Even if there is an appearance stream, ignore it. This is the
// behaviour used by Adobe Reader.
-
- var defaultAppearance = data.defaultAppearance;
- if (!defaultAppearance) {
- promise.resolve(opList);
- return promise;
+ if (!data.defaultAppearance) {
+ return Promise.resolve(opList);
}
- // Include any font resources found in the default appearance
-
- var stream = new Stream(stringToBytes(defaultAppearance));
- evaluator.getOperatorList(stream, this.fieldResources, opList);
- var appearanceFnArray = opList.fnArray;
- var appearanceArgsArray = opList.argsArray;
- var fnArray = [];
- var argsArray = [];
-
- // TODO(mack): Add support for stroke color
- data.rgb = [0, 0, 0];
- // TODO THIS DOESN'T MAKE ANY SENSE SINCE THE fnArray IS EMPTY!
- for (var i = 0, n = fnArray.length; i < n; ++i) {
- var fnId = appearanceFnArray[i];
- var args = appearanceArgsArray[i];
-
- if (fnId === OPS.setFont) {
- data.fontRefName = args[0];
- var size = args[1];
- if (size < 0) {
- data.fontDirection = -1;
- data.fontSize = -size;
- } else {
- data.fontDirection = 1;
- data.fontSize = size;
- }
- } else if (fnId === OPS.setFillRGBColor) {
- data.rgb = args;
- } else if (fnId === OPS.setFillGray) {
- var rgbValue = args[0] * 255;
- data.rgb = [rgbValue, rgbValue, rgbValue];
- }
- }
- promise.resolve(opList);
- return promise;
+ var stream = new Stream(stringToBytes(data.defaultAppearance));
+ return evaluator.getOperatorList(stream, this.fieldResources, opList).
+ then(function () {
+ return opList;
+ });
}
});
@@ -3580,6 +2131,8 @@ var TextAnnotation = (function TextAnnotationClosure() {
if (data.hasAppearance) {
data.name = 'NoIcon';
} else {
+ data.rect[1] = data.rect[3] - DEFAULT_ICON_SIZE;
+ data.rect[2] = data.rect[0] + DEFAULT_ICON_SIZE;
data.name = dict.has('Name') ? dict.get('Name').name : 'Note';
}
@@ -3627,10 +2180,12 @@ var TextAnnotation = (function TextAnnotationClosure() {
var content = document.createElement('div');
content.className = 'annotTextContent';
content.setAttribute('hidden', true);
+
+ var i, ii;
if (item.hasBgColor) {
var color = item.color;
var rgb = [];
- for (var i = 0; i < 3; ++i) {
+ for (i = 0; i < 3; ++i) {
// Enlighten the color (70%)
var c = Math.round(color[i] * 255);
rgb[i] = Math.round((255 - c) * 0.7) + c;
@@ -3647,7 +2202,7 @@ var TextAnnotation = (function TextAnnotationClosure() {
} else {
var e = document.createElement('span');
var lines = item.content.split(/(?:\r\n?|\n)/);
- for (var i = 0, ii = lines.length; i < ii; ++i) {
+ for (i = 0, ii = lines.length; i < ii; ++i) {
var line = lines[i];
e.appendChild(document.createTextNode(line));
if (i < (ii - 1)) {
@@ -3686,7 +2241,6 @@ var TextAnnotation = (function TextAnnotationClosure() {
}
};
- var self = this;
image.addEventListener('click', function image_clickHandler() {
toggleAnnotation();
}, false);
@@ -3791,7 +2345,6 @@ var LinkAnnotation = (function LinkAnnotationClosure() {
container.className = 'annotLink';
var item = this.data;
- var rect = item.rect;
container.style.borderColor = item.colorCssRgb;
container.style.borderStyle = 'solid';
@@ -3824,6 +2377,12 @@ PDFJS.maxImageSize = (PDFJS.maxImageSize === undefined ?
*/
PDFJS.cMapUrl = (PDFJS.cMapUrl === undefined ? null : PDFJS.cMapUrl);
+/**
+ * Specifies if CMaps are binary packed.
+ * @var {boolean}
+ */
+PDFJS.cMapPacked = PDFJS.cMapPacked === undefined ? false : PDFJS.cMapPacked;
+
/*
* By default fonts are converted to OpenType fonts and loaded via font face
* rules. If disabled, the font will be rendered using a built in font renderer
@@ -3897,6 +2456,13 @@ PDFJS.disableCreateObjectURL = (PDFJS.disableCreateObjectURL === undefined ?
false : PDFJS.disableCreateObjectURL);
/**
+ * Disables WebGL usage.
+ * @var {boolean}
+ */
+PDFJS.disableWebGL = (PDFJS.disableWebGL === undefined ?
+ true : PDFJS.disableWebGL);
+
+/**
* Controls the logging level.
* The constants from PDFJS.VERBOSITY_LEVELS should be used:
* - errors
@@ -3949,7 +2515,7 @@ PDFJS.getDocument = function getDocument(source,
pdfDataRangeTransport,
passwordCallback,
progressCallback) {
- var workerInitializedPromise, workerReadyPromise, transport;
+ var workerInitializedCapability, workerReadyCapability, transport;
if (typeof source === 'string') {
source = { url: source };
@@ -3974,15 +2540,16 @@ PDFJS.getDocument = function getDocument(source,
params[key] = source[key];
}
- workerInitializedPromise = new PDFJS.LegacyPromise();
- workerReadyPromise = new PDFJS.LegacyPromise();
- transport = new WorkerTransport(workerInitializedPromise, workerReadyPromise,
- pdfDataRangeTransport, progressCallback);
- workerInitializedPromise.then(function transportInitialized() {
+ workerInitializedCapability = createPromiseCapability();
+ workerReadyCapability = createPromiseCapability();
+ transport = new WorkerTransport(workerInitializedCapability,
+ workerReadyCapability, pdfDataRangeTransport,
+ progressCallback);
+ workerInitializedCapability.promise.then(function transportInitialized() {
transport.passwordCallback = passwordCallback;
transport.fetchDocument(params);
});
- return workerReadyPromise;
+ return workerReadyCapability.promise;
};
/**
@@ -4034,14 +2601,18 @@ var PDFDocumentProxy = (function PDFDocumentProxyClosure() {
return this.transport.getDestinations();
},
/**
+ * @return {Promise} A promise that is resolved with a lookup table for
+ * mapping named attachments to their content.
+ */
+ getAttachments: function PDFDocumentProxy_getAttachments() {
+ return this.transport.getAttachments();
+ },
+ /**
* @return {Promise} A promise that is resolved with an array of all the
* JavaScript strings in the name tree.
*/
getJavaScript: function PDFDocumentProxy_getJavaScript() {
- var promise = new PDFJS.LegacyPromise();
- var js = this.pdfInfo.javaScript;
- promise.resolve(js);
- return promise;
+ return this.transport.getJavaScript();
},
/**
* @return {Promise} A promise that is resolved with an {Array} that is a
@@ -4059,10 +2630,7 @@ var PDFDocumentProxy = (function PDFDocumentProxyClosure() {
* ].
*/
getOutline: function PDFDocumentProxy_getOutline() {
- var promise = new PDFJS.LegacyPromise();
- var outline = this.pdfInfo.outline;
- promise.resolve(outline);
- return promise;
+ return this.transport.getOutline();
},
/**
* @return {Promise} A promise that is resolved with an {Object} that has
@@ -4071,23 +2639,14 @@ var PDFDocumentProxy = (function PDFDocumentProxyClosure() {
* {Metadata} object with information from the metadata section of the PDF.
*/
getMetadata: function PDFDocumentProxy_getMetadata() {
- var promise = new PDFJS.LegacyPromise();
- var info = this.pdfInfo.info;
- var metadata = this.pdfInfo.metadata;
- promise.resolve({
- info: info,
- metadata: (metadata ? new PDFJS.Metadata(metadata) : null)
- });
- return promise;
+ return this.transport.getMetadata();
},
/**
* @return {Promise} A promise that is resolved with a TypedArray that has
* the raw data from the PDF.
*/
getData: function PDFDocumentProxy_getData() {
- var promise = new PDFJS.LegacyPromise();
- this.transport.getData(promise);
- return promise;
+ return this.transport.getData();
},
/**
* @return {Promise} A promise that is resolved when the document's data
@@ -4095,7 +2654,7 @@ var PDFDocumentProxy = (function PDFDocumentProxyClosure() {
* property that indicates size of the PDF data in bytes.
*/
getDownloadInfo: function PDFDocumentProxy_getDownloadInfo() {
- return this.transport.downloadInfoPromise;
+ return this.transport.downloadInfoCapability.promise;
},
/**
* Cleans up resources allocated by the document, e.g. created @font-face.
@@ -4114,15 +2673,51 @@ var PDFDocumentProxy = (function PDFDocumentProxyClosure() {
})();
/**
+ * Page text content.
+ *
+ * @typedef {Object} TextContent
+ * @property {array} items - array of {@link TextItem}
+ * @property {Object} styles - {@link TextStyles} objects, indexed by font
+ * name.
+ */
+
+/**
* Page text content part.
*
- * @typedef {Object} BidiText
+ * @typedef {Object} TextItem
* @property {string} str - text content.
* @property {string} dir - text direction: 'ttb', 'ltr' or 'rtl'.
- * @property {number} x - x position of the text on the page.
- * @property {number} y - y position of the text on the page.
- * @property {number} angle - text rotation.
- * @property {number} size - font size.
+ * @property {array} transform - transformation matrix.
+ * @property {number} width - width in device space.
+ * @property {number} height - height in device space.
+ * @property {string} fontName - font name used by pdf.js for converted font.
+ */
+
+/**
+ * Text style.
+ *
+ * @typedef {Object} TextStyle
+ * @property {number} ascent - font ascent.
+ * @property {number} descent - font descent.
+ * @property {boolean} vertical - text is in vertical mode.
+ * @property {string} fontFamily - possible font family
+ */
+
+/**
+ * Page render parameters.
+ *
+ * @typedef {Object} RenderParameters
+ * @property {Object} canvasContext - A 2D context of a DOM Canvas object.
+ * @property {PDFJS.PageViewport} viewport - Rendering viewport obtained by
+ * calling of PDFPage.getViewport method.
+ * @property {string} intent - Rendering intent, can be 'display' or 'print'
+ * (default value is 'display').
+ * @property {Object} imageLayer - (optional) An object that has beginLayout,
+ * endLayout and appendImage functions.
+ * @property {function} continueCallback - (optional) A function that will be
+ * called each time the rendering is paused. To continue
+ * rendering call the function that is the first argument
+ * to the callback.
*/
/**
@@ -4130,7 +2725,8 @@ var PDFDocumentProxy = (function PDFDocumentProxyClosure() {
* @class
*/
var PDFPageProxy = (function PDFPageProxyClosure() {
- function PDFPageProxy(pageInfo, transport) {
+ function PDFPageProxy(pageIndex, pageInfo, transport) {
+ this.pageIndex = pageIndex;
this.pageInfo = pageInfo;
this.transport = transport;
this.stats = new StatTimer();
@@ -4146,7 +2742,7 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
* @return {number} Page number of the page. First page is 1.
*/
get pageNumber() {
- return this.pageInfo.pageIndex + 1;
+ return this.pageIndex + 1;
},
/**
* @return {number} The number of degrees the page is rotated clockwise.
@@ -4172,8 +2768,8 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
* @param {number} scale The desired scale of the viewport.
* @param {number} rotate Degrees to rotate the viewport. If omitted this
* defaults to the page rotation.
- * @return {PageViewport} Contains 'width' and 'height' properties along
- * with transforms required for rendering.
+ * @return {PDFJS.PageViewport} Contains 'width' and 'height' properties
+ * along with transforms required for rendering.
*/
getViewport: function PDFPageProxy_getViewport(scale, rotate) {
if (arguments.length < 2) {
@@ -4190,27 +2786,15 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
return this.annotationsPromise;
}
- var promise = new PDFJS.LegacyPromise();
+ var promise = this.transport.getAnnotations(this.pageIndex);
this.annotationsPromise = promise;
- this.transport.getAnnotations(this.pageInfo.pageIndex);
return promise;
},
/**
* Begins the process of rendering a page to the desired context.
- * @param {Object} params A parameter object that supports:
- * {
- * canvasContext(required): A 2D context of a DOM Canvas object.,
- * textLayer(optional): An object that has beginLayout, endLayout, and
- * appendText functions.,
- * imageLayer(optional): An object that has beginLayout, endLayout and
- * appendImage functions.,
- * continueCallback(optional): A function that will be called each time
- * the rendering is paused. To continue
- * rendering call the function that is the
- * first argument to the callback.
- * }.
- * @return {RenderTask} An extended promise that is resolved when the page
- * finishes rendering (see RenderTask).
+ * @param {RenderParameters} params Page render parameters.
+ * @return {RenderTask} An object that contains the promise, which
+ * is resolved when the page finishes rendering.
*/
render: function PDFPageProxy_render(params) {
var stats = this.stats;
@@ -4228,11 +2812,11 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
}
var intentState = this.intentStates[renderingIntent];
- // If there is no displayReadyPromise yet, then the operatorList was never
- // requested before. Make the request and create the promise.
- if (!intentState.displayReadyPromise) {
+ // If there's no displayReadyCapability yet, then the operatorList
+ // was never requested before. Make the request and create the promise.
+ if (!intentState.displayReadyCapability) {
intentState.receivingOperatorList = true;
- intentState.displayReadyPromise = new LegacyPromise();
+ intentState.displayReadyCapability = createPromiseCapability();
intentState.operatorList = {
fnArray: [],
argsArray: [],
@@ -4258,7 +2842,7 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
var renderTask = new RenderTask(internalRenderTask);
var self = this;
- intentState.displayReadyPromise.then(
+ intentState.displayReadyCapability.promise.then(
function pageDisplayReadyPromise(transparency) {
if (self.pendingDestroy) {
complete();
@@ -4285,9 +2869,9 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
self._tryDestroy();
if (error) {
- renderTask.promise.reject(error);
+ internalRenderTask.capability.reject(error);
} else {
- renderTask.promise.resolve();
+ internalRenderTask.capability.resolve();
}
stats.timeEnd('Rendering');
stats.timeEnd('Overall');
@@ -4296,19 +2880,13 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
return renderTask;
},
/**
- * @return {Promise} That is resolved with the array of {@link BidiText}
- * objects that represent the page text content.
+ * @return {Promise} That is resolved a {@link TextContent}
+ * object that represent the page text content.
*/
getTextContent: function PDFPageProxy_getTextContent() {
- var promise = new PDFJS.LegacyPromise();
- this.transport.messageHandler.send('GetTextContent', {
- pageIndex: this.pageNumber - 1
- },
- function textContentCallback(textContent) {
- promise.resolve(textContent);
- }
- );
- return promise;
+ return this.transport.messageHandler.sendWithPromise('GetTextContent', {
+ pageIndex: this.pageNumber - 1
+ });
},
/**
* Destroys resources allocated by the page.
@@ -4336,6 +2914,7 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
delete this.intentStates[intent];
}, this);
this.objs.clear();
+ this.annotationsPromise = null;
this.pendingDestroy = false;
},
/**
@@ -4345,7 +2924,7 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
_startRenderPage: function PDFPageProxy_startRenderPage(transparency,
intent) {
var intentState = this.intentStates[intent];
- intentState.displayReadyPromise.resolve(transparency);
+ intentState.displayReadyCapability.resolve(transparency);
},
/**
* For internal use only.
@@ -4354,8 +2933,9 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
_renderPageChunk: function PDFPageProxy_renderPageChunk(operatorListChunk,
intent) {
var intentState = this.intentStates[intent];
+ var i, ii;
// Add the new chunk to the current operator list.
- for (var i = 0, ii = operatorListChunk.length; i < ii; i++) {
+ for (i = 0, ii = operatorListChunk.length; i < ii; i++) {
intentState.operatorList.fnArray.push(operatorListChunk.fnArray[i]);
intentState.operatorList.argsArray.push(
operatorListChunk.argsArray[i]);
@@ -4363,7 +2943,7 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
intentState.operatorList.lastChunk = operatorListChunk.lastChunk;
// Notify all the rendering tasks there are more operators to be consumed.
- for (var i = 0; i < intentState.renderTasks.length; i++) {
+ for (i = 0; i < intentState.renderTasks.length; i++) {
intentState.renderTasks[i].operatorListChanged();
}
@@ -4381,17 +2961,17 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
* @ignore
*/
var WorkerTransport = (function WorkerTransportClosure() {
- function WorkerTransport(workerInitializedPromise, workerReadyPromise,
+ function WorkerTransport(workerInitializedCapability, workerReadyCapability,
pdfDataRangeTransport, progressCallback) {
this.pdfDataRangeTransport = pdfDataRangeTransport;
- this.workerReadyPromise = workerReadyPromise;
+ this.workerReadyCapability = workerReadyCapability;
this.progressCallback = progressCallback;
this.commonObjs = new PDFObjects();
this.pageCache = [];
this.pagePromises = [];
- this.downloadInfoPromise = new PDFJS.LegacyPromise();
+ this.downloadInfoCapability = createPromiseCapability();
this.passwordCallback = null;
// If worker support isn't disabled explicit and the browser has worker
@@ -4420,12 +3000,12 @@ var WorkerTransport = (function WorkerTransportClosure() {
PDFJS.postMessageTransfers = false;
}
this.setupMessageHandler(messageHandler);
- workerInitializedPromise.resolve();
+ workerInitializedCapability.resolve();
} else {
globalScope.PDFJS.disableWorker = true;
this.loadFakeWorkerFiles().then(function() {
this.setupFakeWorker();
- workerInitializedPromise.resolve();
+ workerInitializedCapability.resolve();
}.bind(this));
}
}.bind(this));
@@ -4434,7 +3014,7 @@ var WorkerTransport = (function WorkerTransportClosure() {
// Some versions of Opera throw a DATA_CLONE_ERR on serializing the
// typed array. Also, checking if we can use transfers.
try {
- messageHandler.send('test', testObj, null, [testObj.buffer]);
+ messageHandler.send('test', testObj, [testObj.buffer]);
} catch (ex) {
info('Cannot use postMessage transfers');
testObj[0] = 0;
@@ -4450,7 +3030,7 @@ var WorkerTransport = (function WorkerTransportClosure() {
globalScope.PDFJS.disableWorker = true;
this.loadFakeWorkerFiles().then(function() {
this.setupFakeWorker();
- workerInitializedPromise.resolve();
+ workerInitializedCapability.resolve();
}.bind(this));
}
WorkerTransport.prototype = {
@@ -4458,7 +3038,7 @@ var WorkerTransport = (function WorkerTransportClosure() {
this.pageCache = [];
this.pagePromises = [];
var self = this;
- this.messageHandler.send('Terminate', null, function () {
+ this.messageHandler.sendWithPromise('Terminate', null).then(function () {
FontLoader.clear();
if (self.worker) {
self.worker.terminate();
@@ -4467,16 +3047,16 @@ var WorkerTransport = (function WorkerTransportClosure() {
},
loadFakeWorkerFiles: function WorkerTransport_loadFakeWorkerFiles() {
- if (!PDFJS.fakeWorkerFilesLoadedPromise) {
- PDFJS.fakeWorkerFilesLoadedPromise = new LegacyPromise();
+ if (!PDFJS.fakeWorkerFilesLoadedCapability) {
+ PDFJS.fakeWorkerFilesLoadedCapability = createPromiseCapability();
// In the developer build load worker_loader which in turn loads all the
// other files and resolves the promise. In production only the
// pdf.worker.js file is needed.
Util.loadScript(PDFJS.workerSrc, function() {
- PDFJS.fakeWorkerFilesLoadedPromise.resolve();
+ PDFJS.fakeWorkerFilesLoadedCapability.resolve();
});
}
- return PDFJS.fakeWorkerFilesLoadedPromise;
+ return PDFJS.fakeWorkerFilesLoadedCapability.promise;
},
setupFakeWorker: function WorkerTransport_setupFakeWorker() {
@@ -4531,7 +3111,7 @@ var WorkerTransport = (function WorkerTransportClosure() {
this.numPages = data.pdfInfo.numPages;
var pdfDocument = new PDFDocumentProxy(pdfInfo, this);
this.pdfDocument = pdfDocument;
- this.workerReadyPromise.resolve(pdfDocument);
+ this.workerReadyCapability.resolve(pdfDocument);
}, this);
messageHandler.on('NeedPassword', function transportPassword(data) {
@@ -4539,7 +3119,8 @@ var WorkerTransport = (function WorkerTransportClosure() {
return this.passwordCallback(updatePassword,
PasswordResponses.NEED_PASSWORD);
}
- this.workerReadyPromise.reject(data.exception.message, data.exception);
+ this.workerReadyCapability.reject(data.exception.message,
+ data.exception);
}, this);
messageHandler.on('IncorrectPassword', function transportBadPass(data) {
@@ -4547,37 +3128,26 @@ var WorkerTransport = (function WorkerTransportClosure() {
return this.passwordCallback(updatePassword,
PasswordResponses.INCORRECT_PASSWORD);
}
- this.workerReadyPromise.reject(data.exception.message, data.exception);
+ this.workerReadyCapability.reject(data.exception.message,
+ data.exception);
}, this);
messageHandler.on('InvalidPDF', function transportInvalidPDF(data) {
- this.workerReadyPromise.reject(data.exception.name, data.exception);
+ this.workerReadyCapability.reject(data.exception.name, data.exception);
}, this);
messageHandler.on('MissingPDF', function transportMissingPDF(data) {
- this.workerReadyPromise.reject(data.exception.message, data.exception);
+ this.workerReadyCapability.reject(data.exception.message,
+ data.exception);
}, this);
messageHandler.on('UnknownError', function transportUnknownError(data) {
- this.workerReadyPromise.reject(data.exception.message, data.exception);
+ this.workerReadyCapability.reject(data.exception.message,
+ data.exception);
}, this);
messageHandler.on('DataLoaded', function transportPage(data) {
- this.downloadInfoPromise.resolve(data);
- }, this);
-
- messageHandler.on('GetPage', function transportPage(data) {
- var pageInfo = data.pageInfo;
- var page = new PDFPageProxy(pageInfo, this);
- this.pageCache[pageInfo.pageIndex] = page;
- var promise = this.pagePromises[pageInfo.pageIndex];
- promise.resolve(page);
- }, this);
-
- messageHandler.on('GetAnnotations', function transportAnnotations(data) {
- var annotations = data.annotations;
- var promise = this.pageCache[data.pageIndex].annotationsPromise;
- promise.resolve(annotations);
+ this.downloadInfoCapability.resolve(data);
}, this);
messageHandler.on('StartRenderPage', function transportRender(data) {
@@ -4634,22 +3204,23 @@ var WorkerTransport = (function WorkerTransportClosure() {
var pageIndex = data[1];
var type = data[2];
var pageProxy = this.pageCache[pageIndex];
+ var imageData;
if (pageProxy.objs.hasData(id)) {
return;
}
switch (type) {
case 'JpegStream':
- var imageData = data[3];
+ imageData = data[3];
loadJpegStream(id, imageData, pageProxy.objs);
break;
case 'Image':
- var imageData = data[3];
+ imageData = data[3];
pageProxy.objs.resolve(id, imageData);
// heuristics that will allow not to store large data
var MAX_IMAGE_SIZE_TO_STORE = 8000000;
- if ('data' in imageData &&
+ if (imageData && 'data' in imageData &&
imageData.data.length > MAX_IMAGE_SIZE_TO_STORE) {
pageProxy.cleanupAfterRender = true;
}
@@ -4669,52 +3240,59 @@ var WorkerTransport = (function WorkerTransportClosure() {
}, this);
messageHandler.on('DocError', function transportDocError(data) {
- this.workerReadyPromise.reject(data);
+ this.workerReadyCapability.reject(data);
}, this);
- messageHandler.on('PageError', function transportError(data, intent) {
+ messageHandler.on('PageError', function transportError(data) {
var page = this.pageCache[data.pageNum - 1];
- var intentState = page.intentStates[intent];
- if (intentState.displayReadyPromise) {
- intentState.displayReadyPromise.reject(data.error);
+ var intentState = page.intentStates[data.intent];
+ if (intentState.displayReadyCapability.promise) {
+ intentState.displayReadyCapability.reject(data.error);
} else {
error(data.error);
}
}, this);
- messageHandler.on('JpegDecode', function(data, deferred) {
+ messageHandler.on('JpegDecode', function(data) {
var imageUrl = data[0];
var components = data[1];
if (components != 3 && components != 1) {
- error('Only 3 component or 1 component can be returned');
+ return Promise.reject(
+ new Error('Only 3 components 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;
+ return new Promise(function (resolve, reject) {
+ var img = new Image();
+ img.onload = function () {
+ 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;
+ var i, j;
- 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];
- }
- } else if (components == 1) {
- for (var i = 0, j = 0; i < rgbaLength; i += 4, j++) {
- buf[j] = data[i];
+ if (components == 3) {
+ for (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];
+ }
+ } else if (components == 1) {
+ for (i = 0, j = 0; i < rgbaLength; i += 4, j++) {
+ buf[j] = data[i];
+ }
}
- }
- deferred.resolve({ data: buf, width: width, height: height});
- }).bind(this);
- img.src = imageUrl;
+ resolve({ data: buf, width: width, height: height});
+ };
+ img.onerror = function () {
+ reject(new Error('JpegDecode failed to load image'));
+ };
+ img.src = imageUrl;
+ });
});
},
@@ -4726,74 +3304,85 @@ var WorkerTransport = (function WorkerTransportClosure() {
disableRange: PDFJS.disableRange,
maxImageSize: PDFJS.maxImageSize,
cMapUrl: PDFJS.cMapUrl,
+ cMapPacked: PDFJS.cMapPacked,
disableFontFace: PDFJS.disableFontFace,
disableCreateObjectURL: PDFJS.disableCreateObjectURL,
verbosity: PDFJS.verbosity
});
},
- getData: function WorkerTransport_getData(promise) {
- this.messageHandler.send('GetData', null, function(data) {
- promise.resolve(data);
- });
+ getData: function WorkerTransport_getData() {
+ return this.messageHandler.sendWithPromise('GetData', null);
},
- getPage: function WorkerTransport_getPage(pageNumber, promise) {
+ getPage: function WorkerTransport_getPage(pageNumber, capability) {
if (pageNumber <= 0 || pageNumber > this.numPages ||
(pageNumber|0) !== pageNumber) {
- var pagePromise = new PDFJS.LegacyPromise();
- pagePromise.reject(new Error('Invalid page request'));
- return pagePromise;
+ return Promise.reject(new Error('Invalid page request'));
}
var pageIndex = pageNumber - 1;
if (pageIndex in this.pagePromises) {
return this.pagePromises[pageIndex];
}
- var promise = new PDFJS.LegacyPromise();
+ var promise = this.messageHandler.sendWithPromise('GetPage', {
+ pageIndex: pageIndex
+ }).then(function (pageInfo) {
+ var page = new PDFPageProxy(pageIndex, pageInfo, this);
+ this.pageCache[pageIndex] = page;
+ return page;
+ }.bind(this));
this.pagePromises[pageIndex] = promise;
- this.messageHandler.send('GetPageRequest', { pageIndex: pageIndex });
return promise;
},
getPageIndex: function WorkerTransport_getPageIndexByRef(ref) {
- var promise = new PDFJS.LegacyPromise();
- this.messageHandler.send('GetPageIndex', { ref: ref },
- function (pageIndex) {
- promise.resolve(pageIndex);
- }
- );
- return promise;
+ return this.messageHandler.sendWithPromise('GetPageIndex', { ref: ref });
},
getAnnotations: function WorkerTransport_getAnnotations(pageIndex) {
- this.messageHandler.send('GetAnnotationsRequest',
+ return this.messageHandler.sendWithPromise('GetAnnotations',
{ pageIndex: pageIndex });
},
getDestinations: function WorkerTransport_getDestinations() {
- var promise = new PDFJS.LegacyPromise();
- this.messageHandler.send('GetDestinations', null,
- function transportDestinations(destinations) {
- promise.resolve(destinations);
- }
- );
- return promise;
+ return this.messageHandler.sendWithPromise('GetDestinations', null);
+ },
+
+ getAttachments: function WorkerTransport_getAttachments() {
+ return this.messageHandler.sendWithPromise('GetAttachments', null);
+ },
+
+ getJavaScript: function WorkerTransport_getJavaScript() {
+ return this.messageHandler.sendWithPromise('GetJavaScript', null);
+ },
+
+ getOutline: function WorkerTransport_getOutline() {
+ return this.messageHandler.sendWithPromise('GetOutline', null);
+ },
+
+ getMetadata: function WorkerTransport_getMetadata() {
+ return this.messageHandler.sendWithPromise('GetMetadata', null).
+ then(function transportMetadata(results) {
+ return {
+ info: results[0],
+ metadata: (results[1] ? new PDFJS.Metadata(results[1]) : null)
+ };
+ });
},
startCleanup: function WorkerTransport_startCleanup() {
- this.messageHandler.send('Cleanup', null,
- function endCleanup() {
- for (var i = 0, ii = this.pageCache.length; i < ii; i++) {
- var page = this.pageCache[i];
- if (page) {
- page.destroy();
- }
+ this.messageHandler.sendWithPromise('Cleanup', null).
+ then(function endCleanup() {
+ for (var i = 0, ii = this.pageCache.length; i < ii; i++) {
+ var page = this.pageCache[i];
+ if (page) {
+ page.destroy();
}
- this.commonObjs.clear();
- FontLoader.clear();
- }.bind(this)
- );
+ }
+ this.commonObjs.clear();
+ FontLoader.clear();
+ }.bind(this));
}
};
return WorkerTransport;
@@ -4823,7 +3412,7 @@ var PDFObjects = (function PDFObjectsClosure() {
}
var obj = {
- promise: new LegacyPromise(),
+ capability: createPromiseCapability(),
data: null,
resolved: false
};
@@ -4845,7 +3434,7 @@ var PDFObjects = (function PDFObjectsClosure() {
// If there is a callback, then the get can be async and the object is
// not required to be resolved right now
if (callback) {
- this.ensureObj(objId).promise.then(callback);
+ this.ensureObj(objId).capability.promise.then(callback);
return null;
}
@@ -4870,7 +3459,7 @@ var PDFObjects = (function PDFObjectsClosure() {
obj.resolved = true;
obj.data = data;
- obj.promise.resolve(data);
+ obj.capability.resolve(data);
},
isResolved: function PDFObjects_isResolved(objId) {
@@ -4917,7 +3506,7 @@ var RenderTask = (function RenderTaskClosure() {
* Promise for rendering task completion.
* @type {Promise}
*/
- this.promise = new PDFJS.LegacyPromise();
+ this.promise = this.internalRenderTask.capability.promise;
}
RenderTask.prototype = /** @lends RenderTask.prototype */ {
@@ -4928,7 +3517,18 @@ var RenderTask = (function RenderTaskClosure() {
*/
cancel: function RenderTask_cancel() {
this.internalRenderTask.cancel();
- this.promise.reject(new Error('Rendering is cancelled'));
+ },
+
+ /**
+ * Registers callback to indicate the rendering task completion.
+ *
+ * @param {function} onFulfilled The callback for the rendering completion.
+ * @param {function} onRejected The callback for the rendering failure.
+ * @return {Promise} A promise that is resolved after the onFulfilled or
+ * onRejected callback.
+ */
+ then: function RenderTask_then(onFulfilled, onRejected) {
+ return this.promise.then(onFulfilled, onRejected);
}
};
@@ -4954,6 +3554,11 @@ var InternalRenderTask = (function InternalRenderTaskClosure() {
this.graphicsReadyCallback = null;
this.graphicsReady = false;
this.cancelled = false;
+ this.capability = createPromiseCapability();
+ // caching this-bound methods
+ this._continueBound = this._continue.bind(this);
+ this._scheduleNextBound = this._scheduleNext.bind(this);
+ this._nextBound = this._next.bind(this);
}
InternalRenderTask.prototype = {
@@ -4973,8 +3578,7 @@ var InternalRenderTask = (function InternalRenderTaskClosure() {
var params = this.params;
this.gfx = new CanvasGraphics(params.canvasContext, this.commonObjs,
- this.objs, params.textLayer,
- params.imageLayer);
+ this.objs, params.imageLayer);
this.gfx.beginDrawing(params.viewport, transparency);
this.operatorListIdx = 0;
@@ -4993,7 +3597,7 @@ var InternalRenderTask = (function InternalRenderTaskClosure() {
operatorListChanged: function InternalRenderTask_operatorListChanged() {
if (!this.graphicsReady) {
if (!this.graphicsReadyCallback) {
- this.graphicsReadyCallback = this._continue.bind(this);
+ this.graphicsReadyCallback = this._continueBound;
}
return;
}
@@ -5014,19 +3618,23 @@ var InternalRenderTask = (function InternalRenderTaskClosure() {
return;
}
if (this.params.continueCallback) {
- this.params.continueCallback(this._next.bind(this));
+ this.params.continueCallback(this._scheduleNextBound);
} else {
- this._next();
+ this._scheduleNext();
}
},
+ _scheduleNext: function InternalRenderTask__scheduleNext() {
+ window.requestAnimationFrame(this._nextBound);
+ },
+
_next: function InternalRenderTask__next() {
if (this.cancelled) {
return;
}
this.operatorListIdx = this.gfx.executeOperatorList(this.operatorList,
this.operatorListIdx,
- this._continue.bind(this),
+ this._continueBound,
this.stepper);
if (this.operatorListIdx === this.operatorList.argsArray.length) {
this.running = false;
@@ -5129,6 +3737,7 @@ var Metadata = PDFJS.Metadata = (function MetadataClosure() {
// Minimal font size that would be used during canvas fillText operations.
var MIN_FONT_SIZE = 16;
+var MAX_GROUP_SIZE = 4096;
var COMPILE_TYPE3_GLYPHS = true;
@@ -5453,6 +4062,7 @@ var CanvasExtraState = (function CanvasExtraStateClosure() {
this.fontSize = 0;
this.fontSizeScale = 1;
this.textMatrix = IDENTITY_MATRIX;
+ this.textMatrixScale = 1;
this.fontMatrix = FONT_IDENTITY_MATRIX;
this.leading = 0;
// Current point (in user coordinates)
@@ -5467,13 +4077,6 @@ var CanvasExtraState = (function CanvasExtraStateClosure() {
this.textHScale = 1;
this.textRenderingMode = TextRenderingMode.FILL;
this.textRise = 0;
- // Color spaces
- this.fillColorSpace = ColorSpace.singletons.gray;
- this.fillColorSpaceObj = null;
- this.strokeColorSpace = ColorSpace.singletons.gray;
- this.strokeColorSpaceObj = null;
- this.fillColorObj = null;
- this.strokeColorObj = null;
// Default fore and background colors
this.fillColor = '#000000';
this.strokeColor = '#000000';
@@ -5503,7 +4106,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
// before it stops and shedules a continue of execution.
var EXECUTION_TIME = 15;
- function CanvasGraphics(canvasCtx, commonObjs, objs, textLayer, imageLayer) {
+ function CanvasGraphics(canvasCtx, commonObjs, objs, imageLayer) {
this.ctx = canvasCtx;
this.current = new CanvasExtraState();
this.stateStack = [];
@@ -5513,7 +4116,6 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
this.xobjs = null;
this.commonObjs = commonObjs;
this.objs = objs;
- this.textLayer = textLayer;
this.imageLayer = imageLayer;
this.groupStack = [];
this.processingType3 = null;
@@ -5555,83 +4157,92 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
var partialChunkHeight = height - fullChunks * fullChunkHeight;
var chunkImgData = ctx.createImageData(width, fullChunkHeight);
- var srcPos = 0;
+ var srcPos = 0, destPos;
var src = imgData.data;
var dest = chunkImgData.data;
+ var i, j, thisChunkHeight, elemsInThisChunk;
// There are multiple forms in which the pixel data can be passed, and
// imgData.kind tells us which one this is.
-
if (imgData.kind === ImageKind.GRAYSCALE_1BPP) {
// Grayscale, 1 bit per pixel (i.e. black-and-white).
- var destDataLength = dest.length;
var srcLength = src.byteLength;
- for (var i = 3; i < destDataLength; i += 4) {
- dest[i] = 255;
- }
- for (var i = 0; i < totalChunks; i++) {
- var thisChunkHeight =
+ var dest32 = PDFJS.hasCanvasTypedArrays ? new Uint32Array(dest.buffer) :
+ new Uint32ArrayView(dest);
+ var dest32DataLength = dest32.length;
+ var fullSrcDiff = (width + 7) >> 3;
+ var white = 0xFFFFFFFF;
+ var black = (PDFJS.isLittleEndian || !PDFJS.hasCanvasTypedArrays) ?
+ 0xFF000000 : 0x000000FF;
+ for (i = 0; i < totalChunks; i++) {
+ thisChunkHeight =
(i < fullChunks) ? fullChunkHeight : partialChunkHeight;
- var destPos = 0;
- for (var j = 0; j < thisChunkHeight; j++) {
+ destPos = 0;
+ for (j = 0; j < thisChunkHeight; j++) {
+ var srcDiff = srcLength - srcPos;
+ var k = 0;
+ var kEnd = (srcDiff > fullSrcDiff) ? width : srcDiff * 8 - 7;
+ var kEndUnrolled = kEnd & ~7;
var mask = 0;
var srcByte = 0;
- for (var k = 0; k < width; k++, destPos += 4) {
- if (mask === 0) {
- if (srcPos >= srcLength) {
- break;
- }
- srcByte = src[srcPos++];
- mask = 128;
- }
-
- if ((srcByte & mask)) {
- dest[destPos] = 255;
- dest[destPos + 1] = 255;
- dest[destPos + 2] = 255;
- } else {
- dest[destPos] = 0;
- dest[destPos + 1] = 0;
- dest[destPos + 2] = 0;
- }
+ for (; k < kEndUnrolled; k += 8) {
+ srcByte = src[srcPos++];
+ dest32[destPos++] = (srcByte & 128) ? white : black;
+ dest32[destPos++] = (srcByte & 64) ? white : black;
+ dest32[destPos++] = (srcByte & 32) ? white : black;
+ dest32[destPos++] = (srcByte & 16) ? white : black;
+ dest32[destPos++] = (srcByte & 8) ? white : black;
+ dest32[destPos++] = (srcByte & 4) ? white : black;
+ dest32[destPos++] = (srcByte & 2) ? white : black;
+ dest32[destPos++] = (srcByte & 1) ? white : black;
+ }
+ for (; k < kEnd; k++) {
+ if (mask === 0) {
+ srcByte = src[srcPos++];
+ mask = 128;
+ }
+ dest32[destPos++] = (srcByte & mask) ? white : black;
mask >>= 1;
}
}
- if (destPos < destDataLength) {
- // We ran out of input. Make all remaining pixels transparent.
- destPos += 3;
- do {
- dest[destPos] = 0;
- destPos += 4;
- } while (destPos < destDataLength);
+ // We ran out of input. Make all remaining pixels transparent.
+ while (destPos < dest32DataLength) {
+ dest32[destPos++] = 0;
}
ctx.putImageData(chunkImgData, 0, i * fullChunkHeight);
}
-
} else if (imgData.kind === ImageKind.RGBA_32BPP) {
// RGBA, 32-bits per pixel.
- for (var i = 0; i < totalChunks; i++) {
- var thisChunkHeight =
- (i < fullChunks) ? fullChunkHeight : partialChunkHeight;
- var elemsInThisChunk = imgData.width * thisChunkHeight * 4;
-
+ j = 0;
+ elemsInThisChunk = width * fullChunkHeight * 4;
+ for (i = 0; i < fullChunks; i++) {
dest.set(src.subarray(srcPos, srcPos + elemsInThisChunk));
srcPos += elemsInThisChunk;
- ctx.putImageData(chunkImgData, 0, i * fullChunkHeight);
+ ctx.putImageData(chunkImgData, 0, j);
+ j += fullChunkHeight;
+ }
+ if (i < totalChunks) {
+ elemsInThisChunk = width * partialChunkHeight * 4;
+ dest.set(src.subarray(srcPos, srcPos + elemsInThisChunk));
+ ctx.putImageData(chunkImgData, 0, j);
}
} else if (imgData.kind === ImageKind.RGB_24BPP) {
// RGB, 24-bits per pixel.
- for (var i = 0; i < totalChunks; i++) {
- var thisChunkHeight =
- (i < fullChunks) ? fullChunkHeight : partialChunkHeight;
- var elemsInThisChunk = imgData.width * thisChunkHeight * 3;
- var destPos = 0;
- for (var j = 0; j < elemsInThisChunk; j += 3) {
+ thisChunkHeight = fullChunkHeight;
+ elemsInThisChunk = width * thisChunkHeight;
+ for (i = 0; i < totalChunks; i++) {
+ if (i >= fullChunks) {
+ thisChunkHeight =partialChunkHeight;
+ elemsInThisChunk = width * thisChunkHeight;
+ }
+
+ destPos = 0;
+ for (j = elemsInThisChunk; j--;) {
dest[destPos++] = src[srcPos++];
dest[destPos++] = src[srcPos++];
dest[destPos++] = src[srcPos++];
@@ -5639,9 +4250,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
}
ctx.putImageData(chunkImgData, 0, i * fullChunkHeight);
}
-
} else {
- error('bad image kind: ' + imgData.kind);
+ error('bad image kind: ' + imgData.kind);
}
}
@@ -5700,15 +4310,10 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
}
}
- function composeSMask(ctx, smask, layerCtx) {
- var mask = smask.canvas;
- var maskCtx = smask.context;
- var width = mask.width, height = mask.height;
-
+ function genericComposeSMask(maskCtx, layerCtx, width, height,
+ subtype, backdrop) {
var addBackdropFn;
- if (smask.backdrop) {
- var cs = smask.colorSpace || ColorSpace.singletons.rgb;
- var backdrop = cs.getRgb(smask.backdrop, 0);
+ if (backdrop) {
addBackdropFn = function (r0, g0, b0, bytes) {
var length = bytes.length;
for (var i = 3; i < length; i += 4) {
@@ -5730,7 +4335,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
}
var composeFn;
- if (smask.subtype === 'Luminosity') {
+ if (subtype === 'Luminosity') {
composeFn = function (maskDataBytes, layerDataBytes) {
var length = maskDataBytes.length;
for (var i = 3; i < length; i += 4) {
@@ -5751,7 +4356,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
}
// processing image in chunks to save memory
- var chunkSize = 16;
+ var PIXELS_TO_PROCESS = 65536;
+ var chunkSize = Math.min(height, Math.ceil(PIXELS_TO_PROCESS / width));
for (var row = 0; row < height; row += chunkSize) {
var chunkHeight = Math.min(chunkSize, height - row);
var maskData = maskCtx.getImageData(0, row, width, chunkHeight);
@@ -5762,9 +4368,26 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
maskCtx.putImageData(layerData, 0, row);
}
+ }
- ctx.setTransform(1, 0, 0, 1, 0, 0);
- ctx.drawImage(mask, smask.offsetX, smask.offsetY);
+ function composeSMask(ctx, smask, layerCtx) {
+ var mask = smask.canvas;
+ var maskCtx = smask.context;
+
+ ctx.setTransform(smask.scaleX, 0, 0, smask.scaleY,
+ smask.offsetX, smask.offsetY);
+
+ var backdrop = smask.backdrop || null;
+ if (WebGLUtils.isEnabled) {
+ var composed = WebGLUtils.composeSMask(layerCtx.canvas, mask,
+ {subtype: smask.subtype, backdrop: backdrop});
+ ctx.setTransform(1, 0, 0, 1, 0, 0);
+ ctx.drawImage(composed, smask.offsetX, smask.offsetY);
+ return;
+ }
+ genericComposeSMask(maskCtx, layerCtx, mask.width, mask.height,
+ smask.subtype, backdrop);
+ ctx.drawImage(mask, 0, 0);
}
var LINE_CAP_STYLES = ['butt', 'round', 'square'];
@@ -5799,9 +4422,6 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
this.baseTransform = this.ctx.mozCurrentTransform.slice();
- if (this.textLayer) {
- this.textLayer.beginLayout();
- }
if (this.imageLayer) {
this.imageLayer.beginLayout();
}
@@ -5821,13 +4441,11 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
return i;
}
- var executionEndIdx;
var endTime = Date.now() + EXECUTION_TIME;
var commonObjs = this.commonObjs;
var objs = this.objs;
var fnId;
- var deferred = Promise.resolve();
while (true) {
if (stepper && i === stepper.nextBreakPoint) {
@@ -5865,11 +4483,10 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
return i;
}
- // If the execution took longer then a certain amount of time, schedule
- // to continue exeution after a short delay.
- // However, this is only possible if a 'continueCallback' is passed in.
+ // If the execution took longer then a certain amount of time and
+ // `continueCallback` is specified, interrupt the execution.
if (continueCallback && Date.now() > endTime) {
- deferred.then(continueCallback);
+ continueCallback();
return i;
}
@@ -5881,10 +4498,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
endDrawing: function CanvasGraphics_endDrawing() {
this.ctx.restore();
CachedCanvases.clear();
+ WebGLUtils.clear();
- if (this.textLayer) {
- this.textLayer.endLayout();
- }
if (this.imageLayer) {
this.imageLayer.endLayout();
}
@@ -6004,6 +4619,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
this.ctx.save();
var groupCtx = scratchCanvas.context;
+ groupCtx.scale(1 / activeSMask.scaleX, 1 / activeSMask.scaleY);
groupCtx.translate(-activeSMask.offsetX, -activeSMask.offsetY);
groupCtx.transform.apply(groupCtx, currentTransform);
@@ -6050,31 +4666,60 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
},
// Path
- moveTo: function CanvasGraphics_moveTo(x, y) {
- this.ctx.moveTo(x, y);
- this.current.setCurrentPoint(x, y);
- },
- lineTo: function CanvasGraphics_lineTo(x, y) {
- this.ctx.lineTo(x, y);
- this.current.setCurrentPoint(x, y);
- },
- curveTo: function CanvasGraphics_curveTo(x1, y1, x2, y2, x3, y3) {
- this.ctx.bezierCurveTo(x1, y1, x2, y2, x3, y3);
- this.current.setCurrentPoint(x3, y3);
- },
- curveTo2: function CanvasGraphics_curveTo2(x2, y2, x3, y3) {
+ constructPath: function CanvasGraphics_constructPath(ops, args) {
+ var ctx = this.ctx;
var current = this.current;
- this.ctx.bezierCurveTo(current.x, current.y, x2, y2, x3, y3);
- current.setCurrentPoint(x3, y3);
- },
- curveTo3: function CanvasGraphics_curveTo3(x1, y1, x3, y3) {
- this.curveTo(x1, y1, x3, y3, x3, y3);
- this.current.setCurrentPoint(x3, y3);
+ var x = current.x, y = current.y;
+ for (var i = 0, j = 0, ii = ops.length; i < ii; i++) {
+ switch (ops[i] | 0) {
+ case OPS.moveTo:
+ x = args[j++];
+ y = args[j++];
+ ctx.moveTo(x, y);
+ break;
+ case OPS.lineTo:
+ x = args[j++];
+ y = args[j++];
+ ctx.lineTo(x, y);
+ break;
+ case OPS.curveTo:
+ x = args[j + 4];
+ y = args[j + 5];
+ ctx.bezierCurveTo(args[j], args[j + 1], args[j + 2], args[j + 3],
+ x, y);
+ j += 6;
+ break;
+ case OPS.curveTo2:
+ ctx.bezierCurveTo(x, y, args[j], args[j + 1],
+ args[j + 2], args[j + 3]);
+ x = args[j + 2];
+ y = args[j + 3];
+ j += 4;
+ break;
+ case OPS.curveTo3:
+ x = args[j + 2];
+ y = args[j + 3];
+ ctx.bezierCurveTo(args[j], args[j + 1], x, y, x, y);
+ j += 4;
+ break;
+ case OPS.closePath:
+ ctx.closePath();
+ break;
+ }
+ }
+ current.setCurrentPoint(x, y);
},
closePath: function CanvasGraphics_closePath() {
this.ctx.closePath();
},
rectangle: function CanvasGraphics_rectangle(x, y, width, height) {
+ if (width === 0) {
+ width = this.getSinglePixelWidth();
+ }
+ if (height === 0) {
+ height = this.getSinglePixelWidth();
+ }
+
this.ctx.rect(x, y, width, height);
},
stroke: function CanvasGraphics_stroke(consumePath) {
@@ -6122,21 +4767,21 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
}
if (this.pendingEOFill) {
- if ('mozFillRule' in this.ctx) {
- this.ctx.mozFillRule = 'evenodd';
- this.ctx.fill();
- this.ctx.mozFillRule = 'nonzero';
+ if (ctx.mozFillRule !== undefined) {
+ ctx.mozFillRule = 'evenodd';
+ ctx.fill();
+ ctx.mozFillRule = 'nonzero';
} else {
try {
- this.ctx.fill('evenodd');
+ ctx.fill('evenodd');
} catch (ex) {
// shouldn't really happen, but browsers might think differently
- this.ctx.fill();
+ ctx.fill();
}
}
this.pendingEOFill = false;
} else {
- this.ctx.fill();
+ ctx.fill();
}
if (needRestore) {
@@ -6184,16 +4829,17 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
// Text
beginText: function CanvasGraphics_beginText() {
this.current.textMatrix = IDENTITY_MATRIX;
+ this.current.textMatrixScale = 1;
this.current.x = this.current.lineX = 0;
this.current.y = this.current.lineY = 0;
},
endText: function CanvasGraphics_endText() {
- if (!('pendingTextPaths' in this)) {
- this.ctx.beginPath();
- return;
- }
var paths = this.pendingTextPaths;
var ctx = this.ctx;
+ if (paths === undefined) {
+ ctx.beginPath();
+ return;
+ }
ctx.save();
ctx.beginPath();
@@ -6250,7 +4896,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
this.current.font = fontObj;
this.current.fontSize = size;
- if (fontObj.coded) {
+ if (fontObj.isType3Font) {
return; // we don't need ctx.font for Type3 fonts
}
@@ -6288,6 +4934,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
},
setTextMatrix: function CanvasGraphics_setTextMatrix(a, b, c, d, e, f) {
this.current.textMatrix = [a, b, c, d, e, f];
+ this.current.textMatrixScale = Math.sqrt(a * a + b * b);
this.current.x = this.current.lineX = 0;
this.current.y = this.current.lineY = 0;
@@ -6295,51 +4942,13 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
nextLine: function CanvasGraphics_nextLine() {
this.moveText(0, this.current.leading);
},
- applyTextTransforms: function CanvasGraphics_applyTextTransforms() {
- var ctx = this.ctx;
- var current = this.current;
- ctx.transform.apply(ctx, current.textMatrix);
- ctx.translate(current.x, current.y + current.textRise);
- if (current.fontDirection > 0) {
- ctx.scale(current.textHScale, -1);
- } else {
- ctx.scale(-current.textHScale, 1);
- }
- },
- createTextGeometry: function CanvasGraphics_createTextGeometry() {
- var geometry = {};
- var ctx = this.ctx;
- var font = this.current.font;
- var ctxMatrix = ctx.mozCurrentTransform;
- var a = ctxMatrix[0], b = ctxMatrix[1], c = ctxMatrix[2];
- var d = ctxMatrix[3], e = ctxMatrix[4], f = ctxMatrix[5];
- var sx = (a >= 0) ?
- Math.sqrt((a * a) + (b * b)) : -Math.sqrt((a * a) + (b * b));
- var sy = (d >= 0) ?
- Math.sqrt((c * c) + (d * d)) : -Math.sqrt((c * c) + (d * d));
- var angle = Math.atan2(b, a);
- var x = e;
- var y = f;
- geometry.x = x;
- geometry.y = y;
- geometry.hScale = sx;
- geometry.vScale = sy;
- geometry.angle = angle;
- geometry.spaceWidth = font.spaceWidth;
- geometry.fontName = font.loadedName;
- geometry.fontFamily = font.fallbackName;
- geometry.fontSize = this.current.fontSize;
- geometry.ascent = font.ascent;
- geometry.descent = font.descent;
- return geometry;
- },
- paintChar: function (character, x, y) {
+ paintChar: function CanvasGraphics_paintChar(character, x, y) {
var ctx = this.ctx;
var current = this.current;
var font = current.font;
- var fontSize = current.fontSize / current.fontSizeScale;
var textRenderingMode = current.textRenderingMode;
+ var fontSize = current.fontSize / current.fontSizeScale;
var fillStrokeMode = textRenderingMode &
TextRenderingMode.FILL_STROKE_MASK;
var isAddToPathSet = !!(textRenderingMode &
@@ -6404,236 +5013,183 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
return shadow(this, 'isFontSubpixelAAEnabled', enabled);
},
- showText: function CanvasGraphics_showText(glyphs, skipTextSelection) {
- var ctx = this.ctx;
+ showText: function CanvasGraphics_showText(glyphs) {
var current = this.current;
var font = current.font;
+ if (font.isType3Font) {
+ return this.showType3Text(glyphs);
+ }
+
var fontSize = current.fontSize;
+ if (fontSize === 0) {
+ return;
+ }
+
+ var ctx = this.ctx;
var fontSizeScale = current.fontSizeScale;
var charSpacing = current.charSpacing;
var wordSpacing = current.wordSpacing;
- var textHScale = current.textHScale * current.fontDirection;
- var fontMatrix = current.fontMatrix || FONT_IDENTITY_MATRIX;
+ var fontDirection = current.fontDirection;
+ var textHScale = current.textHScale * fontDirection;
var glyphsLength = glyphs.length;
- var textLayer = this.textLayer;
- var geom;
- var textSelection = textLayer && !skipTextSelection ? true : false;
- var canvasWidth = 0.0;
var vertical = font.vertical;
var defaultVMetrics = font.defaultVMetrics;
+ var widthAdvanceScale = fontSize * current.fontMatrix[0];
- // Type3 fonts - each glyph is a "mini-PDF"
- if (font.coded) {
- ctx.save();
- ctx.transform.apply(ctx, current.textMatrix);
- ctx.translate(current.x, current.y);
-
- ctx.scale(textHScale, 1);
+ var simpleFillText =
+ current.textRenderingMode === TextRenderingMode.FILL &&
+ !font.disableFontFace;
- if (textSelection) {
- this.save();
- ctx.scale(1, -1);
- geom = this.createTextGeometry();
- this.restore();
- }
- for (var i = 0; i < glyphsLength; ++i) {
+ ctx.save();
+ ctx.transform.apply(ctx, current.textMatrix);
+ ctx.translate(current.x, current.y + current.textRise);
- var glyph = glyphs[i];
- if (glyph === null) {
- // word break
- this.ctx.translate(wordSpacing, 0);
- current.x += wordSpacing * textHScale;
- continue;
- }
+ if (fontDirection > 0) {
+ ctx.scale(textHScale, -1);
+ } else {
+ ctx.scale(textHScale, 1);
+ }
- this.processingType3 = glyph;
- this.save();
- ctx.scale(fontSize, fontSize);
- ctx.transform.apply(ctx, fontMatrix);
- this.executeOperatorList(glyph.operatorList);
- this.restore();
+ var lineWidth = current.lineWidth;
+ var scale = current.textMatrixScale;
+ if (scale === 0 || lineWidth === 0) {
+ lineWidth = this.getSinglePixelWidth();
+ } else {
+ lineWidth /= scale;
+ }
- var transformed = Util.applyTransform([glyph.width, 0], fontMatrix);
- var width = (transformed[0] * fontSize + charSpacing) *
- current.fontDirection;
+ if (fontSizeScale != 1.0) {
+ ctx.scale(fontSizeScale, fontSizeScale);
+ lineWidth /= fontSizeScale;
+ }
- ctx.translate(width, 0);
- current.x += width * textHScale;
+ ctx.lineWidth = lineWidth;
- canvasWidth += width;
+ var x = 0, i;
+ for (i = 0; i < glyphsLength; ++i) {
+ var glyph = glyphs[i];
+ if (glyph === null) {
+ // word break
+ x += fontDirection * wordSpacing;
+ continue;
+ } else if (isNum(glyph)) {
+ x += -glyph * fontSize * 0.001;
+ continue;
}
- ctx.restore();
- this.processingType3 = null;
- } else {
- ctx.save();
- this.applyTextTransforms();
- var lineWidth = current.lineWidth;
- var a1 = current.textMatrix[0], b1 = current.textMatrix[1];
- var scale = Math.sqrt(a1 * a1 + b1 * b1);
- if (scale === 0 || lineWidth === 0) {
- lineWidth = this.getSinglePixelWidth();
- } else {
- lineWidth /= scale;
- }
+ var restoreNeeded = false;
+ var character = glyph.fontChar;
+ var accent = glyph.accent;
+ var scaledX, scaledY, scaledAccentX, scaledAccentY;
+ var width = glyph.width;
+ if (vertical) {
+ var vmetric, vx, vy;
+ vmetric = glyph.vmetric || defaultVMetrics;
+ vx = glyph.vmetric ? vmetric[1] : width * 0.5;
+ vx = -vx * widthAdvanceScale;
+ vy = vmetric[2] * widthAdvanceScale;
- if (textSelection) {
- geom = this.createTextGeometry();
+ width = vmetric ? -vmetric[0] : width;
+ scaledX = vx / fontSizeScale;
+ scaledY = (x + vy) / fontSizeScale;
+ } else {
+ scaledX = x / fontSizeScale;
+ scaledY = 0;
}
- if (fontSizeScale != 1.0) {
- ctx.scale(fontSizeScale, fontSizeScale);
- lineWidth /= fontSizeScale;
+ if (font.remeasure && width > 0 && this.isFontSubpixelAAEnabled) {
+ // some standard fonts may not have the exact width, trying to
+ // rescale per character
+ var measuredWidth = ctx.measureText(character).width * 1000 /
+ fontSize * fontSizeScale;
+ var characterScaleX = width / measuredWidth;
+ restoreNeeded = true;
+ ctx.save();
+ ctx.scale(characterScaleX, 1);
+ scaledX /= characterScaleX;
}
- ctx.lineWidth = lineWidth;
-
- var x = 0;
- for (var i = 0; i < glyphsLength; ++i) {
- var glyph = glyphs[i];
- if (glyph === null) {
- // word break
- x += current.fontDirection * wordSpacing;
- continue;
- }
-
- var restoreNeeded = false;
- var character = glyph.fontChar;
- var vmetric = glyph.vmetric || defaultVMetrics;
- if (vertical) {
- var vx = glyph.vmetric ? vmetric[1] : glyph.width * 0.5;
- vx = -vx * fontSize * current.fontMatrix[0];
- var vy = vmetric[2] * fontSize * current.fontMatrix[0];
- }
- var width = vmetric ? -vmetric[0] : glyph.width;
- var charWidth = width * fontSize * current.fontMatrix[0] +
- charSpacing * current.fontDirection;
- var accent = glyph.accent;
-
- var scaledX, scaledY, scaledAccentX, scaledAccentY;
-
- if (vertical) {
- scaledX = vx / fontSizeScale;
- scaledY = (x + vy) / fontSizeScale;
- } else {
- scaledX = x / fontSizeScale;
- scaledY = 0;
- }
-
- if (font.remeasure && width > 0 && this.isFontSubpixelAAEnabled) {
- // some standard fonts may not have the exact width, trying to
- // rescale per character
- var measuredWidth = ctx.measureText(character).width * 1000 /
- current.fontSize * current.fontSizeScale;
- var characterScaleX = width / measuredWidth;
- restoreNeeded = true;
- ctx.save();
- ctx.scale(characterScaleX, 1);
- scaledX /= characterScaleX;
- if (accent) {
- scaledAccentX /= characterScaleX;
- }
- }
-
+ if (simpleFillText && !accent) {
+ // common case
+ ctx.fillText(character, scaledX, scaledY);
+ } else {
this.paintChar(character, scaledX, scaledY);
if (accent) {
scaledAccentX = scaledX + accent.offset.x / fontSizeScale;
scaledAccentY = scaledY - accent.offset.y / fontSizeScale;
this.paintChar(accent.fontChar, scaledAccentX, scaledAccentY);
}
+ }
- x += charWidth;
-
- canvasWidth += charWidth;
+ var charWidth = width * widthAdvanceScale + charSpacing * fontDirection;
+ x += charWidth;
- if (restoreNeeded) {
- ctx.restore();
- }
+ if (restoreNeeded) {
+ ctx.restore();
}
- if (vertical) {
- current.y -= x * textHScale;
- } else {
- current.x += x * textHScale;
- }
- ctx.restore();
}
-
- if (textSelection) {
- geom.canvasWidth = canvasWidth;
- if (vertical) {
- var VERTICAL_TEXT_ROTATION = Math.PI / 2;
- geom.angle += VERTICAL_TEXT_ROTATION;
- }
- this.textLayer.appendText(geom);
+ if (vertical) {
+ current.y -= x * textHScale;
+ } else {
+ current.x += x * textHScale;
}
-
- return canvasWidth;
+ ctx.restore();
},
- showSpacedText: function CanvasGraphics_showSpacedText(arr) {
+
+ showType3Text: function CanvasGraphics_showType3Text(glyphs) {
+ // Type3 fonts - each glyph is a "mini-PDF"
var ctx = this.ctx;
var current = this.current;
var font = current.font;
var fontSize = current.fontSize;
- // TJ array's number is independent from fontMatrix
- var textHScale = current.textHScale * 0.001 * current.fontDirection;
- var arrLength = arr.length;
- var textLayer = this.textLayer;
- var geom;
- var canvasWidth = 0.0;
- var textSelection = textLayer ? true : false;
- var vertical = font.vertical;
- var spacingAccumulator = 0;
+ var fontDirection = current.fontDirection;
+ var charSpacing = current.charSpacing;
+ var wordSpacing = current.wordSpacing;
+ var textHScale = current.textHScale * fontDirection;
+ var fontMatrix = current.fontMatrix || FONT_IDENTITY_MATRIX;
+ var glyphsLength = glyphs.length;
+ var i, glyph, width;
- if (textSelection) {
- ctx.save();
- this.applyTextTransforms();
- geom = this.createTextGeometry();
- ctx.restore();
+ if (fontSize === 0) {
+ return;
}
- for (var i = 0; i < arrLength; ++i) {
- var e = arr[i];
- if (isNum(e)) {
- var spacingLength = -e * fontSize * textHScale;
- if (vertical) {
- current.y += spacingLength;
- } else {
- current.x += spacingLength;
- }
+ ctx.save();
+ ctx.transform.apply(ctx, current.textMatrix);
+ ctx.translate(current.x, current.y);
- if (textSelection) {
- spacingAccumulator += spacingLength;
- }
- } else {
- var shownCanvasWidth = this.showText(e, true);
+ ctx.scale(textHScale, 1);
- if (textSelection) {
- canvasWidth += spacingAccumulator + shownCanvasWidth;
- spacingAccumulator = 0;
- }
+ for (i = 0; i < glyphsLength; ++i) {
+ glyph = glyphs[i];
+ if (glyph === null) {
+ // word break
+ this.ctx.translate(wordSpacing, 0);
+ current.x += wordSpacing * textHScale;
+ continue;
+ } else if (isNum(glyph)) {
+ var spacingLength = -glyph * 0.001 * fontSize;
+ this.ctx.translate(spacingLength, 0);
+ current.x += spacingLength * textHScale;
+ continue;
}
- }
- if (textSelection) {
- geom.canvasWidth = canvasWidth;
- if (vertical) {
- var VERTICAL_TEXT_ROTATION = Math.PI / 2;
- geom.angle += VERTICAL_TEXT_ROTATION;
- }
- this.textLayer.appendText(geom);
+ this.processingType3 = glyph;
+ this.save();
+ ctx.scale(fontSize, fontSize);
+ ctx.transform.apply(ctx, fontMatrix);
+ var operatorList = font.charProcOperatorList[glyph.operatorListId];
+ this.executeOperatorList(operatorList);
+ this.restore();
+
+ var transformed = Util.applyTransform([glyph.width, 0], fontMatrix);
+ width = ((transformed[0] * fontSize + charSpacing) * fontDirection);
+
+ ctx.translate(width, 0);
+ current.x += width * textHScale;
}
- },
- nextLineShowText: function CanvasGraphics_nextLineShowText(text) {
- this.nextLine();
- this.showText(text);
- },
- nextLineSetSpacingShowText:
- function CanvasGraphics_nextLineSetSpacingShowText(wordSpacing,
- charSpacing,
- text) {
- this.setWordSpacing(wordSpacing);
- this.setCharSpacing(charSpacing);
- this.nextLineShowText(text);
+ ctx.restore();
+ this.processingType3 = null;
},
// Type3 fonts
@@ -6655,104 +5211,30 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
},
// Color
- setStrokeColorSpace: function CanvasGraphics_setStrokeColorSpace(raw) {
- this.current.strokeColorSpace = ColorSpace.fromIR(raw);
- },
- setFillColorSpace: function CanvasGraphics_setFillColorSpace(raw) {
- this.current.fillColorSpace = ColorSpace.fromIR(raw);
- },
- setStrokeColor: function CanvasGraphics_setStrokeColor(/*...*/) {
- var cs = this.current.strokeColorSpace;
- var rgbColor = cs.getRgb(arguments, 0);
- var color = Util.makeCssRgb(rgbColor);
- this.ctx.strokeStyle = color;
- this.current.strokeColor = color;
- },
- getColorN_Pattern: function CanvasGraphics_getColorN_Pattern(IR, cs) {
+ getColorN_Pattern: function CanvasGraphics_getColorN_Pattern(IR) {
+ var pattern;
if (IR[0] == 'TilingPattern') {
- var args = IR[1];
- var base = cs.base;
- var color;
- if (base) {
- var baseComps = base.numComps;
-
- color = base.getRgb(args, 0);
- }
- var pattern = new TilingPattern(IR, color, this.ctx, this.objs,
- this.commonObjs, this.baseTransform);
+ var color = IR[1];
+ pattern = new TilingPattern(IR, color, this.ctx, this.objs,
+ this.commonObjs, this.baseTransform);
} else {
- var pattern = getShadingPatternFromIR(IR);
+ pattern = getShadingPatternFromIR(IR);
}
return pattern;
},
setStrokeColorN: function CanvasGraphics_setStrokeColorN(/*...*/) {
- var cs = this.current.strokeColorSpace;
-
- if (cs.name == 'Pattern') {
- this.current.strokeColor = this.getColorN_Pattern(arguments, cs);
- } else {
- this.setStrokeColor.apply(this, arguments);
- }
- },
- setFillColor: function CanvasGraphics_setFillColor(/*...*/) {
- var cs = this.current.fillColorSpace;
- var rgbColor = cs.getRgb(arguments, 0);
- var color = Util.makeCssRgb(rgbColor);
- this.ctx.fillStyle = color;
- this.current.fillColor = color;
+ this.current.strokeColor = this.getColorN_Pattern(arguments);
},
setFillColorN: function CanvasGraphics_setFillColorN(/*...*/) {
- var cs = this.current.fillColorSpace;
-
- if (cs.name == 'Pattern') {
- this.current.fillColor = this.getColorN_Pattern(arguments, cs);
- } else {
- this.setFillColor.apply(this, arguments);
- }
- },
- setStrokeGray: function CanvasGraphics_setStrokeGray(gray) {
- this.current.strokeColorSpace = ColorSpace.singletons.gray;
-
- var rgbColor = this.current.strokeColorSpace.getRgb(arguments, 0);
- var color = Util.makeCssRgb(rgbColor);
- this.ctx.strokeStyle = color;
- this.current.strokeColor = color;
- },
- setFillGray: function CanvasGraphics_setFillGray(gray) {
- this.current.fillColorSpace = ColorSpace.singletons.gray;
-
- var rgbColor = this.current.fillColorSpace.getRgb(arguments, 0);
- var color = Util.makeCssRgb(rgbColor);
- this.ctx.fillStyle = color;
- this.current.fillColor = color;
+ this.current.fillColor = this.getColorN_Pattern(arguments);
},
setStrokeRGBColor: function CanvasGraphics_setStrokeRGBColor(r, g, b) {
- this.current.strokeColorSpace = ColorSpace.singletons.rgb;
-
- var rgbColor = this.current.strokeColorSpace.getRgb(arguments, 0);
- var color = Util.makeCssRgb(rgbColor);
+ var color = Util.makeCssRgb(arguments);
this.ctx.strokeStyle = color;
this.current.strokeColor = color;
},
setFillRGBColor: function CanvasGraphics_setFillRGBColor(r, g, b) {
- this.current.fillColorSpace = ColorSpace.singletons.rgb;
-
- var rgbColor = this.current.fillColorSpace.getRgb(arguments, 0);
- var color = Util.makeCssRgb(rgbColor);
- this.ctx.fillStyle = color;
- this.current.fillColor = color;
- },
- setStrokeCMYKColor: function CanvasGraphics_setStrokeCMYKColor(c, m, y, k) {
- this.current.strokeColorSpace = ColorSpace.singletons.cmyk;
-
- var color = Util.makeCssCmyk(arguments);
- this.ctx.strokeStyle = color;
- this.current.strokeColor = color;
- },
- setFillCMYKColor: function CanvasGraphics_setFillCMYKColor(c, m, y, k) {
- this.current.fillColorSpace = ColorSpace.singletons.cmyk;
-
- var color = Util.makeCssCmyk(arguments);
+ var color = Util.makeCssRgb(arguments);
this.ctx.fillStyle = color;
this.current.fillColor = color;
},
@@ -6872,8 +5354,19 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
bounds = Util.intersect(bounds, canvasBounds) || [0, 0, 0, 0];
// Use ceil in case we're between sizes so we don't create canvas that is
// too small and make the canvas at least 1x1 pixels.
- var drawnWidth = Math.max(Math.ceil(bounds[2] - bounds[0]), 1);
- var drawnHeight = Math.max(Math.ceil(bounds[3] - bounds[1]), 1);
+ var offsetX = Math.floor(bounds[0]);
+ var offsetY = Math.floor(bounds[1]);
+ var drawnWidth = Math.max(Math.ceil(bounds[2]) - offsetX, 1);
+ var drawnHeight = Math.max(Math.ceil(bounds[3]) - offsetY, 1);
+ var scaleX = 1, scaleY = 1;
+ if (drawnWidth > MAX_GROUP_SIZE) {
+ scaleX = drawnWidth / MAX_GROUP_SIZE;
+ drawnWidth = MAX_GROUP_SIZE;
+ }
+ if (drawnHeight > MAX_GROUP_SIZE) {
+ scaleY = drawnHeight / MAX_GROUP_SIZE;
+ drawnHeight = MAX_GROUP_SIZE;
+ }
var cacheId = 'groupAt' + this.groupLevel;
if (group.smask) {
@@ -6886,8 +5379,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
// Since we created a new canvas that is just the size of the bounding box
// we have to translate the group ctx.
- var offsetX = bounds[0];
- var offsetY = bounds[1];
+ groupCtx.scale(1 / scaleX, 1 / scaleY);
groupCtx.translate(-offsetX, -offsetY);
groupCtx.transform.apply(groupCtx, currentTransform);
@@ -6898,15 +5390,17 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
context: groupCtx,
offsetX: offsetX,
offsetY: offsetY,
+ scaleX: scaleX,
+ scaleY: scaleY,
subtype: group.smask.subtype,
- backdrop: group.smask.backdrop,
- colorSpace: group.colorSpace && ColorSpace.fromIR(group.colorSpace)
+ backdrop: group.smask.backdrop
});
} else {
// Setup the current ctx so when the group is popped we draw it at the
// right location.
currentCtx.setTransform(1, 0, 0, 1, 0, 0);
currentCtx.translate(offsetX, offsetY);
+ currentCtx.scale(scaleX, scaleY);
}
// The transparency group inherits all off the current graphics state
// except the blend mode, soft mask, and alpha constants.
@@ -6927,7 +5421,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
this.ctx = this.groupStack.pop();
// Turn off image smoothing to avoid sub pixel interpolation which can
// look kind of blurry for some pdfs.
- if ('imageSmoothingEnabled' in this.ctx) {
+ if (this.ctx.imageSmoothingEnabled !== undefined) {
this.ctx.imageSmoothingEnabled = false;
} else {
this.ctx.mozImageSmoothingEnabled = false;
@@ -6972,7 +5466,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
paintJpegXObject: function CanvasGraphics_paintJpegXObject(objId, w, h) {
var domImage = this.objs.get(objId);
if (!domImage) {
- error('Dependent image isn\'t ready yet');
+ warn('Dependent image isn\'t ready yet');
+ return;
}
this.save();
@@ -7106,7 +5601,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
paintImageXObject: function CanvasGraphics_paintImageXObject(objId) {
var imgData = this.objs.get(objId);
if (!imgData) {
- error('Dependent image isn\'t ready yet');
+ warn('Dependent image isn\'t ready yet');
+ return;
}
this.paintInlineImageXObject(imgData);
@@ -7117,7 +5613,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
positions) {
var imgData = this.objs.get(objId);
if (!imgData) {
- error('Dependent image isn\'t ready yet');
+ warn('Dependent image isn\'t ready yet');
+ return;
}
var width = imgData.width;
@@ -7146,12 +5643,12 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
var c = currentTransform[2], d = currentTransform[3];
var heightScale = Math.max(Math.sqrt(c * c + d * d), 1);
- var imgToPaint;
+ var imgToPaint, tmpCanvas;
// instanceof HTMLElement does not work in jsdom node.js module
if (imgData instanceof HTMLElement || !imgData.data) {
imgToPaint = imgData;
} else {
- var tmpCanvas = CachedCanvases.getCanvas('inlineImage', width, height);
+ tmpCanvas = CachedCanvases.getCanvas('inlineImage', width, height);
var tmpCtx = tmpCanvas.context;
putBinaryImageData(tmpCtx, imgData);
imgToPaint = tmpCanvas.canvas;
@@ -7173,8 +5670,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
newHeight = Math.ceil(paintHeight / 2);
heightScale /= paintHeight / newHeight;
}
- var tmpCanvas = CachedCanvases.getCanvas(tmpCanvasId,
- newWidth, newHeight);
+ tmpCanvas = CachedCanvases.getCanvas(tmpCanvasId, newWidth, newHeight);
tmpCtx = tmpCanvas.context;
tmpCtx.clearRect(0, 0, newWidth, newHeight);
tmpCtx.drawImage(imgToPaint, 0, 0, paintWidth, paintHeight,
@@ -7231,6 +5727,11 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
}
},
+ paintSolidColorImageMask:
+ function CanvasGraphics_paintSolidColorImageMask() {
+ this.ctx.fillRect(0, 0, 1, 1);
+ },
+
// Marked content
markPoint: function CanvasGraphics_markPoint(tag) {
@@ -7262,26 +5763,27 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
// Helper functions
consumePath: function CanvasGraphics_consumePath() {
+ var ctx = this.ctx;
if (this.pendingClip) {
if (this.pendingClip == EO_CLIP) {
- if ('mozFillRule' in this.ctx) {
- this.ctx.mozFillRule = 'evenodd';
- this.ctx.clip();
- this.ctx.mozFillRule = 'nonzero';
+ if (ctx.mozFillRule !== undefined) {
+ ctx.mozFillRule = 'evenodd';
+ ctx.clip();
+ ctx.mozFillRule = 'nonzero';
} else {
try {
- this.ctx.clip('evenodd');
+ ctx.clip('evenodd');
} catch (ex) {
// shouldn't really happen, but browsers might think differently
- this.ctx.clip();
+ ctx.clip();
}
}
} else {
- this.ctx.clip();
+ ctx.clip();
}
this.pendingClip = null;
}
- this.ctx.beginPath();
+ ctx.beginPath();
},
getSinglePixelWidth: function CanvasGraphics_getSinglePixelWidth(scale) {
var inverse = this.ctx.mozCurrentTransformInverse;
@@ -7308,6 +5810,416 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
+var WebGLUtils = (function WebGLUtilsClosure() {
+ function loadShader(gl, code, shaderType) {
+ var shader = gl.createShader(shaderType);
+ gl.shaderSource(shader, code);
+ gl.compileShader(shader);
+ var compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
+ if (!compiled) {
+ var errorMsg = gl.getShaderInfoLog(shader);
+ throw new Error('Error during shader compilation: ' + errorMsg);
+ }
+ return shader;
+ }
+ function createVertexShader(gl, code) {
+ return loadShader(gl, code, gl.VERTEX_SHADER);
+ }
+ function createFragmentShader(gl, code) {
+ return loadShader(gl, code, gl.FRAGMENT_SHADER);
+ }
+ function createProgram(gl, shaders) {
+ var program = gl.createProgram();
+ for (var i = 0, ii = shaders.length; i < ii; ++i) {
+ gl.attachShader(program, shaders[i]);
+ }
+ gl.linkProgram(program);
+ var linked = gl.getProgramParameter(program, gl.LINK_STATUS);
+ if (!linked) {
+ var errorMsg = gl.getProgramInfoLog(program);
+ throw new Error('Error during program linking: ' + errorMsg);
+ }
+ return program;
+ }
+ function createTexture(gl, image, textureId) {
+ gl.activeTexture(textureId);
+ var texture = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+
+ // Set the parameters so we can render any size image.
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+
+ // Upload the image into the texture.
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
+ return texture;
+ }
+
+ var currentGL, currentCanvas;
+ function generageGL() {
+ if (currentGL) {
+ return;
+ }
+ currentCanvas = document.createElement('canvas');
+ currentGL = currentCanvas.getContext('webgl',
+ { premultipliedalpha: false });
+ }
+
+ var smaskVertexShaderCode = '\
+ attribute vec2 a_position; \
+ attribute vec2 a_texCoord; \
+ \
+ uniform vec2 u_resolution; \
+ \
+ varying vec2 v_texCoord; \
+ \
+ void main() { \
+ vec2 clipSpace = (a_position / u_resolution) * 2.0 - 1.0; \
+ gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1); \
+ \
+ v_texCoord = a_texCoord; \
+ } ';
+
+ var smaskFragmentShaderCode = '\
+ precision mediump float; \
+ \
+ uniform vec4 u_backdrop; \
+ uniform int u_subtype; \
+ uniform sampler2D u_image; \
+ uniform sampler2D u_mask; \
+ \
+ varying vec2 v_texCoord; \
+ \
+ void main() { \
+ vec4 imageColor = texture2D(u_image, v_texCoord); \
+ vec4 maskColor = texture2D(u_mask, v_texCoord); \
+ if (u_backdrop.a > 0.0) { \
+ maskColor.rgb = maskColor.rgb * maskColor.a + \
+ u_backdrop.rgb * (1.0 - maskColor.a); \
+ } \
+ float lum; \
+ if (u_subtype == 0) { \
+ lum = maskColor.a; \
+ } else { \
+ lum = maskColor.r * 0.3 + maskColor.g * 0.59 + \
+ maskColor.b * 0.11; \
+ } \
+ imageColor.a *= lum; \
+ imageColor.rgb *= imageColor.a; \
+ gl_FragColor = imageColor; \
+ } ';
+
+ var smaskCache = null;
+
+ function initSmaskGL() {
+ var canvas, gl;
+
+ generageGL();
+ canvas = currentCanvas;
+ currentCanvas = null;
+ gl = currentGL;
+ currentGL = null;
+
+ // setup a GLSL program
+ var vertexShader = createVertexShader(gl, smaskVertexShaderCode);
+ var fragmentShader = createFragmentShader(gl, smaskFragmentShaderCode);
+ var program = createProgram(gl, [vertexShader, fragmentShader]);
+ gl.useProgram(program);
+
+ var cache = {};
+ cache.gl = gl;
+ cache.canvas = canvas;
+ cache.resolutionLocation = gl.getUniformLocation(program, 'u_resolution');
+ cache.positionLocation = gl.getAttribLocation(program, 'a_position');
+ cache.backdropLocation = gl.getUniformLocation(program, 'u_backdrop');
+ cache.subtypeLocation = gl.getUniformLocation(program, 'u_subtype');
+
+ var texCoordLocation = gl.getAttribLocation(program, 'a_texCoord');
+ var texLayerLocation = gl.getUniformLocation(program, 'u_image');
+ var texMaskLocation = gl.getUniformLocation(program, 'u_mask');
+
+ // provide texture coordinates for the rectangle.
+ var texCoordBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
+ 0.0, 0.0,
+ 1.0, 0.0,
+ 0.0, 1.0,
+ 0.0, 1.0,
+ 1.0, 0.0,
+ 1.0, 1.0]), gl.STATIC_DRAW);
+ gl.enableVertexAttribArray(texCoordLocation);
+ gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 0, 0);
+
+ gl.uniform1i(texLayerLocation, 0);
+ gl.uniform1i(texMaskLocation, 1);
+
+ smaskCache = cache;
+ }
+
+ function composeSMask(layer, mask, properties) {
+ var width = layer.width, height = layer.height;
+
+ if (!smaskCache) {
+ initSmaskGL();
+ }
+ var cache = smaskCache,canvas = cache.canvas, gl = cache.gl;
+ canvas.width = width;
+ canvas.height = height;
+ gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
+ gl.uniform2f(cache.resolutionLocation, width, height);
+
+ if (properties.backdrop) {
+ gl.uniform4f(cache.resolutionLocation, properties.backdrop[0],
+ properties.backdrop[1], properties.backdrop[2], 1);
+ } else {
+ gl.uniform4f(cache.resolutionLocation, 0, 0, 0, 0);
+ }
+ gl.uniform1i(cache.subtypeLocation,
+ properties.subtype === 'Luminosity' ? 1 : 0);
+
+ // Create a textures
+ var texture = createTexture(gl, layer, gl.TEXTURE0);
+ var maskTexture = createTexture(gl, mask, gl.TEXTURE1);
+
+
+ // Create a buffer and put a single clipspace rectangle in
+ // it (2 triangles)
+ var buffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
+ 0, 0,
+ width, 0,
+ 0, height,
+ 0, height,
+ width, 0,
+ width, height]), gl.STATIC_DRAW);
+ gl.enableVertexAttribArray(cache.positionLocation);
+ gl.vertexAttribPointer(cache.positionLocation, 2, gl.FLOAT, false, 0, 0);
+
+ // draw
+ gl.clearColor(0, 0, 0, 0);
+ gl.enable(gl.BLEND);
+ gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
+
+ gl.flush();
+
+ gl.deleteTexture(texture);
+ gl.deleteTexture(maskTexture);
+ gl.deleteBuffer(buffer);
+
+ return canvas;
+ }
+
+ var figuresVertexShaderCode = '\
+ attribute vec2 a_position; \
+ attribute vec3 a_color; \
+ \
+ uniform vec2 u_resolution; \
+ uniform vec2 u_scale; \
+ uniform vec2 u_offset; \
+ \
+ varying vec4 v_color; \
+ \
+ void main() { \
+ vec2 position = (a_position + u_offset) * u_scale; \
+ vec2 clipSpace = (position / u_resolution) * 2.0 - 1.0; \
+ gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1); \
+ \
+ v_color = vec4(a_color / 255.0, 1.0); \
+ } ';
+
+ var figuresFragmentShaderCode = '\
+ precision mediump float; \
+ \
+ varying vec4 v_color; \
+ \
+ void main() { \
+ gl_FragColor = v_color; \
+ } ';
+
+ var figuresCache = null;
+
+ function initFiguresGL() {
+ var canvas, gl;
+
+ generageGL();
+ canvas = currentCanvas;
+ currentCanvas = null;
+ gl = currentGL;
+ currentGL = null;
+
+ // setup a GLSL program
+ var vertexShader = createVertexShader(gl, figuresVertexShaderCode);
+ var fragmentShader = createFragmentShader(gl, figuresFragmentShaderCode);
+ var program = createProgram(gl, [vertexShader, fragmentShader]);
+ gl.useProgram(program);
+
+ var cache = {};
+ cache.gl = gl;
+ cache.canvas = canvas;
+ cache.resolutionLocation = gl.getUniformLocation(program, 'u_resolution');
+ cache.scaleLocation = gl.getUniformLocation(program, 'u_scale');
+ cache.offsetLocation = gl.getUniformLocation(program, 'u_offset');
+ cache.positionLocation = gl.getAttribLocation(program, 'a_position');
+ cache.colorLocation = gl.getAttribLocation(program, 'a_color');
+
+ figuresCache = cache;
+ }
+
+ function drawFigures(width, height, backgroundColor, figures, context) {
+ if (!figuresCache) {
+ initFiguresGL();
+ }
+ var cache = figuresCache, canvas = cache.canvas, gl = cache.gl;
+
+ canvas.width = width;
+ canvas.height = height;
+ gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
+ gl.uniform2f(cache.resolutionLocation, width, height);
+
+ // count triangle points
+ var count = 0;
+ var i, ii, rows;
+ for (i = 0, ii = figures.length; i < ii; i++) {
+ switch (figures[i].type) {
+ case 'lattice':
+ rows = (figures[i].coords.length / figures[i].verticesPerRow) | 0;
+ count += (rows - 1) * (figures[i].verticesPerRow - 1) * 6;
+ break;
+ case 'triangles':
+ count += figures[i].coords.length;
+ break;
+ }
+ }
+ // transfer data
+ var coords = new Float32Array(count * 2);
+ var colors = new Uint8Array(count * 3);
+ var coordsMap = context.coords, colorsMap = context.colors;
+ var pIndex = 0, cIndex = 0;
+ for (i = 0, ii = figures.length; i < ii; i++) {
+ var figure = figures[i], ps = figure.coords, cs = figure.colors;
+ switch (figure.type) {
+ case 'lattice':
+ var cols = figure.verticesPerRow;
+ rows = (ps.length / cols) | 0;
+ for (var row = 1; row < rows; row++) {
+ var offset = row * cols + 1;
+ for (var col = 1; col < cols; col++, offset++) {
+ coords[pIndex] = coordsMap[ps[offset - cols - 1]];
+ coords[pIndex + 1] = coordsMap[ps[offset - cols - 1] + 1];
+ coords[pIndex + 2] = coordsMap[ps[offset - cols]];
+ coords[pIndex + 3] = coordsMap[ps[offset - cols] + 1];
+ coords[pIndex + 4] = coordsMap[ps[offset - 1]];
+ coords[pIndex + 5] = coordsMap[ps[offset - 1] + 1];
+ colors[cIndex] = colorsMap[cs[offset - cols - 1]];
+ colors[cIndex + 1] = colorsMap[cs[offset - cols - 1] + 1];
+ colors[cIndex + 2] = colorsMap[cs[offset - cols - 1] + 2];
+ colors[cIndex + 3] = colorsMap[cs[offset - cols]];
+ colors[cIndex + 4] = colorsMap[cs[offset - cols] + 1];
+ colors[cIndex + 5] = colorsMap[cs[offset - cols] + 2];
+ colors[cIndex + 6] = colorsMap[cs[offset - 1]];
+ colors[cIndex + 7] = colorsMap[cs[offset - 1] + 1];
+ colors[cIndex + 8] = colorsMap[cs[offset - 1] + 2];
+
+ coords[pIndex + 6] = coords[pIndex + 2];
+ coords[pIndex + 7] = coords[pIndex + 3];
+ coords[pIndex + 8] = coords[pIndex + 4];
+ coords[pIndex + 9] = coords[pIndex + 5];
+ coords[pIndex + 10] = coordsMap[ps[offset]];
+ coords[pIndex + 11] = coordsMap[ps[offset] + 1];
+ colors[cIndex + 9] = colors[cIndex + 3];
+ colors[cIndex + 10] = colors[cIndex + 4];
+ colors[cIndex + 11] = colors[cIndex + 5];
+ colors[cIndex + 12] = colors[cIndex + 6];
+ colors[cIndex + 13] = colors[cIndex + 7];
+ colors[cIndex + 14] = colors[cIndex + 8];
+ colors[cIndex + 15] = colorsMap[cs[offset]];
+ colors[cIndex + 16] = colorsMap[cs[offset] + 1];
+ colors[cIndex + 17] = colorsMap[cs[offset] + 2];
+ pIndex += 12;
+ cIndex += 18;
+ }
+ }
+ break;
+ case 'triangles':
+ for (var j = 0, jj = ps.length; j < jj; j++) {
+ coords[pIndex] = coordsMap[ps[j]];
+ coords[pIndex + 1] = coordsMap[ps[j] + 1];
+ colors[cIndex] = colorsMap[cs[i]];
+ colors[cIndex + 1] = colorsMap[cs[j] + 1];
+ colors[cIndex + 2] = colorsMap[cs[j] + 2];
+ pIndex += 2;
+ cIndex += 3;
+ }
+ break;
+ }
+ }
+
+ // draw
+ if (backgroundColor) {
+ gl.clearColor(backgroundColor[0] / 255, backgroundColor[1] / 255,
+ backgroundColor[2] / 255, 1.0);
+ } else {
+ gl.clearColor(0, 0, 0, 0);
+ }
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ var coordsBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, coordsBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, coords, gl.STATIC_DRAW);
+ gl.enableVertexAttribArray(cache.positionLocation);
+ gl.vertexAttribPointer(cache.positionLocation, 2, gl.FLOAT, false, 0, 0);
+
+ var colorsBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, colorsBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW);
+ gl.enableVertexAttribArray(cache.colorLocation);
+ gl.vertexAttribPointer(cache.colorLocation, 3, gl.UNSIGNED_BYTE, false,
+ 0, 0);
+
+ gl.uniform2f(cache.scaleLocation, context.scaleX, context.scaleY);
+ gl.uniform2f(cache.offsetLocation, context.offsetX, context.offsetY);
+
+ gl.drawArrays(gl.TRIANGLES, 0, count);
+
+ gl.flush();
+
+ gl.deleteBuffer(coordsBuffer);
+ gl.deleteBuffer(colorsBuffer);
+
+ return canvas;
+ }
+
+ function cleanup() {
+ smaskCache = null;
+ figuresCache = null;
+ }
+
+ return {
+ get isEnabled() {
+ if (PDFJS.disableWebGL) {
+ return false;
+ }
+ var enabled = false;
+ try {
+ generageGL();
+ enabled = !!currentGL;
+ } catch (e) { }
+ return shadow(this, 'isEnabled', enabled);
+ },
+ composeSMask: composeSMask,
+ drawFigures: drawFigures,
+ clear: cleanup
+ };
+})();
+
+
var ShadingIRs = {};
ShadingIRs.RadialAxial = {
@@ -7344,28 +6256,27 @@ var createMeshCanvas = (function createMeshCanvasClosure() {
var coords = context.coords, colors = context.colors;
var bytes = data.data, rowSize = data.width * 4;
var tmp;
- if (coords[p1 * 2 + 1] > coords[p2 * 2 + 1]) {
+ if (coords[p1 + 1] > coords[p2 + 1]) {
tmp = p1; p1 = p2; p2 = tmp; tmp = c1; c1 = c2; c2 = tmp;
}
- if (coords[p2 * 2 + 1] > coords[p3 * 2 + 1]) {
+ if (coords[p2 + 1] > coords[p3 + 1]) {
tmp = p2; p2 = p3; p3 = tmp; tmp = c2; c2 = c3; c3 = tmp;
}
- if (coords[p1 * 2 + 1] > coords[p2 * 2 + 1]) {
+ if (coords[p1 + 1] > coords[p2 + 1]) {
tmp = p1; p1 = p2; p2 = tmp; tmp = c1; c1 = c2; c2 = tmp;
}
- var x1 = (coords[p1 * 2] + context.offsetX) * context.scaleX;
- var y1 = (coords[p1 * 2 + 1] + context.offsetY) * context.scaleY;
- var x2 = (coords[p2 * 2] + context.offsetX) * context.scaleX;
- var y2 = (coords[p2 * 2 + 1] + context.offsetY) * context.scaleY;
- var x3 = (coords[p3 * 2] + context.offsetX) * context.scaleX;
- var y3 = (coords[p3 * 2 + 1] + context.offsetY) * context.scaleY;
+ var x1 = (coords[p1] + context.offsetX) * context.scaleX;
+ var y1 = (coords[p1 + 1] + context.offsetY) * context.scaleY;
+ var x2 = (coords[p2] + context.offsetX) * context.scaleX;
+ var y2 = (coords[p2 + 1] + context.offsetY) * context.scaleY;
+ var x3 = (coords[p3] + context.offsetX) * context.scaleX;
+ var y3 = (coords[p3 + 1] + context.offsetY) * context.scaleY;
if (y1 >= y3) {
return;
}
- var c1i = c1 * 3, c2i = c2 * 3, c3i = c3 * 3;
- var c1r = colors[c1i], c1g = colors[c1i + 1], c1b = colors[c1i + 2];
- var c2r = colors[c2i], c2g = colors[c2i + 1], c2b = colors[c2i + 2];
- var c3r = colors[c3i], c3g = colors[c3i + 1], c3b = colors[c3i + 2];
+ var c1r = colors[c1], c1g = colors[c1 + 1], c1b = colors[c1 + 2];
+ var c2r = colors[c2], c2g = colors[c2 + 1], c2b = colors[c2 + 2];
+ var c3r = colors[c3], c3g = colors[c3 + 1], c3b = colors[c3 + 2];
var minY = Math.round(y1), maxY = Math.round(y3);
var xa, car, cag, cab;
@@ -7407,12 +6318,13 @@ var createMeshCanvas = (function createMeshCanvasClosure() {
function drawFigure(data, figure, context) {
var ps = figure.coords;
var cs = figure.colors;
+ var i, ii;
switch (figure.type) {
case 'lattice':
var verticesPerRow = figure.verticesPerRow;
var rows = Math.floor(ps.length / verticesPerRow) - 1;
var cols = verticesPerRow - 1;
- for (var i = 0; i < rows; i++) {
+ for (i = 0; i < rows; i++) {
var q = i * verticesPerRow;
for (var j = 0; j < cols; j++, q++) {
drawTriangle(data, context,
@@ -7425,7 +6337,7 @@ var createMeshCanvas = (function createMeshCanvasClosure() {
}
break;
case 'triangles':
- for (var i = 0, ii = ps.length; i < ii; i += 3) {
+ for (i = 0, ii = ps.length; i < ii; i += 3) {
drawTriangle(data, context,
ps[i], ps[i + 1], ps[i + 2],
cs[i], cs[i + 1], cs[i + 2]);
@@ -7445,52 +6357,72 @@ var createMeshCanvas = (function createMeshCanvasClosure() {
// MAX_PATTERN_SIZE is used to avoid OOM situation.
var MAX_PATTERN_SIZE = 3000; // 10in @ 300dpi shall be enough
- var boundsWidth = bounds[2] - bounds[0];
- var boundsHeight = bounds[3] - bounds[1];
+ var offsetX = Math.floor(bounds[0]);
+ var offsetY = Math.floor(bounds[1]);
+ var boundsWidth = Math.ceil(bounds[2]) - offsetX;
+ var boundsHeight = Math.ceil(bounds[3]) - offsetY;
var width = Math.min(Math.ceil(Math.abs(boundsWidth * combinesScale[0] *
EXPECTED_SCALE)), MAX_PATTERN_SIZE);
var height = Math.min(Math.ceil(Math.abs(boundsHeight * combinesScale[1] *
EXPECTED_SCALE)), MAX_PATTERN_SIZE);
- var scaleX = width / boundsWidth;
- var scaleY = height / boundsHeight;
-
- var tmpCanvas = CachedCanvases.getCanvas('mesh', width, height, false);
- var tmpCtx = tmpCanvas.context;
- if (backgroundColor) {
- tmpCtx.fillStyle = makeCssRgb(backgroundColor);
- tmpCtx.fillRect(0, 0, width, height);
- }
+ var scaleX = boundsWidth / width;
+ var scaleY = boundsHeight / height;
var context = {
coords: coords,
colors: colors,
- offsetX: -bounds[0],
- offsetY: -bounds[1],
- scaleX: scaleX,
- scaleY: scaleY
+ offsetX: -offsetX,
+ offsetY: -offsetY,
+ scaleX: 1 / scaleX,
+ scaleY: 1 / scaleY
};
- var data = tmpCtx.getImageData(0, 0, width, height);
- for (var i = 0; i < figures.length; i++) {
- drawFigure(data, figures[i], context);
+ var canvas, tmpCanvas, i, ii;
+ if (WebGLUtils.isEnabled) {
+ canvas = WebGLUtils.drawFigures(width, height, backgroundColor,
+ figures, context);
+
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=972126
+ tmpCanvas = CachedCanvases.getCanvas('mesh', width, height, false);
+ tmpCanvas.context.drawImage(canvas, 0, 0);
+ canvas = tmpCanvas.canvas;
+ } else {
+ tmpCanvas = CachedCanvases.getCanvas('mesh', width, height, false);
+ var tmpCtx = tmpCanvas.context;
+
+ var data = tmpCtx.createImageData(width, height);
+ if (backgroundColor) {
+ var bytes = data.data;
+ for (i = 0, ii = bytes.length; i < ii; i += 4) {
+ bytes[i] = backgroundColor[0];
+ bytes[i + 1] = backgroundColor[1];
+ bytes[i + 2] = backgroundColor[2];
+ bytes[i + 3] = 255;
+ }
+ }
+ for (i = 0; i < figures.length; i++) {
+ drawFigure(data, figures[i], context);
+ }
+ tmpCtx.putImageData(data, 0, 0);
+ canvas = tmpCanvas.canvas;
}
- tmpCtx.putImageData(data, 0, 0);
- return {canvas: tmpCanvas.canvas, scaleX: 1 / scaleX, scaleY: 1 / scaleY};
+ return {canvas: canvas, offsetX: offsetX, offsetY: offsetY,
+ scaleX: scaleX, scaleY: scaleY};
}
return createMeshCanvas;
})();
ShadingIRs.Mesh = {
fromIR: function Mesh_fromIR(raw) {
- var type = raw[1];
+ //var type = raw[1];
var coords = raw[2];
var colors = raw[3];
var figures = raw[4];
var bounds = raw[5];
var matrix = raw[6];
- var bbox = raw[7];
+ //var bbox = raw[7];
var background = raw[8];
return {
type: 'Pattern',
@@ -7511,7 +6443,6 @@ ShadingIRs.Mesh = {
// Rasterizing on the main thread since sending/queue large canvases
// might cause OOM.
- // TODO consider using WebGL or asm.js to perform rasterization
var temporaryPatternCanvas = createMeshCanvas(bounds, combinedScale,
coords, colors, figures, shadingFill ? null : background);
@@ -7522,7 +6453,8 @@ ShadingIRs.Mesh = {
}
}
- ctx.translate(bounds[0], bounds[1]);
+ ctx.translate(temporaryPatternCanvas.offsetX,
+ temporaryPatternCanvas.offsetY);
ctx.scale(temporaryPatternCanvas.scaleX,
temporaryPatternCanvas.scaleY);
@@ -7560,7 +6492,6 @@ var TilingPattern = (function TilingPatternClosure() {
var MAX_PATTERN_SIZE = 3000; // 10in @ 300dpi shall be enough
function TilingPattern(IR, color, ctx, objs, commonObjs, baseTransform) {
- this.name = IR[1][0].name;
this.operatorList = IR[2];
this.matrix = IR[3] || [1, 0, 0, 1, 0, 0];
this.bbox = IR[4];
@@ -7587,7 +6518,6 @@ var TilingPattern = (function TilingPatternClosure() {
var color = this.color;
var objs = this.objs;
var commonObjs = this.commonObjs;
- var ctx = this.ctx;
info('TilingType: ' + tilingType);
@@ -7671,8 +6601,7 @@ var TilingPattern = (function TilingPatternClosure() {
context.strokeStyle = ctx.strokeStyle;
break;
case PaintType.UNCOLORED:
- var rgbColor = ColorSpace.singletons.rgb.getRgb(color, 0);
- var cssColor = Util.makeCssRgb(rgbColor);
+ var cssColor = Util.makeCssRgb(color);
context.fillStyle = cssColor;
context.strokeStyle = cssColor;
break;
@@ -7684,7 +6613,7 @@ var TilingPattern = (function TilingPatternClosure() {
getPattern: function TilingPattern_getPattern(ctx, owner) {
var temporaryPatternCanvas = this.createPatternCanvas(owner);
- var ctx = this.ctx;
+ ctx = this.ctx;
ctx.setTransform.apply(ctx, this.baseTransform);
ctx.transform.apply(ctx, this.matrix);
this.scaleToContext();
@@ -7841,16 +6770,9 @@ var FontLoader = {
(data.charCodeAt(offset + 3) & 0xff);
}
- function string32(value) {
- return String.fromCharCode((value >> 24) & 0xff) +
- String.fromCharCode((value >> 16) & 0xff) +
- String.fromCharCode((value >> 8) & 0xff) +
- String.fromCharCode(value & 0xff);
- }
-
function spliceString(s, offset, remove, insert) {
- var chunk1 = data.substr(0, offset);
- var chunk2 = data.substr(offset + remove);
+ var chunk1 = s.substr(0, offset);
+ var chunk2 = s.substr(offset + remove);
return chunk1 + insert + chunk2;
}
@@ -7958,7 +6880,7 @@ var FontFace = (function FontFaceClosure() {
return null;
}
- var data = bytesToString(this.data);
+ var data = bytesToString(new Uint8Array(this.data));
var fontName = this.loadedName;
// Add the font-face rule to the document
diff --git a/js/pdf.worker.js b/js/pdf.worker.js
index 23c1805..a7145d7 100644
--- a/js/pdf.worker.js
+++ b/js/pdf.worker.js
@@ -21,8 +21,8 @@ if (typeof PDFJS === 'undefined') {
(typeof window !== 'undefined' ? window : this).PDFJS = {};
}
-PDFJS.version = '0.8.1239';
-PDFJS.build = '1a6e103';
+PDFJS.version = '1.0.276';
+PDFJS.build = 'a09aecb';
(function pdfjsWrapper() {
// Use strict in our context only - users might not want it
@@ -181,7 +181,9 @@ var OPS = PDFJS.OPS = {
paintInlineImageXObject: 86,
paintInlineImageXObjectGroup: 87,
paintImageXObjectRepeat: 88,
- paintImageMaskXObjectRepeat: 89
+ paintImageMaskXObjectRepeat: 89,
+ paintSolidColorImageMask: 90,
+ constructPath: 91
};
// A notice for devs. These are good for things that are helpful to devs, such
@@ -266,9 +268,10 @@ function combineUrl(baseUrl, url) {
if (/^[a-z][a-z0-9+\-.]*:/i.test(url)) {
return url;
}
+ var i;
if (url.charAt(0) == '/') {
// absolute path
- var i = baseUrl.indexOf('://');
+ i = baseUrl.indexOf('://');
if (url.charAt(1) === '/') {
++i;
} else {
@@ -277,7 +280,7 @@ function combineUrl(baseUrl, url) {
return baseUrl.substring(0, i) + url;
} else {
// relative path
- var pathLength = baseUrl.length, i;
+ var pathLength = baseUrl.length;
i = baseUrl.lastIndexOf('#');
pathLength = i >= 0 ? i : pathLength;
i = baseUrl.lastIndexOf('?', pathLength);
@@ -311,14 +314,6 @@ function isValidUrl(url, allowRelative) {
}
PDFJS.isValidUrl = isValidUrl;
-// In a well-formed PDF, |cond| holds. If it doesn't, subsequent
-// behavior is undefined.
-function assertWellFormed(cond, msg) {
- if (!cond) {
- error(msg);
- }
-}
-
function shadow(obj, prop, value) {
Object.defineProperty(obj, prop, { value: value,
enumerable: true,
@@ -422,23 +417,137 @@ var XRefParseException = (function XRefParseExceptionClosure() {
function bytesToString(bytes) {
- var strBuf = [];
var length = bytes.length;
- for (var n = 0; n < length; ++n) {
- strBuf.push(String.fromCharCode(bytes[n]));
+ var MAX_ARGUMENT_COUNT = 8192;
+ if (length < MAX_ARGUMENT_COUNT) {
+ return String.fromCharCode.apply(null, bytes);
+ }
+ var strBuf = [];
+ for (var i = 0; i < length; i += MAX_ARGUMENT_COUNT) {
+ var chunkEnd = Math.min(i + MAX_ARGUMENT_COUNT, length);
+ var chunk = bytes.subarray(i, chunkEnd);
+ strBuf.push(String.fromCharCode.apply(null, chunk));
}
return strBuf.join('');
}
+function stringToArray(str) {
+ var length = str.length;
+ var array = [];
+ for (var i = 0; i < length; ++i) {
+ array[i] = str.charCodeAt(i);
+ }
+ return array;
+}
+
function stringToBytes(str) {
var length = str.length;
var bytes = new Uint8Array(length);
- for (var n = 0; n < length; ++n) {
- bytes[n] = str.charCodeAt(n) & 0xFF;
+ for (var i = 0; i < length; ++i) {
+ bytes[i] = str.charCodeAt(i) & 0xFF;
}
return bytes;
}
+function string32(value) {
+ return String.fromCharCode((value >> 24) & 0xff, (value >> 16) & 0xff,
+ (value >> 8) & 0xff, value & 0xff);
+}
+
+function log2(x) {
+ var n = 1, i = 0;
+ while (x > n) {
+ n <<= 1;
+ i++;
+ }
+ return i;
+}
+
+function readInt8(data, start) {
+ return (data[start] << 24) >> 24;
+}
+
+function readUint16(data, offset) {
+ return (data[offset] << 8) | data[offset + 1];
+}
+
+function readUint32(data, offset) {
+ return ((data[offset] << 24) | (data[offset + 1] << 16) |
+ (data[offset + 2] << 8) | data[offset + 3]) >>> 0;
+}
+
+// Lazy test the endianness of the platform
+// NOTE: This will be 'true' for simulated TypedArrays
+function isLittleEndian() {
+ var buffer8 = new Uint8Array(2);
+ buffer8[0] = 1;
+ var buffer16 = new Uint16Array(buffer8.buffer);
+ return (buffer16[0] === 1);
+}
+
+Object.defineProperty(PDFJS, 'isLittleEndian', {
+ configurable: true,
+ get: function PDFJS_isLittleEndian() {
+ return shadow(PDFJS, 'isLittleEndian', isLittleEndian());
+ }
+});
+
+ // Lazy test if the userAgant support CanvasTypedArrays
+function hasCanvasTypedArrays() {
+ var canvas = document.createElement('canvas');
+ canvas.width = canvas.height = 1;
+ var ctx = canvas.getContext('2d');
+ var imageData = ctx.createImageData(1, 1);
+ return (typeof imageData.data.buffer !== 'undefined');
+}
+
+Object.defineProperty(PDFJS, 'hasCanvasTypedArrays', {
+ configurable: true,
+ get: function PDFJS_hasCanvasTypedArrays() {
+ return shadow(PDFJS, 'hasCanvasTypedArrays', hasCanvasTypedArrays());
+ }
+});
+
+var Uint32ArrayView = (function Uint32ArrayViewClosure() {
+
+ function Uint32ArrayView(buffer, length) {
+ this.buffer = buffer;
+ this.byteLength = buffer.length;
+ this.length = length === undefined ? (this.byteLength >> 2) : length;
+ ensureUint32ArrayViewProps(this.length);
+ }
+ Uint32ArrayView.prototype = Object.create(null);
+
+ var uint32ArrayViewSetters = 0;
+ function createUint32ArrayProp(index) {
+ return {
+ get: function () {
+ var buffer = this.buffer, offset = index << 2;
+ return (buffer[offset] | (buffer[offset + 1] << 8) |
+ (buffer[offset + 2] << 16) | (buffer[offset + 3] << 24)) >>> 0;
+ },
+ set: function (value) {
+ var buffer = this.buffer, offset = index << 2;
+ buffer[offset] = value & 255;
+ buffer[offset + 1] = (value >> 8) & 255;
+ buffer[offset + 2] = (value >> 16) & 255;
+ buffer[offset + 3] = (value >>> 24) & 255;
+ }
+ };
+ }
+
+ function ensureUint32ArrayViewProps(length) {
+ while (uint32ArrayViewSetters < length) {
+ Object.defineProperty(Uint32ArrayView.prototype,
+ uint32ArrayViewSetters,
+ createUint32ArrayProp(uint32ArrayViewSetters));
+ uint32ArrayViewSetters++;
+ }
+ }
+
+ return Uint32ArrayView;
+})();
+
var IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0];
var Util = PDFJS.Util = (function UtilClosure() {
@@ -448,11 +557,6 @@ var Util = PDFJS.Util = (function UtilClosure() {
return 'rgb(' + rgb[0] + ',' + rgb[1] + ',' + rgb[2] + ')';
};
- Util.makeCssCmyk = function Util_makeCssCmyk(cmyk) {
- var rgb = ColorSpace.singletons.cmyk.getRgb(cmyk, 0);
- return Util.makeCssRgb(rgb);
- };
-
// Concatenates two transformation matrices together and returns the result.
Util.transform = function Util_transform(m1, m2) {
return [
@@ -652,7 +756,22 @@ var Util = PDFJS.Util = (function UtilClosure() {
return Util;
})();
+/**
+ * PDF page viewport created based on scale, rotation and offset.
+ * @class
+ * @alias PDFJS.PageViewport
+ */
var PageViewport = PDFJS.PageViewport = (function PageViewportClosure() {
+ /**
+ * @constructor
+ * @private
+ * @param viewBox {Array} xMin, yMin, xMax and yMax coordinates.
+ * @param scale {number} scale of the viewport.
+ * @param rotation {number} rotations of the viewport in degrees.
+ * @param offsetX {number} offset X
+ * @param offsetY {number} offset Y
+ * @param dontFlip {boolean} if true, axis Y will not be flipped.
+ */
function PageViewport(viewBox, scale, rotation, offsetX, offsetY, dontFlip) {
this.viewBox = viewBox;
this.scale = scale;
@@ -716,7 +835,14 @@ var PageViewport = PDFJS.PageViewport = (function PageViewportClosure() {
this.height = height;
this.fontScale = scale;
}
- PageViewport.prototype = {
+ PageViewport.prototype = /** @lends PDFJS.PageViewport.prototype */ {
+ /**
+ * Clones viewport with additional properties.
+ * @param args {Object} (optional) If specified, may contain the 'scale' or
+ * 'rotation' properties to override the corresponding properties in
+ * the cloned viewport.
+ * @returns {PDFJS.PageViewport} Cloned viewport.
+ */
clone: function PageViewPort_clone(args) {
args = args || {};
var scale = 'scale' in args ? args.scale : this.scale;
@@ -724,15 +850,41 @@ var PageViewport = PDFJS.PageViewport = (function PageViewportClosure() {
return new PageViewport(this.viewBox.slice(), scale, rotation,
this.offsetX, this.offsetY, args.dontFlip);
},
+ /**
+ * Converts PDF point to the viewport coordinates. For examples, useful for
+ * converting PDF location into canvas pixel coordinates.
+ * @param x {number} X coordinate.
+ * @param y {number} Y coordinate.
+ * @returns {Object} Object that contains 'x' and 'y' properties of the
+ * point in the viewport coordinate space.
+ * @see {@link convertToPdfPoint}
+ * @see {@link convertToViewportRectangle}
+ */
convertToViewportPoint: function PageViewport_convertToViewportPoint(x, y) {
return Util.applyTransform([x, y], this.transform);
},
+ /**
+ * Converts PDF rectangle to the viewport coordinates.
+ * @param rect {Array} xMin, yMin, xMax and yMax coordinates.
+ * @returns {Array} Contains corresponding coordinates of the rectangle
+ * in the viewport coordinate space.
+ * @see {@link convertToViewportPoint}
+ */
convertToViewportRectangle:
function PageViewport_convertToViewportRectangle(rect) {
var tl = Util.applyTransform([rect[0], rect[1]], this.transform);
var br = Util.applyTransform([rect[2], rect[3]], this.transform);
return [tl[0], tl[1], br[0], br[1]];
},
+ /**
+ * Converts viewport coordinates to the PDF location. For examples, useful
+ * for converting canvas pixel location into PDF one.
+ * @param x {number} X coordinate.
+ * @param y {number} Y coordinate.
+ * @returns {Object} Object that contains 'x' and 'y' properties of the
+ * point in the PDF coordinate space.
+ * @see {@link convertToViewportPoint}
+ */
convertToPdfPoint: function PageViewport_convertToPdfPoint(x, y) {
return Util.applyInverseTransform([x, y], this.transform);
}
@@ -837,40 +989,36 @@ function isRef(v) {
return v instanceof Ref;
}
-function isPDFFunction(v) {
- var fnDict;
- if (typeof v != 'object') {
- return false;
- } else if (isDict(v)) {
- fnDict = v;
- } else if (isStream(v)) {
- fnDict = v.dict;
- } else {
- return false;
- }
- return fnDict.has('FunctionType');
-}
+/**
+ * Promise Capability object.
+ *
+ * @typedef {Object} PromiseCapability
+ * @property {Promise} promise - A promise object.
+ * @property {function} resolve - Fullfills the promise.
+ * @property {function} reject - Rejects the promise.
+ */
/**
- * Legacy support for PDFJS Promise implementation.
- * TODO remove eventually
+ * Creates a promise capability object.
+ * @alias PDFJS.createPromiseCapability
+ *
+ * @return {PromiseCapability} A capability object contains:
+ * - a Promise, resolve and reject methods.
*/
-var LegacyPromise = PDFJS.LegacyPromise = (function LegacyPromiseClosure() {
- return function LegacyPromise() {
- var resolve, reject;
- var promise = new Promise(function (resolve_, reject_) {
- resolve = resolve_;
- reject = reject_;
- });
- promise.resolve = resolve;
- promise.reject = reject;
- return promise;
- };
-})();
+function createPromiseCapability() {
+ var capability = {};
+ capability.promise = new Promise(function (resolve, reject) {
+ capability.resolve = resolve;
+ capability.reject = reject;
+ });
+ return capability;
+}
+
+PDFJS.createPromiseCapability = createPromiseCapability;
/**
* Polyfill for Promises:
- * The following promise implementation tries to generally implment the
+ * The following promise implementation tries to generally implement the
* Promise/A+ spec. Some notable differences from other promise libaries are:
* - There currently isn't a seperate deferred and promise object.
* - Unhandled rejections eventually show an error if they aren't handled.
@@ -905,8 +1053,20 @@ var LegacyPromise = PDFJS.LegacyPromise = (function LegacyPromiseClosure() {
};
}
if (typeof globalScope.Promise.resolve !== 'function') {
- globalScope.Promise.resolve = function (x) {
- return new globalScope.Promise(function (resolve) { resolve(x); });
+ globalScope.Promise.resolve = function (value) {
+ return new globalScope.Promise(function (resolve) { resolve(value); });
+ };
+ }
+ if (typeof globalScope.Promise.reject !== 'function') {
+ globalScope.Promise.reject = function (reason) {
+ return new globalScope.Promise(function (resolve, reject) {
+ reject(reason);
+ });
+ };
+ }
+ if (typeof globalScope.Promise.prototype.catch !== 'function') {
+ globalScope.Promise.prototype.catch = function (onReject) {
+ return globalScope.Promise.prototype.then(undefined, onReject);
};
}
return;
@@ -1031,7 +1191,11 @@ var LegacyPromise = PDFJS.LegacyPromise = (function LegacyPromiseClosure() {
function Promise(resolver) {
this._status = STATUS_PENDING;
this._handlers = [];
- resolver.call(this, this._resolve.bind(this), this._reject.bind(this));
+ try {
+ resolver.call(this, this._resolve.bind(this), this._reject.bind(this));
+ } catch (e) {
+ this._reject(e);
+ }
}
/**
* Builds a promise that is resolved when all the passed in promises are
@@ -1083,18 +1247,28 @@ var LegacyPromise = PDFJS.LegacyPromise = (function LegacyPromiseClosure() {
/**
* Checks if the value is likely a promise (has a 'then' function).
- * @return {boolean} true if x is thenable
+ * @return {boolean} true if value is thenable
*/
Promise.isPromise = function Promise_isPromise(value) {
return value && typeof value.then === 'function';
};
+
/**
* Creates resolved promise
- * @param x resolve value
+ * @param value resolve value
* @returns {Promise}
*/
- Promise.resolve = function Promise_resolve(x) {
- return new Promise(function (resolve) { resolve(x); });
+ Promise.resolve = function Promise_resolve(value) {
+ return new Promise(function (resolve) { resolve(value); });
+ };
+
+ /**
+ * Creates rejected promise
+ * @param reason rejection value
+ * @returns {Promise}
+ */
+ Promise.reject = function Promise_reject(reason) {
+ return new Promise(function (resolve, reject) { reject(reason); });
};
Promise.prototype = {
@@ -1148,6 +1322,10 @@ var LegacyPromise = PDFJS.LegacyPromise = (function LegacyPromiseClosure() {
});
HandlerManager.scheduleHandlers(this);
return nextPromise;
+ },
+
+ catch: function Promise_catch(onReject) {
+ return this.then(undefined, onReject);
}
};
@@ -1192,17 +1370,18 @@ var StatTimer = (function StatTimerClosure() {
delete this.started[name];
},
toString: function StatTimer_toString() {
+ var i, ii;
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) {
+ for (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) {
+ for (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';
@@ -1254,7 +1433,7 @@ function MessageHandler(name, comObj) {
this.comObj = comObj;
this.callbackIndex = 1;
this.postMessageTransfers = true;
- var callbacks = this.callbacks = {};
+ var callbacksCapabilities = this.callbacksCapabilities = {};
var ah = this.actionHandler = {};
ah['console_log'] = [function ahConsoleLog(data) {
@@ -1271,35 +1450,40 @@ function MessageHandler(name, comObj) {
var data = event.data;
if (data.isReply) {
var callbackId = data.callbackId;
- if (data.callbackId in callbacks) {
- var callback = callbacks[callbackId];
- delete callbacks[callbackId];
- callback(data.data);
+ if (data.callbackId in callbacksCapabilities) {
+ var callback = callbacksCapabilities[callbackId];
+ delete callbacksCapabilities[callbackId];
+ if ('error' in data) {
+ callback.reject(data.error);
+ } else {
+ callback.resolve(data.data);
+ }
} else {
error('Cannot resolve callback ' + callbackId);
}
} else if (data.action in ah) {
var action = ah[data.action];
if (data.callbackId) {
- var deferred = {};
- var promise = new Promise(function (resolve, reject) {
- deferred.resolve = resolve;
- deferred.reject = reject;
- });
- deferred.promise = promise;
- promise.then(function(resolvedData) {
+ Promise.resolve().then(function () {
+ return action[0].call(action[1], data.data);
+ }).then(function (result) {
comObj.postMessage({
isReply: true,
callbackId: data.callbackId,
- data: resolvedData
+ data: result
+ });
+ }, function (reason) {
+ comObj.postMessage({
+ isReply: true,
+ callbackId: data.callbackId,
+ error: reason
});
});
- action[0].call(action[1], data.data, deferred);
} else {
action[0].call(action[1], data.data);
}
} else {
- error('Unkown action from worker: ' + data.action);
+ error('Unknown action from worker: ' + data.action);
}
};
}
@@ -1316,19 +1500,47 @@ MessageHandler.prototype = {
* Sends a message to the comObj to invoke the action with the supplied data.
* @param {String} actionName Action to call.
* @param {JSON} data JSON data to send.
- * @param {function} [callback] Optional callback that will handle a reply.
* @param {Array} [transfers] Optional list of transfers/ArrayBuffers
*/
- send: function messageHandlerSend(actionName, data, callback, transfers) {
+ send: function messageHandlerSend(actionName, data, transfers) {
var message = {
action: actionName,
data: data
};
- if (callback) {
- var callbackId = this.callbackIndex++;
- this.callbacks[callbackId] = callback;
- message.callbackId = callbackId;
+ this.postMessage(message, transfers);
+ },
+ /**
+ * Sends a message to the comObj to invoke the action with the supplied data.
+ * Expects that other side will callback with the response.
+ * @param {String} actionName Action to call.
+ * @param {JSON} data JSON data to send.
+ * @param {Array} [transfers] Optional list of transfers/ArrayBuffers.
+ * @returns {Promise} Promise to be resolved with response data.
+ */
+ sendWithPromise:
+ function messageHandlerSendWithPromise(actionName, data, transfers) {
+ var callbackId = this.callbackIndex++;
+ var message = {
+ action: actionName,
+ data: data,
+ callbackId: callbackId
+ };
+ var capability = createPromiseCapability();
+ this.callbacksCapabilities[callbackId] = capability;
+ try {
+ this.postMessage(message, transfers);
+ } catch (e) {
+ capability.reject(e);
}
+ return capability.promise;
+ },
+ /**
+ * Sends raw message to the comObj.
+ * @private
+ * @param message {Object} Raw message.
+ * @param transfers List of transfers/ArrayBuffers, or undefined.
+ */
+ postMessage: function (message, transfers) {
if (transfers && this.postMessageTransfers) {
this.comObj.postMessage(message, transfers);
} else {
@@ -1346,1635 +1558,7 @@ function loadJpegStream(id, imageUrl, objs) {
}
-var ColorSpace = (function ColorSpaceClosure() {
- // Constructor should define this.numComps, this.defaultColor, this.name
- function ColorSpace() {
- error('should not call ColorSpace constructor');
- }
-
- ColorSpace.prototype = {
- /**
- * Converts the color value to the RGB color. The color components are
- * located in the src array starting from the srcOffset. Returns the array
- * of the rgb components, each value ranging from [0,255].
- */
- getRgb: function ColorSpace_getRgb(src, srcOffset) {
- var rgb = new Uint8Array(3);
- this.getRgbItem(src, srcOffset, rgb, 0);
- return rgb;
- },
- /**
- * Converts the color value to the RGB color, similar to the getRgb method.
- * The result placed into the dest array starting from the destOffset.
- */
- getRgbItem: function ColorSpace_getRgbItem(src, srcOffset,
- dest, destOffset) {
- error('Should not call ColorSpace.getRgbItem');
- },
- /**
- * Converts the specified number of the color values to the RGB colors.
- * The colors are located in the src array starting from the srcOffset.
- * The result is placed into the dest array starting from the destOffset.
- * The src array items shall be in [0,2^bits) range, the dest array items
- * will be in [0,255] range. alpha01 indicates how many alpha components
- * there are in the dest array; it will be either 0 (RGB array) or 1 (RGBA
- * array).
- */
- getRgbBuffer: function ColorSpace_getRgbBuffer(src, srcOffset, count,
- dest, destOffset, bits,
- alpha01) {
- error('Should not call ColorSpace.getRgbBuffer');
- },
- /**
- * Determines the number of bytes required to store the result of the
- * conversion done by the getRgbBuffer method. As in getRgbBuffer,
- * |alpha01| is either 0 (RGB output) or 1 (RGBA output).
- */
- getOutputLength: function ColorSpace_getOutputLength(inputLength,
- alpha01) {
- error('Should not call ColorSpace.getOutputLength');
- },
- /**
- * Returns true if source data will be equal the result/output data.
- */
- isPassthrough: function ColorSpace_isPassthrough(bits) {
- return false;
- },
- /**
- * Fills in the RGB colors in the destination buffer. alpha01 indicates
- * how many alpha components there are in the dest array; it will be either
- * 0 (RGB array) or 1 (RGBA array).
- */
- fillRgb: function ColorSpace_fillRgb(dest, originalWidth,
- originalHeight, width, height,
- actualHeight, bpc, comps, alpha01) {
- var count = originalWidth * originalHeight;
- var rgbBuf = null;
- var numComponentColors = 1 << bpc;
- var needsResizing = originalHeight != height || originalWidth != width;
-
- if (this.isPassthrough(bpc)) {
- rgbBuf = comps;
-
- } else if (this.numComps === 1 && count > numComponentColors &&
- this.name !== 'DeviceGray' && this.name !== 'DeviceRGB') {
- // Optimization: create a color map when there is just one component and
- // we are converting more colors than the size of the color map. We
- // don't build the map if the colorspace is gray or rgb since those
- // methods are faster than building a map. This mainly offers big speed
- // ups for indexed and alternate colorspaces.
- //
- // TODO it may be worth while to cache the color map. While running
- // testing I never hit a cache so I will leave that out for now (perhaps
- // we are reparsing colorspaces too much?).
- var allColors = bpc <= 8 ? new Uint8Array(numComponentColors) :
- new Uint16Array(numComponentColors);
- for (var i = 0; i < numComponentColors; i++) {
- allColors[i] = i;
- }
- var colorMap = new Uint8Array(numComponentColors * 3);
- this.getRgbBuffer(allColors, 0, numComponentColors, colorMap, 0, bpc,
- /* alpha01 = */ 0);
-
- if (!needsResizing) {
- // Fill in the RGB values directly into |dest|.
- var destPos = 0;
- for (var i = 0; i < count; ++i) {
- var key = comps[i] * 3;
- dest[destPos++] = colorMap[key];
- dest[destPos++] = colorMap[key + 1];
- dest[destPos++] = colorMap[key + 2];
- destPos += alpha01;
- }
- } else {
- rgbBuf = new Uint8Array(count * 3);
- var rgbPos = 0;
- for (var i = 0; i < count; ++i) {
- var key = comps[i] * 3;
- rgbBuf[rgbPos++] = colorMap[key];
- rgbBuf[rgbPos++] = colorMap[key + 1];
- rgbBuf[rgbPos++] = colorMap[key + 2];
- }
- }
- } else {
- if (!needsResizing) {
- // Fill in the RGB values directly into |dest|.
- this.getRgbBuffer(comps, 0, width * actualHeight, dest, 0, bpc,
- alpha01);
- } else {
- rgbBuf = new Uint8Array(count * 3);
- this.getRgbBuffer(comps, 0, count, rgbBuf, 0, bpc,
- /* alpha01 = */ 0);
- }
- }
-
- if (rgbBuf) {
- if (needsResizing) {
- rgbBuf = PDFImage.resize(rgbBuf, bpc, 3, originalWidth,
- originalHeight, width, height);
- }
- var rgbPos = 0;
- var destPos = 0;
- for (var i = 0, ii = width * actualHeight; i < ii; i++) {
- dest[destPos++] = rgbBuf[rgbPos++];
- dest[destPos++] = rgbBuf[rgbPos++];
- dest[destPos++] = rgbBuf[rgbPos++];
- destPos += alpha01;
- }
- }
- },
- /**
- * True if the colorspace has components in the default range of [0, 1].
- * This should be true for all colorspaces except for lab color spaces
- * which are [0,100], [-128, 127], [-128, 127].
- */
- usesZeroToOneRange: true
- };
-
- ColorSpace.parse = function ColorSpace_parse(cs, xref, res) {
- var IR = ColorSpace.parseToIR(cs, xref, res);
- if (IR instanceof AlternateCS) {
- return IR;
- }
- return ColorSpace.fromIR(IR);
- };
-
- ColorSpace.fromIR = function ColorSpace_fromIR(IR) {
- var name = isArray(IR) ? IR[0] : IR;
-
- switch (name) {
- case 'DeviceGrayCS':
- return this.singletons.gray;
- case 'DeviceRgbCS':
- return this.singletons.rgb;
- case 'DeviceCmykCS':
- return this.singletons.cmyk;
- case 'CalGrayCS':
- var whitePoint = IR[1].WhitePoint;
- var blackPoint = IR[1].BlackPoint;
- var gamma = IR[1].Gamma;
- return new CalGrayCS(whitePoint, blackPoint, gamma);
- case 'PatternCS':
- var basePatternCS = IR[1];
- if (basePatternCS) {
- basePatternCS = ColorSpace.fromIR(basePatternCS);
- }
- return new PatternCS(basePatternCS);
- case 'IndexedCS':
- var baseIndexedCS = IR[1];
- var hiVal = IR[2];
- var lookup = IR[3];
- return new IndexedCS(ColorSpace.fromIR(baseIndexedCS), hiVal, lookup);
- case 'AlternateCS':
- var numComps = IR[1];
- var alt = IR[2];
- var tintFnIR = IR[3];
-
- 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);
- }
- return null;
- };
-
- ColorSpace.parseToIR = function ColorSpace_parseToIR(cs, xref, res) {
- if (isName(cs)) {
- var colorSpaces = res.get('ColorSpace');
- if (isDict(colorSpaces)) {
- var refcs = colorSpaces.get(cs.name);
- if (refcs) {
- cs = refcs;
- }
- }
- }
-
- cs = xref.fetchIfRef(cs);
- var mode;
-
- if (isName(cs)) {
- mode = cs.name;
- this.mode = mode;
-
- switch (mode) {
- case 'DeviceGray':
- case 'G':
- return 'DeviceGrayCS';
- case 'DeviceRGB':
- case 'RGB':
- return 'DeviceRgbCS';
- case 'DeviceCMYK':
- case 'CMYK':
- return 'DeviceCmykCS';
- case 'Pattern':
- return ['PatternCS', null];
- default:
- error('unrecognized colorspace ' + mode);
- }
- } else if (isArray(cs)) {
- mode = cs[0].name;
- this.mode = mode;
-
- switch (mode) {
- case 'DeviceGray':
- case 'G':
- return 'DeviceGrayCS';
- case 'DeviceRGB':
- case 'RGB':
- return 'DeviceRgbCS';
- case 'DeviceCMYK':
- case 'CMYK':
- return 'DeviceCmykCS';
- case 'CalGray':
- var params = cs[1].getAll();
- return ['CalGrayCS', params];
- case 'CalRGB':
- return 'DeviceRgbCS';
- case 'ICCBased':
- var stream = xref.fetchIfRef(cs[1]);
- var dict = stream.dict;
- var numComps = dict.get('N');
- if (numComps == 1) {
- return 'DeviceGrayCS';
- } else if (numComps == 3) {
- return 'DeviceRgbCS';
- } else if (numComps == 4) {
- return 'DeviceCmykCS';
- }
- break;
- case 'Pattern':
- var basePatternCS = cs[1];
- if (basePatternCS) {
- basePatternCS = ColorSpace.parseToIR(basePatternCS, xref, res);
- }
- return ['PatternCS', basePatternCS];
- case 'Indexed':
- case 'I':
- var baseIndexedCS = ColorSpace.parseToIR(cs[1], xref, res);
- var hiVal = cs[2] + 1;
- var lookup = xref.fetchIfRef(cs[3]);
- if (isStream(lookup)) {
- lookup = lookup.getBytes();
- }
- return ['IndexedCS', baseIndexedCS, hiVal, lookup];
- case 'Separation':
- case 'DeviceN':
- var name = cs[1];
- var numComps = 1;
- if (isName(name)) {
- numComps = 1;
- } else if (isArray(name)) {
- numComps = name.length;
- }
- var alt = ColorSpace.parseToIR(cs[2], xref, res);
- var tintFnIR = PDFFunction.getIR(xref, xref.fetchIfRef(cs[3]));
- return ['AlternateCS', numComps, alt, tintFnIR];
- case 'Lab':
- var params = cs[1].getAll();
- return ['LabCS', params];
- default:
- error('unimplemented color space object "' + mode + '"');
- }
- } else {
- error('unrecognized color space object: "' + cs + '"');
- }
- 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;
- }
-
- if (n * 2 !== decode.length) {
- warn('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;
- };
-
- ColorSpace.singletons = {
- get gray() {
- return shadow(this, 'gray', new DeviceGrayCS());
- },
- get rgb() {
- return shadow(this, 'rgb', new DeviceRgbCS());
- },
- get cmyk() {
- return shadow(this, 'cmyk', new DeviceCmykCS());
- }
- };
-
- return ColorSpace;
-})();
-
-/**
- * Alternate color space handles both Separation and DeviceN color spaces. A
- * Separation color space is actually just a DeviceN with one color component.
- * Both color spaces use a tinting function to convert colors to a base color
- * space.
- */
-var AlternateCS = (function AlternateCSClosure() {
- function AlternateCS(numComps, base, tintFn) {
- this.name = 'Alternate';
- this.numComps = numComps;
- this.defaultColor = new Float32Array(numComps);
- for (var i = 0; i < numComps; ++i) {
- this.defaultColor[i] = 1;
- }
- this.base = base;
- this.tintFn = tintFn;
- }
-
- AlternateCS.prototype = {
- getRgb: ColorSpace.prototype.getRgb,
- getRgbItem: function AlternateCS_getRgbItem(src, srcOffset,
- dest, destOffset) {
- var baseNumComps = this.base.numComps;
- var input = 'subarray' in src ?
- src.subarray(srcOffset, srcOffset + this.numComps) :
- Array.prototype.slice.call(src, srcOffset, srcOffset + this.numComps);
- var tinted = this.tintFn(input);
- this.base.getRgbItem(tinted, 0, dest, destOffset);
- },
- getRgbBuffer: function AlternateCS_getRgbBuffer(src, srcOffset, count,
- dest, destOffset, bits,
- alpha01) {
- var tintFn = this.tintFn;
- var base = this.base;
- var scale = 1 / ((1 << bits) - 1);
- var baseNumComps = base.numComps;
- var usesZeroToOneRange = base.usesZeroToOneRange;
- var isPassthrough = (base.isPassthrough(8) || !usesZeroToOneRange) &&
- alpha01 === 0;
- var pos = isPassthrough ? destOffset : 0;
- var baseBuf = isPassthrough ? dest : new Uint8Array(baseNumComps * count);
- var numComps = this.numComps;
-
- var scaled = new Float32Array(numComps);
- for (var i = 0; i < count; i++) {
- for (var j = 0; j < numComps; j++) {
- scaled[j] = src[srcOffset++] * scale;
- }
- var tinted = tintFn(scaled);
- if (usesZeroToOneRange) {
- for (var j = 0; j < baseNumComps; j++) {
- baseBuf[pos++] = tinted[j] * 255;
- }
- } else {
- base.getRgbItem(tinted, 0, baseBuf, pos);
- pos += baseNumComps;
- }
- }
- if (!isPassthrough) {
- base.getRgbBuffer(baseBuf, 0, count, dest, destOffset, 8, alpha01);
- }
- },
- getOutputLength: function AlternateCS_getOutputLength(inputLength,
- alpha01) {
- return this.base.getOutputLength(inputLength *
- this.base.numComps / this.numComps,
- alpha01);
- },
- isPassthrough: ColorSpace.prototype.isPassthrough,
- fillRgb: ColorSpace.prototype.fillRgb,
- isDefaultDecode: function AlternateCS_isDefaultDecode(decodeMap) {
- return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
- },
- usesZeroToOneRange: true
- };
-
- return AlternateCS;
-})();
-
-var PatternCS = (function PatternCSClosure() {
- function PatternCS(baseCS) {
- this.name = 'Pattern';
- this.base = baseCS;
- }
- PatternCS.prototype = {};
-
- return PatternCS;
-})();
-
-var IndexedCS = (function IndexedCSClosure() {
- function IndexedCS(base, highVal, lookup) {
- this.name = 'Indexed';
- this.numComps = 1;
- this.defaultColor = new Uint8Array([0]);
- this.base = base;
- this.highVal = highVal;
-
- var baseNumComps = base.numComps;
- var length = baseNumComps * highVal;
- var lookupArray;
-
- if (isStream(lookup)) {
- lookupArray = new Uint8Array(length);
- var bytes = lookup.getBytes(length);
- lookupArray.set(bytes);
- } else if (isString(lookup)) {
- lookupArray = new Uint8Array(length);
- for (var i = 0; i < length; ++i) {
- lookupArray[i] = lookup.charCodeAt(i);
- }
- } else if (lookup instanceof Uint8Array || lookup instanceof Array) {
- lookupArray = lookup;
- } else {
- error('Unrecognized lookup table: ' + lookup);
- }
- this.lookup = lookupArray;
- }
-
- IndexedCS.prototype = {
- getRgb: ColorSpace.prototype.getRgb,
- getRgbItem: function IndexedCS_getRgbItem(src, srcOffset,
- dest, destOffset) {
- var numComps = this.base.numComps;
- var start = src[srcOffset] * numComps;
- this.base.getRgbItem(this.lookup, start, dest, destOffset);
- },
- getRgbBuffer: function IndexedCS_getRgbBuffer(src, srcOffset, count,
- dest, destOffset, bits,
- alpha01) {
- var base = this.base;
- var numComps = base.numComps;
- var outputDelta = base.getOutputLength(numComps, alpha01);
- var lookup = this.lookup;
-
- for (var i = 0; i < count; ++i) {
- var lookupPos = src[srcOffset++] * numComps;
- base.getRgbBuffer(lookup, lookupPos, 1, dest, destOffset, 8, alpha01);
- destOffset += outputDelta;
- }
- },
- getOutputLength: function IndexedCS_getOutputLength(inputLength, alpha01) {
- return this.base.getOutputLength(inputLength * this.base.numComps,
- alpha01);
- },
- isPassthrough: ColorSpace.prototype.isPassthrough,
- fillRgb: ColorSpace.prototype.fillRgb,
- isDefaultDecode: function IndexedCS_isDefaultDecode(decodeMap) {
- // indexed color maps shouldn't be changed
- return true;
- },
- usesZeroToOneRange: true
- };
- return IndexedCS;
-})();
-
-var DeviceGrayCS = (function DeviceGrayCSClosure() {
- function DeviceGrayCS() {
- this.name = 'DeviceGray';
- this.numComps = 1;
- this.defaultColor = new Float32Array([0]);
- }
-
- DeviceGrayCS.prototype = {
- getRgb: ColorSpace.prototype.getRgb,
- getRgbItem: function DeviceGrayCS_getRgbItem(src, srcOffset,
- dest, destOffset) {
- var c = (src[srcOffset] * 255) | 0;
- c = c < 0 ? 0 : c > 255 ? 255 : c;
- dest[destOffset] = dest[destOffset + 1] = dest[destOffset + 2] = c;
- },
- getRgbBuffer: function DeviceGrayCS_getRgbBuffer(src, srcOffset, count,
- dest, destOffset, bits,
- alpha01) {
- var scale = 255 / ((1 << bits) - 1);
- var j = srcOffset, q = destOffset;
- for (var i = 0; i < count; ++i) {
- var c = (scale * src[j++]) | 0;
- dest[q++] = c;
- dest[q++] = c;
- dest[q++] = c;
- q += alpha01;
- }
- },
- getOutputLength: function DeviceGrayCS_getOutputLength(inputLength,
- alpha01) {
- return inputLength * (3 + alpha01);
- },
- isPassthrough: ColorSpace.prototype.isPassthrough,
- fillRgb: ColorSpace.prototype.fillRgb,
- isDefaultDecode: function DeviceGrayCS_isDefaultDecode(decodeMap) {
- return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
- },
- usesZeroToOneRange: true
- };
- return DeviceGrayCS;
-})();
-
-var DeviceRgbCS = (function DeviceRgbCSClosure() {
- function DeviceRgbCS() {
- this.name = 'DeviceRGB';
- this.numComps = 3;
- this.defaultColor = new Float32Array([0, 0, 0]);
- }
- DeviceRgbCS.prototype = {
- getRgb: ColorSpace.prototype.getRgb,
- getRgbItem: function DeviceRgbCS_getRgbItem(src, srcOffset,
- dest, destOffset) {
- var r = (src[srcOffset] * 255) | 0;
- var g = (src[srcOffset + 1] * 255) | 0;
- var b = (src[srcOffset + 2] * 255) | 0;
- dest[destOffset] = r < 0 ? 0 : r > 255 ? 255 : r;
- dest[destOffset + 1] = g < 0 ? 0 : g > 255 ? 255 : g;
- dest[destOffset + 2] = b < 0 ? 0 : b > 255 ? 255 : b;
- },
- getRgbBuffer: function DeviceRgbCS_getRgbBuffer(src, srcOffset, count,
- dest, destOffset, bits,
- alpha01) {
- if (bits === 8 && alpha01 === 0) {
- dest.set(src.subarray(srcOffset, srcOffset + count * 3), destOffset);
- return;
- }
- var scale = 255 / ((1 << bits) - 1);
- var j = srcOffset, q = destOffset;
- for (var i = 0; i < count; ++i) {
- dest[q++] = (scale * src[j++]) | 0;
- dest[q++] = (scale * src[j++]) | 0;
- dest[q++] = (scale * src[j++]) | 0;
- q += alpha01;
- }
- },
- getOutputLength: function DeviceRgbCS_getOutputLength(inputLength,
- alpha01) {
- return (inputLength * (3 + alpha01) / 3) | 0;
- },
- isPassthrough: function DeviceRgbCS_isPassthrough(bits) {
- return bits == 8;
- },
- fillRgb: ColorSpace.prototype.fillRgb,
- isDefaultDecode: function DeviceRgbCS_isDefaultDecode(decodeMap) {
- return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
- },
- usesZeroToOneRange: true
- };
- return DeviceRgbCS;
-})();
-
-var DeviceCmykCS = (function DeviceCmykCSClosure() {
- // The coefficients below was found using numerical analysis: the method of
- // steepest descent for the sum((f_i - color_value_i)^2) for r/g/b colors,
- // where color_value is the tabular value from the table of sampled RGB colors
- // from CMYK US Web Coated (SWOP) colorspace, and f_i is the corresponding
- // CMYK color conversion using the estimation below:
- // f(A, B,.. N) = Acc+Bcm+Ccy+Dck+c+Fmm+Gmy+Hmk+Im+Jyy+Kyk+Ly+Mkk+Nk+255
- function convertToRgb(src, srcOffset, srcScale, dest, destOffset) {
- var c = src[srcOffset + 0] * srcScale;
- var m = src[srcOffset + 1] * srcScale;
- var y = src[srcOffset + 2] * srcScale;
- var k = src[srcOffset + 3] * srcScale;
-
- var r =
- c * (-4.387332384609988 * c + 54.48615194189176 * m +
- 18.82290502165302 * y + 212.25662451639585 * k +
- -285.2331026137004) +
- m * (1.7149763477362134 * m - 5.6096736904047315 * y +
- -17.873870861415444 * k - 5.497006427196366) +
- y * (-2.5217340131683033 * y - 21.248923337353073 * k +
- 17.5119270841813) +
- k * (-21.86122147463605 * k - 189.48180835922747) + 255;
- var g =
- c * (8.841041422036149 * c + 60.118027045597366 * m +
- 6.871425592049007 * y + 31.159100130055922 * k +
- -79.2970844816548) +
- m * (-15.310361306967817 * m + 17.575251261109482 * y +
- 131.35250912493976 * k - 190.9453302588951) +
- y * (4.444339102852739 * y + 9.8632861493405 * k - 24.86741582555878) +
- k * (-20.737325471181034 * k - 187.80453709719578) + 255;
- var b =
- c * (0.8842522430003296 * c + 8.078677503112928 * m +
- 30.89978309703729 * y - 0.23883238689178934 * k +
- -14.183576799673286) +
- m * (10.49593273432072 * m + 63.02378494754052 * y +
- 50.606957656360734 * k - 112.23884253719248) +
- y * (0.03296041114873217 * y + 115.60384449646641 * k +
- -193.58209356861505) +
- k * (-22.33816807309886 * k - 180.12613974708367) + 255;
-
- dest[destOffset] = r > 255 ? 255 : r < 0 ? 0 : r;
- dest[destOffset + 1] = g > 255 ? 255 : g < 0 ? 0 : g;
- dest[destOffset + 2] = b > 255 ? 255 : b < 0 ? 0 : b;
- }
-
- function DeviceCmykCS() {
- this.name = 'DeviceCMYK';
- this.numComps = 4;
- this.defaultColor = new Float32Array([0, 0, 0, 1]);
- }
- DeviceCmykCS.prototype = {
- getRgb: ColorSpace.prototype.getRgb,
- getRgbItem: function DeviceCmykCS_getRgbItem(src, srcOffset,
- dest, destOffset) {
- convertToRgb(src, srcOffset, 1, dest, destOffset);
- },
- getRgbBuffer: function DeviceCmykCS_getRgbBuffer(src, srcOffset, count,
- dest, destOffset, bits,
- alpha01) {
- var scale = 1 / ((1 << bits) - 1);
- for (var i = 0; i < count; i++) {
- convertToRgb(src, srcOffset, scale, dest, destOffset);
- srcOffset += 4;
- destOffset += 3 + alpha01;
- }
- },
- getOutputLength: function DeviceCmykCS_getOutputLength(inputLength,
- alpha01) {
- return (inputLength / 4 * (3 + alpha01)) | 0;
- },
- isPassthrough: ColorSpace.prototype.isPassthrough,
- fillRgb: ColorSpace.prototype.fillRgb,
- isDefaultDecode: function DeviceCmykCS_isDefaultDecode(decodeMap) {
- return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
- },
- usesZeroToOneRange: true
- };
-
- return DeviceCmykCS;
-})();
-
-//
-// CalGrayCS: Based on "PDF Reference, Sixth Ed", p.245
-//
-var CalGrayCS = (function CalGrayCSClosure() {
- function CalGrayCS(whitePoint, blackPoint, gamma) {
- this.name = 'CalGray';
- this.numComps = 1;
- this.defaultColor = new Float32Array([0]);
-
- if (!whitePoint) {
- error('WhitePoint missing - required for color space CalGray');
- }
- blackPoint = blackPoint || [0, 0, 0];
- gamma = gamma || 1;
-
- // Translate arguments to spec variables.
- this.XW = whitePoint[0];
- this.YW = whitePoint[1];
- this.ZW = whitePoint[2];
-
- this.XB = blackPoint[0];
- this.YB = blackPoint[1];
- this.ZB = blackPoint[2];
-
- this.G = gamma;
-
- // Validate variables as per spec.
- if (this.XW < 0 || this.ZW < 0 || this.YW !== 1) {
- error('Invalid WhitePoint components for ' + this.name +
- ', no fallback available');
- }
-
- if (this.XB < 0 || this.YB < 0 || this.ZB < 0) {
- info('Invalid BlackPoint for ' + this.name + ', falling back to default');
- this.XB = this.YB = this.ZB = 0;
- }
-
- if (this.XB !== 0 || this.YB !== 0 || this.ZB !== 0) {
- warn(this.name + ', BlackPoint: XB: ' + this.XB + ', YB: ' + this.YB +
- ', ZB: ' + this.ZB + ', only default values are supported.');
- }
-
- if (this.G < 1) {
- info('Invalid Gamma: ' + this.G + ' for ' + this.name +
- ', falling back to default');
- this.G = 1;
- }
- }
-
- function convertToRgb(cs, src, srcOffset, dest, destOffset, scale) {
- // A represents a gray component of a calibrated gray space.
- // A <---> AG in the spec
- var A = src[srcOffset] * scale;
- var AG = Math.pow(A, cs.G);
-
- // Computes intermediate variables M, L, N as per spec.
- // Except if other than default BlackPoint values are used.
- var M = cs.XW * AG;
- var L = cs.YW * AG;
- var N = cs.ZW * AG;
-
- // Decode XYZ, as per spec.
- var X = M;
- var Y = L;
- var Z = N;
-
- // http://www.poynton.com/notes/colour_and_gamma/ColorFAQ.html, Ch 4.
- // This yields values in range [0, 100].
- var Lstar = Math.max(116 * Math.pow(Y, 1 / 3) - 16, 0);
-
- // Convert values to rgb range [0, 255].
- dest[destOffset] = Lstar * 255 / 100;
- dest[destOffset + 1] = Lstar * 255 / 100;
- dest[destOffset + 2] = Lstar * 255 / 100;
- }
-
- CalGrayCS.prototype = {
- getRgb: ColorSpace.prototype.getRgb,
- getRgbItem: function CalGrayCS_getRgbItem(src, srcOffset,
- dest, destOffset) {
- convertToRgb(this, src, srcOffset, dest, destOffset, 1);
- },
- getRgbBuffer: function CalGrayCS_getRgbBuffer(src, srcOffset, count,
- dest, destOffset, bits,
- alpha01) {
- var scale = 1 / ((1 << bits) - 1);
-
- for (var i = 0; i < count; ++i) {
- convertToRgb(this, src, srcOffset, dest, destOffset, scale);
- srcOffset += 1;
- destOffset += 3 + alpha01;
- }
- },
- getOutputLength: function CalGrayCS_getOutputLength(inputLength, alpha01) {
- return inputLength * (3 + alpha01);
- },
- isPassthrough: ColorSpace.prototype.isPassthrough,
- fillRgb: ColorSpace.prototype.fillRgb,
- isDefaultDecode: function CalGrayCS_isDefaultDecode(decodeMap) {
- return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
- },
- usesZeroToOneRange: true
- };
- return CalGrayCS;
-})();
-
-//
-// 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 = new Float32Array([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) {
- info('Invalid BlackPoint, falling back to default');
- this.XB = this.YB = this.ZB = 0;
- }
-
- if (this.amin > this.amax || this.bmin > this.bmax) {
- info('Invalid Range, falling back to defaults');
- this.amin = -100;
- this.amax = 100;
- this.bmin = -100;
- this.bmax = 100;
- }
- }
-
- // Function g(x) from spec
- function fn_g(x) {
- if (x >= 6 / 29) {
- return x * x * x;
- } else {
- return (108 / 841) * (x - 4 / 29);
- }
- }
-
- function decode(value, high1, low2, high2) {
- return low2 + (value) * (high2 - low2) / (high1);
- }
-
- // If decoding is needed maxVal should be 2^bits per component - 1.
- function convertToRgb(cs, src, srcOffset, maxVal, dest, destOffset) {
- // XXX: Lab input is in the range of [0, 100], [amin, amax], [bmin, bmax]
- // not the usual [0, 1]. If a command like setFillColor is used the src
- // values will already be within the correct range. However, if we are
- // converting an image we have to map the values to the correct range given
- // above.
- // Ls,as,bs <---> L*,a*,b* in the spec
- var Ls = src[srcOffset];
- var as = src[srcOffset + 1];
- var bs = src[srcOffset + 2];
- if (maxVal !== false) {
- Ls = decode(Ls, maxVal, 0, 100);
- as = decode(as, maxVal, cs.amin, cs.amax);
- bs = decode(bs, maxVal, cs.bmin, cs.bmax);
- }
-
- // Adjust limits of 'as' and 'bs'
- as = as > cs.amax ? cs.amax : as < cs.amin ? cs.amin : as;
- bs = bs > cs.bmax ? cs.bmax : bs < cs.bmin ? cs.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 = cs.XW * fn_g(L);
- var Y = cs.YW * fn_g(M);
- var Z = cs.ZW * fn_g(N);
-
- var r, g, b;
- // Using different conversions for D50 and D65 white points,
- // per http://www.color.org/srgb.pdf
- if (cs.ZW < 1) {
- // Assuming D50 (X=0.9642, Y=1.00, Z=0.8249)
- r = X * 3.1339 + Y * -1.6170 + Z * -0.4906;
- g = X * -0.9785 + Y * 1.9160 + Z * 0.0333;
- b = X * 0.0720 + Y * -0.2290 + Z * 1.4057;
- } else {
- // Assuming D65 (X=0.9505, Y=1.00, Z=1.0888)
- r = X * 3.2406 + Y * -1.5372 + Z * -0.4986;
- g = X * -0.9689 + Y * 1.8758 + Z * 0.0415;
- b = X * 0.0557 + Y * -0.2040 + Z * 1.0570;
- }
- // clamp color values to [0,1] range then convert to [0,255] range.
- dest[destOffset] = r <= 0 ? 0 : r >= 1 ? 255 : Math.sqrt(r) * 255 | 0;
- dest[destOffset + 1] = g <= 0 ? 0 : g >= 1 ? 255 : Math.sqrt(g) * 255 | 0;
- dest[destOffset + 2] = b <= 0 ? 0 : b >= 1 ? 255 : Math.sqrt(b) * 255 | 0;
- }
-
- LabCS.prototype = {
- getRgb: ColorSpace.prototype.getRgb,
- getRgbItem: function LabCS_getRgbItem(src, srcOffset, dest, destOffset) {
- convertToRgb(this, src, srcOffset, false, dest, destOffset);
- },
- getRgbBuffer: function LabCS_getRgbBuffer(src, srcOffset, count,
- dest, destOffset, bits,
- alpha01) {
- var maxVal = (1 << bits) - 1;
- for (var i = 0; i < count; i++) {
- convertToRgb(this, src, srcOffset, maxVal, dest, destOffset);
- srcOffset += 3;
- destOffset += 3 + alpha01;
- }
- },
- getOutputLength: function LabCS_getOutputLength(inputLength, alpha01) {
- return (inputLength * (3 + alpha01) / 3) | 0;
- },
- isPassthrough: ColorSpace.prototype.isPassthrough,
- isDefaultDecode: function LabCS_isDefaultDecode(decodeMap) {
- // XXX: Decoding is handled with the lab conversion because of the strange
- // ranges that are used.
- return true;
- },
- usesZeroToOneRange: false
- };
- return LabCS;
-})();
-
-
-
-var PDFFunction = (function PDFFunctionClosure() {
- var CONSTRUCT_SAMPLED = 0;
- var CONSTRUCT_INTERPOLATED = 2;
- var CONSTRUCT_STICHED = 3;
- var CONSTRUCT_POSTSCRIPT = 4;
-
- return {
- getSampleArray: function PDFFunction_getSampleArray(size, outputSize, bps,
- str) {
- var length = 1;
- for (var i = 0, ii = size.length; i < ii; i++) {
- length *= size[i];
- }
- length *= outputSize;
-
- var array = [];
- var codeSize = 0;
- var codeBuf = 0;
- // 32 is a valid bps so shifting won't work
- var sampleMul = 1.0 / (Math.pow(2.0, bps) - 1);
-
- var strBytes = str.getBytes((length * bps + 7) / 8);
- var strIdx = 0;
- for (var i = 0; i < length; i++) {
- while (codeSize < bps) {
- codeBuf <<= 8;
- codeBuf |= strBytes[strIdx++];
- codeSize += 8;
- }
- codeSize -= bps;
- array.push((codeBuf >> codeSize) * sampleMul);
- codeBuf &= (1 << codeSize) - 1;
- }
- return array;
- },
-
- getIR: function PDFFunction_getIR(xref, fn) {
- var dict = fn.dict;
- if (!dict) {
- dict = fn;
- }
-
- var types = [this.constructSampled,
- null,
- this.constructInterpolated,
- this.constructStiched,
- this.constructPostScript];
-
- var typeNum = dict.get('FunctionType');
- var typeFn = types[typeNum];
- if (!typeFn) {
- error('Unknown type of function');
- }
-
- return typeFn.call(this, fn, dict, xref);
- },
-
- fromIR: function PDFFunction_fromIR(IR) {
- var type = IR[0];
- switch (type) {
- case CONSTRUCT_SAMPLED:
- return this.constructSampledFromIR(IR);
- case CONSTRUCT_INTERPOLATED:
- return this.constructInterpolatedFromIR(IR);
- case CONSTRUCT_STICHED:
- return this.constructStichedFromIR(IR);
- //case CONSTRUCT_POSTSCRIPT:
- default:
- return this.constructPostScriptFromIR(IR);
- }
- },
-
- parse: function PDFFunction_parse(xref, fn) {
- var IR = this.getIR(xref, fn);
- return this.fromIR(IR);
- },
-
- constructSampled: function PDFFunction_constructSampled(str, dict) {
- function toMultiArray(arr) {
- var inputLength = arr.length;
- var outputLength = arr.length / 2;
- var out = [];
- var index = 0;
- for (var i = 0; i < inputLength; i += 2) {
- out[index] = [arr[i], arr[i + 1]];
- ++index;
- }
- return out;
- }
- var domain = dict.get('Domain');
- var range = dict.get('Range');
-
- if (!domain || !range) {
- error('No domain or range');
- }
-
- var inputSize = domain.length / 2;
- var outputSize = range.length / 2;
-
- domain = toMultiArray(domain);
- range = toMultiArray(range);
-
- var size = dict.get('Size');
- var bps = dict.get('BitsPerSample');
- var order = dict.get('Order') || 1;
- if (order !== 1) {
- // No description how cubic spline interpolation works in PDF32000:2008
- // As in poppler, ignoring order, linear interpolation may work as good
- info('No support for cubic spline interpolation: ' + order);
- }
-
- var encode = dict.get('Encode');
- if (!encode) {
- encode = [];
- for (var i = 0; i < inputSize; ++i) {
- encode.push(0);
- encode.push(size[i] - 1);
- }
- }
- encode = toMultiArray(encode);
-
- var decode = dict.get('Decode');
- if (!decode) {
- decode = range;
- } else {
- decode = toMultiArray(decode);
- }
-
- var samples = this.getSampleArray(size, outputSize, bps, str);
-
- return [
- CONSTRUCT_SAMPLED, inputSize, domain, encode, decode, samples, size,
- outputSize, Math.pow(2, bps) - 1, range
- ];
- },
-
- constructSampledFromIR: function PDFFunction_constructSampledFromIR(IR) {
- // 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 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: ' + m + ' != ' +
- args.length);
- }
-
- var x = args;
-
- // 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;
- }
-
- 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 {
- cubeN[j] *= n0;
- cubeVertex[j] += offset0;
- }
- }
-
- k *= size_i;
- pos <<= 1;
- }
-
- 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;
- };
- },
-
- constructInterpolated: function PDFFunction_constructInterpolated(str,
- dict) {
- var c0 = dict.get('C0') || [0];
- var c1 = dict.get('C1') || [1];
- var n = dict.get('N');
-
- if (!isArray(c0) || !isArray(c1)) {
- error('Illegal dictionary for interpolated function');
- }
-
- var length = c0.length;
- var diff = [];
- for (var i = 0; i < length; ++i) {
- diff.push(c1[i] - c0[i]);
- }
-
- return [CONSTRUCT_INTERPOLATED, c0, diff, n];
- },
-
- constructInterpolatedFromIR:
- function PDFFunction_constructInterpolatedFromIR(IR) {
- var c0 = IR[1];
- var diff = IR[2];
- var n = IR[3];
-
- var length = diff.length;
-
- return function constructInterpolatedFromIRResult(args) {
- var x = n == 1 ? args[0] : Math.pow(args[0], n);
-
- var out = [];
- for (var j = 0; j < length; ++j) {
- out.push(c0[j] + (x * diff[j]));
- }
-
- return out;
-
- };
- },
-
- constructStiched: function PDFFunction_constructStiched(fn, dict, xref) {
- var domain = dict.get('Domain');
-
- if (!domain) {
- error('No domain');
- }
-
- var inputSize = domain.length / 2;
- if (inputSize != 1) {
- error('Bad domain for stiched function');
- }
-
- var fnRefs = dict.get('Functions');
- var fns = [];
- for (var i = 0, ii = fnRefs.length; i < ii; ++i) {
- fns.push(PDFFunction.getIR(xref, xref.fetchIfRef(fnRefs[i])));
- }
-
- var bounds = dict.get('Bounds');
- var encode = dict.get('Encode');
-
- return [CONSTRUCT_STICHED, domain, bounds, encode, fns];
- },
-
- constructStichedFromIR: function PDFFunction_constructStichedFromIR(IR) {
- var domain = IR[1];
- var bounds = IR[2];
- var encode = IR[3];
- var fnsIR = IR[4];
- var fns = [];
-
- for (var i = 0, ii = fnsIR.length; i < ii; i++) {
- fns.push(PDFFunction.fromIR(fnsIR[i]));
- }
-
- return function constructStichedFromIRResult(args) {
- var clip = function constructStichedFromIRClip(v, min, max) {
- if (v > max) {
- v = max;
- } else if (v < min) {
- v = min;
- }
- return v;
- };
-
- // clip to domain
- var v = clip(args[0], domain[0], domain[1]);
- // calulate which bound the value is in
- for (var i = 0, ii = bounds.length; i < ii; ++i) {
- if (v < bounds[i]) {
- break;
- }
- }
-
- // encode value into domain of function
- var dmin = domain[0];
- if (i > 0) {
- dmin = bounds[i - 1];
- }
- var dmax = domain[1];
- if (i < bounds.length) {
- dmax = bounds[i];
- }
-
- var rmin = encode[2 * i];
- var rmax = encode[2 * i + 1];
-
- var v2 = rmin + (v - dmin) * (rmax - rmin) / (dmax - dmin);
-
- // call the appropriate function
- return fns[i]([v2]);
- };
- },
-
- constructPostScript: function PDFFunction_constructPostScript(fn, dict,
- 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 PDFFunction_constructPostScriptFromIR(
- IR) {
- var domain = IR[1];
- 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) {
- this.operators = operators;
- }
- 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 DEFAULT_ICON_SIZE = 22; // px
var HIGHLIGHT_OFFSET = 4; // px
var SUPPORTED_TYPES = ['Link', 'Text', 'Widget'];
@@ -3034,7 +1618,7 @@ var Annotation = (function AnnotationClosure() {
var data = this.data = {};
data.subtype = dict.get('Subtype').name;
- var rect = dict.get('Rect');
+ var rect = dict.get('Rect') || [0, 0, 0, 0];
data.rect = Util.normalizeRect(rect);
data.annotationFlags = dict.get('F');
@@ -3058,23 +1642,30 @@ var Annotation = (function AnnotationClosure() {
// TODO: implement proper support for annotations with line dash patterns.
var dashArray = borderArray[3];
- if (data.borderWidth > 0 && dashArray && isArray(dashArray)) {
- var dashArrayLength = dashArray.length;
- if (dashArrayLength > 0) {
- // According to the PDF specification: the elements in a dashArray
- // shall be numbers that are nonnegative and not all equal to zero.
- var isInvalid = false;
- var numPositive = 0;
- for (var i = 0; i < dashArrayLength; i++) {
- if (!(+dashArray[i] >= 0)) {
- isInvalid = true;
- break;
- } else if (dashArray[i] > 0) {
- numPositive++;
+ if (data.borderWidth > 0 && dashArray) {
+ if (!isArray(dashArray)) {
+ // Ignore the border if dashArray is not actually an array,
+ // this is consistent with the behaviour in Adobe Reader.
+ data.borderWidth = 0;
+ } else {
+ var dashArrayLength = dashArray.length;
+ if (dashArrayLength > 0) {
+ // According to the PDF specification: the elements in a dashArray
+ // shall be numbers that are nonnegative and not all equal to zero.
+ var isInvalid = false;
+ var numPositive = 0;
+ for (var i = 0; i < dashArrayLength; i++) {
+ var validNumber = (+dashArray[i] >= 0);
+ if (!validNumber) {
+ isInvalid = true;
+ break;
+ } else if (dashArray[i] > 0) {
+ numPositive++;
+ }
+ }
+ if (isInvalid || numPositive === 0) {
+ data.borderWidth = 0;
}
- }
- if (isInvalid || numPositive === 0) {
- data.borderWidth = 0;
}
}
}
@@ -3082,6 +1673,7 @@ var Annotation = (function AnnotationClosure() {
this.appearance = getDefaultAppearance(dict);
data.hasAppearance = !!this.appearance;
+ data.id = params.ref.num;
}
Annotation.prototype = {
@@ -3146,31 +1738,27 @@ var Annotation = (function AnnotationClosure() {
data.rect); // rectangle is nessessary
},
- loadResources: function(keys) {
- var promise = new LegacyPromise();
- this.appearance.dict.getAsync('Resources').then(function(resources) {
- if (!resources) {
- promise.resolve();
- return;
- }
- var objectLoader = new ObjectLoader(resources.map,
- keys,
- resources.xref);
- objectLoader.load().then(function() {
- promise.resolve(resources);
- });
+ loadResources: function Annotation_loadResources(keys) {
+ return new Promise(function (resolve, reject) {
+ this.appearance.dict.getAsync('Resources').then(function (resources) {
+ if (!resources) {
+ resolve();
+ return;
+ }
+ var objectLoader = new ObjectLoader(resources.map,
+ keys,
+ resources.xref);
+ objectLoader.load().then(function() {
+ resolve(resources);
+ }, reject);
+ }, reject);
}.bind(this));
-
- return promise;
},
getOperatorList: function Annotation_getOperatorList(evaluator) {
- var promise = new LegacyPromise();
-
if (!this.appearance) {
- promise.resolve(new OperatorList());
- return promise;
+ return Promise.resolve(new OperatorList());
}
var data = this.data;
@@ -3189,20 +1777,18 @@ var Annotation = (function AnnotationClosure() {
var bbox = appearanceDict.get('BBox') || [0, 0, 1, 1];
var matrix = appearanceDict.get('Matrix') || [1, 0, 0, 1, 0 ,0];
var transform = getTransformMatrix(data.rect, bbox, matrix);
+ var self = this;
- var border = data.border;
-
- resourcesPromise.then(function(resources) {
- var opList = new OperatorList();
- opList.addOp(OPS.beginAnnotation, [data.rect, transform, matrix]);
- evaluator.getOperatorList(this.appearance, resources, opList);
- opList.addOp(OPS.endAnnotation, []);
- promise.resolve(opList);
-
- this.appearance.reset();
- }.bind(this));
-
- return promise;
+ return resourcesPromise.then(function(resources) {
+ var opList = new OperatorList();
+ opList.addOp(OPS.beginAnnotation, [data.rect, transform, matrix]);
+ return evaluator.getOperatorList(self.appearance, resources, opList).
+ then(function () {
+ opList.addOp(OPS.endAnnotation, []);
+ self.appearance.reset();
+ return opList;
+ });
+ });
}
};
@@ -3282,10 +1868,10 @@ var Annotation = (function AnnotationClosure() {
annotations, opList, pdfManager, partialEvaluator, intent) {
function reject(e) {
- annotationsReadyPromise.reject(e);
+ annotationsReadyCapability.reject(e);
}
- var annotationsReadyPromise = new LegacyPromise();
+ var annotationsReadyCapability = createPromiseCapability();
var annotationPromises = [];
for (var i = 0, n = annotations.length; i < n; ++i) {
@@ -3302,10 +1888,10 @@ var Annotation = (function AnnotationClosure() {
opList.addOpList(annotOpList);
}
opList.addOp(OPS.endAnnotations, []);
- annotationsReadyPromise.resolve();
+ annotationsReadyCapability.resolve();
}, reject);
- return annotationsReadyPromise;
+ return annotationsReadyCapability.promise;
};
return Annotation;
@@ -3332,7 +1918,7 @@ var WidgetAnnotation = (function WidgetAnnotationClosure() {
var fieldType = Util.getInheritableProperty(dict, 'FT');
data.fieldType = isName(fieldType) ? fieldType.name : '';
data.fieldFlags = Util.getInheritableProperty(dict, 'Ff') || 0;
- this.fieldResources = Util.getInheritableProperty(dict, 'DR') || new Dict();
+ this.fieldResources = Util.getInheritableProperty(dict, 'DR') || Dict.empty;
// Building the full field name by collecting the field and
// its ancestors 'T' data and joining them using '.'.
@@ -3417,7 +2003,6 @@ var TextWidgetAnnotation = (function TextWidgetAnnotationClosure() {
}
- var parent = WidgetAnnotation.prototype;
Util.inherit(TextWidgetAnnotation, WidgetAnnotation, {
hasHtml: function TextWidgetAnnotation_hasHtml() {
return !this.data.hasAppearance && !!this.data.fieldValue;
@@ -3440,7 +2025,7 @@ var TextWidgetAnnotation = (function TextWidgetAnnotationClosure() {
var fontObj = item.fontRefName ?
commonObjs.getData(item.fontRefName) : null;
- var cssRules = setTextStyles(content, item, fontObj);
+ setTextStyles(content, item, fontObj);
element.appendChild(content);
@@ -3452,54 +2037,20 @@ var TextWidgetAnnotation = (function TextWidgetAnnotationClosure() {
return Annotation.prototype.getOperatorList.call(this, evaluator);
}
- var promise = new LegacyPromise();
var opList = new OperatorList();
var data = this.data;
// Even if there is an appearance stream, ignore it. This is the
// behaviour used by Adobe Reader.
-
- var defaultAppearance = data.defaultAppearance;
- if (!defaultAppearance) {
- promise.resolve(opList);
- return promise;
+ if (!data.defaultAppearance) {
+ return Promise.resolve(opList);
}
- // Include any font resources found in the default appearance
-
- var stream = new Stream(stringToBytes(defaultAppearance));
- evaluator.getOperatorList(stream, this.fieldResources, opList);
- var appearanceFnArray = opList.fnArray;
- var appearanceArgsArray = opList.argsArray;
- var fnArray = [];
- var argsArray = [];
-
- // TODO(mack): Add support for stroke color
- data.rgb = [0, 0, 0];
- // TODO THIS DOESN'T MAKE ANY SENSE SINCE THE fnArray IS EMPTY!
- for (var i = 0, n = fnArray.length; i < n; ++i) {
- var fnId = appearanceFnArray[i];
- var args = appearanceArgsArray[i];
-
- if (fnId === OPS.setFont) {
- data.fontRefName = args[0];
- var size = args[1];
- if (size < 0) {
- data.fontDirection = -1;
- data.fontSize = -size;
- } else {
- data.fontDirection = 1;
- data.fontSize = size;
- }
- } else if (fnId === OPS.setFillRGBColor) {
- data.rgb = args;
- } else if (fnId === OPS.setFillGray) {
- var rgbValue = args[0] * 255;
- data.rgb = [rgbValue, rgbValue, rgbValue];
- }
- }
- promise.resolve(opList);
- return promise;
+ var stream = new Stream(stringToBytes(data.defaultAppearance));
+ return evaluator.getOperatorList(stream, this.fieldResources, opList).
+ then(function () {
+ return opList;
+ });
}
});
@@ -3580,6 +2131,8 @@ var TextAnnotation = (function TextAnnotationClosure() {
if (data.hasAppearance) {
data.name = 'NoIcon';
} else {
+ data.rect[1] = data.rect[3] - DEFAULT_ICON_SIZE;
+ data.rect[2] = data.rect[0] + DEFAULT_ICON_SIZE;
data.name = dict.has('Name') ? dict.get('Name').name : 'Note';
}
@@ -3627,10 +2180,12 @@ var TextAnnotation = (function TextAnnotationClosure() {
var content = document.createElement('div');
content.className = 'annotTextContent';
content.setAttribute('hidden', true);
+
+ var i, ii;
if (item.hasBgColor) {
var color = item.color;
var rgb = [];
- for (var i = 0; i < 3; ++i) {
+ for (i = 0; i < 3; ++i) {
// Enlighten the color (70%)
var c = Math.round(color[i] * 255);
rgb[i] = Math.round((255 - c) * 0.7) + c;
@@ -3647,7 +2202,7 @@ var TextAnnotation = (function TextAnnotationClosure() {
} else {
var e = document.createElement('span');
var lines = item.content.split(/(?:\r\n?|\n)/);
- for (var i = 0, ii = lines.length; i < ii; ++i) {
+ for (i = 0, ii = lines.length; i < ii; ++i) {
var line = lines[i];
e.appendChild(document.createTextNode(line));
if (i < (ii - 1)) {
@@ -3686,7 +2241,6 @@ var TextAnnotation = (function TextAnnotationClosure() {
}
};
- var self = this;
image.addEventListener('click', function image_clickHandler() {
toggleAnnotation();
}, false);
@@ -3791,7 +2345,6 @@ var LinkAnnotation = (function LinkAnnotationClosure() {
container.className = 'annotLink';
var item = this.data;
- var rect = item.rect;
container.style.borderColor = item.colorCssRgb;
container.style.borderStyle = 'solid';
@@ -4048,7 +2601,7 @@ var ChunkedStream = (function ChunkedStreamClosure() {
return this.numChunksLoaded === this.numChunks;
},
- onReceiveData: function(begin, chunk) {
+ onReceiveData: function ChunkedStream_onReceiveData(begin, chunk) {
var end = begin + chunk.byteLength;
assert(begin % this.chunkSize === 0, 'Bad begin offset: ' + begin);
@@ -4056,26 +2609,27 @@ var ChunkedStream = (function ChunkedStreamClosure() {
// See ChunkedStream.moveStart()
var length = this.bytes.length;
assert(end % this.chunkSize === 0 || end === length,
- 'Bad end offset: ' + end);
+ 'Bad end offset: ' + end);
this.bytes.set(new Uint8Array(chunk), begin);
var chunkSize = this.chunkSize;
var beginChunk = Math.floor(begin / chunkSize);
var endChunk = Math.floor((end - 1) / chunkSize) + 1;
+ var curChunk;
- for (var chunk = beginChunk; chunk < endChunk; ++chunk) {
- if (!(chunk in this.loadedChunks)) {
- this.loadedChunks[chunk] = true;
+ for (curChunk = beginChunk; curChunk < endChunk; ++curChunk) {
+ if (!(curChunk in this.loadedChunks)) {
+ this.loadedChunks[curChunk] = true;
++this.numChunksLoaded;
}
}
},
- onReceiveInitialData: function (data) {
+ onReceiveInitialData: function ChunkedStream_onReceiveInitialData(data) {
this.bytes.set(data);
this.initialDataLength = data.length;
- var endChunk = this.end === data.length ?
- this.numChunks : Math.floor(data.length / this.chunkSize);
+ var endChunk = (this.end === data.length ?
+ this.numChunks : Math.floor(data.length / this.chunkSize));
for (var i = 0; i < endChunk; i++) {
this.loadedChunks[i] = true;
++this.numChunksLoaded;
@@ -4102,13 +2656,14 @@ var ChunkedStream = (function ChunkedStreamClosure() {
},
nextEmptyChunk: function ChunkedStream_nextEmptyChunk(beginChunk) {
- for (var chunk = beginChunk, n = this.numChunks; chunk < n; ++chunk) {
+ var chunk, n;
+ for (chunk = beginChunk, n = this.numChunks; chunk < n; ++chunk) {
if (!(chunk in this.loadedChunks)) {
return chunk;
}
}
// Wrap around to beginning
- for (var chunk = 0; chunk < beginChunk; ++chunk) {
+ for (chunk = 0; chunk < beginChunk; ++chunk) {
if (!(chunk in this.loadedChunks)) {
return chunk;
}
@@ -4124,6 +2679,10 @@ var ChunkedStream = (function ChunkedStreamClosure() {
return this.end - this.start;
},
+ get isEmpty() {
+ return this.length === 0;
+ },
+
getByte: function ChunkedStream_getByte() {
var pos = this.pos;
if (pos >= this.end) {
@@ -4133,6 +2692,20 @@ var ChunkedStream = (function ChunkedStreamClosure() {
return this.bytes[this.pos++];
},
+ getUint16: function ChunkedStream_getUint16() {
+ var b0 = this.getByte();
+ var b1 = this.getByte();
+ return (b0 << 8) + b1;
+ },
+
+ getInt32: function ChunkedStream_getInt32() {
+ var b0 = this.getByte();
+ var b1 = this.getByte();
+ var b2 = this.getByte();
+ var b3 = this.getByte();
+ return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3;
+ },
+
// returns subarray of original buffer
// should only be read
getBytes: function ChunkedStream_getBytes(length) {
@@ -4146,8 +2719,9 @@ var ChunkedStream = (function ChunkedStreamClosure() {
}
var end = pos + length;
- if (end > strEnd)
+ if (end > strEnd) {
end = strEnd;
+ }
this.ensureRange(pos, end);
this.pos = end;
@@ -4166,8 +2740,9 @@ var ChunkedStream = (function ChunkedStreamClosure() {
},
skip: function ChunkedStream_skip(n) {
- if (!n)
+ if (!n) {
n = 1;
+ }
this.pos += n;
},
@@ -4212,7 +2787,6 @@ var ChunkedStream = (function ChunkedStreamClosure() {
var ChunkedStreamManager = (function ChunkedStreamManagerClosure() {
function ChunkedStreamManager(length, chunkSize, url, args) {
- var self = this;
this.stream = new ChunkedStream(length, chunkSize, this);
this.length = length;
this.chunkSize = chunkSize;
@@ -4250,7 +2824,8 @@ var ChunkedStreamManager = (function ChunkedStreamManagerClosure() {
this.requestsByChunk = {};
this.callbacksByRequest = {};
- this.loadedStream = new LegacyPromise();
+ this._loadedStreamCapability = createPromiseCapability();
+
if (args.initialData) {
this.setInitialData(args.initialData);
}
@@ -4261,7 +2836,7 @@ var ChunkedStreamManager = (function ChunkedStreamManagerClosure() {
setInitialData: function ChunkedStreamManager_setInitialData(data) {
this.stream.onReceiveInitialData(data);
if (this.stream.allChunksLoaded()) {
- this.loadedStream.resolve(this.stream);
+ this._loadedStreamCapability.resolve(this.stream);
} else if (this.msgHandler) {
this.msgHandler.send('DocProgress', {
loaded: data.length,
@@ -4271,7 +2846,7 @@ var ChunkedStreamManager = (function ChunkedStreamManagerClosure() {
},
onLoadedStream: function ChunkedStreamManager_getLoadedStream() {
- return this.loadedStream;
+ return this._loadedStreamCapability.promise;
},
// Get all the chunks that are not yet loaded and groups them into
@@ -4279,7 +2854,7 @@ var ChunkedStreamManager = (function ChunkedStreamManagerClosure() {
requestAllChunks: function ChunkedStreamManager_requestAllChunks() {
var missingChunks = this.stream.getMissingChunks();
this.requestChunks(missingChunks);
- return this.loadedStream;
+ return this._loadedStreamCapability.promise;
},
requestChunks: function ChunkedStreamManager_requestChunks(chunks,
@@ -4287,8 +2862,9 @@ var ChunkedStreamManager = (function ChunkedStreamManagerClosure() {
var requestId = this.currRequestId++;
var chunksNeeded;
+ var i, ii;
this.chunksNeededByRequest[requestId] = chunksNeeded = {};
- for (var i = 0, ii = chunks.length; i < ii; i++) {
+ for (i = 0, ii = chunks.length; i < ii; i++) {
if (!this.stream.hasChunk(chunks[i])) {
chunksNeeded[chunks[i]] = true;
}
@@ -4319,7 +2895,7 @@ var ChunkedStreamManager = (function ChunkedStreamManagerClosure() {
var groupedChunksToRequest = this.groupChunks(chunksToRequest);
- for (var i = 0; i < groupedChunksToRequest.length; ++i) {
+ for (i = 0; i < groupedChunksToRequest.length; ++i) {
var groupedChunk = groupedChunksToRequest[i];
var begin = groupedChunk.beginChunk * this.chunkSize;
var end = Math.min(groupedChunk.endChunk * this.chunkSize, this.length);
@@ -4381,13 +2957,13 @@ var ChunkedStreamManager = (function ChunkedStreamManagerClosure() {
}
if (prevChunk >= 0 && prevChunk + 1 !== chunk) {
- groupedChunks.push({
- beginChunk: beginChunk, endChunk: prevChunk + 1});
+ groupedChunks.push({ beginChunk: beginChunk,
+ endChunk: prevChunk + 1 });
beginChunk = chunk;
}
if (i + 1 === chunks.length) {
- groupedChunks.push({
- beginChunk: beginChunk, endChunk: chunk + 1});
+ groupedChunks.push({ beginChunk: beginChunk,
+ endChunk: chunk + 1 });
}
prevChunk = chunk;
@@ -4396,8 +2972,8 @@ var ChunkedStreamManager = (function ChunkedStreamManagerClosure() {
},
onProgress: function ChunkedStreamManager_onProgress(args) {
- var bytesLoaded = this.stream.numChunksLoaded * this.chunkSize +
- args.loaded;
+ var bytesLoaded = (this.stream.numChunksLoaded * this.chunkSize +
+ args.loaded);
this.msgHandler.send('DocProgress', {
loaded: bytesLoaded,
total: this.length
@@ -4414,18 +2990,18 @@ var ChunkedStreamManager = (function ChunkedStreamManagerClosure() {
this.stream.onReceiveData(begin, chunk);
if (this.stream.allChunksLoaded()) {
- this.loadedStream.resolve(this.stream);
+ this._loadedStreamCapability.resolve(this.stream);
}
var loadedRequests = [];
- for (var chunk = beginChunk; chunk < endChunk; ++chunk) {
-
+ var i, requestId;
+ for (chunk = beginChunk; chunk < endChunk; ++chunk) {
// The server might return more chunks than requested
var requestIds = this.requestsByChunk[chunk] || [];
delete this.requestsByChunk[chunk];
- for (var i = 0; i < requestIds.length; ++i) {
- var requestId = requestIds[i];
+ for (i = 0; i < requestIds.length; ++i) {
+ requestId = requestIds[i];
var chunksNeeded = this.chunksNeededByRequest[requestId];
if (chunk in chunksNeeded) {
delete chunksNeeded[chunk];
@@ -4459,8 +3035,8 @@ var ChunkedStreamManager = (function ChunkedStreamManagerClosure() {
}
}
- for (var i = 0; i < loadedRequests.length; ++i) {
- var requestId = loadedRequests[i];
+ for (i = 0; i < loadedRequests.length; ++i) {
+ requestId = loadedRequests[i];
var callback = this.callbacksByRequest[requestId];
delete this.callbacksByRequest[requestId];
if (callback) {
@@ -4474,6 +3050,10 @@ var ChunkedStreamManager = (function ChunkedStreamManagerClosure() {
});
},
+ onError: function ChunkedStreamManager_onError(err) {
+ this._loadedStreamCapability.reject(err);
+ },
+
getBeginChunk: function ChunkedStreamManager_getBeginChunk(begin) {
var chunk = Math.floor(begin / this.chunkSize);
return chunk;
@@ -4513,24 +3093,24 @@ var BasePdfManager = (function BasePdfManagerClosure() {
throw new NotImplementedException();
},
- ensureModel: function BasePdfManager_ensureModel(prop, args) {
- return this.ensure(this.pdfModel, prop, args);
+ ensureDoc: function BasePdfManager_ensureDoc(prop, args) {
+ return this.ensure(this.pdfDocument, prop, args);
},
ensureXRef: function BasePdfManager_ensureXRef(prop, args) {
- return this.ensure(this.pdfModel.xref, prop, args);
+ return this.ensure(this.pdfDocument.xref, prop, args);
},
ensureCatalog: function BasePdfManager_ensureCatalog(prop, args) {
- return this.ensure(this.pdfModel.catalog, prop, args);
+ return this.ensure(this.pdfDocument.catalog, prop, args);
},
getPage: function BasePdfManager_pagePage(pageIndex) {
- return this.pdfModel.getPage(pageIndex);
+ return this.pdfDocument.getPage(pageIndex);
},
cleanup: function BasePdfManager_cleanup() {
- return this.pdfModel.cleanup();
+ return this.pdfDocument.cleanup();
},
ensure: function BasePdfManager_ensure(obj, prop, args) {
@@ -4546,12 +3126,17 @@ var BasePdfManager = (function BasePdfManagerClosure() {
},
updatePassword: function BasePdfManager_updatePassword(password) {
- this.pdfModel.xref.password = this.password = password;
- if (this.passwordChangedPromise) {
- this.passwordChangedPromise.resolve();
+ this.pdfDocument.xref.password = this.password = password;
+ if (this._passwordChangedCapability) {
+ this._passwordChangedCapability.resolve();
}
},
+ passwordChanged: function BasePdfManager_passwordChanged() {
+ this._passwordChangedCapability = createPromiseCapability();
+ return this._passwordChangedCapability.promise;
+ },
+
terminate: function BasePdfManager_terminate() {
return new NotImplementedException();
}
@@ -4563,9 +3148,9 @@ var BasePdfManager = (function BasePdfManagerClosure() {
var LocalPdfManager = (function LocalPdfManagerClosure() {
function LocalPdfManager(data, password) {
var stream = new Stream(data);
- this.pdfModel = new PDFDocument(this, stream, password);
- this.loadedStream = new LegacyPromise();
- this.loadedStream.resolve(stream);
+ this.pdfDocument = new PDFDocument(this, stream, password);
+ this._loadedStreamCapability = createPromiseCapability();
+ this._loadedStreamCapability.resolve(stream);
}
LocalPdfManager.prototype = Object.create(BasePdfManager.prototype);
@@ -4573,28 +3158,25 @@ var LocalPdfManager = (function LocalPdfManagerClosure() {
LocalPdfManager.prototype.ensure =
function LocalPdfManager_ensure(obj, prop, args) {
- var promise = new LegacyPromise();
- try {
- var value = obj[prop];
- var result;
- if (typeof(value) === 'function') {
- result = value.apply(obj, args);
- } else {
- result = value;
+ return new Promise(function (resolve, reject) {
+ try {
+ var value = obj[prop];
+ var result;
+ if (typeof value === 'function') {
+ result = value.apply(obj, args);
+ } else {
+ result = value;
+ }
+ resolve(result);
+ } catch (e) {
+ reject(e);
}
- promise.resolve(result);
- } catch (e) {
- console.log(e.stack);
- promise.reject(e);
- }
- return promise;
+ });
};
LocalPdfManager.prototype.requestRange =
function LocalPdfManager_requestRange(begin, end) {
- var promise = new LegacyPromise();
- promise.resolve();
- return promise;
+ return Promise.resolve();
};
LocalPdfManager.prototype.requestLoadedStream =
@@ -4603,7 +3185,7 @@ var LocalPdfManager = (function LocalPdfManagerClosure() {
LocalPdfManager.prototype.onLoadedStream =
function LocalPdfManager_getLoadedStream() {
- return this.loadedStream;
+ return this._loadedStreamCapability.promise;
};
LocalPdfManager.prototype.terminate =
@@ -4630,7 +3212,7 @@ var NetworkPdfManager = (function NetworkPdfManagerClosure() {
this.streamManager = new ChunkedStreamManager(args.length, RANGE_CHUNK_SIZE,
args.url, params);
- this.pdfModel = new PDFDocument(this, this.streamManager.getStream(),
+ this.pdfDocument = new PDFDocument(this, this.streamManager.getStream(),
args.password);
}
@@ -4639,42 +3221,39 @@ var NetworkPdfManager = (function NetworkPdfManagerClosure() {
NetworkPdfManager.prototype.ensure =
function NetworkPdfManager_ensure(obj, prop, args) {
- var promise = new LegacyPromise();
- this.ensureHelper(promise, obj, prop, args);
- return promise;
- };
+ var pdfManager = this;
- NetworkPdfManager.prototype.ensureHelper =
- function NetworkPdfManager_ensureHelper(promise, obj, prop, args) {
- try {
- var result;
- var value = obj[prop];
- if (typeof(value) === 'function') {
- result = value.apply(obj, args);
- } else {
- result = value;
- }
- promise.resolve(result);
- } catch(e) {
- if (!(e instanceof MissingDataException)) {
- console.log(e.stack);
- promise.reject(e);
- return;
+ return new Promise(function (resolve, reject) {
+ function ensureHelper() {
+ try {
+ var result;
+ var value = obj[prop];
+ if (typeof value === 'function') {
+ result = value.apply(obj, args);
+ } else {
+ result = value;
+ }
+ resolve(result);
+ } catch(e) {
+ if (!(e instanceof MissingDataException)) {
+ reject(e);
+ return;
+ }
+ pdfManager.streamManager.requestRange(e.begin, e.end, ensureHelper);
+ }
}
- this.streamManager.requestRange(e.begin, e.end, function() {
- this.ensureHelper(promise, obj, prop, args);
- }.bind(this));
- }
+ ensureHelper();
+ });
};
NetworkPdfManager.prototype.requestRange =
function NetworkPdfManager_requestRange(begin, end) {
- var promise = new LegacyPromise();
- this.streamManager.requestRange(begin, end, function() {
- promise.resolve();
- });
- return promise;
+ return new Promise(function (resolve) {
+ this.streamManager.requestRange(begin, end, function() {
+ resolve();
+ });
+ }.bind(this));
};
NetworkPdfManager.prototype.requestLoadedStream =
@@ -4699,6 +3278,8 @@ var NetworkPdfManager = (function NetworkPdfManagerClosure() {
var Page = (function PageClosure() {
+ var LETTER_SIZE_MEDIABOX = [0, 0, 612, 792];
+
function Page(pdfManager, xref, pageIndex, pageDict, ref, fontCache) {
this.pdfManager = pdfManager;
this.pageIndex = pageIndex;
@@ -4716,51 +3297,69 @@ var Page = (function PageClosure() {
getPageProp: function Page_getPageProp(key) {
return this.pageDict.get(key);
},
- inheritPageProp: function Page_inheritPageProp(key) {
+
+ getInheritedPageProp: function Page_inheritPageProp(key) {
var dict = this.pageDict;
- var obj = dict.get(key);
- while (obj === undefined) {
+ var value = dict.get(key);
+ while (value === undefined) {
dict = dict.get('Parent');
- if (!dict)
+ if (!dict) {
break;
- obj = dict.get(key);
+ }
+ value = dict.get(key);
}
- return obj;
+ return value;
},
+
get content() {
return this.getPageProp('Contents');
},
+
get resources() {
- return shadow(this, 'resources', this.inheritPageProp('Resources'));
+ var value = this.getInheritedPageProp('Resources');
+ // For robustness: The spec states that a \Resources entry has to be
+ // present, but can be empty. Some document omit it still. In this case
+ // return an empty dictionary:
+ if (value === undefined) {
+ value = Dict.empty;
+ }
+ return shadow(this, 'resources', value);
},
+
get mediaBox() {
- var obj = this.inheritPageProp('MediaBox');
+ var obj = this.getInheritedPageProp('MediaBox');
// Reset invalid media box to letter size.
- if (!isArray(obj) || obj.length !== 4)
- obj = [0, 0, 612, 792];
+ if (!isArray(obj) || obj.length !== 4) {
+ obj = LETTER_SIZE_MEDIABOX;
+ }
return shadow(this, 'mediaBox', obj);
},
+
get view() {
var mediaBox = this.mediaBox;
- var cropBox = this.inheritPageProp('CropBox');
- if (!isArray(cropBox) || cropBox.length !== 4)
+ var cropBox = this.getInheritedPageProp('CropBox');
+ if (!isArray(cropBox) || cropBox.length !== 4) {
return shadow(this, 'view', mediaBox);
+ }
// 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)
+ if (!cropBox) {
return shadow(this, 'view', mediaBox);
-
+ }
return shadow(this, 'view', cropBox);
},
+
get annotationRefs() {
- return shadow(this, 'annotationRefs', this.inheritPageProp('Annots'));
+ return shadow(this, 'annotationRefs',
+ this.getInheritedPageProp('Annots'));
},
+
get rotate() {
- var rotate = this.inheritPageProp('Rotate') || 0;
+ var rotate = this.getInheritedPageProp('Rotate') || 0;
// Normalize rotation so it's a multiple of 90 and between 0 and 270
if (rotate % 90 !== 0) {
rotate = 0;
@@ -4773,6 +3372,7 @@ var Page = (function PageClosure() {
}
return shadow(this, 'rotate', rotate);
},
+
getContentStream: function Page_getContentStream() {
var content = this.content;
var stream;
@@ -4781,8 +3381,9 @@ var Page = (function PageClosure() {
var xref = this.xref;
var i, n = content.length;
var streams = [];
- for (i = 0; i < n; ++i)
+ for (i = 0; i < n; ++i) {
streams.push(xref.fetchIfRef(content[i]));
+ }
stream = new StreamsSequenceStream(streams);
} else if (isStream(content)) {
stream = content;
@@ -4792,31 +3393,22 @@ var Page = (function PageClosure() {
}
return stream;
},
- loadResources: function(keys) {
+
+ loadResources: function Page_loadResources(keys) {
if (!this.resourcesPromise) {
- // TODO: add async inheritPageProp and remove this.
+ // TODO: add async getInheritedPageProp and remove this.
this.resourcesPromise = this.pdfManager.ensure(this, 'resources');
}
- var promise = new LegacyPromise();
- this.resourcesPromise.then(function resourceSuccess() {
+ return this.resourcesPromise.then(function resourceSuccess() {
var objectLoader = new ObjectLoader(this.resources.map,
keys,
this.xref);
- objectLoader.load().then(function objectLoaderSuccess() {
- promise.resolve();
- });
+ return objectLoader.load();
}.bind(this));
- return promise;
},
+
getOperatorList: function Page_getOperatorList(handler, intent) {
var self = this;
- var promise = new LegacyPromise();
-
- function reject(e) {
- promise.reject(e);
- }
-
- var pageListPromise = new LegacyPromise();
var pdfManager = this.pdfManager;
var contentStreamPromise = pdfManager.ensure(this, 'getContentStream',
@@ -4827,22 +3419,20 @@ var Page = (function PageClosure() {
'Pattern',
'Shading',
'XObject',
- 'Font',
+ 'Font'
// ProcSet
// Properties
]);
- var partialEvaluator = new PartialEvaluator(
- pdfManager, this.xref, handler,
- this.pageIndex, 'p' + this.pageIndex + '_',
- this.idCounters, this.fontCache);
+ var partialEvaluator = new PartialEvaluator(pdfManager, this.xref,
+ handler, this.pageIndex,
+ 'p' + this.pageIndex + '_',
+ this.idCounters,
+ this.fontCache);
- var dataPromises = Promise.all(
- [contentStreamPromise, resourcesPromise], reject);
- dataPromises.then(function(data) {
+ var dataPromises = Promise.all([contentStreamPromise, resourcesPromise]);
+ var pageListPromise = dataPromises.then(function(data) {
var contentStream = data[0];
-
-
var opList = new OperatorList(intent, handler, self.pageIndex);
handler.send('StartRenderPage', {
@@ -4850,31 +3440,32 @@ var Page = (function PageClosure() {
pageIndex: self.pageIndex,
intent: intent
});
- partialEvaluator.getOperatorList(contentStream, self.resources, opList);
- pageListPromise.resolve(opList);
+ return partialEvaluator.getOperatorList(contentStream, self.resources,
+ opList).then(function () {
+ return opList;
+ });
});
var annotationsPromise = pdfManager.ensure(this, 'annotations');
- Promise.all([pageListPromise, annotationsPromise]).then(function(datas) {
+ return Promise.all([pageListPromise, annotationsPromise]).then(
+ function(datas) {
var pageOpList = datas[0];
var annotations = datas[1];
if (annotations.length === 0) {
pageOpList.flush(true);
- promise.resolve(pageOpList);
- return;
+ return pageOpList;
}
var annotationsReadyPromise = Annotation.appendToOperatorList(
annotations, pageOpList, pdfManager, partialEvaluator, intent);
- annotationsReadyPromise.then(function () {
+ return annotationsReadyPromise.then(function () {
pageOpList.flush(true);
- promise.resolve(pageOpList);
- }, reject);
- }, reject);
-
- return promise;
+ return pageOpList;
+ });
+ });
},
+
extractTextContent: function Page_extractTextContent() {
var handler = {
on: function nullHandlerOn() {},
@@ -4883,8 +3474,6 @@ var Page = (function PageClosure() {
var self = this;
- var textContentPromise = new LegacyPromise();
-
var pdfManager = this.pdfManager;
var contentStreamPromise = pdfManager.ensure(this, 'getContentStream',
[]);
@@ -4897,19 +3486,17 @@ var Page = (function PageClosure() {
var dataPromises = Promise.all([contentStreamPromise,
resourcesPromise]);
- dataPromises.then(function(data) {
+ return dataPromises.then(function(data) {
var contentStream = data[0];
- var partialEvaluator = new PartialEvaluator(
- pdfManager, self.xref, handler,
- self.pageIndex, 'p' + self.pageIndex + '_',
- self.idCounters, self.fontCache);
+ var partialEvaluator = new PartialEvaluator(pdfManager, self.xref,
+ handler, self.pageIndex,
+ 'p' + self.pageIndex + '_',
+ self.idCounters,
+ self.fontCache);
- var bidiTexts = partialEvaluator.getTextContent(contentStream,
- self.resources);
- textContentPromise.resolve(bidiTexts);
+ return partialEvaluator.getTextContent(contentStream,
+ self.resources);
});
-
- return textContentPromise;
},
getAnnotationsData: function Page_getAnnotationsData() {
@@ -4923,7 +3510,7 @@ var Page = (function PageClosure() {
get annotations() {
var annotations = [];
- var annotationRefs = this.annotationRefs || [];
+ var annotationRefs = (this.annotationRefs || []);
for (var i = 0, n = annotationRefs.length; i < n; ++i) {
var annotationRef = annotationRefs[i];
var annotation = Annotation.fromRef(this.xref, annotationRef);
@@ -4947,16 +3534,17 @@ var Page = (function PageClosure() {
*/
var PDFDocument = (function PDFDocumentClosure() {
function PDFDocument(pdfManager, arg, password) {
- if (isStream(arg))
+ if (isStream(arg)) {
init.call(this, pdfManager, arg, password);
- else if (isArrayBuffer(arg))
+ } else if (isArrayBuffer(arg)) {
init.call(this, pdfManager, new Stream(arg), password);
- else
+ } else {
error('PDFDocument: Unknown argument type');
+ }
}
function init(pdfManager, stream, password) {
- assertWellFormed(stream.length > 0, 'stream must have data');
+ assert(stream.length > 0, 'stream must have data');
this.pdfManager = pdfManager;
this.stream = stream;
var xref = new XRef(this.stream, password, pdfManager);
@@ -4967,16 +3555,18 @@ var PDFDocument = (function PDFDocumentClosure() {
var pos = stream.pos;
var end = stream.end;
var strBuf = [];
- if (pos + limit > end)
+ if (pos + limit > end) {
limit = end - pos;
+ }
for (var n = 0; n < limit; ++n) {
strBuf.push(String.fromCharCode(stream.getByte()));
}
var str = strBuf.join('');
stream.pos = pos;
var index = backwards ? str.lastIndexOf(needle) : str.indexOf(needle);
- if (index == -1)
+ if (index == -1) {
return false; /* not found */
+ }
stream.pos += index;
return true; /* found */
}
@@ -5049,16 +3639,18 @@ var PDFDocument = (function PDFDocumentClosure() {
if (linearization) {
// Find end of first obj.
stream.reset();
- if (find(stream, 'endobj', 1024))
+ if (find(stream, 'endobj', 1024)) {
startXRef = stream.pos + 6;
+ }
} else {
// Find startxref by jumping backward from the end of the file.
var step = 1024;
var found = false, pos = stream.end;
while (!found && pos > 0) {
pos -= step - 'startxref'.length;
- if (pos < 0)
+ if (pos < 0) {
pos = 0;
+ }
stream.pos = pos;
found = find(stream, 'startxref', step, true);
}
@@ -5074,8 +3666,9 @@ var PDFDocument = (function PDFDocumentClosure() {
ch = stream.getByte();
}
startXRef = parseInt(str, 10);
- if (isNaN(startXRef))
+ if (isNaN(startXRef)) {
startXRef = 0;
+ }
}
}
// shadow the prototype getter with a data property
@@ -5084,8 +3677,9 @@ var PDFDocument = (function PDFDocumentClosure() {
get mainXRefEntriesOffset() {
var mainXRefEntriesOffset = 0;
var linearization = this.linearization;
- if (linearization)
+ if (linearization) {
mainXRefEntriesOffset = linearization.mainXRefEntriesOffset;
+ }
// shadow the prototype getter with a data property
return shadow(this, 'mainXRefEntriesOffset', mainXRefEntriesOffset);
},
@@ -5146,8 +3740,8 @@ var PDFDocument = (function PDFDocumentClosure() {
var value = infoDict.get(key);
// Make sure the value conforms to the spec.
if (validEntries[key](value)) {
- docInfo[key] = typeof value !== 'string' ? value :
- stringToPDFString(value);
+ docInfo[key] = (typeof value !== 'string' ?
+ value : stringToPDFString(value));
} else {
info('Bad value in document info for "' + key + '"');
}
@@ -5197,7 +3791,7 @@ var Name = (function NameClosure() {
Name.get = function Name_get(name) {
var nameValue = nameCache[name];
- return nameValue ? nameValue : (nameCache[name] = new Name(name));
+ return (nameValue ? nameValue : (nameCache[name] = new Name(name)));
};
return Name;
@@ -5214,7 +3808,7 @@ var Cmd = (function CmdClosure() {
Cmd.get = function Cmd_get(cmd) {
var cmdValue = cmdCache[cmd];
- return cmdValue ? cmdValue : (cmdCache[cmd] = new Cmd(cmd));
+ return (cmdValue ? cmdValue : (cmdCache[cmd] = new Cmd(cmd)));
};
return Cmd;
@@ -5225,11 +3819,30 @@ var Dict = (function DictClosure() {
return nonSerializable; // creating closure on some variable
};
+ var GETALL_DICTIONARY_TYPES_WHITELIST = {
+ 'Background': true,
+ 'ExtGState': true,
+ 'Halftone': true,
+ 'Layout': true,
+ 'Mask': true,
+ 'Pagination': true,
+ 'Printing': true
+ };
+
+ function isRecursionAllowedFor(dict) {
+ if (!isName(dict.Type)) {
+ return true;
+ }
+ var dictType = dict.Type.name;
+ return GETALL_DICTIONARY_TYPES_WHITELIST[dictType] === true;
+ }
+
// xref is optional
function Dict(xref) {
// Map should only be used internally, use functions below to access.
this.map = Object.create(null);
this.xref = xref;
+ this.objId = null;
this.__nonSerializable__ = nonSerializable; // disable cloning of the Dict
}
@@ -5257,33 +3870,26 @@ var Dict = (function DictClosure() {
// Same as get(), but returns a promise and uses fetchIfRefAsync().
getAsync: function Dict_getAsync(key1, key2, key3) {
var value;
- var promise;
var xref = this.xref;
if (typeof (value = this.map[key1]) !== undefined || key1 in this.map ||
typeof key2 === undefined) {
if (xref) {
return xref.fetchIfRefAsync(value);
}
- promise = new LegacyPromise();
- promise.resolve(value);
- return promise;
+ return Promise.resolve(value);
}
if (typeof (value = this.map[key2]) !== undefined || key2 in this.map ||
typeof key3 === undefined) {
if (xref) {
return xref.fetchIfRefAsync(value);
}
- promise = new LegacyPromise();
- promise.resolve(value);
- return promise;
+ return Promise.resolve(value);
}
value = this.map[key3] || null;
if (xref) {
return xref.fetchIfRefAsync(value);
}
- promise = new LegacyPromise();
- promise.resolve(value);
- return promise;
+ return Promise.resolve(value);
},
// no dereferencing
@@ -5293,10 +3899,52 @@ var Dict = (function DictClosure() {
// creates new map and dereferences all Refs
getAll: function Dict_getAll() {
- var all = {};
- for (var key in this.map) {
- var obj = this.get(key);
- all[key] = obj instanceof Dict ? obj.getAll() : obj;
+ var all = Object.create(null);
+ var queue = null;
+ var key, obj;
+ for (key in this.map) {
+ obj = this.get(key);
+ if (obj instanceof Dict) {
+ if (isRecursionAllowedFor(obj)) {
+ (queue || (queue = [])).push({target: all, key: key, obj: obj});
+ } else {
+ all[key] = this.getRaw(key);
+ }
+ } else {
+ all[key] = obj;
+ }
+ }
+ if (!queue) {
+ return all;
+ }
+
+ // trying to take cyclic references into the account
+ var processed = Object.create(null);
+ while (queue.length > 0) {
+ var item = queue.shift();
+ var itemObj = item.obj;
+ var objId = itemObj.objId;
+ if (objId && objId in processed) {
+ item.target[item.key] = processed[objId];
+ continue;
+ }
+ var dereferenced = Object.create(null);
+ for (key in itemObj.map) {
+ obj = itemObj.get(key);
+ if (obj instanceof Dict) {
+ if (isRecursionAllowedFor(obj)) {
+ queue.push({target: dereferenced, key: key, obj: obj});
+ } else {
+ dereferenced[key] = itemObj.getRaw(key);
+ }
+ } else {
+ dereferenced[key] = obj;
+ }
+ }
+ if (objId) {
+ processed[objId] = dereferenced;
+ }
+ item.target[item.key] = dereferenced;
}
return all;
},
@@ -5316,6 +3964,8 @@ var Dict = (function DictClosure() {
}
};
+ Dict.empty = new Dict(null);
+
return Dict;
})();
@@ -5330,8 +3980,8 @@ var Ref = (function RefClosure() {
return Ref;
})();
-// The reference is identified by number and generation,
-// this structure stores only one instance of the reference.
+// The reference is identified by number and generation.
+// This structure stores only one instance of the reference.
var RefSet = (function RefSetClosure() {
function RefSet() {
this.dict = {};
@@ -5372,6 +4022,10 @@ var RefSetCache = (function RefSetCacheClosure() {
this.dict['R' + ref.num + '.' + ref.gen] = obj;
},
+ putAlias: function RefSetCache_putAlias(ref, aliasRef) {
+ this.dict['R' + ref.num + '.' + ref.gen] = this.get(aliasRef);
+ },
+
forEach: function RefSetCache_forEach(fn, thisArg) {
for (var i in this.dict) {
fn.call(thisArg, this.dict[i]);
@@ -5392,7 +4046,7 @@ var Catalog = (function CatalogClosure() {
this.xref = xref;
this.catDict = xref.getCatalogObj();
this.fontCache = new RefSetCache();
- assertWellFormed(isDict(this.catDict),
+ assert(isDict(this.catDict),
'catalog object is not a dictionary');
this.pagePromises = [];
@@ -5405,8 +4059,8 @@ var Catalog = (function CatalogClosure() {
return shadow(this, 'metadata', null);
}
- var encryptMetadata = !this.xref.encrypt ? false :
- this.xref.encrypt.encryptMetadata;
+ var encryptMetadata = (!this.xref.encrypt ? false :
+ this.xref.encrypt.encryptMetadata);
var stream = this.xref.fetch(streamRef, !encryptMetadata);
var metadata;
@@ -5433,7 +4087,7 @@ var Catalog = (function CatalogClosure() {
},
get toplevelPagesDict() {
var pagesObj = this.catDict.get('Pages');
- assertWellFormed(isDict(pagesObj), 'invalid top-level pages dictionary');
+ assert(isDict(pagesObj), 'invalid top-level pages dictionary');
// shadow the prototype getter
return shadow(this, 'toplevelPagesDict', pagesObj);
},
@@ -5503,11 +4157,11 @@ var Catalog = (function CatalogClosure() {
}
}
}
- return root.items.length > 0 ? root.items : null;
+ return (root.items.length > 0 ? root.items : null);
},
get numPages() {
var obj = this.toplevelPagesDict.get('Count');
- assertWellFormed(
+ assert(
isInt(obj),
'page count in top level pages object is not an integer'
);
@@ -5522,7 +4176,7 @@ var Catalog = (function CatalogClosure() {
var xref = this.xref;
var dests = {}, nameTreeRef, nameDictionaryRef;
var obj = this.catDict.get('Names');
- if (obj) {
+ if (obj && obj.has('Dests')) {
nameTreeRef = obj.getRaw('Dests');
} else if (this.catDict.has('Dests')) {
nameDictionaryRef = this.catDict.get('Dests');
@@ -5550,6 +4204,30 @@ var Catalog = (function CatalogClosure() {
}
return shadow(this, 'destinations', dests);
},
+ get attachments() {
+ var xref = this.xref;
+ var attachments = null, nameTreeRef;
+ var obj = this.catDict.get('Names');
+ if (obj) {
+ nameTreeRef = obj.getRaw('EmbeddedFiles');
+ }
+
+ if (nameTreeRef) {
+ var nameTree = new NameTree(nameTreeRef, xref);
+ var names = nameTree.getAll();
+ for (var name in names) {
+ if (!names.hasOwnProperty(name)) {
+ continue;
+ }
+ var fs = new FileSpec(names[name], xref);
+ if (!attachments) {
+ attachments = {};
+ }
+ attachments[stringToPDFString(name)] = fs.serializable;
+ }
+ }
+ return shadow(this, 'attachments', attachments);
+ },
get javaScript() {
var xref = this.xref;
var obj = this.catDict.get('Names');
@@ -5562,7 +4240,7 @@ var Catalog = (function CatalogClosure() {
if (!names.hasOwnProperty(name)) {
continue;
}
- // We don't really use the JavaScript right now so this code is
+ // We don't really use the JavaScript right now. This code is
// defensive so we don't cause errors on document load.
var jsDict = names[name];
if (!isDict(jsDict)) {
@@ -5582,15 +4260,37 @@ var Catalog = (function CatalogClosure() {
javaScript.push(stringToPDFString(js));
}
}
+
+ // Append OpenAction actions to javaScript array
+ var openactionDict = this.catDict.get('OpenAction');
+ if (isDict(openactionDict)) {
+ var objType = openactionDict.get('Type');
+ var actionType = openactionDict.get('S');
+ var action = openactionDict.get('N');
+ var isPrintAction = (isName(objType) && objType.name === 'Action' &&
+ isName(actionType) && actionType.name === 'Named' &&
+ isName(action) && action.name === 'Print');
+
+ if (isPrintAction) {
+ javaScript.push('print(true);');
+ }
+ }
+
return shadow(this, 'javaScript', javaScript);
},
cleanup: function Catalog_cleanup() {
- this.fontCache.forEach(function (font) {
- delete font.sent;
- delete font.translated;
+ var promises = [];
+ this.fontCache.forEach(function (promise) {
+ promises.push(promise);
});
- this.fontCache.clear();
+ return Promise.all(promises).then(function (translatedFonts) {
+ for (var i = 0, ii = translatedFonts.length; i < ii; i++) {
+ var font = translatedFonts[i].dict;
+ delete font.translated;
+ }
+ this.fontCache.clear();
+ }.bind(this));
},
getPage: function Catalog_getPage(pageIndex) {
@@ -5608,7 +4308,7 @@ var Catalog = (function CatalogClosure() {
},
getPageDict: function Catalog_getPageDict(pageIndex) {
- var promise = new LegacyPromise();
+ var capability = createPromiseCapability();
var nodesToVisit = [this.catDict.getRaw('Pages')];
var currentPageIndex = 0;
var xref = this.xref;
@@ -5621,7 +4321,7 @@ var Catalog = (function CatalogClosure() {
xref.fetchAsync(currentNode).then(function (obj) {
if ((isDict(obj, 'Page') || (isDict(obj) && !obj.has('Kids')))) {
if (pageIndex === currentPageIndex) {
- promise.resolve([obj, currentNode]);
+ capability.resolve([obj, currentNode]);
} else {
currentPageIndex++;
next();
@@ -5630,7 +4330,7 @@ var Catalog = (function CatalogClosure() {
}
nodesToVisit.push(obj);
next();
- }.bind(this), promise.reject.bind(promise));
+ }.bind(this), capability.reject.bind(capability));
return;
}
@@ -5665,10 +4365,10 @@ var Catalog = (function CatalogClosure() {
}
}
}
- promise.reject('Page index ' + pageIndex + ' not found.');
+ capability.reject('Page index ' + pageIndex + ' not found.');
}
next();
- return promise;
+ return capability.promise;
},
getPageIndex: function Catalog_getPageIndex(ref) {
@@ -5698,7 +4398,7 @@ var Catalog = (function CatalogClosure() {
var found = false;
for (var i = 0; i < kids.length; i++) {
var kid = kids[i];
- assert(isRef(kid), 'kids must be an ref');
+ assert(isRef(kid), 'kids must be a ref');
if (kid.num == kidRef.num) {
found = true;
break;
@@ -5743,7 +4443,6 @@ var Catalog = (function CatalogClosure() {
var XRef = (function XRefClosure() {
function XRef(stream, password) {
-
this.stream = stream;
this.entries = [];
this.xrefstms = {};
@@ -5773,8 +4472,8 @@ var XRef = (function XRefClosure() {
if (encrypt) {
var ids = trailerDict.get('ID');
var fileId = (ids && ids.length) ? ids[0] : '';
- this.encrypt = new CipherTransformFactory(
- encrypt, fileId, this.password);
+ this.encrypt = new CipherTransformFactory(encrypt, fileId,
+ this.password);
}
// get the root dictionary (catalog) object
@@ -5811,6 +4510,11 @@ var XRef = (function XRefClosure() {
// The parser goes through the entire stream << ... >> and provides
// a getter interface for the key-value table
var dict = parser.getObj();
+
+ // The pdflib PDF generator can generate a nested trailer dictionary
+ if (!isDict(dict) && dict.dict) {
+ dict = dict.dict;
+ }
if (!isDict(dict)) {
error('Invalid XRef table: could not parse trailer dictionary');
}
@@ -5865,16 +4569,17 @@ var XRef = (function XRefClosure() {
entry.gen = parser.getObj();
var type = parser.getObj();
- if (isCmd(type, 'f'))
+ if (isCmd(type, 'f')) {
entry.free = true;
- else if (isCmd(type, 'n'))
+ } else if (isCmd(type, 'n')) {
entry.uncompressed = true;
+ }
// Validate entry obj
if (!isInt(entry.offset) || !isInt(entry.gen) ||
!(entry.free || entry.uncompressed)) {
console.log(entry.offset, entry.gen, entry.free,
- entry.uncompressed);
+ entry.uncompressed);
error('Invalid entry in XRef subsection: ' + first + ', ' + count);
}
@@ -5940,7 +4645,6 @@ var XRef = (function XRefClosure() {
var entryRanges = streamState.entryRanges;
while (entryRanges.length > 0) {
-
var first = entryRanges[0];
var n = entryRanges[1];
@@ -5956,9 +4660,10 @@ var XRef = (function XRefClosure() {
streamState.streamPos = stream.pos;
var type = 0, offset = 0, generation = 0;
- for (j = 0; j < typeFieldWidth; ++j)
+ for (j = 0; j < typeFieldWidth; ++j) {
type = (type << 8) | stream.getByte();
- // if type field is absent, its default value = 1
+ }
+ // if type field is absent, its default value is 1
if (typeFieldWidth === 0) {
type = 1;
}
@@ -6000,8 +4705,9 @@ var XRef = (function XRefClosure() {
function readToken(data, offset) {
var token = '', ch = data[offset];
while (ch !== 13 && ch !== 10) {
- if (++offset >= data.length)
+ if (++offset >= data.length) {
break;
+ }
token += String.fromCharCode(ch);
ch = data[offset];
}
@@ -6016,9 +4722,9 @@ var XRef = (function XRefClosure() {
while (i < length && data[offset + i] == what[i]) {
++i;
}
- if (i >= length)
+ if (i >= length) {
break; // sequence found
-
+ }
offset++;
skipped++;
}
@@ -6035,8 +4741,6 @@ var XRef = (function XRefClosure() {
var buffer = stream.getBytes();
var position = stream.start, length = buffer.length;
var trailers = [], xrefStms = [];
- var state = 0;
- var currentToken;
while (position < length) {
var ch = buffer[position];
if (ch === 32 || ch === 9 || ch === 13 || ch === 10) {
@@ -6084,13 +4788,14 @@ var XRef = (function XRefClosure() {
}
}
// reading XRef streams
- for (var i = 0, ii = xrefStms.length; i < ii; ++i) {
+ var i, ii;
+ for (i = 0, ii = xrefStms.length; i < ii; ++i) {
this.startXRefQueue.push(xrefStms[i]);
this.readXRef(/* recoveryMode */ true);
}
// finding main trailer
var dict;
- for (var i = 0, ii = trailers.length; i < ii; ++i) {
+ for (i = 0, ii = trailers.length; i < ii; ++i) {
stream.pos = trailers[i];
var parser = new Parser(new Lexer(stream), true, null);
var obj = parser.getObj();
@@ -6130,7 +4835,6 @@ var XRef = (function XRefClosure() {
// Get dictionary
if (isCmd(obj, 'xref')) {
-
// Parse end-of-file XRef
dict = this.processXRefTable(parser);
if (!this.topDict) {
@@ -6149,7 +4853,6 @@ var XRef = (function XRefClosure() {
}
}
} else if (isInt(obj)) {
-
// Parse in-stream XRef
if (!isInt(parser.getObj()) ||
!isCmd(parser.getObj(), 'obj') ||
@@ -6160,7 +4863,6 @@ var XRef = (function XRefClosure() {
if (!this.topDict) {
this.topDict = dict;
}
-
if (!dict) {
error('Failed to read XRef stream');
}
@@ -6197,7 +4899,7 @@ var XRef = (function XRefClosure() {
getEntry: function XRef_getEntry(i) {
var xrefEntry = this.entries[i];
- if (xrefEntry !== null && !xrefEntry.free && xrefEntry.offset) {
+ if (xrefEntry && !xrefEntry.free && xrefEntry.offset) {
return xrefEntry;
}
return null;
@@ -6211,7 +4913,7 @@ var XRef = (function XRefClosure() {
},
fetch: function XRef_fetch(ref, suppressEncryption) {
- assertWellFormed(isRef(ref), 'ref object is not a reference');
+ assert(isRef(ref), 'ref object is not a reference');
var num = ref.num;
if (num in this.cache) {
var cacheEntry = this.cache[num];
@@ -6226,14 +4928,18 @@ var XRef = (function XRefClosure() {
}
if (xrefEntry.uncompressed) {
- return this.fetchUncompressed(ref, xrefEntry, suppressEncryption);
+ xrefEntry = this.fetchUncompressed(ref, xrefEntry, suppressEncryption);
} else {
- return this.fetchCompressed(xrefEntry, suppressEncryption);
+ xrefEntry = this.fetchCompressed(xrefEntry, suppressEncryption);
+ }
+
+ if (isDict(xrefEntry)) {
+ xrefEntry.objId = 'R' + ref.num + '.' + ref.gen;
}
+ return xrefEntry;
},
- fetchUncompressed: function XRef_fetchUncompressed(ref,
- xrefEntry,
+ fetchUncompressed: function XRef_fetchUncompressed(ref, xrefEntry,
suppressEncryption) {
var gen = ref.gen;
var num = ref.num;
@@ -6252,7 +4958,7 @@ var XRef = (function XRefClosure() {
error('bad XRef entry');
}
if (!isCmd(obj3, 'obj')) {
- // some bad pdfs use "obj1234" and really mean 1234
+ // some bad PDFs use "obj1234" and really mean 1234
if (obj3.cmd.indexOf('obj') === 0) {
num = parseInt(obj3.cmd.substring(3), 10);
if (!isNaN(num)) {
@@ -6266,9 +4972,9 @@ var XRef = (function XRefClosure() {
xrefEntry = parser.getObj(this.encrypt.createCipherTransform(num,
gen));
} catch (ex) {
- // almost all streams must be encrypted, but sometimes
- // they are not probably due to some broken generators
- // re-trying without encryption
+ // Almost all streams must be encrypted, but sometimes
+ // they are not, probably due to some broken generators.
+ // Retrying without encryption...
return this.fetch(ref, true);
}
} else {
@@ -6325,29 +5031,27 @@ var XRef = (function XRefClosure() {
fetchIfRefAsync: function XRef_fetchIfRefAsync(obj) {
if (!isRef(obj)) {
- var promise = new LegacyPromise();
- promise.resolve(obj);
- return promise;
+ return Promise.resolve(obj);
}
return this.fetchAsync(obj);
},
fetchAsync: function XRef_fetchAsync(ref, suppressEncryption) {
- var promise = new LegacyPromise();
- var tryFetch = function (promise) {
- try {
- promise.resolve(this.fetch(ref, suppressEncryption));
- } catch (e) {
- if (e instanceof MissingDataException) {
- this.stream.manager.requestRange(e.begin, e.end, tryFetch);
- return;
- }
- promise.reject(e);
- }
- }.bind(this, promise);
- tryFetch();
- return promise;
- },
+ return new Promise(function (resolve, reject) {
+ var tryFetch = function () {
+ try {
+ resolve(this.fetch(ref, suppressEncryption));
+ } catch (e) {
+ if (e instanceof MissingDataException) {
+ this.stream.manager.requestRange(e.begin, e.end, tryFetch);
+ return;
+ }
+ reject(e);
+ }
+ }.bind(this);
+ tryFetch();
+ }.bind(this));
+ },
getCatalogObj: function XRef_getCatalogObj() {
return this.root;
@@ -6358,8 +5062,8 @@ var XRef = (function XRefClosure() {
})();
/**
- * A NameTree is like a Dict but has some adventagous properties, see the spec
- * (7.9.6) for more details.
+ * A NameTree is like a Dict but has some advantageous properties, see the
+ * spec (7.9.6) for more details.
* TODO: implement all the Dict functions and make this more efficent.
*/
var NameTree = (function NameTreeClosure() {
@@ -6411,6 +5115,97 @@ var NameTree = (function NameTreeClosure() {
})();
/**
+ * "A PDF file can refer to the contents of another file by using a File
+ * Specification (PDF 1.1)", see the spec (7.11) for more details.
+ * NOTE: Only embedded files are supported (as part of the attachments support)
+ * TODO: support the 'URL' file system (with caching if !/V), portable
+ * collections attributes and related files (/RF)
+ */
+var FileSpec = (function FileSpecClosure() {
+ function FileSpec(root, xref) {
+ if (!root || !isDict(root)) {
+ return;
+ }
+ this.xref = xref;
+ this.root = root;
+ if (root.has('FS')) {
+ this.fs = root.get('FS');
+ }
+ this.description = root.has('Desc') ?
+ stringToPDFString(root.get('Desc')) :
+ '';
+ if (root.has('RF')) {
+ warn('Related file specifications are not supported');
+ }
+ this.contentAvailable = true;
+ if (!root.has('EF')) {
+ this.contentAvailable = false;
+ warn('Non-embedded file specifications are not supported');
+ }
+ }
+
+ function pickPlatformItem(dict) {
+ // Look for the filename in this order:
+ // UF, F, Unix, Mac, DOS
+ if (dict.has('UF')) {
+ return dict.get('UF');
+ } else if (dict.has('F')) {
+ return dict.get('F');
+ } else if (dict.has('Unix')) {
+ return dict.get('Unix');
+ } else if (dict.has('Mac')) {
+ return dict.get('Mac');
+ } else if (dict.has('DOS')) {
+ return dict.get('DOS');
+ } else {
+ return null;
+ }
+ }
+
+ FileSpec.prototype = {
+ get filename() {
+ if (!this._filename && this.root) {
+ var filename = pickPlatformItem(this.root) || 'unnamed';
+ this._filename = stringToPDFString(filename).
+ replace(/\\\\/g, '\\').
+ replace(/\\\//g, '/').
+ replace(/\\/g, '/');
+ }
+ return this._filename;
+ },
+ get content() {
+ if (!this.contentAvailable) {
+ return null;
+ }
+ if (!this.contentRef && this.root) {
+ this.contentRef = pickPlatformItem(this.root.get('EF'));
+ }
+ var content = null;
+ if (this.contentRef) {
+ var xref = this.xref;
+ var fileObj = xref.fetchIfRef(this.contentRef);
+ if (fileObj && isStream(fileObj)) {
+ content = fileObj.getBytes();
+ } else {
+ warn('Embedded file specification points to non-existing/invalid ' +
+ 'content');
+ }
+ } else {
+ warn('Embedded file specification does not have a content');
+ }
+ return content;
+ },
+ get serializable() {
+ return {
+ filename: this.filename,
+ content: this.content
+ };
+ }
+ };
+ return FileSpec;
+})();
+
+/**
* A helper for loading missing data in object graphs. It traverses the graph
* depth first and queues up any objects that have missing data. Once it has
* has traversed as many objects that are available it attempts to bundle the
@@ -6422,12 +5217,12 @@ var NameTree = (function NameTreeClosure() {
* entire PDF document object graph to be traversed.
*/
var ObjectLoader = (function() {
-
function mayHaveChildren(value) {
return isRef(value) || isDict(value) || isArray(value) || isStream(value);
}
function addChildren(node, nodesToVisit) {
+ var value;
if (isDict(node) || isStream(node)) {
var map;
if (isDict(node)) {
@@ -6436,14 +5231,14 @@ var ObjectLoader = (function() {
map = node.dict.map;
}
for (var key in map) {
- var value = map[key];
+ value = map[key];
if (mayHaveChildren(value)) {
nodesToVisit.push(value);
}
}
} else if (isArray(node)) {
for (var i = 0, ii = node.length; i < ii; i++) {
- var value = node[i];
+ value = node[i];
if (mayHaveChildren(value)) {
nodesToVisit.push(value);
}
@@ -6459,15 +5254,14 @@ var ObjectLoader = (function() {
}
ObjectLoader.prototype = {
-
load: function ObjectLoader_load() {
var keys = this.keys;
- this.promise = new LegacyPromise();
+ this.capability = createPromiseCapability();
// Don't walk the graph if all the data is already loaded.
if (!(this.xref.stream instanceof ChunkedStream) ||
this.xref.stream.getMissingChunks().length === 0) {
- this.promise.resolve();
- return this.promise;
+ this.capability.resolve();
+ return this.capability.promise;
}
this.refSet = new RefSet();
@@ -6478,7 +5272,7 @@ var ObjectLoader = (function() {
}
this.walk(nodesToVisit);
- return this.promise;
+ return this.capability.promise;
},
walk: function ObjectLoader_walk(nodesToVisit) {
@@ -6545,9 +5339,8 @@ var ObjectLoader = (function() {
}
// Everything is loaded.
this.refSet = null;
- this.promise.resolve();
+ this.capability.resolve();
}
-
};
return ObjectLoader;
@@ -13587,6 +12380,1644 @@ var CIDToUnicodeMaps = {
+var PDFFunction = (function PDFFunctionClosure() {
+ var CONSTRUCT_SAMPLED = 0;
+ var CONSTRUCT_INTERPOLATED = 2;
+ var CONSTRUCT_STICHED = 3;
+ var CONSTRUCT_POSTSCRIPT = 4;
+
+ return {
+ getSampleArray: function PDFFunction_getSampleArray(size, outputSize, bps,
+ str) {
+ var i, ii;
+ var length = 1;
+ for (i = 0, ii = size.length; i < ii; i++) {
+ length *= size[i];
+ }
+ length *= outputSize;
+
+ var array = [];
+ var codeSize = 0;
+ var codeBuf = 0;
+ // 32 is a valid bps so shifting won't work
+ var sampleMul = 1.0 / (Math.pow(2.0, bps) - 1);
+
+ var strBytes = str.getBytes((length * bps + 7) / 8);
+ var strIdx = 0;
+ for (i = 0; i < length; i++) {
+ while (codeSize < bps) {
+ codeBuf <<= 8;
+ codeBuf |= strBytes[strIdx++];
+ codeSize += 8;
+ }
+ codeSize -= bps;
+ array.push((codeBuf >> codeSize) * sampleMul);
+ codeBuf &= (1 << codeSize) - 1;
+ }
+ return array;
+ },
+
+ getIR: function PDFFunction_getIR(xref, fn) {
+ var dict = fn.dict;
+ if (!dict) {
+ dict = fn;
+ }
+
+ var types = [this.constructSampled,
+ null,
+ this.constructInterpolated,
+ this.constructStiched,
+ this.constructPostScript];
+
+ var typeNum = dict.get('FunctionType');
+ var typeFn = types[typeNum];
+ if (!typeFn) {
+ error('Unknown type of function');
+ }
+
+ return typeFn.call(this, fn, dict, xref);
+ },
+
+ fromIR: function PDFFunction_fromIR(IR) {
+ var type = IR[0];
+ switch (type) {
+ case CONSTRUCT_SAMPLED:
+ return this.constructSampledFromIR(IR);
+ case CONSTRUCT_INTERPOLATED:
+ return this.constructInterpolatedFromIR(IR);
+ case CONSTRUCT_STICHED:
+ return this.constructStichedFromIR(IR);
+ //case CONSTRUCT_POSTSCRIPT:
+ default:
+ return this.constructPostScriptFromIR(IR);
+ }
+ },
+
+ parse: function PDFFunction_parse(xref, fn) {
+ var IR = this.getIR(xref, fn);
+ return this.fromIR(IR);
+ },
+
+ constructSampled: function PDFFunction_constructSampled(str, dict) {
+ function toMultiArray(arr) {
+ var inputLength = arr.length;
+ var out = [];
+ var index = 0;
+ for (var i = 0; i < inputLength; i += 2) {
+ out[index] = [arr[i], arr[i + 1]];
+ ++index;
+ }
+ return out;
+ }
+ var domain = dict.get('Domain');
+ var range = dict.get('Range');
+
+ if (!domain || !range) {
+ error('No domain or range');
+ }
+
+ var inputSize = domain.length / 2;
+ var outputSize = range.length / 2;
+
+ domain = toMultiArray(domain);
+ range = toMultiArray(range);
+
+ var size = dict.get('Size');
+ var bps = dict.get('BitsPerSample');
+ var order = dict.get('Order') || 1;
+ if (order !== 1) {
+ // No description how cubic spline interpolation works in PDF32000:2008
+ // As in poppler, ignoring order, linear interpolation may work as good
+ info('No support for cubic spline interpolation: ' + order);
+ }
+
+ var encode = dict.get('Encode');
+ if (!encode) {
+ encode = [];
+ for (var i = 0; i < inputSize; ++i) {
+ encode.push(0);
+ encode.push(size[i] - 1);
+ }
+ }
+ encode = toMultiArray(encode);
+
+ var decode = dict.get('Decode');
+ if (!decode) {
+ decode = range;
+ } else {
+ decode = toMultiArray(decode);
+ }
+
+ var samples = this.getSampleArray(size, outputSize, bps, str);
+
+ return [
+ CONSTRUCT_SAMPLED, inputSize, domain, encode, decode, samples, size,
+ outputSize, Math.pow(2, bps) - 1, range
+ ];
+ },
+
+ constructSampledFromIR: function PDFFunction_constructSampledFromIR(IR) {
+ // 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 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: ' + m + ' != ' +
+ args.length);
+ }
+
+ var x = args;
+
+ // 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);
+ var i, j;
+ for (j = 0; j < cubeVertices; j++) {
+ cubeN[j] = 1;
+ }
+
+ var k = n, pos = 1;
+ // Map x_i to y_j for 0 <= i < m using the sampled function.
+ for (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 (j = 0; j < cubeVertices; j++) {
+ if (j & pos) {
+ cubeN[j] *= n1;
+ cubeVertex[j] += offset1;
+ } else {
+ cubeN[j] *= n0;
+ cubeVertex[j] += offset0;
+ }
+ }
+
+ k *= size_i;
+ pos <<= 1;
+ }
+
+ var y = new Float64Array(n);
+ for (j = 0; j < n; ++j) {
+ // Sum all cube vertices' samples portions
+ var rj = 0;
+ for (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;
+ };
+ },
+
+ constructInterpolated: function PDFFunction_constructInterpolated(str,
+ dict) {
+ var c0 = dict.get('C0') || [0];
+ var c1 = dict.get('C1') || [1];
+ var n = dict.get('N');
+
+ if (!isArray(c0) || !isArray(c1)) {
+ error('Illegal dictionary for interpolated function');
+ }
+
+ var length = c0.length;
+ var diff = [];
+ for (var i = 0; i < length; ++i) {
+ diff.push(c1[i] - c0[i]);
+ }
+
+ return [CONSTRUCT_INTERPOLATED, c0, diff, n];
+ },
+
+ constructInterpolatedFromIR:
+ function PDFFunction_constructInterpolatedFromIR(IR) {
+ var c0 = IR[1];
+ var diff = IR[2];
+ var n = IR[3];
+
+ var length = diff.length;
+
+ return function constructInterpolatedFromIRResult(args) {
+ var x = n == 1 ? args[0] : Math.pow(args[0], n);
+
+ var out = [];
+ for (var j = 0; j < length; ++j) {
+ out.push(c0[j] + (x * diff[j]));
+ }
+
+ return out;
+
+ };
+ },
+
+ constructStiched: function PDFFunction_constructStiched(fn, dict, xref) {
+ var domain = dict.get('Domain');
+
+ if (!domain) {
+ error('No domain');
+ }
+
+ var inputSize = domain.length / 2;
+ if (inputSize != 1) {
+ error('Bad domain for stiched function');
+ }
+
+ var fnRefs = dict.get('Functions');
+ var fns = [];
+ for (var i = 0, ii = fnRefs.length; i < ii; ++i) {
+ fns.push(PDFFunction.getIR(xref, xref.fetchIfRef(fnRefs[i])));
+ }
+
+ var bounds = dict.get('Bounds');
+ var encode = dict.get('Encode');
+
+ return [CONSTRUCT_STICHED, domain, bounds, encode, fns];
+ },
+
+ constructStichedFromIR: function PDFFunction_constructStichedFromIR(IR) {
+ var domain = IR[1];
+ var bounds = IR[2];
+ var encode = IR[3];
+ var fnsIR = IR[4];
+ var fns = [];
+
+ for (var i = 0, ii = fnsIR.length; i < ii; i++) {
+ fns.push(PDFFunction.fromIR(fnsIR[i]));
+ }
+
+ return function constructStichedFromIRResult(args) {
+ var clip = function constructStichedFromIRClip(v, min, max) {
+ if (v > max) {
+ v = max;
+ } else if (v < min) {
+ v = min;
+ }
+ return v;
+ };
+
+ // clip to domain
+ var v = clip(args[0], domain[0], domain[1]);
+ // calulate which bound the value is in
+ for (var i = 0, ii = bounds.length; i < ii; ++i) {
+ if (v < bounds[i]) {
+ break;
+ }
+ }
+
+ // encode value into domain of function
+ var dmin = domain[0];
+ if (i > 0) {
+ dmin = bounds[i - 1];
+ }
+ var dmax = domain[1];
+ if (i < bounds.length) {
+ dmax = bounds[i];
+ }
+
+ var rmin = encode[2 * i];
+ var rmax = encode[2 * i + 1];
+
+ var v2 = rmin + (v - dmin) * (rmax - rmin) / (dmax - dmin);
+
+ // call the appropriate function
+ return fns[i]([v2]);
+ };
+ },
+
+ constructPostScript: function PDFFunction_constructPostScript(fn, dict,
+ 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 PDFFunction_constructPostScriptFromIR(
+ IR) {
+ var domain = IR[1];
+ var range = IR[2];
+ var code = IR[3];
+ var numOutputs = range.length >> 1;
+ var numInputs = domain.length >> 1;
+ 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 = {};
+ // The MAX_CACHE_SIZE is set to ~4x the maximum number of distinct values
+ // seen in our tests.
+ var MAX_CACHE_SIZE = 2048 * 4;
+ var cache_available = MAX_CACHE_SIZE;
+ return function constructPostScriptFromIRResult(args) {
+ var i, value;
+ var key = '';
+ var input = new Array(numInputs);
+ for (i = 0; i < numInputs; i++) {
+ value = args[i];
+ input[i] = value;
+ key += value + '_';
+ }
+
+ var cachedValue = cache[key];
+ if (cachedValue !== undefined) {
+ return cachedValue;
+ }
+
+ var output = new Array(numOutputs);
+ var stack = evaluator.execute(input);
+ var stackIndex = stack.length - numOutputs;
+ for (i = 0; i < numOutputs; i++) {
+ value = stack[stackIndex + i];
+ var bound = range[i * 2];
+ if (value < bound) {
+ value = bound;
+ } else {
+ bound = range[i * 2 +1];
+ if (value > bound) {
+ value = bound;
+ }
+ }
+ output[i] = value;
+ }
+ if (cache_available > 0) {
+ cache_available--;
+ cache[key] = output;
+ }
+ return output;
+ };
+ }
+ };
+})();
+
+function isPDFFunction(v) {
+ var fnDict;
+ if (typeof v != 'object') {
+ return false;
+ } else if (isDict(v)) {
+ fnDict = v;
+ } else if (isStream(v)) {
+ fnDict = v.dict;
+ } else {
+ return false;
+ }
+ return fnDict.has('FunctionType');
+}
+
+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) {
+ this.operators = operators;
+ }
+ 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(-a);
+ break;
+ case 'not':
+ a = stack.pop();
+ if (isBool(a)) {
+ stack.push(!a);
+ } else {
+ stack.push(~a);
+ }
+ 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 ColorSpace = (function ColorSpaceClosure() {
+ // Constructor should define this.numComps, this.defaultColor, this.name
+ function ColorSpace() {
+ error('should not call ColorSpace constructor');
+ }
+
+ ColorSpace.prototype = {
+ /**
+ * Converts the color value to the RGB color. The color components are
+ * located in the src array starting from the srcOffset. Returns the array
+ * of the rgb components, each value ranging from [0,255].
+ */
+ getRgb: function ColorSpace_getRgb(src, srcOffset) {
+ var rgb = new Uint8Array(3);
+ this.getRgbItem(src, srcOffset, rgb, 0);
+ return rgb;
+ },
+ /**
+ * Converts the color value to the RGB color, similar to the getRgb method.
+ * The result placed into the dest array starting from the destOffset.
+ */
+ getRgbItem: function ColorSpace_getRgbItem(src, srcOffset,
+ dest, destOffset) {
+ error('Should not call ColorSpace.getRgbItem');
+ },
+ /**
+ * Converts the specified number of the color values to the RGB colors.
+ * The colors are located in the src array starting from the srcOffset.
+ * The result is placed into the dest array starting from the destOffset.
+ * The src array items shall be in [0,2^bits) range, the dest array items
+ * will be in [0,255] range. alpha01 indicates how many alpha components
+ * there are in the dest array; it will be either 0 (RGB array) or 1 (RGBA
+ * array).
+ */
+ getRgbBuffer: function ColorSpace_getRgbBuffer(src, srcOffset, count,
+ dest, destOffset, bits,
+ alpha01) {
+ error('Should not call ColorSpace.getRgbBuffer');
+ },
+ /**
+ * Determines the number of bytes required to store the result of the
+ * conversion done by the getRgbBuffer method. As in getRgbBuffer,
+ * |alpha01| is either 0 (RGB output) or 1 (RGBA output).
+ */
+ getOutputLength: function ColorSpace_getOutputLength(inputLength,
+ alpha01) {
+ error('Should not call ColorSpace.getOutputLength');
+ },
+ /**
+ * Returns true if source data will be equal the result/output data.
+ */
+ isPassthrough: function ColorSpace_isPassthrough(bits) {
+ return false;
+ },
+ /**
+ * Fills in the RGB colors in the destination buffer. alpha01 indicates
+ * how many alpha components there are in the dest array; it will be either
+ * 0 (RGB array) or 1 (RGBA array).
+ */
+ fillRgb: function ColorSpace_fillRgb(dest, originalWidth,
+ originalHeight, width, height,
+ actualHeight, bpc, comps, alpha01) {
+ var count = originalWidth * originalHeight;
+ var rgbBuf = null;
+ var numComponentColors = 1 << bpc;
+ var needsResizing = originalHeight != height || originalWidth != width;
+ var i, ii;
+
+ if (this.isPassthrough(bpc)) {
+ rgbBuf = comps;
+ } else if (this.numComps === 1 && count > numComponentColors &&
+ this.name !== 'DeviceGray' && this.name !== 'DeviceRGB') {
+ // Optimization: create a color map when there is just one component and
+ // we are converting more colors than the size of the color map. We
+ // don't build the map if the colorspace is gray or rgb since those
+ // methods are faster than building a map. This mainly offers big speed
+ // ups for indexed and alternate colorspaces.
+ //
+ // TODO it may be worth while to cache the color map. While running
+ // testing I never hit a cache so I will leave that out for now (perhaps
+ // we are reparsing colorspaces too much?).
+ var allColors = bpc <= 8 ? new Uint8Array(numComponentColors) :
+ new Uint16Array(numComponentColors);
+ var key;
+ for (i = 0; i < numComponentColors; i++) {
+ allColors[i] = i;
+ }
+ var colorMap = new Uint8Array(numComponentColors * 3);
+ this.getRgbBuffer(allColors, 0, numComponentColors, colorMap, 0, bpc,
+ /* alpha01 = */ 0);
+
+ var destPos, rgbPos;
+ if (!needsResizing) {
+ // Fill in the RGB values directly into |dest|.
+ destPos = 0;
+ for (i = 0; i < count; ++i) {
+ key = comps[i] * 3;
+ dest[destPos++] = colorMap[key];
+ dest[destPos++] = colorMap[key + 1];
+ dest[destPos++] = colorMap[key + 2];
+ destPos += alpha01;
+ }
+ } else {
+ rgbBuf = new Uint8Array(count * 3);
+ rgbPos = 0;
+ for (i = 0; i < count; ++i) {
+ key = comps[i] * 3;
+ rgbBuf[rgbPos++] = colorMap[key];
+ rgbBuf[rgbPos++] = colorMap[key + 1];
+ rgbBuf[rgbPos++] = colorMap[key + 2];
+ }
+ }
+ } else {
+ if (!needsResizing) {
+ // Fill in the RGB values directly into |dest|.
+ this.getRgbBuffer(comps, 0, width * actualHeight, dest, 0, bpc,
+ alpha01);
+ } else {
+ rgbBuf = new Uint8Array(count * 3);
+ this.getRgbBuffer(comps, 0, count, rgbBuf, 0, bpc,
+ /* alpha01 = */ 0);
+ }
+ }
+
+ if (rgbBuf) {
+ if (needsResizing) {
+ PDFImage.resize(rgbBuf, bpc, 3, originalWidth, originalHeight, width,
+ height, dest, alpha01);
+ } else {
+ rgbPos = 0;
+ destPos = 0;
+ for (i = 0, ii = width * actualHeight; i < ii; i++) {
+ dest[destPos++] = rgbBuf[rgbPos++];
+ dest[destPos++] = rgbBuf[rgbPos++];
+ dest[destPos++] = rgbBuf[rgbPos++];
+ destPos += alpha01;
+ }
+ }
+ }
+ },
+ /**
+ * True if the colorspace has components in the default range of [0, 1].
+ * This should be true for all colorspaces except for lab color spaces
+ * which are [0,100], [-128, 127], [-128, 127].
+ */
+ usesZeroToOneRange: true
+ };
+
+ ColorSpace.parse = function ColorSpace_parse(cs, xref, res) {
+ var IR = ColorSpace.parseToIR(cs, xref, res);
+ if (IR instanceof AlternateCS) {
+ return IR;
+ }
+ return ColorSpace.fromIR(IR);
+ };
+
+ ColorSpace.fromIR = function ColorSpace_fromIR(IR) {
+ var name = isArray(IR) ? IR[0] : IR;
+ var whitePoint, blackPoint;
+
+ switch (name) {
+ case 'DeviceGrayCS':
+ return this.singletons.gray;
+ case 'DeviceRgbCS':
+ return this.singletons.rgb;
+ case 'DeviceCmykCS':
+ return this.singletons.cmyk;
+ case 'CalGrayCS':
+ whitePoint = IR[1].WhitePoint;
+ blackPoint = IR[1].BlackPoint;
+ var gamma = IR[1].Gamma;
+ return new CalGrayCS(whitePoint, blackPoint, gamma);
+ case 'PatternCS':
+ var basePatternCS = IR[1];
+ if (basePatternCS) {
+ basePatternCS = ColorSpace.fromIR(basePatternCS);
+ }
+ return new PatternCS(basePatternCS);
+ case 'IndexedCS':
+ var baseIndexedCS = IR[1];
+ var hiVal = IR[2];
+ var lookup = IR[3];
+ return new IndexedCS(ColorSpace.fromIR(baseIndexedCS), hiVal, lookup);
+ case 'AlternateCS':
+ var numComps = IR[1];
+ var alt = IR[2];
+ var tintFnIR = IR[3];
+
+ return new AlternateCS(numComps, ColorSpace.fromIR(alt),
+ PDFFunction.fromIR(tintFnIR));
+ case 'LabCS':
+ whitePoint = IR[1].WhitePoint;
+ blackPoint = IR[1].BlackPoint;
+ var range = IR[1].Range;
+ return new LabCS(whitePoint, blackPoint, range);
+ default:
+ error('Unkown name ' + name);
+ }
+ return null;
+ };
+
+ ColorSpace.parseToIR = function ColorSpace_parseToIR(cs, xref, res) {
+ if (isName(cs)) {
+ var colorSpaces = res.get('ColorSpace');
+ if (isDict(colorSpaces)) {
+ var refcs = colorSpaces.get(cs.name);
+ if (refcs) {
+ cs = refcs;
+ }
+ }
+ }
+
+ cs = xref.fetchIfRef(cs);
+ var mode;
+
+ if (isName(cs)) {
+ mode = cs.name;
+ this.mode = mode;
+
+ switch (mode) {
+ case 'DeviceGray':
+ case 'G':
+ return 'DeviceGrayCS';
+ case 'DeviceRGB':
+ case 'RGB':
+ return 'DeviceRgbCS';
+ case 'DeviceCMYK':
+ case 'CMYK':
+ return 'DeviceCmykCS';
+ case 'Pattern':
+ return ['PatternCS', null];
+ default:
+ error('unrecognized colorspace ' + mode);
+ }
+ } else if (isArray(cs)) {
+ mode = cs[0].name;
+ this.mode = mode;
+ var numComps, params;
+
+ switch (mode) {
+ case 'DeviceGray':
+ case 'G':
+ return 'DeviceGrayCS';
+ case 'DeviceRGB':
+ case 'RGB':
+ return 'DeviceRgbCS';
+ case 'DeviceCMYK':
+ case 'CMYK':
+ return 'DeviceCmykCS';
+ case 'CalGray':
+ params = cs[1].getAll();
+ return ['CalGrayCS', params];
+ case 'CalRGB':
+ return 'DeviceRgbCS';
+ case 'ICCBased':
+ var stream = xref.fetchIfRef(cs[1]);
+ var dict = stream.dict;
+ numComps = dict.get('N');
+ if (numComps == 1) {
+ return 'DeviceGrayCS';
+ } else if (numComps == 3) {
+ return 'DeviceRgbCS';
+ } else if (numComps == 4) {
+ return 'DeviceCmykCS';
+ }
+ break;
+ case 'Pattern':
+ var basePatternCS = cs[1];
+ if (basePatternCS) {
+ basePatternCS = ColorSpace.parseToIR(basePatternCS, xref, res);
+ }
+ return ['PatternCS', basePatternCS];
+ case 'Indexed':
+ case 'I':
+ var baseIndexedCS = ColorSpace.parseToIR(cs[1], xref, res);
+ var hiVal = cs[2] + 1;
+ var lookup = xref.fetchIfRef(cs[3]);
+ if (isStream(lookup)) {
+ lookup = lookup.getBytes();
+ }
+ return ['IndexedCS', baseIndexedCS, hiVal, lookup];
+ case 'Separation':
+ case 'DeviceN':
+ var name = cs[1];
+ numComps = 1;
+ if (isName(name)) {
+ numComps = 1;
+ } else if (isArray(name)) {
+ numComps = name.length;
+ }
+ var alt = ColorSpace.parseToIR(cs[2], xref, res);
+ var tintFnIR = PDFFunction.getIR(xref, xref.fetchIfRef(cs[3]));
+ return ['AlternateCS', numComps, alt, tintFnIR];
+ case 'Lab':
+ params = cs[1].getAll();
+ return ['LabCS', params];
+ default:
+ error('unimplemented color space object "' + mode + '"');
+ }
+ } else {
+ error('unrecognized color space object: "' + cs + '"');
+ }
+ 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;
+ }
+
+ if (n * 2 !== decode.length) {
+ warn('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;
+ };
+
+ ColorSpace.singletons = {
+ get gray() {
+ return shadow(this, 'gray', new DeviceGrayCS());
+ },
+ get rgb() {
+ return shadow(this, 'rgb', new DeviceRgbCS());
+ },
+ get cmyk() {
+ return shadow(this, 'cmyk', new DeviceCmykCS());
+ }
+ };
+
+ return ColorSpace;
+})();
+
+/**
+ * Alternate color space handles both Separation and DeviceN color spaces. A
+ * Separation color space is actually just a DeviceN with one color component.
+ * Both color spaces use a tinting function to convert colors to a base color
+ * space.
+ */
+var AlternateCS = (function AlternateCSClosure() {
+ function AlternateCS(numComps, base, tintFn) {
+ this.name = 'Alternate';
+ this.numComps = numComps;
+ this.defaultColor = new Float32Array(numComps);
+ for (var i = 0; i < numComps; ++i) {
+ this.defaultColor[i] = 1;
+ }
+ this.base = base;
+ this.tintFn = tintFn;
+ }
+
+ AlternateCS.prototype = {
+ getRgb: ColorSpace.prototype.getRgb,
+ getRgbItem: function AlternateCS_getRgbItem(src, srcOffset,
+ dest, destOffset) {
+ var baseNumComps = this.base.numComps;
+ var input = 'subarray' in src ?
+ src.subarray(srcOffset, srcOffset + this.numComps) :
+ Array.prototype.slice.call(src, srcOffset, srcOffset + this.numComps);
+ var tinted = this.tintFn(input);
+ this.base.getRgbItem(tinted, 0, dest, destOffset);
+ },
+ getRgbBuffer: function AlternateCS_getRgbBuffer(src, srcOffset, count,
+ dest, destOffset, bits,
+ alpha01) {
+ var tinted;
+ var tintFn = this.tintFn;
+ var base = this.base;
+ var scale = 1 / ((1 << bits) - 1);
+ var baseNumComps = base.numComps;
+ var usesZeroToOneRange = base.usesZeroToOneRange;
+ var isPassthrough = (base.isPassthrough(8) || !usesZeroToOneRange) &&
+ alpha01 === 0;
+ var pos = isPassthrough ? destOffset : 0;
+ var baseBuf = isPassthrough ? dest : new Uint8Array(baseNumComps * count);
+ var numComps = this.numComps;
+
+ var scaled = new Float32Array(numComps);
+ var i, j;
+ if (usesZeroToOneRange) {
+ for (i = 0; i < count; i++) {
+ for (j = 0; j < numComps; j++) {
+ scaled[j] = src[srcOffset++] * scale;
+ }
+ tinted = tintFn(scaled);
+ for (j = 0; j < baseNumComps; j++) {
+ baseBuf[pos++] = tinted[j] * 255;
+ }
+ }
+ } else {
+ for (i = 0; i < count; i++) {
+ for (j = 0; j < numComps; j++) {
+ scaled[j] = src[srcOffset++] * scale;
+ }
+ tinted = tintFn(scaled);
+ base.getRgbItem(tinted, 0, baseBuf, pos);
+ pos += baseNumComps;
+ }
+ }
+ if (!isPassthrough) {
+ base.getRgbBuffer(baseBuf, 0, count, dest, destOffset, 8, alpha01);
+ }
+ },
+ getOutputLength: function AlternateCS_getOutputLength(inputLength,
+ alpha01) {
+ return this.base.getOutputLength(inputLength *
+ this.base.numComps / this.numComps,
+ alpha01);
+ },
+ isPassthrough: ColorSpace.prototype.isPassthrough,
+ fillRgb: ColorSpace.prototype.fillRgb,
+ isDefaultDecode: function AlternateCS_isDefaultDecode(decodeMap) {
+ return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
+ },
+ usesZeroToOneRange: true
+ };
+
+ return AlternateCS;
+})();
+
+var PatternCS = (function PatternCSClosure() {
+ function PatternCS(baseCS) {
+ this.name = 'Pattern';
+ this.base = baseCS;
+ }
+ PatternCS.prototype = {};
+
+ return PatternCS;
+})();
+
+var IndexedCS = (function IndexedCSClosure() {
+ function IndexedCS(base, highVal, lookup) {
+ this.name = 'Indexed';
+ this.numComps = 1;
+ this.defaultColor = new Uint8Array([0]);
+ this.base = base;
+ this.highVal = highVal;
+
+ var baseNumComps = base.numComps;
+ var length = baseNumComps * highVal;
+ var lookupArray;
+
+ if (isStream(lookup)) {
+ lookupArray = new Uint8Array(length);
+ var bytes = lookup.getBytes(length);
+ lookupArray.set(bytes);
+ } else if (isString(lookup)) {
+ lookupArray = new Uint8Array(length);
+ for (var i = 0; i < length; ++i) {
+ lookupArray[i] = lookup.charCodeAt(i);
+ }
+ } else if (lookup instanceof Uint8Array || lookup instanceof Array) {
+ lookupArray = lookup;
+ } else {
+ error('Unrecognized lookup table: ' + lookup);
+ }
+ this.lookup = lookupArray;
+ }
+
+ IndexedCS.prototype = {
+ getRgb: ColorSpace.prototype.getRgb,
+ getRgbItem: function IndexedCS_getRgbItem(src, srcOffset,
+ dest, destOffset) {
+ var numComps = this.base.numComps;
+ var start = src[srcOffset] * numComps;
+ this.base.getRgbItem(this.lookup, start, dest, destOffset);
+ },
+ getRgbBuffer: function IndexedCS_getRgbBuffer(src, srcOffset, count,
+ dest, destOffset, bits,
+ alpha01) {
+ var base = this.base;
+ var numComps = base.numComps;
+ var outputDelta = base.getOutputLength(numComps, alpha01);
+ var lookup = this.lookup;
+
+ for (var i = 0; i < count; ++i) {
+ var lookupPos = src[srcOffset++] * numComps;
+ base.getRgbBuffer(lookup, lookupPos, 1, dest, destOffset, 8, alpha01);
+ destOffset += outputDelta;
+ }
+ },
+ getOutputLength: function IndexedCS_getOutputLength(inputLength, alpha01) {
+ return this.base.getOutputLength(inputLength * this.base.numComps,
+ alpha01);
+ },
+ isPassthrough: ColorSpace.prototype.isPassthrough,
+ fillRgb: ColorSpace.prototype.fillRgb,
+ isDefaultDecode: function IndexedCS_isDefaultDecode(decodeMap) {
+ // indexed color maps shouldn't be changed
+ return true;
+ },
+ usesZeroToOneRange: true
+ };
+ return IndexedCS;
+})();
+
+var DeviceGrayCS = (function DeviceGrayCSClosure() {
+ function DeviceGrayCS() {
+ this.name = 'DeviceGray';
+ this.numComps = 1;
+ this.defaultColor = new Float32Array([0]);
+ }
+
+ DeviceGrayCS.prototype = {
+ getRgb: ColorSpace.prototype.getRgb,
+ getRgbItem: function DeviceGrayCS_getRgbItem(src, srcOffset,
+ dest, destOffset) {
+ var c = (src[srcOffset] * 255) | 0;
+ c = c < 0 ? 0 : c > 255 ? 255 : c;
+ dest[destOffset] = dest[destOffset + 1] = dest[destOffset + 2] = c;
+ },
+ getRgbBuffer: function DeviceGrayCS_getRgbBuffer(src, srcOffset, count,
+ dest, destOffset, bits,
+ alpha01) {
+ var scale = 255 / ((1 << bits) - 1);
+ var j = srcOffset, q = destOffset;
+ for (var i = 0; i < count; ++i) {
+ var c = (scale * src[j++]) | 0;
+ dest[q++] = c;
+ dest[q++] = c;
+ dest[q++] = c;
+ q += alpha01;
+ }
+ },
+ getOutputLength: function DeviceGrayCS_getOutputLength(inputLength,
+ alpha01) {
+ return inputLength * (3 + alpha01);
+ },
+ isPassthrough: ColorSpace.prototype.isPassthrough,
+ fillRgb: ColorSpace.prototype.fillRgb,
+ isDefaultDecode: function DeviceGrayCS_isDefaultDecode(decodeMap) {
+ return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
+ },
+ usesZeroToOneRange: true
+ };
+ return DeviceGrayCS;
+})();
+
+var DeviceRgbCS = (function DeviceRgbCSClosure() {
+ function DeviceRgbCS() {
+ this.name = 'DeviceRGB';
+ this.numComps = 3;
+ this.defaultColor = new Float32Array([0, 0, 0]);
+ }
+ DeviceRgbCS.prototype = {
+ getRgb: ColorSpace.prototype.getRgb,
+ getRgbItem: function DeviceRgbCS_getRgbItem(src, srcOffset,
+ dest, destOffset) {
+ var r = (src[srcOffset] * 255) | 0;
+ var g = (src[srcOffset + 1] * 255) | 0;
+ var b = (src[srcOffset + 2] * 255) | 0;
+ dest[destOffset] = r < 0 ? 0 : r > 255 ? 255 : r;
+ dest[destOffset + 1] = g < 0 ? 0 : g > 255 ? 255 : g;
+ dest[destOffset + 2] = b < 0 ? 0 : b > 255 ? 255 : b;
+ },
+ getRgbBuffer: function DeviceRgbCS_getRgbBuffer(src, srcOffset, count,
+ dest, destOffset, bits,
+ alpha01) {
+ if (bits === 8 && alpha01 === 0) {
+ dest.set(src.subarray(srcOffset, srcOffset + count * 3), destOffset);
+ return;
+ }
+ var scale = 255 / ((1 << bits) - 1);
+ var j = srcOffset, q = destOffset;
+ for (var i = 0; i < count; ++i) {
+ dest[q++] = (scale * src[j++]) | 0;
+ dest[q++] = (scale * src[j++]) | 0;
+ dest[q++] = (scale * src[j++]) | 0;
+ q += alpha01;
+ }
+ },
+ getOutputLength: function DeviceRgbCS_getOutputLength(inputLength,
+ alpha01) {
+ return (inputLength * (3 + alpha01) / 3) | 0;
+ },
+ isPassthrough: function DeviceRgbCS_isPassthrough(bits) {
+ return bits == 8;
+ },
+ fillRgb: ColorSpace.prototype.fillRgb,
+ isDefaultDecode: function DeviceRgbCS_isDefaultDecode(decodeMap) {
+ return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
+ },
+ usesZeroToOneRange: true
+ };
+ return DeviceRgbCS;
+})();
+
+var DeviceCmykCS = (function DeviceCmykCSClosure() {
+ // The coefficients below was found using numerical analysis: the method of
+ // steepest descent for the sum((f_i - color_value_i)^2) for r/g/b colors,
+ // where color_value is the tabular value from the table of sampled RGB colors
+ // from CMYK US Web Coated (SWOP) colorspace, and f_i is the corresponding
+ // CMYK color conversion using the estimation below:
+ // f(A, B,.. N) = Acc+Bcm+Ccy+Dck+c+Fmm+Gmy+Hmk+Im+Jyy+Kyk+Ly+Mkk+Nk+255
+ function convertToRgb(src, srcOffset, srcScale, dest, destOffset) {
+ var c = src[srcOffset + 0] * srcScale;
+ var m = src[srcOffset + 1] * srcScale;
+ var y = src[srcOffset + 2] * srcScale;
+ var k = src[srcOffset + 3] * srcScale;
+
+ var r =
+ (c * (-4.387332384609988 * c + 54.48615194189176 * m +
+ 18.82290502165302 * y + 212.25662451639585 * k +
+ -285.2331026137004) +
+ m * (1.7149763477362134 * m - 5.6096736904047315 * y +
+ -17.873870861415444 * k - 5.497006427196366) +
+ y * (-2.5217340131683033 * y - 21.248923337353073 * k +
+ 17.5119270841813) +
+ k * (-21.86122147463605 * k - 189.48180835922747) + 255) | 0;
+ var g =
+ (c * (8.841041422036149 * c + 60.118027045597366 * m +
+ 6.871425592049007 * y + 31.159100130055922 * k +
+ -79.2970844816548) +
+ m * (-15.310361306967817 * m + 17.575251261109482 * y +
+ 131.35250912493976 * k - 190.9453302588951) +
+ y * (4.444339102852739 * y + 9.8632861493405 * k - 24.86741582555878) +
+ k * (-20.737325471181034 * k - 187.80453709719578) + 255) | 0;
+ var b =
+ (c * (0.8842522430003296 * c + 8.078677503112928 * m +
+ 30.89978309703729 * y - 0.23883238689178934 * k +
+ -14.183576799673286) +
+ m * (10.49593273432072 * m + 63.02378494754052 * y +
+ 50.606957656360734 * k - 112.23884253719248) +
+ y * (0.03296041114873217 * y + 115.60384449646641 * k +
+ -193.58209356861505) +
+ k * (-22.33816807309886 * k - 180.12613974708367) + 255) | 0;
+
+ dest[destOffset] = r > 255 ? 255 : r < 0 ? 0 : r;
+ dest[destOffset + 1] = g > 255 ? 255 : g < 0 ? 0 : g;
+ dest[destOffset + 2] = b > 255 ? 255 : b < 0 ? 0 : b;
+ }
+
+ function DeviceCmykCS() {
+ this.name = 'DeviceCMYK';
+ this.numComps = 4;
+ this.defaultColor = new Float32Array([0, 0, 0, 1]);
+ }
+ DeviceCmykCS.prototype = {
+ getRgb: ColorSpace.prototype.getRgb,
+ getRgbItem: function DeviceCmykCS_getRgbItem(src, srcOffset,
+ dest, destOffset) {
+ convertToRgb(src, srcOffset, 1, dest, destOffset);
+ },
+ getRgbBuffer: function DeviceCmykCS_getRgbBuffer(src, srcOffset, count,
+ dest, destOffset, bits,
+ alpha01) {
+ var scale = 1 / ((1 << bits) - 1);
+ for (var i = 0; i < count; i++) {
+ convertToRgb(src, srcOffset, scale, dest, destOffset);
+ srcOffset += 4;
+ destOffset += 3 + alpha01;
+ }
+ },
+ getOutputLength: function DeviceCmykCS_getOutputLength(inputLength,
+ alpha01) {
+ return (inputLength / 4 * (3 + alpha01)) | 0;
+ },
+ isPassthrough: ColorSpace.prototype.isPassthrough,
+ fillRgb: ColorSpace.prototype.fillRgb,
+ isDefaultDecode: function DeviceCmykCS_isDefaultDecode(decodeMap) {
+ return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
+ },
+ usesZeroToOneRange: true
+ };
+
+ return DeviceCmykCS;
+})();
+
+//
+// CalGrayCS: Based on "PDF Reference, Sixth Ed", p.245
+//
+var CalGrayCS = (function CalGrayCSClosure() {
+ function CalGrayCS(whitePoint, blackPoint, gamma) {
+ this.name = 'CalGray';
+ this.numComps = 1;
+ this.defaultColor = new Float32Array([0]);
+
+ if (!whitePoint) {
+ error('WhitePoint missing - required for color space CalGray');
+ }
+ blackPoint = blackPoint || [0, 0, 0];
+ gamma = gamma || 1;
+
+ // Translate arguments to spec variables.
+ this.XW = whitePoint[0];
+ this.YW = whitePoint[1];
+ this.ZW = whitePoint[2];
+
+ this.XB = blackPoint[0];
+ this.YB = blackPoint[1];
+ this.ZB = blackPoint[2];
+
+ this.G = gamma;
+
+ // Validate variables as per spec.
+ if (this.XW < 0 || this.ZW < 0 || this.YW !== 1) {
+ error('Invalid WhitePoint components for ' + this.name +
+ ', no fallback available');
+ }
+
+ if (this.XB < 0 || this.YB < 0 || this.ZB < 0) {
+ info('Invalid BlackPoint for ' + this.name + ', falling back to default');
+ this.XB = this.YB = this.ZB = 0;
+ }
+
+ if (this.XB !== 0 || this.YB !== 0 || this.ZB !== 0) {
+ warn(this.name + ', BlackPoint: XB: ' + this.XB + ', YB: ' + this.YB +
+ ', ZB: ' + this.ZB + ', only default values are supported.');
+ }
+
+ if (this.G < 1) {
+ info('Invalid Gamma: ' + this.G + ' for ' + this.name +
+ ', falling back to default');
+ this.G = 1;
+ }
+ }
+
+ function convertToRgb(cs, src, srcOffset, dest, destOffset, scale) {
+ // A represents a gray component of a calibrated gray space.
+ // A <---> AG in the spec
+ var A = src[srcOffset] * scale;
+ var AG = Math.pow(A, cs.G);
+
+ // Computes L as per spec. ( = cs.YW * AG )
+ // Except if other than default BlackPoint values are used.
+ var L = cs.YW * AG;
+ // http://www.poynton.com/notes/colour_and_gamma/ColorFAQ.html, Ch 4.
+ // Convert values to rgb range [0, 255].
+ var val = Math.max(295.8 * Math.pow(L, 0.333333333333333333) - 40.8, 0) | 0;
+ dest[destOffset] = val;
+ dest[destOffset + 1] = val;
+ dest[destOffset + 2] = val;
+ }
+
+ CalGrayCS.prototype = {
+ getRgb: ColorSpace.prototype.getRgb,
+ getRgbItem: function CalGrayCS_getRgbItem(src, srcOffset,
+ dest, destOffset) {
+ convertToRgb(this, src, srcOffset, dest, destOffset, 1);
+ },
+ getRgbBuffer: function CalGrayCS_getRgbBuffer(src, srcOffset, count,
+ dest, destOffset, bits,
+ alpha01) {
+ var scale = 1 / ((1 << bits) - 1);
+
+ for (var i = 0; i < count; ++i) {
+ convertToRgb(this, src, srcOffset, dest, destOffset, scale);
+ srcOffset += 1;
+ destOffset += 3 + alpha01;
+ }
+ },
+ getOutputLength: function CalGrayCS_getOutputLength(inputLength, alpha01) {
+ return inputLength * (3 + alpha01);
+ },
+ isPassthrough: ColorSpace.prototype.isPassthrough,
+ fillRgb: ColorSpace.prototype.fillRgb,
+ isDefaultDecode: function CalGrayCS_isDefaultDecode(decodeMap) {
+ return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
+ },
+ usesZeroToOneRange: true
+ };
+ return CalGrayCS;
+})();
+
+//
+// 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 = new Float32Array([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) {
+ info('Invalid BlackPoint, falling back to default');
+ this.XB = this.YB = this.ZB = 0;
+ }
+
+ if (this.amin > this.amax || this.bmin > this.bmax) {
+ info('Invalid Range, falling back to defaults');
+ this.amin = -100;
+ this.amax = 100;
+ this.bmin = -100;
+ this.bmax = 100;
+ }
+ }
+
+ // Function g(x) from spec
+ function fn_g(x) {
+ if (x >= 6 / 29) {
+ return x * x * x;
+ } else {
+ return (108 / 841) * (x - 4 / 29);
+ }
+ }
+
+ function decode(value, high1, low2, high2) {
+ return low2 + (value) * (high2 - low2) / (high1);
+ }
+
+ // If decoding is needed maxVal should be 2^bits per component - 1.
+ function convertToRgb(cs, src, srcOffset, maxVal, dest, destOffset) {
+ // XXX: Lab input is in the range of [0, 100], [amin, amax], [bmin, bmax]
+ // not the usual [0, 1]. If a command like setFillColor is used the src
+ // values will already be within the correct range. However, if we are
+ // converting an image we have to map the values to the correct range given
+ // above.
+ // Ls,as,bs <---> L*,a*,b* in the spec
+ var Ls = src[srcOffset];
+ var as = src[srcOffset + 1];
+ var bs = src[srcOffset + 2];
+ if (maxVal !== false) {
+ Ls = decode(Ls, maxVal, 0, 100);
+ as = decode(as, maxVal, cs.amin, cs.amax);
+ bs = decode(bs, maxVal, cs.bmin, cs.bmax);
+ }
+
+ // Adjust limits of 'as' and 'bs'
+ as = as > cs.amax ? cs.amax : as < cs.amin ? cs.amin : as;
+ bs = bs > cs.bmax ? cs.bmax : bs < cs.bmin ? cs.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 = cs.XW * fn_g(L);
+ var Y = cs.YW * fn_g(M);
+ var Z = cs.ZW * fn_g(N);
+
+ var r, g, b;
+ // Using different conversions for D50 and D65 white points,
+ // per http://www.color.org/srgb.pdf
+ if (cs.ZW < 1) {
+ // Assuming D50 (X=0.9642, Y=1.00, Z=0.8249)
+ r = X * 3.1339 + Y * -1.6170 + Z * -0.4906;
+ g = X * -0.9785 + Y * 1.9160 + Z * 0.0333;
+ b = X * 0.0720 + Y * -0.2290 + Z * 1.4057;
+ } else {
+ // Assuming D65 (X=0.9505, Y=1.00, Z=1.0888)
+ r = X * 3.2406 + Y * -1.5372 + Z * -0.4986;
+ g = X * -0.9689 + Y * 1.8758 + Z * 0.0415;
+ b = X * 0.0557 + Y * -0.2040 + Z * 1.0570;
+ }
+ // clamp color values to [0,1] range then convert to [0,255] range.
+ dest[destOffset] = r <= 0 ? 0 : r >= 1 ? 255 : Math.sqrt(r) * 255 | 0;
+ dest[destOffset + 1] = g <= 0 ? 0 : g >= 1 ? 255 : Math.sqrt(g) * 255 | 0;
+ dest[destOffset + 2] = b <= 0 ? 0 : b >= 1 ? 255 : Math.sqrt(b) * 255 | 0;
+ }
+
+ LabCS.prototype = {
+ getRgb: ColorSpace.prototype.getRgb,
+ getRgbItem: function LabCS_getRgbItem(src, srcOffset, dest, destOffset) {
+ convertToRgb(this, src, srcOffset, false, dest, destOffset);
+ },
+ getRgbBuffer: function LabCS_getRgbBuffer(src, srcOffset, count,
+ dest, destOffset, bits,
+ alpha01) {
+ var maxVal = (1 << bits) - 1;
+ for (var i = 0; i < count; i++) {
+ convertToRgb(this, src, srcOffset, maxVal, dest, destOffset);
+ srcOffset += 3;
+ destOffset += 3 + alpha01;
+ }
+ },
+ getOutputLength: function LabCS_getOutputLength(inputLength, alpha01) {
+ return (inputLength * (3 + alpha01) / 3) | 0;
+ },
+ isPassthrough: ColorSpace.prototype.isPassthrough,
+ isDefaultDecode: function LabCS_isDefaultDecode(decodeMap) {
+ // XXX: Decoding is handled with the lab conversion because of the strange
+ // ranges that are used.
+ return true;
+ },
+ usesZeroToOneRange: false
+ };
+ return LabCS;
+})();
+
+
+
var ARCFourCipher = (function ARCFourCipherClosure() {
function ARCFourCipher(key) {
this.a = 0;
@@ -14073,7 +14504,7 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
hashData[i++] = fileId[j];
}
cipher = new ARCFourCipher(encryptionKey);
- var checkData = cipher.encryptBlock(calculateMD5(hashData, 0, i));
+ checkData = cipher.encryptBlock(calculateMD5(hashData, 0, i));
n = encryptionKey.length;
var derivedKey = new Uint8Array(n), k;
for (j = 1; j <= 19; ++j) {
@@ -14412,15 +14843,16 @@ Shadings.RadialAxial = (function RadialAxialClosure() {
return;
}
+ var rgbColor;
for (var i = t0; i <= t1; i += step) {
- var rgbColor = cs.getRgb(fn([i]), 0);
+ rgbColor = cs.getRgb(fn([i]), 0);
var cssColor = Util.makeCssRgb(rgbColor);
colorStops.push([(i - t0) / diff, cssColor]);
}
var background = 'transparent';
if (dict.has('Background')) {
- var rgbColor = cs.getRgb(dict.get('Background'), 0);
+ rgbColor = cs.getRgb(dict.get('Background'), 0);
background = Util.makeCssRgb(rgbColor);
}
@@ -14610,7 +15042,6 @@ Shadings.Mesh = (function MeshClosure() {
function decodeType5Shading(mesh, reader, verticesPerRow) {
var coords = mesh.coords;
var colors = mesh.colors;
- var operators = [];
var ps = []; // not maintaining cs since that will match ps
while (reader.hasData) {
var coord = reader.readCoordinate();
@@ -14920,6 +15351,38 @@ Shadings.Mesh = (function MeshClosure() {
mesh.bounds = [minX, minY, maxX, maxY];
}
+ function packData(mesh) {
+ var i, ii, j, jj;
+
+ var coords = mesh.coords;
+ var coordsPacked = new Float32Array(coords.length * 2);
+ for (i = 0, j = 0, ii = coords.length; i < ii; i++) {
+ var xy = coords[i];
+ coordsPacked[j++] = xy[0];
+ coordsPacked[j++] = xy[1];
+ }
+ mesh.coords = coordsPacked;
+
+ var colors = mesh.colors;
+ var colorsPacked = new Uint8Array(colors.length * 3);
+ for (i = 0, j = 0, ii = colors.length; i < ii; i++) {
+ var c = colors[i];
+ colorsPacked[j++] = c[0];
+ colorsPacked[j++] = c[1];
+ colorsPacked[j++] = c[2];
+ }
+ mesh.colors = colorsPacked;
+
+ var figures = mesh.figures;
+ for (i = 0, ii = figures.length; i < ii; i++) {
+ var figure = figures[i], ps = figure.coords, cs = figure.colors;
+ for (j = 0, jj = ps.length; j < jj; j++) {
+ ps[j] *= 2;
+ cs[j] *= 3;
+ }
+ }
+ }
+
function Mesh(stream, matrix, xref, res) {
assert(isStream(stream), 'Mesh data is not a stream');
var dict = stream.dict;
@@ -15007,35 +15470,14 @@ Shadings.Mesh = (function MeshClosure() {
}
// calculate bounds
updateBounds(this);
+
+ packData(this);
}
Mesh.prototype = {
getIR: function Mesh_getIR() {
- var type = this.shadingType;
- var i, ii, j;
- var coords = this.coords;
- var coordsPacked = new Float32Array(coords.length * 2);
- for (i = 0, j = 0, ii = coords.length; i < ii; i++) {
- var xy = coords[i];
- coordsPacked[j++] = xy[0];
- coordsPacked[j++] = xy[1];
- }
- var colors = this.colors;
- var colorsPacked = new Uint8Array(colors.length * 3);
- for (i = 0, j = 0, ii = colors.length; i < ii; i++) {
- var c = colors[i];
- colorsPacked[j++] = c[0];
- colorsPacked[j++] = c[1];
- colorsPacked[j++] = c[2];
- }
- var figures = this.figures;
- var bbox = this.bbox;
- var bounds = this.bounds;
- var matrix = this.matrix;
- var background = this.background;
-
- return ['Mesh', type, coordsPacked, colorsPacked, figures, bounds,
- matrix, bbox, background];
+ return ['Mesh', this.shadingType, this.coords, this.colors, this.figures,
+ this.bounds, this.matrix, this.bbox, this.background];
}
};
@@ -15073,9 +15515,6 @@ function getTilingPatternIR(operatorList, dict, args) {
var PartialEvaluator = (function PartialEvaluatorClosure() {
function PartialEvaluator(pdfManager, xref, handler, pageIndex,
uniquePrefix, idCounters, fontCache) {
- this.state = new EvalState();
- this.stateStack = [];
-
this.pdfManager = pdfManager;
this.xref = xref;
this.handler = handler;
@@ -15085,6 +15524,28 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
this.fontCache = fontCache;
}
+ // Trying to minimize Date.now() usage and check every 100 time
+ var TIME_SLOT_DURATION_MS = 20;
+ var CHECK_TIME_EVERY = 100;
+ function TimeSlotManager() {
+ this.reset();
+ }
+ TimeSlotManager.prototype = {
+ check: function TimeSlotManager_check() {
+ if (++this.checked < CHECK_TIME_EVERY) {
+ return false;
+ }
+ this.checked = 0;
+ return this.endTime <= Date.now();
+ },
+ reset: function TimeSlotManager_reset() {
+ this.endTime = Date.now() + TIME_SLOT_DURATION_MS;
+ this.checked = 0;
+ }
+ };
+
+ var deferred = Promise.resolve();
+
var TILING_PATTERN = 1, SHADING_PATTERN = 2;
PartialEvaluator.prototype = {
@@ -15093,14 +15554,20 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
return false;
}
+ var processed = Object.create(null);
+ if (resources.objId) {
+ processed[resources.objId] = true;
+ }
+
var nodes = [resources];
while (nodes.length) {
+ var key;
var node = nodes.shift();
// First check the current resources for blend modes.
var graphicStates = node.get('ExtGState');
if (isDict(graphicStates)) {
graphicStates = graphicStates.getAll();
- for (var key in graphicStates) {
+ for (key in graphicStates) {
var graphicState = graphicStates[key];
var bm = graphicState['BM'];
if (isName(bm) && bm.name !== 'Normal') {
@@ -15114,16 +15581,19 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
continue;
}
xObjects = xObjects.getAll();
- for (var key in xObjects) {
+ for (key in xObjects) {
var xObject = xObjects[key];
if (!isStream(xObject)) {
continue;
}
var xResources = xObject.dict.get('Resources');
- // Only add the resource if it's different from the current one,
- // otherwise we can get stuck in an infinite loop.
- if (isDict(xResources) && xResources !== node) {
+ // Checking objId to detect an infinite loop.
+ if (isDict(xResources) &&
+ (!xResources.objId || !processed[xResources.objId])) {
nodes.push(xResources);
+ if (xResources.objId) {
+ processed[xResources.objId] = true;
+ }
}
}
}
@@ -15133,7 +15603,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
buildFormXObject: function PartialEvaluator_buildFormXObject(resources,
xobj, smask,
operatorList,
- state) {
+ initialState) {
var matrix = xobj.dict.get('Matrix');
var bbox = xobj.dict.get('BBox');
var group = xobj.dict.get('Group');
@@ -15147,43 +15617,57 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
};
var groupSubtype = group.get('S');
+ var colorSpace;
if (isName(groupSubtype) && groupSubtype.name === 'Transparency') {
- groupOptions.isolated = group.get('I') || false;
- groupOptions.knockout = group.get('K') || false;
- var colorSpace = group.get('CS');
- groupOptions.colorSpace = colorSpace ?
- ColorSpace.parseToIR(colorSpace, this.xref, resources) : null;
+ groupOptions.isolated = (group.get('I') || false);
+ groupOptions.knockout = (group.get('K') || false);
+ colorSpace = (group.has('CS') ?
+ ColorSpace.parse(group.get('CS'), this.xref, resources) : null);
}
+
+ if (smask && smask.backdrop) {
+ colorSpace = colorSpace || ColorSpace.singletons.rgb;
+ smask.backdrop = colorSpace.getRgb(smask.backdrop, 0);
+ }
+
operatorList.addOp(OPS.beginGroup, [groupOptions]);
}
operatorList.addOp(OPS.paintFormXObjectBegin, [matrix, bbox]);
- this.getOperatorList(xobj, xobj.dict.get('Resources') || resources,
- operatorList, state);
- operatorList.addOp(OPS.paintFormXObjectEnd, []);
+ return this.getOperatorList(xobj,
+ (xobj.dict.get('Resources') || resources), operatorList, initialState).
+ then(function () {
+ operatorList.addOp(OPS.paintFormXObjectEnd, []);
- if (group) {
- operatorList.addOp(OPS.endGroup, [groupOptions]);
- }
+ if (group) {
+ operatorList.addOp(OPS.endGroup, [groupOptions]);
+ }
+ });
},
- buildPaintImageXObject: function PartialEvaluator_buildPaintImageXObject(
- resources, image, inline, operatorList,
- cacheKey, cache) {
+ buildPaintImageXObject:
+ function PartialEvaluator_buildPaintImageXObject(resources, image,
+ inline, operatorList,
+ cacheKey, cache) {
var self = this;
var dict = image.dict;
var w = dict.get('Width', 'W');
var h = dict.get('Height', 'H');
+ if (!(w && isNum(w)) || !(h && isNum(h))) {
+ warn('Image dimensions are missing, or not numbers.');
+ return;
+ }
if (PDFJS.maxImageSize !== -1 && w * h > PDFJS.maxImageSize) {
warn('Image exceeded maximum allowed size and was removed.');
return;
}
- var imageMask = dict.get('ImageMask', 'IM') || false;
+ var imageMask = (dict.get('ImageMask', 'IM') || false);
+ var imgData, args;
if (imageMask) {
- // This depends on a tmpCanvas beeing filled with the
+ // This depends on a tmpCanvas being filled with the
// current fillStyle, such that processing the pixel
// data can't be done here. Instead of creating a
// complete PDFImage, only read the information needed
@@ -15195,12 +15679,12 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
var imgArray = image.getBytes(bitStrideLength * height);
var decode = dict.get('Decode', 'D');
var canTransfer = image instanceof DecodeStream;
- var inverseDecode = !!decode && decode[0] > 0;
+ var inverseDecode = (!!decode && decode[0] > 0);
- var imgData = PDFImage.createMask(imgArray, width, height,
- canTransfer, inverseDecode);
+ imgData = PDFImage.createMask(imgArray, width, height,
+ canTransfer, inverseDecode);
imgData.cached = true;
- var args = [imgData];
+ args = [imgData];
operatorList.addOp(OPS.paintImageMaskXObject, args);
if (cacheKey) {
cache.key = cacheKey;
@@ -15210,45 +15694,48 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
return;
}
- var softMask = dict.get('SMask', 'SM') || false;
- var mask = dict.get('Mask') || false;
+ var softMask = (dict.get('SMask', 'SM') || false);
+ var mask = (dict.get('Mask') || false);
var SMALL_IMAGE_DIMENSIONS = 200;
// Inlining small images into the queue as RGB data
- if (inline && !softMask && !mask &&
- !(image instanceof JpegStream) &&
+ if (inline && !softMask && !mask && !(image instanceof JpegStream) &&
(w + h) < SMALL_IMAGE_DIMENSIONS) {
var imageObj = new PDFImage(this.xref, resources, image,
inline, null, null);
// We force the use of RGBA_32BPP images here, because we can't handle
// any other kind.
- var imgData = imageObj.createImageData(/* forceRGBA = */ true);
+ imgData = imageObj.createImageData(/* forceRGBA = */ true);
operatorList.addOp(OPS.paintInlineImageXObject, [imgData]);
return;
}
// If there is no imageMask, create the PDFImage and a lot
// of image processing can be done here.
- var uniquePrefix = this.uniquePrefix || '';
+ var uniquePrefix = (this.uniquePrefix || '');
var objId = 'img_' + uniquePrefix + (++this.idCounters.obj);
operatorList.addDependency(objId);
- var args = [objId, w, h];
+ args = [objId, w, h];
if (!softMask && !mask && image instanceof JpegStream &&
image.isNativelySupported(this.xref, resources)) {
// These JPEGs don't need any more processing so we can just send it.
operatorList.addOp(OPS.paintJpegXObject, args);
- this.handler.send(
- 'obj', [objId, this.pageIndex, 'JpegStream', image.getIR()]);
+ this.handler.send('obj',
+ [objId, this.pageIndex, 'JpegStream', image.getIR()]);
return;
}
-
- PDFImage.buildImage(function(imageObj) {
+ PDFImage.buildImage(self.handler, self.xref, resources, image, inline).
+ then(function(imageObj) {
var imgData = imageObj.createImageData(/* forceRGBA = */ false);
self.handler.send('obj', [objId, self.pageIndex, 'Image', imgData],
- null, [imgData.data.buffer]);
- }, self.handler, self.xref, resources, image, inline);
+ [imgData.data.buffer]);
+ }).then(null, function (reason) {
+ warn('Unable to decode image: ' + reason);
+ self.handler.send('obj', [objId, self.pageIndex, 'Image', null]);
+ });
+
operatorList.addOp(OPS.paintImageXObject, args);
if (cacheKey) {
cache.key = cacheKey;
@@ -15258,71 +15745,70 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
},
handleSMask: function PartialEvaluator_handleSmask(smask, resources,
- operatorList) {
+ operatorList,
+ stateManager) {
var smaskContent = smask.get('G');
var smaskOptions = {
subtype: smask.get('S').name,
backdrop: smask.get('BC')
};
-
- this.buildFormXObject(resources, smaskContent, smaskOptions,
- operatorList);
+ return this.buildFormXObject(resources, smaskContent, smaskOptions,
+ operatorList, stateManager.state.clone());
},
- handleTilingType: function PartialEvaluator_handleTilingType(
- fn, args, resources, pattern, patternDict,
- operatorList) {
+ handleTilingType:
+ function PartialEvaluator_handleTilingType(fn, args, resources,
+ pattern, patternDict,
+ operatorList) {
// Create an IR of the pattern code.
- var tilingOpList = this.getOperatorList(pattern,
- patternDict.get('Resources') || resources);
- // Add the dependencies to the parent operator list so they are resolved
- // before sub operator list is executed synchronously.
- operatorList.addDependencies(tilingOpList.dependencies);
- operatorList.addOp(fn, getTilingPatternIR({
- fnArray: tilingOpList.fnArray,
- argsArray: tilingOpList.argsArray
- }, patternDict, args));
+ var tilingOpList = new OperatorList();
+ return this.getOperatorList(pattern,
+ (patternDict.get('Resources') || resources), tilingOpList).
+ then(function () {
+ // Add the dependencies to the parent operator list so they are
+ // resolved before sub operator list is executed synchronously.
+ operatorList.addDependencies(tilingOpList.dependencies);
+ operatorList.addOp(fn, getTilingPatternIR({
+ fnArray: tilingOpList.fnArray,
+ argsArray: tilingOpList.argsArray
+ }, patternDict, args));
+ });
},
- handleSetFont: function PartialEvaluator_handleSetFont(
- resources, fontArgs, fontRef, operatorList) {
-
+ handleSetFont:
+ function PartialEvaluator_handleSetFont(resources, fontArgs, fontRef,
+ operatorList, state) {
// TODO(mack): Not needed?
var fontName;
if (fontArgs) {
fontArgs = fontArgs.slice();
fontName = fontArgs[0].name;
}
- var self = this;
- var font = this.loadFont(fontName, fontRef, this.xref, resources,
- operatorList);
- this.state.font = font;
- var loadedName = font.loadedName;
- if (!font.sent) {
- var fontData = font.translated.exportData();
-
- self.handler.send('commonobj', [
- loadedName,
- 'Font',
- fontData
- ]);
- font.sent = true;
- }
- return loadedName;
+ var self = this;
+ return this.loadFont(fontName, fontRef, this.xref, resources).then(
+ function (translated) {
+ if (!translated.font.isType3Font) {
+ return translated;
+ }
+ return translated.loadType3Data(self, resources, operatorList).then(
+ function () {
+ return translated;
+ });
+ }).then(function (translated) {
+ state.font = translated.font;
+ translated.send(self.handler);
+ return translated.loadedName;
+ });
},
- handleText: function PartialEvaluator_handleText(chars) {
- var font = this.state.font.translated;
+ handleText: function PartialEvaluator_handleText(chars, state) {
+ var font = state.font;
var glyphs = font.charsToGlyphs(chars);
- var isAddToPathSet = !!(this.state.textRenderingMode &
+ var isAddToPathSet = !!(state.textRenderingMode &
TextRenderingMode.ADD_TO_PATH_FLAG);
if (font.data && (isAddToPathSet || PDFJS.disableFontFace)) {
- for (var i = 0; i < glyphs.length; i++) {
- if (glyphs[i] === null) {
- continue;
- }
- var fontChar = glyphs[i].fontChar;
+ var buildPath = function (fontChar) {
if (!font.renderer.hasBuiltPath(fontChar)) {
var path = font.renderer.getPathJs(fontChar);
this.handler.send('commonobj', [
@@ -15331,6 +15817,21 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
path
]);
}
+ }.bind(this);
+
+ for (var i = 0, ii = glyphs.length; i < ii; i++) {
+ var glyph = glyphs[i];
+ if (glyph === null) {
+ continue;
+ }
+ buildPath(glyph.fontChar);
+
+ // If the glyph has an accent we need to build a path for its
+ // fontChar too, otherwise CanvasGraphics_paintChar will fail.
+ var accent = glyph.accent;
+ if (accent && accent.fontChar) {
+ buildPath(accent.fontChar);
+ }
}
}
@@ -15338,9 +15839,9 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
},
setGState: function PartialEvaluator_setGState(resources, gState,
- operatorList, xref) {
+ operatorList, xref,
+ stateManager) {
- var self = this;
// TODO(mack): This should be rewritten so that this function returns
// what should be added to the queue during each iteration
function setGStateForKey(gStateObj, key, value) {
@@ -15359,10 +15860,14 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
gStateObj.push([key, value]);
break;
case 'Font':
- var loadedName = self.handleSetFont(resources, null, value[0],
- operatorList);
- operatorList.addDependency(loadedName);
- gStateObj.push([key, [loadedName, value[1]]]);
+ promise = promise.then(function () {
+ return self.handleSetFont(resources, null, value[0],
+ operatorList, stateManager.state).
+ then(function (loadedName) {
+ operatorList.addDependency(loadedName);
+ gStateObj.push([key, [loadedName, value[1]]]);
+ });
+ });
break;
case 'BM':
gStateObj.push([key, value]);
@@ -15374,7 +15879,10 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
}
var dict = xref.fetchIfRef(value);
if (isDict(dict)) {
- self.handleSMask(dict, resources, operatorList);
+ promise = promise.then(function () {
+ return self.handleSMask(dict, resources, operatorList,
+ stateManager);
+ });
gStateObj.push([key, true]);
} else {
warn('Unsupported SMask type');
@@ -15409,25 +15917,24 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
// This array holds the converted/processed state data.
var gStateObj = [];
var gStateMap = gState.map;
+ var self = this;
+ var promise = Promise.resolve();
for (var key in gStateMap) {
var value = gStateMap[key];
setGStateForKey(gStateObj, key, value);
}
-
- operatorList.addOp(OPS.setGState, [gStateObj]);
+ return promise.then(function () {
+ operatorList.addOp(OPS.setGState, [gStateObj]);
+ });
},
loadFont: function PartialEvaluator_loadFont(fontName, font, xref,
- resources,
- parentOperatorList) {
+ resources) {
function errorFont() {
- return {
- translated: new ErrorFont('Font ' + fontName + ' is not available'),
- loadedName: 'g_font_error'
- };
+ return Promise.resolve(new TranslatedFont('g_font_error',
+ new ErrorFont('Font ' + fontName + ' is not available'), font));
}
-
var fontRef;
if (font) { // Loading by ref.
assert(isRef(font));
@@ -15449,115 +15956,151 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
if (!isDict(font)) {
return errorFont();
}
- // Workaround for bad PDF generators that doesn't reference fonts
+
+ // We are holding font.translated references just for fontRef that are not
+ // dictionaries (Dict). See explanation below.
+ if (font.translated) {
+ return font.translated;
+ }
+
+ var fontCapability = createPromiseCapability();
+
+ var preEvaluatedFont = this.preEvaluateFont(font, xref);
+ var descriptor = preEvaluatedFont.descriptor;
+ var fontID = fontRef.num + '_' + fontRef.gen;
+ if (isDict(descriptor)) {
+ if (!descriptor.fontAliases) {
+ descriptor.fontAliases = Object.create(null);
+ }
+
+ var fontAliases = descriptor.fontAliases;
+ var hash = preEvaluatedFont.hash;
+ if (fontAliases[hash]) {
+ var aliasFontRef = fontAliases[hash].aliasRef;
+ if (aliasFontRef && this.fontCache.has(aliasFontRef)) {
+ this.fontCache.putAlias(fontRef, aliasFontRef);
+ return this.fontCache.get(fontRef);
+ }
+ }
+
+ if (!fontAliases[hash]) {
+ fontAliases[hash] = {
+ fontID: Font.getFontID()
+ };
+ }
+
+ fontAliases[hash].aliasRef = fontRef;
+ fontID = fontAliases[hash].fontID;
+ }
+
+ // Workaround for bad PDF generators that don't reference fonts
// properly, i.e. by not using an object identifier.
// Check if the fontRef is a Dict (as opposed to a standard object),
// in which case we don't cache the font and instead reference it by
// fontName in font.loadedName below.
var fontRefIsDict = isDict(fontRef);
if (!fontRefIsDict) {
- this.fontCache.put(fontRef, font);
+ this.fontCache.put(fontRef, fontCapability.promise);
}
- // keep track of each font we translated so the caller can
- // load them asynchronously before calling display on a page
+ // Keep track of each font we translated so the caller can
+ // load them asynchronously before calling display on a page.
font.loadedName = 'g_font_' + (fontRefIsDict ?
- fontName.replace(/\W/g, '') : (fontRef.num + '_' + fontRef.gen));
+ fontName.replace(/\W/g, '') : fontID);
- if (!font.translated) {
- var translated;
- try {
- translated = this.translateFont(font, xref);
- } catch (e) {
- UnsupportedManager.notify(UNSUPPORTED_FEATURES.font);
- translated = new ErrorFont(e instanceof Error ? e.message : e);
- }
- font.translated = translated;
+ font.translated = fontCapability.promise;
+
+ // TODO move promises into translate font
+ var translatedPromise;
+ try {
+ translatedPromise = Promise.resolve(
+ this.translateFont(preEvaluatedFont, xref));
+ } catch (e) {
+ translatedPromise = Promise.reject(e);
}
- if (font.translated.loadCharProcs) {
- var charProcs = font.get('CharProcs').getAll();
- var fontResources = font.get('Resources') || resources;
- var charProcKeys = Object.keys(charProcs);
- var charProcOperatorList = {};
- for (var i = 0, n = charProcKeys.length; i < n; ++i) {
- var key = charProcKeys[i];
- var glyphStream = charProcs[key];
- var operatorList = this.getOperatorList(glyphStream, fontResources);
- charProcOperatorList[key] = operatorList.getIR();
- if (!parentOperatorList) {
- continue;
- }
- // Add the dependencies to the parent operator list so they are
- // resolved before sub operator list is executed synchronously.
- parentOperatorList.addDependencies(charProcOperatorList.dependencies);
- }
- font.translated.charProcOperatorList = charProcOperatorList;
- font.loaded = true;
+ translatedPromise.then(function (translatedFont) {
+ fontCapability.resolve(new TranslatedFont(font.loadedName,
+ translatedFont, font));
+ }, function (reason) {
+ // TODO fontCapability.reject?
+ UnsupportedManager.notify(UNSUPPORTED_FEATURES.font);
+ fontCapability.resolve(new TranslatedFont(font.loadedName,
+ new ErrorFont(reason instanceof Error ? reason.message : reason),
+ font));
+ });
+ return fontCapability.promise;
+ },
+
+ buildPath: function PartialEvaluator_buildPath(operatorList, fn, args) {
+ var lastIndex = operatorList.length - 1;
+ if (lastIndex < 0 ||
+ operatorList.fnArray[lastIndex] !== OPS.constructPath) {
+ operatorList.addOp(OPS.constructPath, [[fn], args]);
} else {
- font.loaded = true;
+ var opArgs = operatorList.argsArray[lastIndex];
+ opArgs[0].push(fn);
+ Array.prototype.push.apply(opArgs[1], args);
}
- return font;
+ },
+
+ handleColorN: function PartialEvaluator_handleColorN(operatorList, fn, args,
+ cs, patterns, resources, xref) {
+ // compile tiling patterns
+ var patternName = args[args.length - 1];
+ // SCN/scn applies patterns along with normal colors
+ var pattern;
+ if (isName(patternName) &&
+ (pattern = patterns.get(patternName.name))) {
+ var dict = (isStream(pattern) ? pattern.dict : pattern);
+ var typeNum = dict.get('PatternType');
+
+ if (typeNum == TILING_PATTERN) {
+ var color = cs.base ? cs.base.getRgb(args, 0) : null;
+ return this.handleTilingType(fn, color, resources, pattern,
+ dict, operatorList);
+ } else if (typeNum == SHADING_PATTERN) {
+ var shading = dict.get('Shading');
+ var matrix = dict.get('Matrix');
+ pattern = Pattern.parseShading(shading, matrix, xref, resources);
+ operatorList.addOp(fn, pattern.getIR());
+ return Promise.resolve();
+ } else {
+ return Promise.reject('Unknown PatternType: ' + typeNum);
+ }
+ }
+ // TODO shall we fail here?
+ operatorList.addOp(fn, args);
+ return Promise.resolve();
},
getOperatorList: function PartialEvaluator_getOperatorList(stream,
resources,
operatorList,
- evaluatorState) {
+ initialState) {
var self = this;
var xref = this.xref;
- var handler = this.handler;
var imageCache = {};
- operatorList = operatorList || new OperatorList();
+ assert(operatorList);
- resources = resources || new Dict();
- var xobjs = resources.get('XObject') || new Dict();
- var patterns = resources.get('Pattern') || new Dict();
- var preprocessor = new EvaluatorPreprocessor(stream, xref);
- if (evaluatorState) {
- preprocessor.setState(evaluatorState);
- }
+ resources = (resources || Dict.empty);
+ var xobjs = (resources.get('XObject') || Dict.empty);
+ var patterns = (resources.get('Pattern') || Dict.empty);
+ var stateManager = new StateManager(initialState || new EvalState());
+ var preprocessor = new EvaluatorPreprocessor(stream, xref, stateManager);
+ var timeSlotManager = new TimeSlotManager();
- var promise = new LegacyPromise();
- var operation;
- while ((operation = preprocessor.read())) {
+ return new Promise(function next(resolve, reject) {
+ timeSlotManager.reset();
+ var stop, operation, i, ii, cs;
+ while (!(stop = timeSlotManager.check()) &&
+ (operation = preprocessor.read())) {
var args = operation.args;
var fn = operation.fn;
- switch (fn) {
- case OPS.setStrokeColorN:
- case OPS.setFillColorN:
- if (args[args.length - 1].code) {
- break;
- }
- // compile tiling patterns
- var patternName = args[args.length - 1];
- // SCN/scn applies patterns along with normal colors
- var pattern;
- if (isName(patternName) &&
- (pattern = patterns.get(patternName.name))) {
-
- var dict = isStream(pattern) ? pattern.dict : pattern;
- var typeNum = dict.get('PatternType');
-
- if (typeNum == TILING_PATTERN) {
- self.handleTilingType(fn, args, resources, pattern, dict,
- operatorList);
- args = [];
- continue;
- } else if (typeNum == SHADING_PATTERN) {
- var shading = dict.get('Shading');
- var matrix = dict.get('Matrix');
- var pattern = Pattern.parseShading(shading, matrix, xref,
- resources);
- args = pattern.getIR();
- } else {
- error('Unkown PatternType ' + typeNum);
- }
- }
- break;
+ switch (fn | 0) {
case OPS.paintXObject:
if (args[0].code) {
break;
@@ -15572,37 +16115,46 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
var xobj = xobjs.get(name);
if (xobj) {
- assertWellFormed(
- isStream(xobj), 'XObject should be a stream');
+ assert(isStream(xobj), 'XObject should be a stream');
var type = xobj.dict.get('Subtype');
- assertWellFormed(
- isName(type),
- 'XObject should have a Name subtype'
- );
+ assert(isName(type),
+ 'XObject should have a Name subtype');
- if ('Form' == type.name) {
- self.buildFormXObject(resources, xobj, null, operatorList,
- preprocessor.getState());
- args = [];
- continue;
- } else if ('Image' == type.name) {
+ if (type.name === 'Form') {
+ stateManager.save();
+ return self.buildFormXObject(resources, xobj, null,
+ operatorList,
+ stateManager.state.clone()).
+ then(function () {
+ stateManager.restore();
+ next(resolve, reject);
+ }, reject);
+ } else if (type.name === 'Image') {
self.buildPaintImageXObject(resources, xobj, false,
- operatorList, name, imageCache);
+ operatorList, name, imageCache);
args = [];
continue;
+ } else if (type.name === 'PS') {
+ // PostScript XObjects are unused when viewing documents.
+ // See section 4.7.1 of Adobe's PDF reference.
+ info('Ignored XObject subtype PS');
+ continue;
} else {
error('Unhandled XObject subtype ' + type.name);
}
}
break;
case OPS.setFont:
+ var fontSize = args[1];
// eagerly collect all fonts
- var loadedName = self.handleSetFont(resources, args, null,
- operatorList);
- operatorList.addDependency(loadedName);
- args[0] = loadedName;
- break;
+ return self.handleSetFont(resources, args, null,
+ operatorList, stateManager.state).
+ then(function (loadedName) {
+ operatorList.addDependency(loadedName);
+ operatorList.addOp(OPS.setFont, [loadedName, fontSize]);
+ next(resolve, reject);
+ }, reject);
case OPS.endInlineImage:
var cacheKey = args[0].cacheKey;
if (cacheKey && imageCache.key === cacheKey) {
@@ -15611,57 +16163,126 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
continue;
}
self.buildPaintImageXObject(resources, args[0], true,
- operatorList, cacheKey, imageCache);
+ operatorList, cacheKey, imageCache);
args = [];
continue;
- case OPS.save:
- var old = this.state;
- this.stateStack.push(this.state);
- this.state = old.clone();
- break;
- case OPS.restore:
- var prev = this.stateStack.pop();
- if (prev) {
- this.state = prev;
- }
- break;
case OPS.showText:
- args[0] = this.handleText(args[0]);
+ args[0] = self.handleText(args[0], stateManager.state);
break;
case OPS.showSpacedText:
var arr = args[0];
+ var combinedGlyphs = [];
var arrLength = arr.length;
- for (var i = 0; i < arrLength; ++i) {
- if (isString(arr[i])) {
- arr[i] = this.handleText(arr[i]);
+ for (i = 0; i < arrLength; ++i) {
+ var arrItem = arr[i];
+ if (isString(arrItem)) {
+ Array.prototype.push.apply(combinedGlyphs,
+ self.handleText(arrItem, stateManager.state));
+ } else if (isNum(arrItem)) {
+ combinedGlyphs.push(arrItem);
}
}
+ args[0] = combinedGlyphs;
+ fn = OPS.showText;
break;
case OPS.nextLineShowText:
- args[0] = this.handleText(args[0]);
+ operatorList.addOp(OPS.nextLine);
+ args[0] = self.handleText(args[0], stateManager.state);
+ fn = OPS.showText;
break;
case OPS.nextLineSetSpacingShowText:
- args[2] = this.handleText(args[2]);
+ operatorList.addOp(OPS.nextLine);
+ operatorList.addOp(OPS.setWordSpacing, [args.shift()]);
+ operatorList.addOp(OPS.setCharSpacing, [args.shift()]);
+ args[0] = self.handleText(args[0], stateManager.state);
+ fn = OPS.showText;
break;
case OPS.setTextRenderingMode:
- this.state.textRenderingMode = args[0];
+ stateManager.state.textRenderingMode = args[0];
break;
- // Parse the ColorSpace data to a raw format.
+
case OPS.setFillColorSpace:
+ stateManager.state.fillColorSpace =
+ ColorSpace.parse(args[0], xref, resources);
+ continue;
case OPS.setStrokeColorSpace:
- args = [ColorSpace.parseToIR(args[0], xref, resources)];
+ stateManager.state.strokeColorSpace =
+ ColorSpace.parse(args[0], xref, resources);
+ continue;
+ case OPS.setFillColor:
+ cs = stateManager.state.fillColorSpace;
+ args = cs.getRgb(args, 0);
+ fn = OPS.setFillRGBColor;
+ break;
+ case OPS.setStrokeColor:
+ cs = stateManager.state.strokeColorSpace;
+ args = cs.getRgb(args, 0);
+ fn = OPS.setStrokeRGBColor;
+ break;
+ case OPS.setFillGray:
+ stateManager.state.fillColorSpace = ColorSpace.singletons.gray;
+ args = ColorSpace.singletons.gray.getRgb(args, 0);
+ fn = OPS.setFillRGBColor;
+ break;
+ case OPS.setStrokeGray:
+ stateManager.state.strokeColorSpace = ColorSpace.singletons.gray;
+ args = ColorSpace.singletons.gray.getRgb(args, 0);
+ fn = OPS.setStrokeRGBColor;
+ break;
+ case OPS.setFillCMYKColor:
+ stateManager.state.fillColorSpace = ColorSpace.singletons.cmyk;
+ args = ColorSpace.singletons.cmyk.getRgb(args, 0);
+ fn = OPS.setFillRGBColor;
+ break;
+ case OPS.setStrokeCMYKColor:
+ stateManager.state.strokeColorSpace = ColorSpace.singletons.cmyk;
+ args = ColorSpace.singletons.cmyk.getRgb(args, 0);
+ fn = OPS.setStrokeRGBColor;
+ break;
+ case OPS.setFillRGBColor:
+ stateManager.state.fillColorSpace = ColorSpace.singletons.rgb;
+ args = ColorSpace.singletons.rgb.getRgb(args, 0);
+ break;
+ case OPS.setStrokeRGBColor:
+ stateManager.state.strokeColorSpace = ColorSpace.singletons.rgb;
+ args = ColorSpace.singletons.rgb.getRgb(args, 0);
+ break;
+ case OPS.setFillColorN:
+ cs = stateManager.state.fillColorSpace;
+ if (cs.name === 'Pattern') {
+ return self.handleColorN(operatorList, OPS.setFillColorN,
+ args, cs, patterns, resources, xref).then(function() {
+ next(resolve, reject);
+ }, reject);
+ }
+ args = cs.getRgb(args, 0);
+ fn = OPS.setFillRGBColor;
+ break;
+ case OPS.setStrokeColorN:
+ cs = stateManager.state.strokeColorSpace;
+ if (cs.name === 'Pattern') {
+ return self.handleColorN(operatorList, OPS.setStrokeColorN,
+ args, cs, patterns, resources, xref).then(function() {
+ next(resolve, reject);
+ }, reject);
+ }
+ args = cs.getRgb(args, 0);
+ fn = OPS.setStrokeRGBColor;
break;
+
case OPS.shadingFill:
var shadingRes = resources.get('Shading');
- if (!shadingRes)
+ if (!shadingRes) {
error('No shading resource found');
+ }
var shading = shadingRes.get(args[0].name);
- if (!shading)
+ if (!shading) {
error('No shading object found');
+ }
- var shadingFill = Pattern.parseShading(
- shading, null, xref, resources);
+ var shadingFill = Pattern.parseShading(shading, null, xref,
+ resources);
var patternIR = shadingFill.getIR();
args = [patternIR];
fn = OPS.shadingFill;
@@ -15670,64 +16291,212 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
var dictName = args[0];
var extGState = resources.get('ExtGState');
- if (!isDict(extGState) || !extGState.has(dictName.name))
+ if (!isDict(extGState) || !extGState.has(dictName.name)) {
break;
+ }
var gState = extGState.get(dictName.name);
- self.setGState(resources, gState, operatorList, xref);
- args = [];
+ return self.setGState(resources, gState, operatorList, xref,
+ stateManager).then(function() {
+ next(resolve, reject);
+ }, reject);
+ case OPS.moveTo:
+ case OPS.lineTo:
+ case OPS.curveTo:
+ case OPS.curveTo2:
+ case OPS.curveTo3:
+ case OPS.closePath:
+ self.buildPath(operatorList, fn, args);
continue;
- } // switch
-
+ }
operatorList.addOp(fn, args);
- }
-
- // some pdf don't close all restores inside object/form
- // closing those for them
- for (var i = 0, ii = preprocessor.savedStatesDepth; i < ii; i++) {
- operatorList.addOp(OPS.restore, []);
- }
-
- return operatorList;
+ }
+ if (stop) {
+ deferred.then(function () {
+ next(resolve, reject);
+ });
+ return;
+ }
+ // Some PDFs don't close all restores inside object/form.
+ // Closing those for them.
+ for (i = 0, ii = preprocessor.savedStatesDepth; i < ii; i++) {
+ operatorList.addOp(OPS.restore, []);
+ }
+ resolve();
+ });
},
- getTextContent: function PartialEvaluator_getTextContent(
- stream, resources, textState) {
+ getTextContent: function PartialEvaluator_getTextContent(stream, resources,
+ stateManager) {
- textState = textState || new TextState();
+ stateManager = (stateManager || new StateManager(new TextState()));
- var bidiTexts = [];
+ var textContent = {
+ items: [],
+ styles: Object.create(null)
+ };
+ var bidiTexts = textContent.items;
var SPACE_FACTOR = 0.35;
var MULTI_SPACE_FACTOR = 1.5;
var self = this;
var xref = this.xref;
- function handleSetFont(fontName, fontRef) {
- return self.loadFont(fontName, fontRef, xref, resources, null);
- }
+ resources = (xref.fetchIfRef(resources) || Dict.empty);
- resources = xref.fetchIfRef(resources) || new Dict();
// The xobj is parsed iff it's needed, e.g. if there is a `DO` cmd.
var xobjs = null;
var xobjsCache = {};
- var preprocessor = new EvaluatorPreprocessor(stream, xref);
- var res = resources;
+ var preprocessor = new EvaluatorPreprocessor(stream, xref, stateManager);
- var chunkBuf = [];
- var font = null;
- var charSpace = 0, wordSpace = 0;
var operation;
- while ((operation = preprocessor.read())) {
+ var textState;
+
+ function newTextChunk() {
+ var font = textState.font;
+ if (!(font.loadedName in textContent.styles)) {
+ textContent.styles[font.loadedName] = {
+ fontFamily: font.fallbackName,
+ ascent: font.ascent,
+ descent: font.descent,
+ vertical: font.vertical
+ };
+ }
+ return {
+ str: '',
+ dir: null,
+ width: 0,
+ height: 0,
+ transform: null,
+ fontName: font.loadedName
+ };
+ }
+
+ function runBidi(textChunk) {
+ var bidiResult = PDFJS.bidi(textChunk.str, -1, textState.font.vertical);
+ textChunk.str = bidiResult.str;
+ textChunk.dir = bidiResult.dir;
+ return textChunk;
+ }
+
+ function handleSetFont(fontName, fontRef) {
+ return self.loadFont(fontName, fontRef, xref, resources).
+ then(function (translated) {
+ textState.font = translated.font;
+ textState.fontMatrix = translated.font.fontMatrix ||
+ FONT_IDENTITY_MATRIX;
+ });
+ }
+
+ function buildTextGeometry(chars, textChunk) {
+ var font = textState.font;
+ textChunk = textChunk || newTextChunk();
+ if (!textChunk.transform) {
+ // 9.4.4 Text Space Details
+ var tsm = [textState.fontSize * textState.textHScale, 0,
+ 0, textState.fontSize,
+ 0, textState.textRise];
+ var trm = textChunk.transform = Util.transform(textState.ctm,
+ Util.transform(textState.textMatrix, tsm));
+ if (!font.vertical) {
+ textChunk.height = Math.sqrt(trm[2] * trm[2] + trm[3] * trm[3]);
+ } else {
+ textChunk.width = Math.sqrt(trm[0] * trm[0] + trm[1] * trm[1]);
+ }
+ }
+ var width = 0;
+ var height = 0;
+ var glyphs = font.charsToGlyphs(chars);
+ var defaultVMetrics = font.defaultVMetrics;
+ for (var i = 0; i < glyphs.length; i++) {
+ var glyph = glyphs[i];
+ if (!glyph) { // Previous glyph was a space.
+ width += textState.wordSpacing * textState.textHScale;
+ continue;
+ }
+ var vMetricX = null;
+ var vMetricY = null;
+ var glyphWidth = null;
+ if (font.vertical) {
+ if (glyph.vmetric) {
+ glyphWidth = glyph.vmetric[0];
+ vMetricX = glyph.vmetric[1];
+ vMetricY = glyph.vmetric[2];
+ } else {
+ glyphWidth = glyph.width;
+ vMetricX = glyph.width * 0.5;
+ vMetricY = defaultVMetrics[2];
+ }
+ } else {
+ glyphWidth = glyph.width;
+ }
+
+ var glyphUnicode = glyph.unicode;
+ if (glyphUnicode in NormalizedUnicodes) {
+ glyphUnicode = NormalizedUnicodes[glyphUnicode];
+ }
+ glyphUnicode = reverseIfRtl(glyphUnicode);
+
+ // The following will calculate the x and y of the individual glyphs.
+ // if (font.vertical) {
+ // tsm[4] -= vMetricX * Math.abs(textState.fontSize) *
+ // textState.fontMatrix[0];
+ // tsm[5] -= vMetricY * textState.fontSize *
+ // textState.fontMatrix[0];
+ // }
+ // var trm = Util.transform(textState.textMatrix, tsm);
+ // var pt = Util.applyTransform([trm[4], trm[5]], textState.ctm);
+ // var x = pt[0];
+ // var y = pt[1];
+
+ var tx = 0;
+ var ty = 0;
+ if (!font.vertical) {
+ var w0 = glyphWidth * textState.fontMatrix[0];
+ tx = (w0 * textState.fontSize + textState.charSpacing) *
+ textState.textHScale;
+ width += tx;
+ } else {
+ var w1 = glyphWidth * textState.fontMatrix[0];
+ ty = w1 * textState.fontSize + textState.charSpacing;
+ height += ty;
+ }
+ textState.translateTextMatrix(tx, ty);
+
+ textChunk.str += glyphUnicode;
+ }
+
+ var a = textState.textLineMatrix[0];
+ var b = textState.textLineMatrix[1];
+ var scaleLineX = Math.sqrt(a * a + b * b);
+ a = textState.ctm[0];
+ b = textState.ctm[1];
+ var scaleCtmX = Math.sqrt(a * a + b * b);
+ if (!font.vertical) {
+ textChunk.width += width * scaleCtmX * scaleLineX;
+ } else {
+ textChunk.height += Math.abs(height * scaleCtmX * scaleLineX);
+ }
+ return textChunk;
+ }
+
+ var timeSlotManager = new TimeSlotManager();
+
+ return new Promise(function next(resolve, reject) {
+ timeSlotManager.reset();
+ var stop;
+ while (!(stop = timeSlotManager.check()) &&
+ (operation = preprocessor.read())) {
+ textState = stateManager.state;
var fn = operation.fn;
var args = operation.args;
- switch (fn) {
- // TODO: Add support for SAVE/RESTORE and XFORM here.
+ switch (fn | 0) {
case OPS.setFont:
- font = handleSetFont(args[0].name).translated;
textState.fontSize = args[1];
- break;
+ return handleSetFont(args[0].name).then(function() {
+ next(resolve, reject);
+ }, reject);
case OPS.setTextRise:
textState.textRise = args[0];
break;
@@ -15738,90 +16507,108 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
textState.leading = args[0];
break;
case OPS.moveText:
- textState.translateTextMatrix(args[0], args[1]);
+ textState.translateTextLineMatrix(args[0], args[1]);
+ textState.textMatrix = textState.textLineMatrix.slice();
break;
case OPS.setLeadingMoveText:
textState.leading = -args[1];
- textState.translateTextMatrix(args[0], args[1]);
+ textState.translateTextLineMatrix(args[0], args[1]);
+ textState.textMatrix = textState.textLineMatrix.slice();
break;
case OPS.nextLine:
- textState.translateTextMatrix(0, -textState.leading);
+ textState.carriageReturn();
break;
case OPS.setTextMatrix:
- textState.setTextMatrix(args[0], args[1],
- args[2], args[3], args[4], args[5]);
+ textState.setTextMatrix(args[0], args[1], args[2], args[3],
+ args[4], args[5]);
+ textState.setTextLineMatrix(args[0], args[1], args[2], args[3],
+ args[4], args[5]);
break;
case OPS.setCharSpacing:
- charSpace = args[0];
+ textState.charSpacing = args[0];
break;
case OPS.setWordSpacing:
- wordSpace = args[0];
+ textState.wordSpacing = args[0];
break;
case OPS.beginText:
- textState.initialiseTextObj();
+ textState.textMatrix = IDENTITY_MATRIX.slice();
+ textState.textLineMatrix = IDENTITY_MATRIX.slice();
break;
case OPS.showSpacedText:
var items = args[0];
+ var textChunk = newTextChunk();
+ var offset;
for (var j = 0, jj = items.length; j < jj; j++) {
if (typeof items[j] === 'string') {
- chunkBuf.push(fontCharsToUnicode(items[j], font));
- } else if (items[j] < 0 && font.spaceWidth > 0) {
- var fakeSpaces = -items[j] / font.spaceWidth;
- if (fakeSpaces > MULTI_SPACE_FACTOR) {
- fakeSpaces = Math.round(fakeSpaces);
- while (fakeSpaces--) {
- chunkBuf.push(' ');
+ buildTextGeometry(items[j], textChunk);
+ } else {
+ var val = items[j] / 1000;
+ if (!textState.font.vertical) {
+ offset = -val * textState.fontSize * textState.textHScale *
+ textState.textMatrix[0];
+ textState.translateTextMatrix(offset, 0);
+ textChunk.width += offset;
+ } else {
+ offset = -val * textState.fontSize *
+ textState.textMatrix[3];
+ textState.translateTextMatrix(0, offset);
+ textChunk.height += offset;
+ }
+ if (items[j] < 0 && textState.font.spaceWidth > 0) {
+ var fakeSpaces = -items[j] / textState.font.spaceWidth;
+ if (fakeSpaces > MULTI_SPACE_FACTOR) {
+ fakeSpaces = Math.round(fakeSpaces);
+ while (fakeSpaces--) {
+ textChunk.str += ' ';
+ }
+ } else if (fakeSpaces > SPACE_FACTOR) {
+ textChunk.str += ' ';
}
- } else if (fakeSpaces > SPACE_FACTOR) {
- chunkBuf.push(' ');
}
}
}
+ bidiTexts.push(runBidi(textChunk));
break;
case OPS.showText:
- chunkBuf.push(fontCharsToUnicode(args[0], font));
+ bidiTexts.push(runBidi(buildTextGeometry(args[0])));
break;
case OPS.nextLineShowText:
- // For search, adding a extra white space for line breaks would be
- // better here, but that causes too much spaces in the
- // text-selection divs.
- chunkBuf.push(fontCharsToUnicode(args[0], font));
+ textState.carriageReturn();
+ bidiTexts.push(runBidi(buildTextGeometry(args[0])));
break;
case OPS.nextLineSetSpacingShowText:
- // Note comment in "'"
- chunkBuf.push(fontCharsToUnicode(args[2], font));
+ textState.wordSpacing = args[0];
+ textState.charSpacing = args[1];
+ textState.carriageReturn();
+ bidiTexts.push(runBidi(buildTextGeometry(args[2])));
break;
case OPS.paintXObject:
- // Set the chunk such that the following if won't add something
- // to the state.
- chunkBuf.length = 0;
-
if (args[0].code) {
break;
}
if (!xobjs) {
- xobjs = resources.get('XObject') || new Dict();
+ xobjs = (resources.get('XObject') || Dict.empty);
}
var name = args[0].name;
if (xobjsCache.key === name) {
if (xobjsCache.texts) {
- Util.concatenateToArray(bidiTexts, xobjsCache.texts);
+ Util.concatenateToArray(bidiTexts, xobjsCache.texts.items);
+ Util.extendObj(textContent.styles, xobjsCache.texts.styles);
}
break;
}
var xobj = xobjs.get(name);
- if (!xobj)
+ if (!xobj) {
break;
- assertWellFormed(isStream(xobj), 'XObject should be a stream');
+ }
+ assert(isStream(xobj), 'XObject should be a stream');
var type = xobj.dict.get('Subtype');
- assertWellFormed(
- isName(type),
- 'XObject should have a Name subtype'
- );
+ assert(isName(type),
+ 'XObject should have a Name subtype');
if ('Form' !== type.name) {
xobjsCache.key = name;
@@ -15829,71 +16616,67 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
break;
}
- var formTexts = this.getTextContent(
- xobj,
- xobj.dict.get('Resources') || resources,
- textState
- );
- xobjsCache.key = name;
- xobjsCache.texts = formTexts;
- Util.concatenateToArray(bidiTexts, formTexts);
- break;
+ stateManager.save();
+ var matrix = xobj.dict.get('Matrix');
+ if (isArray(matrix) && matrix.length === 6) {
+ stateManager.transform(matrix);
+ }
+
+ return self.getTextContent(xobj,
+ xobj.dict.get('Resources') || resources, stateManager).
+ then(function (formTextContent) {
+ Util.concatenateToArray(bidiTexts, formTextContent.items);
+ Util.extendObj(textContent.styles, formTextContent.styles);
+ stateManager.restore();
+
+ xobjsCache.key = name;
+ xobjsCache.texts = formTextContent;
+
+ next(resolve, reject);
+ }, reject);
case OPS.setGState:
var dictName = args[0];
var extGState = resources.get('ExtGState');
- if (!isDict(extGState) || !extGState.has(dictName.name))
+ if (!isDict(extGState) || !extGState.has(dictName.name)) {
break;
+ }
- var gsState = extGState.get(dictName.name);
-
- for (var i = 0; i < gsState.length; i++) {
- if (gsState[i] === 'Font') {
- font = handleSetFont(args[0].name).translated;
+ var gsStateMap = extGState.get(dictName.name);
+ var gsStateFont = null;
+ for (var key in gsStateMap) {
+ if (key === 'Font') {
+ assert(!gsStateFont);
+ gsStateFont = gsStateMap[key];
}
}
+ if (gsStateFont) {
+ textState.fontSize = gsStateFont[1];
+ return handleSetFont(gsStateFont[0]).then(function() {
+ next(resolve, reject);
+ }, reject);
+ }
break;
} // switch
-
- if (chunkBuf.length > 0) {
- var chunk = chunkBuf.join('');
- var bidiResult = PDFJS.bidi(chunk, -1, font.vertical);
- var bidiText = {
- str: bidiResult.str,
- dir: bidiResult.dir
- };
- var renderParams = textState.calcRenderParams(preprocessor.ctm);
- var fontHeight = textState.fontSize * renderParams.vScale;
- var fontAscent = font.ascent ? font.ascent * fontHeight :
- font.descent ? (1 + font.descent) * fontHeight : fontHeight;
- bidiText.x = renderParams.renderMatrix[4] - (fontAscent *
- Math.sin(renderParams.angle));
- bidiText.y = renderParams.renderMatrix[5] + (fontAscent *
- Math.cos(renderParams.angle));
- if (bidiText.dir == 'ttb') {
- bidiText.x += renderParams.vScale / 2;
- bidiText.y -= renderParams.vScale;
- }
- bidiText.angle = renderParams.angle;
- bidiText.size = fontHeight;
- bidiTexts.push(bidiText);
-
- chunkBuf.length = 0;
- }
- } // while
-
- return bidiTexts;
+ } // while
+ if (stop) {
+ deferred.then(function () {
+ next(resolve, reject);
+ });
+ return;
+ }
+ resolve(textContent);
+ });
},
extractDataStructures: function
partialEvaluatorExtractDataStructures(dict, baseDict,
xref, properties) {
// 9.10.2
- var toUnicode = dict.get('ToUnicode') ||
- baseDict.get('ToUnicode');
- if (toUnicode)
+ var toUnicode = (dict.get('ToUnicode') || baseDict.get('ToUnicode'));
+ if (toUnicode) {
properties.toUnicode = this.readToUnicode(toUnicode, xref, properties);
-
+ }
if (properties.composite) {
// CIDSystemInfo helps to match CID to glyphs
var cidSystemInfo = dict.get('CIDSystemInfo');
@@ -15906,8 +16689,9 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
}
var cidToGidMap = dict.get('CIDToGIDMap');
- if (isStream(cidToGidMap))
+ if (isStream(cidToGidMap)) {
properties.cidToGidMap = this.readCidToGidMap(cidToGidMap);
+ }
}
// Based on 9.6.6 of the spec the encoding can come from multiple places
@@ -15918,22 +16702,24 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
// differences to be merged in here not require us to hold on to it.
var differences = [];
var baseEncodingName = null;
+ var encoding;
if (dict.has('Encoding')) {
- var encoding = dict.get('Encoding');
+ encoding = dict.get('Encoding');
if (isDict(encoding)) {
baseEncodingName = encoding.get('BaseEncoding');
- baseEncodingName = isName(baseEncodingName) ? baseEncodingName.name :
- null;
+ baseEncodingName = (isName(baseEncodingName) ?
+ baseEncodingName.name : null);
// Load the differences between the base and original
if (encoding.has('Differences')) {
var diffEncoding = encoding.get('Differences');
var index = 0;
for (var j = 0, jj = diffEncoding.length; j < jj; j++) {
var data = diffEncoding[j];
- if (isNum(data))
+ if (isNum(data)) {
index = data;
- else
+ } else {
differences[index++] = data.name;
+ }
}
}
} else if (isName(encoding)) {
@@ -15953,14 +16739,14 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
if (baseEncodingName) {
properties.defaultEncoding = Encodings[baseEncodingName].slice();
} else {
- var encoding = properties.type === 'TrueType' ?
- Encodings.WinAnsiEncoding :
- Encodings.StandardEncoding;
+ encoding = (properties.type === 'TrueType' ?
+ Encodings.WinAnsiEncoding : Encodings.StandardEncoding);
// The Symbolic attribute can be misused for regular fonts
// Heuristic: we have to check if the font is a standard one also
if (!!(properties.flags & FontFlags.Symbolic)) {
- encoding = !properties.file && /Symbol/i.test(properties.name) ?
- Encodings.SymbolSetEncoding : Encodings.MacRomanEncoding;
+ encoding = (!properties.file && /Symbol/i.test(properties.name) ?
+ Encodings.SymbolSetEncoding :
+ Encodings.MacRomanEncoding);
}
properties.defaultEncoding = encoding;
}
@@ -15972,14 +16758,13 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
readToUnicode: function PartialEvaluator_readToUnicode(toUnicode) {
var cmapObj = toUnicode;
- var charToUnicode = [];
if (isName(cmapObj)) {
return CMapFactory.create(cmapObj).map;
} else if (isStream(cmapObj)) {
var cmap = CMapFactory.create(cmapObj).map;
// Convert UTF-16BE
// NOTE: cmap can be a sparse array, so use forEach instead of for(;;)
- // to iterate over all keys.
+ // to iterate over all keys.
cmap.forEach(function(token, i) {
var str = [];
for (var k = 0; k < token.length; k += 2) {
@@ -15998,6 +16783,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
}
return null;
},
+
readCidToGidMap: function PartialEvaluator_readCidToGidMap(cidToGidStream) {
// Extract the encoding from the CIDToGIDMap
var glyphsData = cidToGidStream.getBytes();
@@ -16006,69 +16792,74 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
var result = [];
for (var j = 0, jj = glyphsData.length; j < jj; j++) {
var glyphID = (glyphsData[j++] << 8) | glyphsData[j];
- if (glyphID === 0)
+ if (glyphID === 0) {
continue;
-
+ }
var code = j >> 1;
result[code] = glyphID;
}
return result;
},
- extractWidths: function PartialEvaluator_extractWidths(dict,
- xref,
- descriptor,
- properties) {
+ extractWidths: function PartialEvaluator_extractWidths(dict, xref,
+ descriptor,
+ properties) {
var glyphsWidths = [];
var defaultWidth = 0;
var glyphsVMetrics = [];
var defaultVMetrics;
+ var i, ii, j, jj, start, code, widths;
if (properties.composite) {
defaultWidth = dict.get('DW') || 1000;
- var widths = dict.get('W');
+ widths = dict.get('W');
if (widths) {
- for (var i = 0, ii = widths.length; i < ii; i++) {
- var start = widths[i++];
- var code = xref.fetchIfRef(widths[i]);
+ for (i = 0, ii = widths.length; i < ii; i++) {
+ start = widths[i++];
+ code = xref.fetchIfRef(widths[i]);
if (isArray(code)) {
- for (var j = 0, jj = code.length; j < jj; j++)
+ for (j = 0, jj = code.length; j < jj; j++) {
glyphsWidths[start++] = code[j];
+ }
} else {
var width = widths[++i];
- for (var j = start; j <= code; j++)
+ for (j = start; j <= code; j++) {
glyphsWidths[j] = width;
+ }
}
}
}
if (properties.vertical) {
- var vmetrics = dict.get('DW2') || [880, -1000];
+ var vmetrics = (dict.get('DW2') || [880, -1000]);
defaultVMetrics = [vmetrics[1], defaultWidth * 0.5, vmetrics[0]];
vmetrics = dict.get('W2');
if (vmetrics) {
- for (var i = 0, ii = vmetrics.length; i < ii; i++) {
- var start = vmetrics[i++];
- var code = xref.fetchIfRef(vmetrics[i]);
+ for (i = 0, ii = vmetrics.length; i < ii; i++) {
+ start = vmetrics[i++];
+ code = xref.fetchIfRef(vmetrics[i]);
if (isArray(code)) {
- for (var j = 0, jj = code.length; j < jj; j++)
+ for (j = 0, jj = code.length; j < jj; j++) {
glyphsVMetrics[start++] = [code[j++], code[j++], code[j]];
+ }
} else {
var vmetric = [vmetrics[++i], vmetrics[++i], vmetrics[++i]];
- for (var j = start; j <= code; j++)
+ for (j = start; j <= code; j++) {
glyphsVMetrics[j] = vmetric;
+ }
}
}
}
}
} else {
var firstChar = properties.firstChar;
- var widths = dict.get('Widths');
+ widths = dict.get('Widths');
if (widths) {
- var j = firstChar;
- for (var i = 0, ii = widths.length; i < ii; i++)
+ j = firstChar;
+ for (i = 0, ii = widths.length; i < ii; i++) {
glyphsWidths[j++] = widths[i];
- defaultWidth = parseFloat(descriptor.get('MissingWidth')) || 0;
+ }
+ defaultWidth = (parseFloat(descriptor.get('MissingWidth')) || 0);
} else {
// Trying get the BaseFont metrics (see comment above).
var baseFontName = dict.get('BaseFont');
@@ -16083,11 +16874,13 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
}
// Heuristic: detection of monospace font by checking all non-zero widths
- var isMonospace = true, firstWidth = defaultWidth;
+ var isMonospace = true;
+ var firstWidth = defaultWidth;
for (var glyph in glyphsWidths) {
var glyphWidth = glyphsWidths[glyph];
- if (!glyphWidth)
+ if (!glyphWidth) {
continue;
+ }
if (!firstWidth) {
firstWidth = glyphWidth;
continue;
@@ -16097,8 +16890,9 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
break;
}
}
- if (isMonospace)
+ if (isMonospace) {
properties.flags |= FontFlags.FixedPitch;
+ }
properties.defaultWidth = defaultWidth;
properties.widths = glyphsWidths;
@@ -16107,17 +16901,17 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
},
isSerifFont: function PartialEvaluator_isSerifFont(baseFontName) {
-
// Simulating descriptor flags attribute
var fontNameWoStyle = baseFontName.split('-')[0];
return (fontNameWoStyle in serifFonts) ||
- (fontNameWoStyle.search(/serif/gi) !== -1);
+ (fontNameWoStyle.search(/serif/gi) !== -1);
},
getBaseFontMetrics: function PartialEvaluator_getBaseFontMetrics(name) {
- var defaultWidth = 0, widths = [], monospace = false;
-
- var lookupName = stdFontMap[name] || name;
+ var defaultWidth = 0;
+ var widths = [];
+ var monospace = false;
+ var lookupName = (stdFontMap[name] || name);
if (!(lookupName in Metrics)) {
// Use default fonts for looking up font metrics if the passed
@@ -16144,8 +16938,9 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
};
},
- buildCharCodeToWidth: function PartialEvaluator_bulildCharCodeToWidth(
- widthsByGlyphName, properties) {
+ buildCharCodeToWidth:
+ function PartialEvaluator_bulildCharCodeToWidth(widthsByGlyphName,
+ properties) {
var widths = Object.create(null);
var differences = properties.differences;
var encoding = properties.defaultEncoding;
@@ -16163,44 +16958,92 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
return widths;
},
- translateFont: function PartialEvaluator_translateFont(dict,
- xref) {
+ preEvaluateFont: function PartialEvaluator_preEvaluateFont(dict, xref) {
var baseDict = dict;
var type = dict.get('Subtype');
- assertWellFormed(isName(type), 'invalid font Subtype');
+ assert(isName(type), 'invalid font Subtype');
var composite = false;
+ var uint8array;
if (type.name == 'Type0') {
// If font is a composite
// - get the descendant font
// - set the type according to the descendant font
// - get the FontDescriptor from the descendant font
var df = dict.get('DescendantFonts');
- if (!df)
+ if (!df) {
error('Descendant fonts are not specified');
-
- dict = isArray(df) ? xref.fetchIfRef(df[0]) : df;
+ }
+ dict = (isArray(df) ? xref.fetchIfRef(df[0]) : df);
type = dict.get('Subtype');
- assertWellFormed(isName(type), 'invalid font Subtype');
+ assert(isName(type), 'invalid font Subtype');
composite = true;
}
- var maxCharIndex = composite ? 0xFFFF : 0xFF;
var descriptor = dict.get('FontDescriptor');
+ if (descriptor) {
+ var hash = new MurmurHash3_64();
+ var encoding = baseDict.getRaw('Encoding');
+ if (isName(encoding)) {
+ hash.update(encoding.name);
+ } else if (isRef(encoding)) {
+ hash.update(encoding.num + '_' + encoding.gen);
+ }
+
+ var toUnicode = dict.get('ToUnicode') || baseDict.get('ToUnicode');
+ if (isStream(toUnicode)) {
+ var stream = toUnicode.str || toUnicode;
+ uint8array = stream.buffer ?
+ new Uint8Array(stream.buffer.buffer, 0, stream.bufferLength) :
+ new Uint8Array(stream.bytes.buffer,
+ stream.start, stream.end - stream.start);
+ hash.update(uint8array);
+
+ } else if (isName(toUnicode)) {
+ hash.update(toUnicode.name);
+ }
+
+ var widths = dict.get('Widths') || baseDict.get('Widths');
+ if (widths) {
+ uint8array = new Uint8Array(new Uint32Array(widths).buffer);
+ hash.update(uint8array);
+ }
+ }
+
+ return {
+ descriptor: descriptor,
+ dict: dict,
+ baseDict: baseDict,
+ composite: composite,
+ hash: hash ? hash.hexdigest() : ''
+ };
+ },
+
+ translateFont: function PartialEvaluator_translateFont(preEvaluatedFont,
+ xref) {
+ var baseDict = preEvaluatedFont.baseDict;
+ var dict = preEvaluatedFont.dict;
+ var composite = preEvaluatedFont.composite;
+ var descriptor = preEvaluatedFont.descriptor;
+ var type = dict.get('Subtype');
+ var maxCharIndex = (composite ? 0xFFFF : 0xFF);
+ var properties;
+
if (!descriptor) {
if (type.name == 'Type3') {
// FontDescriptor is only required for Type3 fonts when the document
// is a tagged pdf. Create a barbebones one to get by.
- descriptor = new Dict();
+ descriptor = new Dict(null);
descriptor.set('FontName', Name.get(type.name));
} else {
// Before PDF 1.5 if the font was one of the base 14 fonts, having a
// FontDescriptor was not required.
// This case is here for compatibility.
var baseFontName = dict.get('BaseFont');
- if (!isName(baseFontName))
+ if (!isName(baseFontName)) {
error('Base font is not specified');
+ }
// Using base font name as a font name.
baseFontName = baseFontName.name.replace(/[,_]/g, '-');
@@ -16208,13 +17051,13 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
// Simulating descriptor flags attribute
var fontNameWoStyle = baseFontName.split('-')[0];
- var flags = (
- this.isSerifFont(fontNameWoStyle) ? FontFlags.Serif : 0) |
+ var flags =
+ (this.isSerifFont(fontNameWoStyle) ? FontFlags.Serif : 0) |
(metrics.monospace ? FontFlags.FixedPitch : 0) |
(symbolsFonts[fontNameWoStyle] ? FontFlags.Symbolic :
- FontFlags.Nonsymbolic);
+ FontFlags.Nonsymbolic);
- var properties = {
+ properties = {
type: type.name,
name: baseFontName,
widths: metrics.widths,
@@ -16226,7 +17069,6 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
this.extractDataStructures(dict, dict, xref, properties);
properties.widths = this.buildCharCodeToWidth(metrics.widths,
properties);
-
return new Font(baseFontName, null, properties);
}
}
@@ -16236,12 +17078,12 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
// 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.
- var firstChar = dict.get('FirstChar') || 0;
- var lastChar = dict.get('LastChar') || maxCharIndex;
+ var firstChar = (dict.get('FirstChar') || 0);
+ var lastChar = (dict.get('LastChar') || maxCharIndex);
var fontName = descriptor.get('FontName');
var baseFont = dict.get('BaseFont');
- // Some bad pdf's have a string as the font name.
+ // Some bad PDFs have a string as the font name.
if (isString(fontName)) {
fontName = Name.get(fontName);
}
@@ -16256,26 +17098,31 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
info('The FontDescriptor\'s FontName is "' + fontNameStr +
'" but should be the same as the Font\'s BaseFont "' +
baseFontStr + '"');
+ // Workaround for cases where e.g. fontNameStr = 'Arial' and
+ // baseFontStr = 'Arial,Bold' (needed when no font file is embedded).
+ if (fontNameStr && baseFontStr &&
+ baseFontStr.search(fontNameStr) === 0) {
+ fontName = baseFont;
+ }
}
}
- fontName = fontName || baseFont;
+ fontName = (fontName || baseFont);
- assertWellFormed(isName(fontName), 'invalid font name');
+ assert(isName(fontName), 'invalid font name');
var fontFile = descriptor.get('FontFile', 'FontFile2', 'FontFile3');
if (fontFile) {
if (fontFile.dict) {
var subtype = fontFile.dict.get('Subtype');
- if (subtype)
+ if (subtype) {
subtype = subtype.name;
-
+ }
var length1 = fontFile.dict.get('Length1');
-
var length2 = fontFile.dict.get('Length2');
}
}
- var properties = {
+ properties = {
type: type.name,
name: fontName.name,
subtype: subtype,
@@ -16286,9 +17133,9 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
composite: composite,
wideChars: composite,
fixedPitch: false,
- fontMatrix: dict.get('FontMatrix') || FONT_IDENTITY_MATRIX,
+ fontMatrix: (dict.get('FontMatrix') || FONT_IDENTITY_MATRIX),
firstChar: firstChar || 0,
- lastChar: lastChar || maxCharIndex,
+ lastChar: (lastChar || maxCharIndex),
bbox: descriptor.get('FontBBox'),
ascent: descriptor.get('Ascent'),
descent: descriptor.get('Descent'),
@@ -16304,14 +17151,15 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
if (isName(cidEncoding)) {
properties.cidEncoding = cidEncoding.name;
}
- properties.cMap = CMapFactory.create(cidEncoding, PDFJS.cMapUrl, null);
+ properties.cMap = CMapFactory.create(cidEncoding,
+ { url: PDFJS.cMapUrl, packed: PDFJS.cMapPacked }, null);
properties.vertical = properties.cMap.vertical;
}
this.extractDataStructures(dict, baseDict, xref, properties);
this.extractWidths(dict, xref, descriptor, properties);
if (type.name === 'Type3') {
- properties.coded = true;
+ properties.isType3Font = true;
}
return new Font(fontName.name, fontFile, properties);
@@ -16321,65 +17169,111 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
return PartialEvaluator;
})();
+var TranslatedFont = (function TranslatedFontClosure() {
+ function TranslatedFont(loadedName, font, dict) {
+ this.loadedName = loadedName;
+ this.font = font;
+ this.dict = dict;
+ this.type3Loaded = null;
+ this.sent = false;
+ }
+ TranslatedFont.prototype = {
+ send: function (handler) {
+ if (this.sent) {
+ return;
+ }
+ var fontData = this.font.exportData();
+ handler.send('commonobj', [
+ this.loadedName,
+ 'Font',
+ fontData
+ ]);
+ this.sent = true;
+ },
+ loadType3Data: function (evaluator, resources, parentOperatorList) {
+ assert(this.font.isType3Font);
+
+ if (this.type3Loaded) {
+ return this.type3Loaded;
+ }
+
+ var translatedFont = this.font;
+ var loadCharProcsPromise = Promise.resolve();
+ var charProcs = this.dict.get('CharProcs').getAll();
+ var fontResources = this.dict.get('Resources') || resources;
+ var charProcKeys = Object.keys(charProcs);
+ var charProcOperatorList = {};
+ for (var i = 0, n = charProcKeys.length; i < n; ++i) {
+ loadCharProcsPromise = loadCharProcsPromise.then(function (key) {
+ var glyphStream = charProcs[key];
+ var operatorList = new OperatorList();
+ return evaluator.getOperatorList(glyphStream, fontResources,
+ operatorList).
+ then(function () {
+ charProcOperatorList[key] = operatorList.getIR();
+
+ // Add the dependencies to the parent operator list so they are
+ // resolved before sub operator list is executed synchronously.
+ parentOperatorList.addDependencies(operatorList.dependencies);
+ });
+ }.bind(this, charProcKeys[i]));
+ }
+ this.type3Loaded = loadCharProcsPromise.then(function () {
+ translatedFont.charProcOperatorList = charProcOperatorList;
+ });
+ return this.type3Loaded;
+ }
+ };
+ return TranslatedFont;
+})();
+
var OperatorList = (function OperatorListClosure() {
var CHUNK_SIZE = 1000;
var CHUNK_SIZE_ABOUT = CHUNK_SIZE - 5; // close to chunk size
- function getTransfers(queue) {
- var transfers = [];
- var fnArray = queue.fnArray, argsArray = queue.argsArray;
- for (var i = 0, ii = queue.length; i < ii; i++) {
- switch (fnArray[i]) {
- case OPS.paintInlineImageXObject:
- case OPS.paintInlineImageXObjectGroup:
- case OPS.paintImageMaskXObject:
- var arg = argsArray[i][0]; // first param in imgData
- if (!arg.cached) {
- transfers.push(arg.data.buffer);
- }
- break;
- }
+ function getTransfers(queue) {
+ var transfers = [];
+ var fnArray = queue.fnArray, argsArray = queue.argsArray;
+ for (var i = 0, ii = queue.length; i < ii; i++) {
+ switch (fnArray[i]) {
+ case OPS.paintInlineImageXObject:
+ case OPS.paintInlineImageXObjectGroup:
+ case OPS.paintImageMaskXObject:
+ var arg = argsArray[i][0]; // first param in imgData
+ if (!arg.cached) {
+ transfers.push(arg.data.buffer);
+ }
+ break;
}
- return transfers;
}
+ return transfers;
+ }
-
- function OperatorList(intent, messageHandler, pageIndex) {
+ function OperatorList(intent, messageHandler, pageIndex) {
this.messageHandler = messageHandler;
- // When there isn't a message handler the fn array needs to be able to grow
- // since we can't flush the operators.
- if (messageHandler) {
- this.fnArray = new Uint8Array(CHUNK_SIZE);
- } else {
- this.fnArray = [];
- }
+ this.fnArray = [];
this.argsArray = [];
this.dependencies = {};
this.pageIndex = pageIndex;
- this.fnIndex = 0;
this.intent = intent;
}
OperatorList.prototype = {
-
get length() {
return this.argsArray.length;
},
addOp: function(fn, args) {
+ this.fnArray.push(fn);
+ this.argsArray.push(args);
if (this.messageHandler) {
- this.fnArray[this.fnIndex++] = fn;
- this.argsArray.push(args);
- if (this.fnIndex >= CHUNK_SIZE) {
+ if (this.fnArray.length >= CHUNK_SIZE) {
this.flush();
- } else if (this.fnIndex >= CHUNK_SIZE_ABOUT &&
- (fn === OPS.restore || fn === OPS.endText)) {
+ } else if (this.fnArray.length >= CHUNK_SIZE_ABOUT &&
+ (fn === OPS.restore || fn === OPS.endText)) {
// heuristic to flush on boundary of restore or endText
this.flush();
}
- } else {
- this.fnArray.push(fn);
- this.argsArray.push(args);
}
},
@@ -16424,75 +17318,103 @@ var OperatorList = (function OperatorListClosure() {
},
pageIndex: this.pageIndex,
intent: this.intent
- }, null, transfers);
- this.dependencies = [];
- this.fnIndex = 0;
- this.argsArray = [];
+ }, transfers);
+ this.dependencies = {};
+ this.fnArray.length = 0;
+ this.argsArray.length = 0;
}
};
return OperatorList;
})();
+var StateManager = (function StateManagerClosure() {
+ function StateManager(initialState) {
+ this.state = initialState;
+ this.stateStack = [];
+ }
+ StateManager.prototype = {
+ save: function () {
+ var old = this.state;
+ this.stateStack.push(this.state);
+ this.state = old.clone();
+ },
+ restore: function () {
+ var prev = this.stateStack.pop();
+ if (prev) {
+ this.state = prev;
+ }
+ },
+ transform: function (args) {
+ this.state.ctm = Util.transform(this.state.ctm, args);
+ }
+ };
+ return StateManager;
+})();
+
var TextState = (function TextStateClosure() {
function TextState() {
+ this.ctm = new Float32Array(IDENTITY_MATRIX);
this.fontSize = 0;
- this.textMatrix = [1, 0, 0, 1, 0, 0];
- this.stateStack = [];
- //textState variables
+ this.font = null;
+ this.fontMatrix = FONT_IDENTITY_MATRIX;
+ this.textMatrix = IDENTITY_MATRIX.slice();
+ this.textLineMatrix = IDENTITY_MATRIX.slice();
+ this.charSpacing = 0;
+ this.wordSpacing = 0;
this.leading = 0;
this.textHScale = 1;
this.textRise = 0;
}
+
TextState.prototype = {
- initialiseTextObj: function TextState_initialiseTextObj() {
- var m = this.textMatrix;
- m[0] = 1; m[1] = 0; m[2] = 0; m[3] = 1; m[4] = 0; m[5] = 0;
- },
setTextMatrix: function TextState_setTextMatrix(a, b, c, d, e, f) {
var m = this.textMatrix;
m[0] = a; m[1] = b; m[2] = c; m[3] = d; m[4] = e; m[5] = f;
},
+ setTextLineMatrix: function TextState_setTextMatrix(a, b, c, d, e, f) {
+ var m = this.textLineMatrix;
+ m[0] = a; m[1] = b; m[2] = c; m[3] = d; m[4] = e; m[5] = f;
+ },
translateTextMatrix: function TextState_translateTextMatrix(x, y) {
var m = this.textMatrix;
m[4] = m[0] * x + m[2] * y + m[4];
m[5] = m[1] * x + m[3] * y + m[5];
},
- calcRenderParams: function TextState_calcRenderingParams(cm) {
- var tm = this.textMatrix;
- var a = this.fontSize;
- var b = a * this.textHScale;
- var c = this.textRise;
- var vScale = Math.sqrt((tm[2] * tm[2]) + (tm[3] * tm[3]));
- var angle = Math.atan2(tm[1], tm[0]);
- var m0 = tm[0] * cm[0] + tm[1] * cm[2];
- var m1 = tm[0] * cm[1] + tm[1] * cm[3];
- var m2 = tm[2] * cm[0] + tm[3] * cm[2];
- var m3 = tm[2] * cm[1] + tm[3] * cm[3];
- var m4 = tm[4] * cm[0] + tm[5] * cm[2] + cm[4];
- var m5 = tm[4] * cm[1] + tm[5] * cm[3] + cm[5];
- var renderMatrix = [
- b * m0,
- b * m1,
- a * m2,
- a * m3,
- c * m2 + m4,
- c * m3 + m5
- ];
- return {
- renderMatrix: renderMatrix,
- vScale: vScale,
- angle: angle
- };
+ translateTextLineMatrix: function TextState_translateTextMatrix(x, y) {
+ var m = this.textLineMatrix;
+ m[4] = m[0] * x + m[2] * y + m[4];
+ m[5] = m[1] * x + m[3] * y + m[5];
+ },
+ calcRenderMatrix: function TextState_calcRendeMatrix(ctm) {
+ // 9.4.4 Text Space Details
+ var tsm = [this.fontSize * this.textHScale, 0,
+ 0, this.fontSize,
+ 0, this.textRise];
+ return Util.transform(ctm, Util.transform(this.textMatrix, tsm));
},
+ carriageReturn: function TextState_carriageReturn() {
+ this.translateTextLineMatrix(0, -this.leading);
+ this.textMatrix = this.textLineMatrix.slice();
+ },
+ clone: function TextState_clone() {
+ var clone = Object.create(this);
+ clone.textMatrix = this.textMatrix.slice();
+ clone.textLineMatrix = this.textLineMatrix.slice();
+ clone.fontMatrix = this.fontMatrix.slice();
+ return clone;
+ }
};
return TextState;
})();
var EvalState = (function EvalStateClosure() {
function EvalState() {
+ this.ctm = new Float32Array(IDENTITY_MATRIX);
this.font = null;
this.textRenderingMode = TextRenderingMode.FILL;
+ this.fillColorSpace = ColorSpace.singletons.gray;
+ this.strokeColorSpace = ColorSpace.singletons.gray;
}
EvalState.prototype = {
clone: function CanvasExtraState_clone() {
@@ -16502,7 +17424,7 @@ var EvalState = (function EvalStateClosure() {
return EvalState;
})();
-var EvaluatorPreprocessor = (function EvaluatorPreprocessor() {
+var EvaluatorPreprocessor = (function EvaluatorPreprocessorClosure() {
// Specifies properties for each command
//
// If variableArgs === true: [0, `numArgs`] expected
@@ -16562,7 +17484,7 @@ var EvaluatorPreprocessor = (function EvaluatorPreprocessor() {
TJ: { id: OPS.showSpacedText, numArgs: 1, variableArgs: false },
'\'': { id: OPS.nextLineShowText, numArgs: 1, variableArgs: false },
'"': { id: OPS.nextLineSetSpacingShowText, numArgs: 3,
- variableArgs: false },
+ variableArgs: false },
// Type3 fonts
d0: { id: OPS.setCharWidth, numArgs: 2, variableArgs: false },
@@ -16596,7 +17518,7 @@ var EvaluatorPreprocessor = (function EvaluatorPreprocessor() {
DP: { id: OPS.markPointProps, numArgs: 2, variableArgs: false },
BMC: { id: OPS.beginMarkedContent, numArgs: 1, variableArgs: false },
BDC: { id: OPS.beginMarkedContentProps, numArgs: 2,
- variableArgs: false },
+ variableArgs: false },
EMC: { id: OPS.endMarkedContent, numArgs: 0, variableArgs: false },
// Compatibility
@@ -16616,17 +17538,19 @@ var EvaluatorPreprocessor = (function EvaluatorPreprocessor() {
'null': null
};
- function EvaluatorPreprocessor(stream, xref) {
+ function EvaluatorPreprocessor(stream, xref, stateManager) {
// TODO(mduan): pass array of knownCommands rather than OP_MAP
// dictionary
this.parser = new Parser(new Lexer(stream, OP_MAP), false, xref);
- this.ctm = new Float32Array([1, 0, 0, 1, 0, 0]);
- this.savedStates = [];
+ this.stateManager = stateManager;
+ this.nonProcessedArgs = [];
}
+
EvaluatorPreprocessor.prototype = {
get savedStatesDepth() {
- return this.savedStates.length;
+ return this.stateManager.stateStack.length;
},
+
read: function EvaluatorPreprocessor_read() {
var args = [];
while (true) {
@@ -16637,8 +17561,8 @@ var EvaluatorPreprocessor = (function EvaluatorPreprocessor() {
if (!isCmd(obj)) {
// argument
if (obj !== null && obj !== undefined) {
- args.push(obj instanceof Dict ? obj.getAll() : obj);
- assertWellFormed(args.length <= 33, 'Too many arguments');
+ args.push((obj instanceof Dict ? obj.getAll() : obj));
+ assert(args.length <= 33, 'Too many arguments');
}
continue;
}
@@ -16653,64 +17577,56 @@ var EvaluatorPreprocessor = (function EvaluatorPreprocessor() {
var fn = opSpec.id;
+ // Some post script commands can be nested, e.g. /F2 /GS2 gs 5.711 Tf
+ if (!opSpec.variableArgs && args.length !== opSpec.numArgs) {
+ while (args.length > opSpec.numArgs) {
+ this.nonProcessedArgs.push(args.shift());
+ }
+
+ while (args.length < opSpec.numArgs && this.nonProcessedArgs.length) {
+ args.unshift(this.nonProcessedArgs.pop());
+ }
+ }
+
// Validate the number of arguments for the command
if (opSpec.variableArgs) {
if (args.length > opSpec.numArgs) {
info('Command ' + fn + ': expected [0,' + opSpec.numArgs +
- '] args, but received ' + args.length + ' args');
+ '] args, but received ' + args.length + ' args');
}
} else {
if (args.length < opSpec.numArgs) {
// If we receive too few args, it's not possible to possible
// to execute the command, so skip the command
info('Command ' + fn + ': because expected ' +
- opSpec.numArgs + ' args, but received ' + args.length +
- ' args; skipping');
+ opSpec.numArgs + ' args, but received ' + args.length +
+ ' args; skipping');
args = [];
continue;
} else if (args.length > opSpec.numArgs) {
info('Command ' + fn + ': expected ' + opSpec.numArgs +
- ' args, but received ' + args.length + ' args');
+ ' args, but received ' + args.length + ' args');
}
}
// TODO figure out how to type-check vararg functions
-
this.preprocessCommand(fn, args);
- return {fn: fn, args: args};
+ return { fn: fn, args: args };
}
},
- getState: function EvaluatorPreprocessor_getState() {
- return {
- ctm: this.ctm
- };
- },
- setState: function EvaluatorPreprocessor_setState(state) {
- this.ctm = state.ctm;
- },
- preprocessCommand: function EvaluatorPreprocessor_preprocessCommand(fn,
- args) {
+
+ preprocessCommand:
+ function EvaluatorPreprocessor_preprocessCommand(fn, args) {
switch (fn | 0) {
case OPS.save:
- this.savedStates.push(this.getState());
+ this.stateManager.save();
break;
case OPS.restore:
- var previousState = this.savedStates.pop();
- if (previousState) {
- this.setState(previousState);
- }
+ this.stateManager.restore();
break;
case OPS.transform:
- var ctm = this.ctm;
- var m = new Float32Array(6);
- m[0] = ctm[0] * args[0] + ctm[2] * args[1];
- m[1] = ctm[1] * args[0] + ctm[3] * args[1];
- m[2] = ctm[0] * args[2] + ctm[2] * args[3];
- m[3] = ctm[1] * args[2] + ctm[3] * args[3];
- m[4] = ctm[0] * args[4] + ctm[2] * args[5] + ctm[4];
- m[5] = ctm[1] * args[4] + ctm[3] * args[5] + ctm[5];
- this.ctm = m;
+ this.stateManager.transform(args);
break;
}
}
@@ -16719,31 +17635,34 @@ var EvaluatorPreprocessor = (function EvaluatorPreprocessor() {
})();
var QueueOptimizer = (function QueueOptimizerClosure() {
- function squash(array, index, howMany, element) {
- if (isArray(array)) {
- array.splice(index, howMany, element);
- } else if (typeof element !== 'undefined') {
- // Replace the element.
- array[index] = element;
- // Shift everything after the element up.
- var sub = array.subarray(index + howMany);
- array.set(sub, index + 1);
- } else {
- // Shift everything after the element up.
- var sub = array.subarray(index + howMany);
- array.set(sub, index);
- }
- }
-
function addState(parentState, pattern, fn) {
var state = parentState;
for (var i = 0, ii = pattern.length - 1; i < ii; i++) {
var item = pattern[i];
- state = state[item] || (state[item] = []);
+ state = (state[item] || (state[item] = []));
}
state[pattern[pattern.length - 1]] = fn;
}
+ function handlePaintSolidColorImageMask(index, count, fnArray, argsArray) {
+ // Handles special case of mainly LaTeX documents which
+ // use image masks to draw lines with the current fill style.
+ // 'count' groups of (save, transform, paintImageMaskXObject, restore)+
+ // have been found at index.
+ for (var i = 0; i < count; i++) {
+ var arg = argsArray[index + 4 * i + 2];
+ var imageMask = arg.length == 1 && arg[0];
+ if (imageMask && imageMask.width == 1 && imageMask.height == 1 &&
+ (!imageMask.data.length || (imageMask.data.length == 1 &&
+ imageMask.data[0] === 0))) {
+ fnArray[index + 4 * i + 2] = OPS.paintSolidColorImageMask;
+ continue;
+ }
+ break;
+ }
+ return count - i;
+ }
+
var InitialState = [];
addState(InitialState,
@@ -16758,10 +17677,9 @@ var QueueOptimizer = (function QueueOptimizerClosure() {
var fnArray = context.fnArray, argsArray = context.argsArray;
var j = context.currentOperation - 3, i = j + 4;
- var ii = context.operationsLength;
+ var ii = fnArray.length;
- for (; i < ii && fnArray[i - 4] === fnArray[i]; i++) {
- }
+ for (; i < ii && fnArray[i - 4] === fnArray[i]; i++) {}
var count = Math.min((i - j) >> 2, MAX_IMAGES_IN_INLINE_IMAGES_BLOCK);
if (count < MIN_IMAGES_IN_INLINE_IMAGES_BLOCK) {
context.currentOperation = i - 1;
@@ -16772,7 +17690,8 @@ var QueueOptimizer = (function QueueOptimizerClosure() {
var maxX = 0;
var map = [], maxLineHeight = 0;
var currentX = IMAGE_PADDING, currentY = IMAGE_PADDING;
- for (var q = 0; q < count; q++) {
+ var q;
+ for (q = 0; q < count; q++) {
var transform = argsArray[j + (q << 2) + 1];
var img = argsArray[j + (q << 2) + 2][0];
if (currentX + img.width > MAX_WIDTH) {
@@ -16794,22 +17713,19 @@ var QueueOptimizer = (function QueueOptimizerClosure() {
var imgHeight = currentY + maxLineHeight + IMAGE_PADDING;
var imgData = new Uint8Array(imgWidth * imgHeight * 4);
var imgRowSize = imgWidth << 2;
- for (var q = 0; q < count; q++) {
+ for (q = 0; q < count; q++) {
var data = argsArray[j + (q << 2) + 2][0].data;
// copy image by lines and extends pixels into padding
var rowSize = map[q].w << 2;
var dataOffset = 0;
var offset = (map[q].x + map[q].y * imgWidth) << 2;
- imgData.set(
- data.subarray(0, rowSize), offset - imgRowSize);
+ imgData.set(data.subarray(0, rowSize), offset - imgRowSize);
for (var k = 0, kk = map[q].h; k < kk; k++) {
- imgData.set(
- data.subarray(dataOffset, dataOffset + rowSize), offset);
+ imgData.set(data.subarray(dataOffset, dataOffset + rowSize), offset);
dataOffset += rowSize;
offset += imgRowSize;
}
- imgData.set(
- data.subarray(dataOffset - rowSize, dataOffset), offset);
+ imgData.set(data.subarray(dataOffset - rowSize, dataOffset), offset);
while (offset >= 0) {
data[offset - 4] = data[offset];
data[offset - 3] = data[offset + 1];
@@ -16823,12 +17739,11 @@ var QueueOptimizer = (function QueueOptimizerClosure() {
}
}
// replacing queue items
- squash(fnArray, j, count * 4, OPS.paintInlineImageXObjectGroup);
+ fnArray.splice(j, count * 4, OPS.paintInlineImageXObjectGroup);
argsArray.splice(j, count * 4,
- [{width: imgWidth, height: imgHeight, kind: ImageKind.RGBA_32BPP,
- data: imgData}, map]);
+ [{ width: imgWidth, height: imgHeight, kind: ImageKind.RGBA_32BPP,
+ data: imgData }, map]);
context.currentOperation = j;
- context.operationsLength -= count * 4 - 1;
});
addState(InitialState,
@@ -16842,23 +17757,24 @@ var QueueOptimizer = (function QueueOptimizerClosure() {
var fnArray = context.fnArray, argsArray = context.argsArray;
var j = context.currentOperation - 3, i = j + 4;
- var ii = context.operationsLength;
+ var ii = fnArray.length, q;
- for (; i < ii && fnArray[i - 4] === fnArray[i]; i++) {
- }
+ for (; i < ii && fnArray[i - 4] === fnArray[i]; i++) {}
var count = (i - j) >> 2;
+ count = handlePaintSolidColorImageMask(j, count, fnArray, argsArray);
if (count < MIN_IMAGES_IN_MASKS_BLOCK) {
context.currentOperation = i - 1;
return;
}
var isSameImage = false;
+ var transformArgs;
if (argsArray[j + 1][1] === 0 && argsArray[j + 1][2] === 0) {
i = j + 4;
isSameImage = true;
- for (var q = 1; q < count; q++, i += 4) {
+ for (q = 1; q < count; q++, i += 4) {
var prevTransformArgs = argsArray[i - 3];
- var transformArgs = argsArray[i + 1];
+ transformArgs = argsArray[i + 1];
if (argsArray[i - 2][0] !== argsArray[i + 2][0] ||
prevTransformArgs[0] !== transformArgs[0] ||
prevTransformArgs[1] !== transformArgs[1] ||
@@ -16878,36 +17794,35 @@ var QueueOptimizer = (function QueueOptimizerClosure() {
count = Math.min(count, MAX_SAME_IMAGES_IN_MASKS_BLOCK);
var positions = new Float32Array(count * 2);
i = j + 1;
- for (var q = 0; q < count; q++) {
- var transformArgs = argsArray[i];
+ for (q = 0; q < count; q++) {
+ transformArgs = argsArray[i];
positions[(q << 1)] = transformArgs[4];
positions[(q << 1) + 1] = transformArgs[5];
i += 4;
}
// replacing queue items
- squash(fnArray, j, count * 4, OPS.paintImageMaskXObjectRepeat);
+ fnArray.splice(j, count * 4, OPS.paintImageMaskXObjectRepeat);
argsArray.splice(j, count * 4, [argsArray[j + 2][0],
- argsArray[j + 1][0], argsArray[j + 1][3], positions]);
+ argsArray[j + 1][0], argsArray[j + 1][3], positions]);
context.currentOperation = j;
- context.operationsLength -= count * 4 - 1;
} else {
count = Math.min(count, MAX_IMAGES_IN_MASKS_BLOCK);
var images = [];
- for (var q = 0; q < count; q++) {
- var transformArgs = argsArray[j + (q << 2) + 1];
+ for (q = 0; q < count; q++) {
+ transformArgs = argsArray[j + (q << 2) + 1];
var maskParams = argsArray[j + (q << 2) + 2][0];
- images.push({data: maskParams.data, width: maskParams.width,
- height: maskParams.height, transform: transformArgs});
+ images.push({ data: maskParams.data, width: maskParams.width,
+ height: maskParams.height,
+ transform: transformArgs });
}
// replacing queue items
- squash(fnArray, j, count * 4, OPS.paintImageMaskXObjectGroup);
+ fnArray.splice(j, count * 4, OPS.paintImageMaskXObjectGroup);
argsArray.splice(j, count * 4, [images]);
context.currentOperation = j;
- context.operationsLength -= count * 4 - 1;
}
});
@@ -16922,7 +17837,8 @@ var QueueOptimizer = (function QueueOptimizerClosure() {
if (argsArray[j + 1][1] !== 0 || argsArray[j + 1][2] !== 0) {
return;
}
- var ii = context.operationsLength;
+ var ii = fnArray.length;
+ var transformArgs;
for (; i + 3 < ii && fnArray[i - 4] === fnArray[i]; i += 4) {
if (fnArray[i - 3] !== fnArray[i + 1] ||
fnArray[i - 2] !== fnArray[i + 2] ||
@@ -16933,7 +17849,7 @@ var QueueOptimizer = (function QueueOptimizerClosure() {
break; // different image
}
var prevTransformArgs = argsArray[i - 3];
- var transformArgs = argsArray[i + 1];
+ transformArgs = argsArray[i + 1];
if (prevTransformArgs[0] !== transformArgs[0] ||
prevTransformArgs[1] !== transformArgs[1] ||
prevTransformArgs[2] !== transformArgs[2] ||
@@ -16950,19 +17866,18 @@ var QueueOptimizer = (function QueueOptimizerClosure() {
var positions = new Float32Array(count * 2);
i = j + 1;
for (var q = 0; q < count; q++) {
- var transformArgs = argsArray[i];
+ transformArgs = argsArray[i];
positions[(q << 1)] = transformArgs[4];
positions[(q << 1) + 1] = transformArgs[5];
i += 4;
}
var args = [argsArray[j + 2][0], argsArray[j + 1][0],
- argsArray[j + 1][3], positions];
+ argsArray[j + 1][3], positions];
// replacing queue items
- squash(fnArray, j, count * 4, OPS.paintImageXObjectRepeat);
+ fnArray.splice(j, count * 4, OPS.paintImageXObjectRepeat);
argsArray.splice(j, count * 4, args);
context.currentOperation = j;
- context.operationsLength -= count * 4 - 1;
});
addState(InitialState,
@@ -16975,12 +17890,12 @@ var QueueOptimizer = (function QueueOptimizerClosure() {
var fnArray = context.fnArray, argsArray = context.argsArray;
var j = context.currentOperation - 4, i = j + 5;
- var ii = context.operationsLength;
+ var ii = fnArray.length;
for (; i < ii && fnArray[i - 5] === fnArray[i]; i++) {
if (fnArray[i] === OPS.setFont) {
if (argsArray[i - 5][0] !== argsArray[i][0] ||
- argsArray[i - 5][1] !== argsArray[i][1]) {
+ argsArray[i - 5][1] !== argsArray[i][1]) {
break;
}
}
@@ -16991,11 +17906,11 @@ var QueueOptimizer = (function QueueOptimizerClosure() {
return;
}
if (j >= 4 && fnArray[j - 4] === fnArray[j + 1] &&
- fnArray[j - 3] === fnArray[j + 2] &&
- fnArray[j - 2] === fnArray[j + 3] &&
- fnArray[j - 1] === fnArray[j + 4] &&
- argsArray[j - 4][0] === argsArray[j + 1][0] &&
- argsArray[j - 4][1] === argsArray[j + 1][1]) {
+ fnArray[j - 3] === fnArray[j + 2] &&
+ fnArray[j - 2] === fnArray[j + 3] &&
+ fnArray[j - 1] === fnArray[j + 4] &&
+ argsArray[j - 4][0] === argsArray[j + 1][0] &&
+ argsArray[j - 4][1] === argsArray[j + 1][1]) {
// extending one block ahead (very first block might have 'dependency')
count++;
j -= 5;
@@ -17011,22 +17926,19 @@ var QueueOptimizer = (function QueueOptimizerClosure() {
k += 5;
}
var removed = (count - 1) * 3;
- squash(fnArray, i, removed);
+ fnArray.splice(i, removed);
argsArray.splice(i, removed);
context.currentOperation = i;
- context.operationsLength -= removed;
-
});
- function QueueOptimizer() {
- }
+ function QueueOptimizer() {}
+
QueueOptimizer.prototype = {
optimize: function QueueOptimizer_optimize(queue) {
var fnArray = queue.fnArray, argsArray = queue.argsArray;
var context = {
currentOperation: 0,
- operationsLength: argsArray.length,
fnArray: fnArray,
argsArray: argsArray
};
@@ -17038,7 +17950,7 @@ var QueueOptimizer = (function QueueOptimizerClosure() {
context.currentOperation = i;
state = state(context);
i = context.currentOperation;
- ii = context.operationsLength;
+ ii = context.fnArray.length;
}
}
}
@@ -17047,6 +17959,841 @@ var QueueOptimizer = (function QueueOptimizerClosure() {
})();
+var BUILT_IN_CMAPS = [
+// << Start unicode maps.
+'Adobe-GB1-UCS2',
+'Adobe-CNS1-UCS2',
+'Adobe-Japan1-UCS2',
+'Adobe-Korea1-UCS2',
+// >> End unicode maps.
+'78-EUC-H',
+'78-EUC-V',
+'78-H',
+'78-RKSJ-H',
+'78-RKSJ-V',
+'78-V',
+'78ms-RKSJ-H',
+'78ms-RKSJ-V',
+'83pv-RKSJ-H',
+'90ms-RKSJ-H',
+'90ms-RKSJ-V',
+'90msp-RKSJ-H',
+'90msp-RKSJ-V',
+'90pv-RKSJ-H',
+'90pv-RKSJ-V',
+'Add-H',
+'Add-RKSJ-H',
+'Add-RKSJ-V',
+'Add-V',
+'Adobe-CNS1-0',
+'Adobe-CNS1-1',
+'Adobe-CNS1-2',
+'Adobe-CNS1-3',
+'Adobe-CNS1-4',
+'Adobe-CNS1-5',
+'Adobe-CNS1-6',
+'Adobe-GB1-0',
+'Adobe-GB1-1',
+'Adobe-GB1-2',
+'Adobe-GB1-3',
+'Adobe-GB1-4',
+'Adobe-GB1-5',
+'Adobe-Japan1-0',
+'Adobe-Japan1-1',
+'Adobe-Japan1-2',
+'Adobe-Japan1-3',
+'Adobe-Japan1-4',
+'Adobe-Japan1-5',
+'Adobe-Japan1-6',
+'Adobe-Korea1-0',
+'Adobe-Korea1-1',
+'Adobe-Korea1-2',
+'B5-H',
+'B5-V',
+'B5pc-H',
+'B5pc-V',
+'CNS-EUC-H',
+'CNS-EUC-V',
+'CNS1-H',
+'CNS1-V',
+'CNS2-H',
+'CNS2-V',
+'ETHK-B5-H',
+'ETHK-B5-V',
+'ETen-B5-H',
+'ETen-B5-V',
+'ETenms-B5-H',
+'ETenms-B5-V',
+'EUC-H',
+'EUC-V',
+'Ext-H',
+'Ext-RKSJ-H',
+'Ext-RKSJ-V',
+'Ext-V',
+'GB-EUC-H',
+'GB-EUC-V',
+'GB-H',
+'GB-V',
+'GBK-EUC-H',
+'GBK-EUC-V',
+'GBK2K-H',
+'GBK2K-V',
+'GBKp-EUC-H',
+'GBKp-EUC-V',
+'GBT-EUC-H',
+'GBT-EUC-V',
+'GBT-H',
+'GBT-V',
+'GBTpc-EUC-H',
+'GBTpc-EUC-V',
+'GBpc-EUC-H',
+'GBpc-EUC-V',
+'H',
+'HKdla-B5-H',
+'HKdla-B5-V',
+'HKdlb-B5-H',
+'HKdlb-B5-V',
+'HKgccs-B5-H',
+'HKgccs-B5-V',
+'HKm314-B5-H',
+'HKm314-B5-V',
+'HKm471-B5-H',
+'HKm471-B5-V',
+'HKscs-B5-H',
+'HKscs-B5-V',
+'Hankaku',
+'Hiragana',
+'KSC-EUC-H',
+'KSC-EUC-V',
+'KSC-H',
+'KSC-Johab-H',
+'KSC-Johab-V',
+'KSC-V',
+'KSCms-UHC-H',
+'KSCms-UHC-HW-H',
+'KSCms-UHC-HW-V',
+'KSCms-UHC-V',
+'KSCpc-EUC-H',
+'KSCpc-EUC-V',
+'Katakana',
+'NWP-H',
+'NWP-V',
+'RKSJ-H',
+'RKSJ-V',
+'Roman',
+'UniCNS-UCS2-H',
+'UniCNS-UCS2-V',
+'UniCNS-UTF16-H',
+'UniCNS-UTF16-V',
+'UniCNS-UTF32-H',
+'UniCNS-UTF32-V',
+'UniCNS-UTF8-H',
+'UniCNS-UTF8-V',
+'UniGB-UCS2-H',
+'UniGB-UCS2-V',
+'UniGB-UTF16-H',
+'UniGB-UTF16-V',
+'UniGB-UTF32-H',
+'UniGB-UTF32-V',
+'UniGB-UTF8-H',
+'UniGB-UTF8-V',
+'UniJIS-UCS2-H',
+'UniJIS-UCS2-HW-H',
+'UniJIS-UCS2-HW-V',
+'UniJIS-UCS2-V',
+'UniJIS-UTF16-H',
+'UniJIS-UTF16-V',
+'UniJIS-UTF32-H',
+'UniJIS-UTF32-V',
+'UniJIS-UTF8-H',
+'UniJIS-UTF8-V',
+'UniJIS2004-UTF16-H',
+'UniJIS2004-UTF16-V',
+'UniJIS2004-UTF32-H',
+'UniJIS2004-UTF32-V',
+'UniJIS2004-UTF8-H',
+'UniJIS2004-UTF8-V',
+'UniJISPro-UCS2-HW-V',
+'UniJISPro-UCS2-V',
+'UniJISPro-UTF8-V',
+'UniJISX0213-UTF32-H',
+'UniJISX0213-UTF32-V',
+'UniJISX02132004-UTF32-H',
+'UniJISX02132004-UTF32-V',
+'UniKS-UCS2-H',
+'UniKS-UCS2-V',
+'UniKS-UTF16-H',
+'UniKS-UTF16-V',
+'UniKS-UTF32-H',
+'UniKS-UTF32-V',
+'UniKS-UTF8-H',
+'UniKS-UTF8-V',
+'V',
+'WP-Symbol'];
+
+// CMap, not to be confused with TrueType's cmap.
+var CMap = (function CMapClosure() {
+ function CMap(builtInCMap) {
+ // Codespace ranges are stored as follows:
+ // [[1BytePairs], [2BytePairs], [3BytePairs], [4BytePairs]]
+ // where nBytePairs are ranges e.g. [low1, high1, low2, high2, ...]
+ this.codespaceRanges = [[], [], [], []];
+ this.numCodespaceRanges = 0;
+ this.map = [];
+ this.vertical = false;
+ this.useCMap = null;
+ this.builtInCMap = builtInCMap;
+ }
+ CMap.prototype = {
+ addCodespaceRange: function(n, low, high) {
+ this.codespaceRanges[n - 1].push(low, high);
+ this.numCodespaceRanges++;
+ },
+
+ mapRange: function(low, high, dstLow) {
+ var lastByte = dstLow.length - 1;
+ while (low <= high) {
+ this.map[low] = dstLow;
+ // Only the last byte has to be incremented.
+ dstLow = dstLow.substr(0, lastByte) +
+ String.fromCharCode(dstLow.charCodeAt(lastByte) + 1);
+ ++low;
+ }
+ },
+
+ mapRangeToArray: function(low, high, array) {
+ var i = 0;
+ while (low <= high) {
+ this.map[low] = array[i++];
+ ++low;
+ }
+ },
+
+ mapOne: function(src, dst) {
+ this.map[src] = dst;
+ },
+
+ lookup: function(code) {
+ return this.map[code];
+ },
+
+ readCharCode: function(str, offset) {
+ var c = 0;
+ var codespaceRanges = this.codespaceRanges;
+ var codespaceRangesLen = this.codespaceRanges.length;
+ // 9.7.6.2 CMap Mapping
+ // The code length is at most 4.
+ for (var n = 0; n < codespaceRangesLen; n++) {
+ c = ((c << 8) | str.charCodeAt(offset + n)) >>> 0;
+ // Check each codespace range to see if it falls within.
+ var codespaceRange = codespaceRanges[n];
+ for (var k = 0, kk = codespaceRange.length; k < kk;) {
+ var low = codespaceRange[k++];
+ var high = codespaceRange[k++];
+ if (c >= low && c <= high) {
+ return [c, n + 1];
+ }
+ }
+ }
+
+ return [0, 1];
+ }
+
+ };
+ return CMap;
+})();
+
+var IdentityCMap = (function IdentityCMapClosure() {
+ function IdentityCMap(vertical, n) {
+ CMap.call(this);
+ this.vertical = vertical;
+ this.addCodespaceRange(n, 0, 0xffff);
+ this.mapRange(0, 0xffff, '\u0000');
+ }
+ Util.inherit(IdentityCMap, CMap, {});
+
+ return IdentityCMap;
+})();
+
+var BinaryCMapReader = (function BinaryCMapReaderClosure() {
+ function fetchBinaryData(url) {
+ var nonBinaryRequest = PDFJS.disableWorker;
+ var request = new XMLHttpRequest();
+ request.open('GET', url, false);
+ if (!nonBinaryRequest) {
+ try {
+ request.responseType = 'arraybuffer';
+ nonBinaryRequest = request.responseType !== 'arraybuffer';
+ } catch (e) {
+ nonBinaryRequest = true;
+ }
+ }
+ if (nonBinaryRequest && request.overrideMimeType) {
+ request.overrideMimeType('text/plain; charset=x-user-defined');
+ }
+ request.send(null);
+ if (request.status === 0 && /^https?:/i.test(url)) {
+ error('Unable to get binary cMap at: ' + url);
+ }
+ if (nonBinaryRequest) {
+ var data = Array.prototype.map.call(request.responseText, function (ch) {
+ return ch.charCodeAt(0) & 255;
+ });
+ return new Uint8Array(data);
+ }
+ return new Uint8Array(request.response);
+ }
+
+ function hexToInt(a, size) {
+ var n = 0;
+ for (var i = 0; i <= size; i++) {
+ n = (n << 8) | a[i];
+ }
+ return n >>> 0;
+ }
+
+ function hexToStr(a, size) {
+ return String.fromCharCode.apply(null, a.subarray(0, size + 1));
+ }
+
+ function addHex(a, b, size) {
+ var c = 0;
+ for (var i = size; i >= 0; i--) {
+ c += a[i] + b[i];
+ a[i] = c & 255;
+ c >>= 8;
+ }
+ }
+
+ function incHex(a, size) {
+ var c = 1;
+ for (var i = size; i >= 0 && c > 0; i--) {
+ c += a[i];
+ a[i] = c & 255;
+ c >>= 8;
+ }
+ }
+
+ var MAX_NUM_SIZE = 16;
+ var MAX_ENCODED_NUM_SIZE = 19; // ceil(MAX_NUM_SIZE * 7 / 8)
+
+ function BinaryCMapStream(data) {
+ this.buffer = data;
+ this.pos = 0;
+ this.end = data.length;
+ this.tmpBuf = new Uint8Array(MAX_ENCODED_NUM_SIZE);
+ }
+
+ BinaryCMapStream.prototype = {
+ readByte: function () {
+ if (this.pos >= this.end) {
+ return -1;
+ }
+ return this.buffer[this.pos++];
+ },
+ readNumber: function () {
+ var n = 0;
+ var last;
+ do {
+ var b = this.readByte();
+ if (b < 0) {
+ error('unexpected EOF in bcmap');
+ }
+ last = !(b & 0x80);
+ n = (n << 7) | (b & 0x7F);
+ } while (!last);
+ return n;
+ },
+ readSigned: function () {
+ var n = this.readNumber();
+ return (n & 1) ? ~(n >>> 1) : n >>> 1;
+ },
+ readHex: function (num, size) {
+ num.set(this.buffer.subarray(this.pos,
+ this.pos + size + 1));
+ this.pos += size + 1;
+ },
+ readHexNumber: function (num, size) {
+ var last;
+ var stack = this.tmpBuf, sp = 0;
+ do {
+ var b = this.readByte();
+ if (b < 0) {
+ error('unexpected EOF in bcmap');
+ }
+ last = !(b & 0x80);
+ stack[sp++] = b & 0x7F;
+ } while (!last);
+ var i = size, buffer = 0, bufferSize = 0;
+ while (i >= 0) {
+ while (bufferSize < 8 && stack.length > 0) {
+ buffer = (stack[--sp] << bufferSize) | buffer;
+ bufferSize += 7;
+ }
+ num[i] = buffer & 255;
+ i--;
+ buffer >>= 8;
+ bufferSize -= 8;
+ }
+ },
+ readHexSigned: function (num, size) {
+ this.readHexNumber(num, size);
+ var sign = num[size] & 1 ? 255 : 0;
+ var c = 0;
+ for (var i = 0; i <= size; i++) {
+ c = ((c & 1) << 8) | num[i];
+ num[i] = (c >> 1) ^ sign;
+ }
+ },
+ readString: function () {
+ var len = this.readNumber();
+ var s = '';
+ for (var i = 0; i < len; i++) {
+ s += String.fromCharCode(this.readNumber());
+ }
+ return s;
+ }
+ };
+
+ function processBinaryCMap(url, cMap, extend) {
+ var data = fetchBinaryData(url);
+ var stream = new BinaryCMapStream(data);
+
+ var header = stream.readByte();
+ cMap.vertical = !!(header & 1);
+
+ var useCMap = null;
+ var start = new Uint8Array(MAX_NUM_SIZE);
+ var end = new Uint8Array(MAX_NUM_SIZE);
+ var char = new Uint8Array(MAX_NUM_SIZE);
+ var charCode = new Uint8Array(MAX_NUM_SIZE);
+ var tmp = new Uint8Array(MAX_NUM_SIZE);
+ var code;
+
+ var b;
+ while ((b = stream.readByte()) >= 0) {
+ var type = b >> 5;
+ if (type === 7) { // metadata, e.g. comment or usecmap
+ switch (b & 0x1F) {
+ case 0:
+ stream.readString(); // skipping comment
+ break;
+ case 1:
+ useCMap = stream.readString();
+ break;
+ }
+ continue;
+ }
+ var sequence = !!(b & 0x10);
+ var dataSize = b & 15;
+
+ assert(dataSize + 1 <= MAX_NUM_SIZE);
+
+ var ucs2DataSize = 1;
+ var subitemsCount = stream.readNumber();
+ var i;
+ switch (type) {
+ case 0: // codespacerange
+ stream.readHex(start, dataSize);
+ stream.readHexNumber(end, dataSize);
+ addHex(end, start, dataSize);
+ cMap.addCodespaceRange(dataSize + 1, hexToInt(start, dataSize),
+ hexToInt(end, dataSize));
+ for (i = 1; i < subitemsCount; i++) {
+ incHex(end, dataSize);
+ stream.readHexNumber(start, dataSize);
+ addHex(start, end, dataSize);
+ stream.readHexNumber(end, dataSize);
+ addHex(end, start, dataSize);
+ cMap.addCodespaceRange(dataSize + 1, hexToInt(start, dataSize),
+ hexToInt(end, dataSize));
+ }
+ break;
+ case 1: // notdefrange
+ stream.readHex(start, dataSize);
+ stream.readHexNumber(end, dataSize);
+ addHex(end, start, dataSize);
+ code = stream.readNumber();
+ // undefined range, skipping
+ for (i = 1; i < subitemsCount; i++) {
+ incHex(end, dataSize);
+ stream.readHexNumber(start, dataSize);
+ addHex(start, end, dataSize);
+ stream.readHexNumber(end, dataSize);
+ addHex(end, start, dataSize);
+ code = stream.readNumber();
+ // nop
+ }
+ break;
+ case 2: // cidchar
+ stream.readHex(char, dataSize);
+ code = stream.readNumber();
+ cMap.mapOne(hexToInt(char, dataSize), String.fromCharCode(code));
+ for (i = 1; i < subitemsCount; i++) {
+ incHex(char, dataSize);
+ if (!sequence) {
+ stream.readHexNumber(tmp, dataSize);
+ addHex(char, tmp, dataSize);
+ }
+ code = stream.readSigned() + (code + 1);
+ cMap.mapOne(hexToInt(char, dataSize), String.fromCharCode(code));
+ }
+ break;
+ case 3: // cidrange
+ stream.readHex(start, dataSize);
+ stream.readHexNumber(end, dataSize);
+ addHex(end, start, dataSize);
+ code = stream.readNumber();
+ cMap.mapRange(hexToInt(start, dataSize), hexToInt(end, dataSize),
+ String.fromCharCode(code));
+ for (i = 1; i < subitemsCount; i++) {
+ incHex(end, dataSize);
+ if (!sequence) {
+ stream.readHexNumber(start, dataSize);
+ addHex(start, end, dataSize);
+ } else {
+ start.set(end);
+ }
+ stream.readHexNumber(end, dataSize);
+ addHex(end, start, dataSize);
+ code = stream.readNumber();
+ cMap.mapRange(hexToInt(start, dataSize), hexToInt(end, dataSize),
+ String.fromCharCode(code));
+ }
+ break;
+ case 4: // bfchar
+ stream.readHex(char, ucs2DataSize);
+ stream.readHex(charCode, dataSize);
+ cMap.mapOne(hexToInt(char, ucs2DataSize),
+ hexToStr(charCode, dataSize));
+ for (i = 1; i < subitemsCount; i++) {
+ incHex(char, ucs2DataSize);
+ if (!sequence) {
+ stream.readHexNumber(tmp, ucs2DataSize);
+ addHex(char, tmp, ucs2DataSize);
+ }
+ incHex(charCode, dataSize);
+ stream.readHexSigned(tmp, dataSize);
+ addHex(charCode, tmp, dataSize);
+ cMap.mapOne(hexToInt(char, ucs2DataSize),
+ hexToStr(charCode, dataSize));
+ }
+ break;
+ case 5: // bfrange
+ stream.readHex(start, ucs2DataSize);
+ stream.readHexNumber(end, ucs2DataSize);
+ addHex(end, start, ucs2DataSize);
+ stream.readHex(charCode, dataSize);
+ cMap.mapRange(hexToInt(start, ucs2DataSize),
+ hexToInt(end, ucs2DataSize),
+ hexToStr(charCode, dataSize));
+ for (i = 1; i < subitemsCount; i++) {
+ incHex(end, ucs2DataSize);
+ if (!sequence) {
+ stream.readHexNumber(start, ucs2DataSize);
+ addHex(start, end, ucs2DataSize);
+ } else {
+ start.set(end);
+ }
+ stream.readHexNumber(end, ucs2DataSize);
+ addHex(end, start, ucs2DataSize);
+ stream.readHex(charCode, dataSize);
+ cMap.mapRange(hexToInt(start, ucs2DataSize),
+ hexToInt(end, ucs2DataSize),
+ hexToStr(charCode, dataSize));
+ }
+ break;
+ default:
+ error('Unknown type: ' + type);
+ break;
+ }
+ }
+
+ if (useCMap) {
+ extend(useCMap);
+ }
+ return cMap;
+ }
+
+ function BinaryCMapReader() {}
+
+ BinaryCMapReader.prototype = {
+ read: processBinaryCMap
+ };
+
+ return BinaryCMapReader;
+})();
+
+var CMapFactory = (function CMapFactoryClosure() {
+ function strToInt(str) {
+ var a = 0;
+ for (var i = 0; i < str.length; i++) {
+ a = (a << 8) | str.charCodeAt(i);
+ }
+ return a >>> 0;
+ }
+
+ function expectString(obj) {
+ if (!isString(obj)) {
+ error('Malformed CMap: expected string.');
+ }
+ }
+
+ function expectInt(obj) {
+ if (!isInt(obj)) {
+ error('Malformed CMap: expected int.');
+ }
+ }
+
+ function parseBfChar(cMap, lexer) {
+ while (true) {
+ var obj = lexer.getObj();
+ if (isEOF(obj)) {
+ break;
+ }
+ if (isCmd(obj, 'endbfchar')) {
+ return;
+ }
+ expectString(obj);
+ var src = strToInt(obj);
+ obj = lexer.getObj();
+ // TODO are /dstName used?
+ expectString(obj);
+ var dst = obj;
+ cMap.mapOne(src, dst);
+ }
+ }
+
+ function parseBfRange(cMap, lexer) {
+ while (true) {
+ var obj = lexer.getObj();
+ if (isEOF(obj)) {
+ break;
+ }
+ if (isCmd(obj, 'endbfrange')) {
+ return;
+ }
+ expectString(obj);
+ var low = strToInt(obj);
+ obj = lexer.getObj();
+ expectString(obj);
+ var high = strToInt(obj);
+ obj = lexer.getObj();
+ if (isInt(obj) || isString(obj)) {
+ var dstLow = isInt(obj) ? String.fromCharCode(obj) : obj;
+ cMap.mapRange(low, high, dstLow);
+ } else if (isCmd(obj, '[')) {
+ obj = lexer.getObj();
+ var array = [];
+ while (!isCmd(obj, ']') && !isEOF(obj)) {
+ array.push(obj);
+ obj = lexer.getObj();
+ }
+ cMap.mapRangeToArray(low, high, array);
+ } else {
+ break;
+ }
+ }
+ error('Invalid bf range.');
+ }
+
+ function parseCidChar(cMap, lexer) {
+ while (true) {
+ var obj = lexer.getObj();
+ if (isEOF(obj)) {
+ break;
+ }
+ if (isCmd(obj, 'endcidchar')) {
+ return;
+ }
+ expectString(obj);
+ var src = strToInt(obj);
+ obj = lexer.getObj();
+ expectInt(obj);
+ var dst = String.fromCharCode(obj);
+ cMap.mapOne(src, dst);
+ }
+ }
+
+ function parseCidRange(cMap, lexer) {
+ while (true) {
+ var obj = lexer.getObj();
+ if (isEOF(obj)) {
+ break;
+ }
+ if (isCmd(obj, 'endcidrange')) {
+ return;
+ }
+ expectString(obj);
+ var low = strToInt(obj);
+ obj = lexer.getObj();
+ expectString(obj);
+ var high = strToInt(obj);
+ obj = lexer.getObj();
+ expectInt(obj);
+ var dstLow = String.fromCharCode(obj);
+ cMap.mapRange(low, high, dstLow);
+ }
+ }
+
+ function parseCodespaceRange(cMap, lexer) {
+ while (true) {
+ var obj = lexer.getObj();
+ if (isEOF(obj)) {
+ break;
+ }
+ if (isCmd(obj, 'endcodespacerange')) {
+ return;
+ }
+ if (!isString(obj)) {
+ break;
+ }
+ var low = strToInt(obj);
+ obj = lexer.getObj();
+ if (!isString(obj)) {
+ break;
+ }
+ var high = strToInt(obj);
+ cMap.addCodespaceRange(obj.length, low, high);
+ }
+ error('Invalid codespace range.');
+ }
+
+ function parseWMode(cMap, lexer) {
+ var obj = lexer.getObj();
+ if (isInt(obj)) {
+ cMap.vertical = !!obj;
+ }
+ }
+
+ function parseCMap(cMap, lexer, builtInCMapParams, useCMap) {
+ var previous;
+ var embededUseCMap;
+ objLoop: while (true) {
+ var obj = lexer.getObj();
+ if (isEOF(obj)) {
+ break;
+ } else if (isName(obj)) {
+ if (obj.name === 'WMode') {
+ parseWMode(cMap, lexer);
+ }
+ previous = obj;
+ } else if (isCmd(obj)) {
+ switch (obj.cmd) {
+ case 'endcmap':
+ break objLoop;
+ case 'usecmap':
+ if (isName(previous)) {
+ embededUseCMap = previous.name;
+ }
+ break;
+ case 'begincodespacerange':
+ parseCodespaceRange(cMap, lexer);
+ break;
+ case 'beginbfchar':
+ parseBfChar(cMap, lexer);
+ break;
+ case 'begincidchar':
+ parseCidChar(cMap, lexer);
+ break;
+ case 'beginbfrange':
+ parseBfRange(cMap, lexer);
+ break;
+ case 'begincidrange':
+ parseCidRange(cMap, lexer);
+ break;
+ }
+ }
+ }
+
+ if (!useCMap && embededUseCMap) {
+ // Load the usecmap definition from the file only if there wasn't one
+ // specified.
+ useCMap = embededUseCMap;
+ }
+ if (useCMap) {
+ extendCMap(cMap, builtInCMapParams, useCMap);
+ }
+ }
+
+ function extendCMap(cMap, builtInCMapParams, useCMap) {
+ cMap.useCMap = createBuiltInCMap(useCMap, builtInCMapParams);
+ // If there aren't any code space ranges defined clone all the parent ones
+ // into this cMap.
+ if (cMap.numCodespaceRanges === 0) {
+ var useCodespaceRanges = cMap.useCMap.codespaceRanges;
+ for (var i = 0; i < useCodespaceRanges.length; i++) {
+ cMap.codespaceRanges[i] = useCodespaceRanges[i].slice();
+ }
+ cMap.numCodespaceRanges = cMap.useCMap.numCodespaceRanges;
+ }
+ // Merge the map into the current one, making sure not to override
+ // any previously defined entries.
+ for (var key in cMap.useCMap.map) {
+ if (key in cMap.map) {
+ continue;
+ }
+ cMap.map[key] = cMap.useCMap.map[key];
+ }
+ }
+
+ function parseBinaryCMap(name, builtInCMapParams) {
+ var url = builtInCMapParams.url + name + '.bcmap';
+ var cMap = new CMap(true);
+ new BinaryCMapReader().read(url, cMap, function (useCMap) {
+ extendCMap(cMap, builtInCMapParams, useCMap);
+ });
+ return cMap;
+ }
+
+ function createBuiltInCMap(name, builtInCMapParams) {
+ if (name === 'Identity-H') {
+ return new IdentityCMap(false, 2);
+ } else if (name === 'Identity-V') {
+ return new IdentityCMap(true, 2);
+ }
+ if (BUILT_IN_CMAPS.indexOf(name) === -1) {
+ error('Unknown cMap name: ' + name);
+ }
+ assert (builtInCMapParams, 'buildin cmap parameters are not provided');
+
+ if (builtInCMapParams.packed) {
+ return parseBinaryCMap(name, builtInCMapParams);
+ }
+
+ var request = new XMLHttpRequest();
+ var url = builtInCMapParams.url + name;
+ request.open('GET', url, false);
+ request.send(null);
+ if (request.status === 0 && /^https?:/i.test(url)) {
+ error('Unable to get cMap at: ' + url);
+ }
+ var cMap = new CMap(true);
+ var lexer = new Lexer(new StringStream(request.responseText));
+ parseCMap(cMap, lexer, builtInCMapParams, null);
+ return cMap;
+ }
+
+ return {
+ create: function (encoding, builtInCMapParams, useCMap) {
+ if (isName(encoding)) {
+ return createBuiltInCMap(encoding.name, builtInCMapParams);
+ } else if (isStream(encoding)) {
+ var cMap = new CMap();
+ var lexer = new Lexer(encoding);
+ try {
+ parseCMap(cMap, lexer, builtInCMapParams, useCMap);
+ } catch (e) {
+ warn('Invalid CMap data. ' + e);
+ }
+ return cMap;
+ }
+ error('Encoding required.');
+ }
+ };
+})();
+
+
// Unicode Private Use Area
var PRIVATE_USE_OFFSET_START = 0xE000;
var PRIVATE_USE_OFFSET_END = 0xF8FF;
@@ -17182,7 +18929,7 @@ var Encodings = {
'summation', 'product', 'pi', 'integral', 'ordfeminine', 'ordmasculine',
'Omega', 'ae', 'oslash', 'questiondown', 'exclamdown', 'logicalnot',
'radical', 'florin', 'approxequal', 'Delta', 'guillemotleft',
- 'guillemotright', 'ellipsis', '', 'Agrave', 'Atilde', 'Otilde', 'OE',
+ 'guillemotright', 'ellipsis', 'space', 'Agrave', 'Atilde', 'Otilde', 'OE',
'oe', 'endash', 'emdash', 'quotedblleft', 'quotedblright', 'quoteleft',
'quoteright', 'divide', 'lozenge', 'ydieresis', 'Ydieresis', 'fraction',
'currency', 'guilsinglleft', 'guilsinglright', 'fi', 'fl', 'daggerdbl',
@@ -17234,7 +18981,7 @@ var Encodings = {
'guilsinglleft', 'OE', 'bullet', 'Zcaron', 'bullet', 'bullet', 'quoteleft',
'quoteright', 'quotedblleft', 'quotedblright', 'bullet', 'endash',
'emdash', 'tilde', 'trademark', 'scaron', 'guilsinglright', 'oe', 'bullet',
- 'zcaron', 'Ydieresis', '', 'exclamdown', 'cent', 'sterling',
+ 'zcaron', 'Ydieresis', 'space', 'exclamdown', 'cent', 'sterling',
'currency', 'yen', 'brokenbar', 'section', 'dieresis', 'copyright',
'ordfeminine', 'guillemotleft', 'logicalnot', 'hyphen', 'registered',
'macron', 'degree', 'plusminus', 'twosuperior', 'threesuperior', 'acute',
@@ -17396,7 +19143,7 @@ var nonStdFontMap = {
'MS-PMincho': 'MS PMincho',
'MS-PMincho-Bold': 'MS PMincho-Bold',
'MS-PMincho-BoldItalic': 'MS PMincho-BoldItalic',
- 'MS-PMincho-Italic': 'MS PMincho-Italic',
+ 'MS-PMincho-Italic': 'MS PMincho-Italic'
};
var serifFonts = {
@@ -17455,7 +19202,7 @@ var symbolsFonts = {
// glyphs, but common for some set of the standard fonts.
var GlyphMapForStandardFonts = {
'2': 10, '3': 32, '4': 33, '5': 34, '6': 35, '7': 36, '8': 37, '9': 38,
- '10': 39, '11': 40, '12': 41, '13': 42, '14': 43, '15': 44, '16': 173,
+ '10': 39, '11': 40, '12': 41, '13': 42, '14': 43, '15': 44, '16': 45,
'17': 46, '18': 47, '19': 48, '20': 49, '21': 50, '22': 51, '23': 52,
'24': 53, '25': 54, '26': 55, '27': 56, '28': 57, '29': 58, '30': 894,
'31': 60, '32': 61, '33': 62, '34': 63, '35': 64, '36': 65, '37': 66,
@@ -17479,7 +19226,9 @@ var GlyphMapForStandardFonts = {
'149': 8805, '150': 165, '151': 181, '152': 8706, '153': 8721, '154': 8719,
'156': 8747, '157': 170, '158': 186, '159': 8486, '160': 230, '161': 248,
'162': 191, '163': 161, '164': 172, '165': 8730, '166': 402, '167': 8776,
- '168': 8710, '169': 171, '170': 187, '171': 8230, '210': 218, '305': 963,
+ '168': 8710, '169': 171, '170': 187, '171': 8230, '210': 218, '223': 711,
+ '227': 353, '229': 382, '234': 253, '253': 268, '254': 269, '258': 258,
+ '268': 283, '269': 313, '278': 328, '284': 345, '292': 367, '305': 963,
'306': 964, '307': 966, '308': 8215, '309': 8252, '310': 8319, '311': 8359,
'312': 8592, '313': 8593, '337': 9552, '493': 1039, '494': 1040, '705': 1524,
'706': 8362, '710': 64288, '711': 64298, '759': 1617, '761': 1776,
@@ -17712,19 +19461,22 @@ var MacStandardGlyphOrdering = [
function getUnicodeRangeFor(value) {
for (var i = 0, ii = UnicodeRanges.length; i < ii; i++) {
var range = UnicodeRanges[i];
- if (value >= range.begin && value < range.end)
+ if (value >= range.begin && value < range.end) {
return i;
+ }
}
return -1;
}
function isRTLRangeFor(value) {
var range = UnicodeRanges[13];
- if (value >= range.begin && value < range.end)
+ if (value >= range.begin && value < range.end) {
return true;
+ }
range = UnicodeRanges[11];
- if (value >= range.begin && value < range.end)
+ if (value >= range.begin && value < range.end) {
return true;
+ }
return false;
}
@@ -19113,29 +20865,14 @@ var NormalizedUnicodes = {
function reverseIfRtl(chars) {
var charsLength = chars.length;
//reverse an arabic ligature
- if (charsLength <= 1 || !isRTLRangeFor(chars.charCodeAt(0)))
+ if (charsLength <= 1 || !isRTLRangeFor(chars.charCodeAt(0))) {
return chars;
-
+ }
var s = '';
- for (var ii = charsLength - 1; ii >= 0; ii--)
+ for (var ii = charsLength - 1; ii >= 0; ii--) {
s += chars[ii];
- return s;
-}
-
-function fontCharsToUnicode(charCodes, font) {
- var glyphs = font.charsToGlyphs(charCodes);
- var result = '';
- for (var i = 0, ii = glyphs.length; i < ii; i++) {
- var glyph = glyphs[i];
- if (!glyph)
- continue;
-
- var glyphUnicode = glyph.unicode;
- if (glyphUnicode in NormalizedUnicodes)
- glyphUnicode = NormalizedUnicodes[glyphUnicode];
- result += reverseIfRtl(glyphUnicode);
}
- return result;
+ return s;
}
function adjustWidths(properties) {
@@ -19151,6 +20888,29 @@ function adjustWidths(properties) {
properties.defaultWidth *= scale;
}
+var Glyph = (function GlyphClosure() {
+ function Glyph(fontChar, unicode, accent, width, vmetric, operatorListId) {
+ this.fontChar = fontChar;
+ this.unicode = unicode;
+ this.accent = accent;
+ this.width = width;
+ this.vmetric = vmetric;
+ this.operatorListId = operatorListId;
+ }
+
+ Glyph.prototype.matchesForCache =
+ function(fontChar, unicode, accent, width, vmetric, operatorListId) {
+ return this.fontChar === fontChar &&
+ this.unicode === unicode &&
+ this.accent === accent &&
+ this.width === width &&
+ this.vmetric === vmetric &&
+ this.operatorListId === operatorListId;
+ };
+
+ return Glyph;
+})();
+
/**
* 'Font' is the class the outside world should use, it encapsulate all the font
* decoding logics whatever type it is (assuming the font type is supported).
@@ -19161,13 +20921,15 @@ function adjustWidths(properties) {
*/
var Font = (function FontClosure() {
function Font(name, file, properties) {
+ var charCode;
this.name = name;
this.loadedName = properties.loadedName;
- this.coded = properties.coded;
- this.loadCharProcs = properties.coded;
+ this.isType3Font = properties.isType3Font;
this.sizes = [];
+ this.glyphCache = {};
+
var names = name.split('+');
names = names.length > 1 ? names[1] : names[0];
names = names.split(/[-,_]/g)[0];
@@ -19178,8 +20940,8 @@ var Font = (function FontClosure() {
var type = properties.type;
this.type = type;
- this.fallbackName = this.isMonospace ? 'monospace' :
- this.isSerifFont ? 'serif' : 'sans-serif';
+ this.fallbackName = (this.isMonospace ? 'monospace' :
+ (this.isSerifFont ? 'serif' : 'sans-serif'));
this.differences = properties.differences;
this.widths = properties.widths;
@@ -19198,9 +20960,9 @@ var Font = (function FontClosure() {
this.toFontChar = [];
if (properties.type == 'Type3') {
- for (var charCode = 0; charCode < 256; charCode++) {
- this.toFontChar[charCode] = this.differences[charCode] ||
- properties.defaultEncoding[charCode];
+ for (charCode = 0; charCode < 256; charCode++) {
+ this.toFontChar[charCode] = (this.differences[charCode] ||
+ properties.defaultEncoding[charCode]);
}
return;
}
@@ -19212,7 +20974,13 @@ var Font = (function FontClosure() {
this.defaultVMetrics = properties.defaultVMetrics;
}
- if (!file) {
+ if (!file || file.isEmpty) {
+ if (file) {
+ // Some bad PDF generators will include empty font files,
+ // attempting to recover by assuming that no file exists.
+ warn('Font file is empty in "' + name + '" (' + this.loadedName + ')');
+ }
+
this.missingFile = true;
// The file data is not specified. Trying to fix the font name
// to be used with the canvas.font.
@@ -19221,8 +20989,8 @@ var Font = (function FontClosure() {
fontName = stdFontMap[fontName] || nonStdFontMap[fontName] || fontName;
this.bold = (fontName.search(/bold/gi) != -1);
- this.italic = (fontName.search(/oblique/gi) != -1) ||
- (fontName.search(/italic/gi) != -1);
+ this.italic = ((fontName.search(/oblique/gi) != -1) ||
+ (fontName.search(/italic/gi) != -1));
// Use 'name' instead of 'fontName' here because the original
// name ArialBlack for example will be replaced by Helvetica.
@@ -19242,7 +21010,7 @@ var Font = (function FontClosure() {
this.toUnicode = map;
} else if (/Symbol/i.test(fontName)) {
var symbols = Encodings.SymbolSetEncoding;
- for (var charCode in symbols) {
+ for (charCode in symbols) {
var fontChar = GlyphsUnicode[symbols[charCode]];
if (!fontChar) {
continue;
@@ -19251,13 +21019,13 @@ var Font = (function FontClosure() {
}
} else if (isStandardFont) {
this.toFontChar = [];
- for (var charCode in properties.defaultEncoding) {
+ for (charCode in properties.defaultEncoding) {
var glyphName = properties.differences[charCode] ||
properties.defaultEncoding[charCode];
this.toFontChar[charCode] = GlyphsUnicode[glyphName];
}
} else {
- for (var charCode in this.toUnicode) {
+ for (charCode in this.toUnicode) {
this.toFontChar[charCode] = this.toUnicode[charCode].charCodeAt(0);
}
}
@@ -19268,10 +21036,17 @@ var Font = (function FontClosure() {
// Some fonts might use wrong font types for Type1C or CIDFontType0C
var subtype = properties.subtype;
- if (subtype == 'Type1C' && (type != 'Type1' && type != 'MMType1'))
- type = 'Type1';
- if (subtype == 'CIDFontType0C' && type != 'CIDFontType0')
+ if (subtype == 'Type1C' && (type != 'Type1' && type != 'MMType1')) {
+ // Some TrueType fonts by mistake claim Type1C
+ if (isTrueTypeFile(file)) {
+ subtype = 'TrueType';
+ } else {
+ type = 'Type1';
+ }
+ }
+ if (subtype == 'CIDFontType0C' && type != 'CIDFontType0') {
type = 'CIDFontType0';
+ }
// XXX: Temporarily change the type for open type so we trigger a warning.
// This should be removed when we add support for open type.
if (subtype === 'OpenType') {
@@ -19320,29 +21095,19 @@ var Font = (function FontClosure() {
this.loading = true;
}
- function stringToArray(str) {
- var array = [];
- for (var i = 0, ii = str.length; i < ii; ++i)
- array[i] = str.charCodeAt(i);
-
- return array;
- }
-
- function arrayToString(arr) {
- var strBuf = [];
- for (var i = 0, ii = arr.length; i < ii; ++i) {
- strBuf.push(String.fromCharCode(arr[i]));
- }
- return strBuf.join('');
- }
+ Font.getFontID = (function () {
+ var ID = 1;
+ return function Font_getFontID() {
+ return String(ID++);
+ };
+ })();
- function int16(bytes) {
- return (bytes[0] << 8) + (bytes[1] & 0xff);
+ function int16(b0, b1) {
+ return (b0 << 8) + b1;
}
- function int32(bytes) {
- return (bytes[0] << 24) + (bytes[1] << 16) +
- (bytes[2] << 8) + (bytes[3] & 0xff);
+ function int32(b0, b1, b2, b3) {
+ return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3;
}
function getMaxPower2(number) {
@@ -19354,34 +21119,27 @@ var Font = (function FontClosure() {
}
value = 2;
- for (var i = 1; i < maxPower; i++)
+ for (var i = 1; i < maxPower; i++) {
value *= 2;
+ }
return value;
}
function string16(value) {
- return String.fromCharCode((value >> 8) & 0xff) +
- String.fromCharCode(value & 0xff);
+ return String.fromCharCode((value >> 8) & 0xff, value & 0xff);
}
function safeString16(value) {
// clamp value to the 16-bit int range
- value = value > 0x7FFF ? 0x7FFF : value < -0x8000 ? -0x8000 : value;
- return String.fromCharCode((value >> 8) & 0xff) +
- String.fromCharCode(value & 0xff);
- }
-
- function string32(value) {
- return String.fromCharCode((value >> 24) & 0xff) +
- String.fromCharCode((value >> 16) & 0xff) +
- String.fromCharCode((value >> 8) & 0xff) +
- String.fromCharCode(value & 0xff);
+ value = (value > 0x7FFF ? 0x7FFF : (value < -0x8000 ? -0x8000 : value));
+ return String.fromCharCode((value >> 8) & 0xff, value & 0xff);
}
function createOpenTypeHeader(sfnt, file, numTables) {
// Windows hates the Mac TrueType sfnt version number
- if (sfnt == 'true')
+ if (sfnt == 'true') {
sfnt = string32(0x00010000);
+ }
// sfnt version (4 bytes)
var header = sfnt;
@@ -19412,17 +21170,19 @@ var Font = (function FontClosure() {
var length = data.length;
// Per spec tables must be 4-bytes align so add padding as needed
- while (data.length & 3)
+ while (data.length & 3) {
data.push(0x00);
-
- while (file.virtualOffset & 3)
+ }
+ while (file.virtualOffset & 3) {
file.virtualOffset++;
+ }
// checksum
var checksum = 0, n = data.length;
- for (var i = 0; i < n; i += 4)
- checksum = (checksum + int32([data[i], data[i + 1], data[i + 2],
- data[i + 3]])) | 0;
+ for (var i = 0; i < n; i += 4) {
+ checksum = (checksum + int32(data[i], data[i + 1], data[i + 2],
+ data[i + 3])) | 0;
+ }
var tableEntry = (tag + string32(checksum) +
string32(offset) + string32(length));
@@ -19430,6 +21190,11 @@ var Font = (function FontClosure() {
file.virtualOffset += data.length;
}
+ function isTrueTypeFile(file) {
+ var header = file.peekBytes(4);
+ return readUint32(header, 0) === 0x00010000;
+ }
+
/**
* Rebuilds the char code to glyph ID map by trying to replace the char codes
* with their unicode value. It also moves char codes that are in known
@@ -19446,7 +21211,6 @@ var Font = (function FontClosure() {
var isIdentityUnicode = properties.isIdentityUnicode;
var newMap = Object.create(null);
var toFontChar = [];
- var usedCharCodes = [];
var usedFontCharCodes = [];
var nextAvailableFontCharCode = PRIVATE_USE_OFFSET_START;
for (var originalCharCode in charCodeToGlyphId) {
@@ -19473,6 +21237,8 @@ var Font = (function FontClosure() {
fontCharCode === 0x7F || // Control char
fontCharCode === 0xAD || // Soft hyphen
(fontCharCode >= 0x80 && fontCharCode <= 0x9F) || // Control chars
+ // Prevent drawing characters in the specials unicode block.
+ (fontCharCode >= 0xFFF0 && fontCharCode <= 0xFFFF) ||
(isSymbolic && isIdentityUnicode)) &&
nextAvailableFontCharCode <= PRIVATE_USE_OFFSET_END) { // Room left.
// Loop to try and find a free spot in the private use area.
@@ -19494,7 +21260,8 @@ var Font = (function FontClosure() {
}
return {
toFontChar: toFontChar,
- charCodeToGlyphId: newMap
+ charCodeToGlyphId: newMap,
+ nextAvailableFontCharCode: nextAvailableFontCharCode
};
}
@@ -19521,7 +21288,9 @@ var Font = (function FontClosure() {
codeIndices.push(codes[n].glyphId);
++end;
++n;
- if (end === 0xFFFF) { break; }
+ if (end === 0xFFFF) {
+ break;
+ }
}
ranges.push([start, end, codeIndices]);
}
@@ -19538,7 +21307,8 @@ var Font = (function FontClosure() {
'\x00\x01' + // encodingID
string32(4 + numTables * 8); // start of the table record
- for (var i = ranges.length - 1; i >= 0; --i) {
+ var i, ii, j, jj;
+ for (i = ranges.length - 1; i >= 0; --i) {
if (ranges[i][0] <= 0xFFFF) { break; }
}
var bmpLength = i + 1;
@@ -19561,15 +21331,16 @@ var Font = (function FontClosure() {
var glyphsIds = '';
var bias = 0;
- for (var i = 0, ii = bmpLength; i < ii; i++) {
- var range = ranges[i];
- var start = range[0];
- var end = range[1];
+ var range, start, end, codes;
+ for (i = 0, ii = bmpLength; i < ii; i++) {
+ range = ranges[i];
+ start = range[0];
+ end = range[1];
startCount += string16(start);
endCount += string16(end);
- var codes = range[2];
+ codes = range[2];
var contiguous = true;
- for (var j = 1, jj = codes.length; j < jj; ++j) {
+ for (j = 1, jj = codes.length; j < jj; ++j) {
if (codes[j] !== codes[j - 1] + 1) {
contiguous = false;
break;
@@ -19582,7 +21353,7 @@ var Font = (function FontClosure() {
idDeltas += string16(0);
idRangeOffsets += string16(offset);
- for (var j = 0, jj = codes.length; j < jj; ++j) {
+ for (j = 0, jj = codes.length; j < jj; ++j) {
glyphsIds += string16(codes[j]);
}
} else {
@@ -19616,14 +21387,14 @@ var Font = (function FontClosure() {
string32(4 + numTables * 8 +
4 + format314.length); // start of the table record
format31012 = '';
- for (var i = 0, ii = ranges.length; i < ii; i++) {
- var range = ranges[i];
- var start = range[0];
- var codes = range[2];
+ for (i = 0, ii = ranges.length; i < ii; i++) {
+ range = ranges[i];
+ start = range[0];
+ codes = range[2];
var code = codes[0];
- for (var j = 1, jj = codes.length; j < jj; ++j) {
+ for (j = 1, jj = codes.length; j < jj; ++j) {
if (codes[j] !== codes[j - 1] + 1) {
- var end = range[0] + j - 1;
+ end = range[0] + j - 1;
format31012 += string32(start) + // startCharCode
string32(end) + // endCharCode
string32(code); // startGlyphID
@@ -19650,21 +21421,21 @@ var Font = (function FontClosure() {
function validateOS2Table(os2) {
var stream = new Stream(os2.data);
- var version = int16(stream.getBytes(2));
+ var version = stream.getUint16();
// TODO verify all OS/2 tables fields, but currently we validate only those
// that give us issues
stream.getBytes(60); // skipping type, misc sizes, panose, unicode ranges
- var selection = int16(stream.getBytes(2));
+ var selection = stream.getUint16();
if (version < 4 && (selection & 0x0300)) {
return false;
}
- var firstChar = int16(stream.getBytes(2));
- var lastChar = int16(stream.getBytes(2));
+ var firstChar = stream.getUint16();
+ var lastChar = stream.getUint16();
if (firstChar > lastChar) {
return false;
}
stream.getBytes(6); // skipping sTypoAscender/Descender/LineGap
- var usWinAscent = int16(stream.getBytes(2));
+ var usWinAscent = stream.getUint16();
if (usWinAscent === 0) { // makes font unreadable by windows
return false;
}
@@ -19694,10 +21465,12 @@ var Font = (function FontClosure() {
if (charstrings) {
for (var code in charstrings) {
code |= 0;
- if (firstCharIndex > code || !firstCharIndex)
+ if (firstCharIndex > code || !firstCharIndex) {
firstCharIndex = code;
- if (lastCharIndex < code)
+ }
+ if (lastCharIndex < code) {
lastCharIndex = code;
+ }
var position = getUnicodeRangeFor(code);
if (position < 32) {
@@ -19719,18 +21492,18 @@ var Font = (function FontClosure() {
}
var bbox = properties.bbox || [0, 0, 0, 0];
- var unitsPerEm = override.unitsPerEm ||
- 1 / (properties.fontMatrix || FONT_IDENTITY_MATRIX)[0];
+ var unitsPerEm = (override.unitsPerEm ||
+ 1 / (properties.fontMatrix || FONT_IDENTITY_MATRIX)[0]);
// if the font units differ to the PDF glyph space units
// then scale up the values
- var scale = properties.ascentScaled ? 1.0 :
- unitsPerEm / PDF_GLYPH_SPACE_UNITS;
+ var scale = (properties.ascentScaled ? 1.0 :
+ unitsPerEm / PDF_GLYPH_SPACE_UNITS);
- var typoAscent = override.ascent || Math.round(scale *
- (properties.ascent || bbox[3]));
- var typoDescent = override.descent || Math.round(scale *
- (properties.descent || bbox[1]));
+ var typoAscent = (override.ascent ||
+ Math.round(scale * (properties.ascent || bbox[3])));
+ var typoDescent = (override.descent ||
+ Math.round(scale * (properties.descent || bbox[1])));
if (typoDescent > 0 && properties.descent > 0 && bbox[1] < 0) {
typoDescent = -typoDescent; // fixing incorrect descent
}
@@ -19781,15 +21554,15 @@ var Font = (function FontClosure() {
function createPostTable(properties) {
var angle = Math.floor(properties.italicAngle * (Math.pow(2, 16)));
- return '\x00\x03\x00\x00' + // Version number
- string32(angle) + // italicAngle
- '\x00\x00' + // underlinePosition
- '\x00\x00' + // underlineThickness
- string32(properties.fixedPitch) + // isFixedPitch
- '\x00\x00\x00\x00' + // minMemType42
- '\x00\x00\x00\x00' + // maxMemType42
- '\x00\x00\x00\x00' + // minMemType1
- '\x00\x00\x00\x00'; // maxMemType1
+ return ('\x00\x03\x00\x00' + // Version number
+ string32(angle) + // italicAngle
+ '\x00\x00' + // underlinePosition
+ '\x00\x00' + // underlineThickness
+ string32(properties.fixedPitch) + // isFixedPitch
+ '\x00\x00\x00\x00' + // minMemType42
+ '\x00\x00\x00\x00' + // maxMemType42
+ '\x00\x00\x00\x00' + // minMemType1
+ '\x00\x00\x00\x00'); // maxMemType1
}
function createNameTable(name, proto) {
@@ -19813,11 +21586,12 @@ var Font = (function FontClosure() {
// Mac want 1-byte per character strings while Windows want
// 2-bytes per character, so duplicate the names table
var stringsUnicode = [];
- for (var i = 0, ii = strings.length; i < ii; i++) {
- var str = proto[1][i] || strings[i];
+ var i, ii, j, jj, str;
+ for (i = 0, ii = strings.length; i < ii; i++) {
+ str = proto[1][i] || strings[i];
var strBufUnicode = [];
- for (var j = 0, jj = str.length; j < jj; j++) {
+ for (j = 0, jj = str.length; j < jj; j++) {
strBufUnicode.push(string16(str.charCodeAt(j)));
}
stringsUnicode.push(strBufUnicode.join(''));
@@ -19836,10 +21610,10 @@ var Font = (function FontClosure() {
// Build the name records field
var strOffset = 0;
- for (var i = 0, ii = platforms.length; i < ii; i++) {
+ for (i = 0, ii = platforms.length; i < ii; i++) {
var strs = names[i];
- for (var j = 0, jj = strs.length; j < jj; j++) {
- var str = strs[j];
+ for (j = 0, jj = strs.length; j < jj; j++) {
+ str = strs[j];
var nameRecord =
platforms[i] + // platform ID
encodings[i] + // encoding ID
@@ -19869,23 +21643,20 @@ var Font = (function FontClosure() {
exportData: function Font_exportData() {
var data = {};
for (var i in this) {
- if (this.hasOwnProperty(i))
+ if (this.hasOwnProperty(i)) {
data[i] = this[i];
+ }
}
return data;
},
checkAndRepair: function Font_checkAndRepair(name, font, properties) {
function readTableEntry(file) {
- var tag = file.getBytes(4);
- tag = String.fromCharCode(tag[0]) +
- String.fromCharCode(tag[1]) +
- String.fromCharCode(tag[2]) +
- String.fromCharCode(tag[3]);
+ var tag = bytesToString(file.getBytes(4));
- var checksum = int32(file.getBytes(4));
- var offset = int32(file.getBytes(4));
- var length = int32(file.getBytes(4));
+ var checksum = file.getInt32();
+ var offset = file.getInt32() >>> 0;
+ var length = file.getInt32() >>> 0;
// Read the table associated data
var previousPosition = file.pos;
@@ -19911,11 +21682,11 @@ var Font = (function FontClosure() {
function readOpenTypeHeader(ttf) {
return {
- version: arrayToString(ttf.getBytes(4)),
- numTables: int16(ttf.getBytes(2)),
- searchRange: int16(ttf.getBytes(2)),
- entrySelector: int16(ttf.getBytes(2)),
- rangeShift: int16(ttf.getBytes(2))
+ version: bytesToString(ttf.getBytes(4)),
+ numTables: ttf.getUint16(),
+ searchRange: ttf.getUint16(),
+ entrySelector: ttf.getUint16(),
+ rangeShift: ttf.getUint16()
};
}
@@ -19924,11 +21695,12 @@ var Font = (function FontClosure() {
* PDF spec
*/
function readCmapTable(cmap, font, isSymbolicFont) {
+ var segment;
var start = (font.start ? font.start : 0) + cmap.offset;
font.pos = start;
- var version = int16(font.getBytes(2));
- var numTables = int16(font.getBytes(2));
+ var version = font.getUint16();
+ var numTables = font.getUint16();
var potentialTable;
var canBreak = false;
@@ -19939,9 +21711,9 @@ var Font = (function FontClosure() {
// The following takes advantage of the fact that the tables are sorted
// to work.
for (var i = 0; i < numTables; i++) {
- var platformId = int16(font.getBytes(2));
- var encodingId = int16(font.getBytes(2));
- var offset = int32(font.getBytes(4));
+ var platformId = font.getUint16();
+ var encodingId = font.getUint16();
+ var offset = font.getInt32() >>> 0;
var useTable = false;
if (platformId == 1 && encodingId === 0) {
@@ -19974,16 +21746,17 @@ var Font = (function FontClosure() {
}
font.pos = start + potentialTable.offset;
- var format = int16(font.getBytes(2));
- var length = int16(font.getBytes(2));
- var language = int16(font.getBytes(2));
+ var format = font.getUint16();
+ var length = font.getUint16();
+ var language = font.getUint16();
var hasShortCmap = false;
var mappings = [];
+ var j, glyphId;
// TODO(mack): refactor this cmap subtable reading logic out
if (format === 0) {
- for (var j = 0; j < 256; j++) {
+ for (j = 0; j < 256; j++) {
var index = font.getByte();
if (!index) {
continue;
@@ -19997,25 +21770,25 @@ var Font = (function FontClosure() {
} else if (format === 4) {
// re-creating the table in format 4 since the encoding
// might be changed
- var segCount = (int16(font.getBytes(2)) >> 1);
+ var segCount = (font.getUint16() >> 1);
font.getBytes(6); // skipping range fields
var segIndex, segments = [];
for (segIndex = 0; segIndex < segCount; segIndex++) {
- segments.push({ end: int16(font.getBytes(2)) });
+ segments.push({ end: font.getUint16() });
}
- font.getBytes(2);
+ font.getUint16();
for (segIndex = 0; segIndex < segCount; segIndex++) {
- segments[segIndex].start = int16(font.getBytes(2));
+ segments[segIndex].start = font.getUint16();
}
for (segIndex = 0; segIndex < segCount; segIndex++) {
- segments[segIndex].delta = int16(font.getBytes(2));
+ segments[segIndex].delta = font.getUint16();
}
var offsetsCount = 0;
for (segIndex = 0; segIndex < segCount; segIndex++) {
- var segment = segments[segIndex];
- var rangeOffset = int16(font.getBytes(2));
+ segment = segments[segIndex];
+ var rangeOffset = font.getUint16();
if (!rangeOffset) {
segment.offsetIndex = -1;
continue;
@@ -20024,26 +21797,28 @@ var Font = (function FontClosure() {
var offsetIndex = (rangeOffset >> 1) - (segCount - segIndex);
segment.offsetIndex = offsetIndex;
offsetsCount = Math.max(offsetsCount, offsetIndex +
- segment.end - segment.start + 1);
+ segment.end - segment.start + 1);
}
var offsets = [];
- for (var j = 0; j < offsetsCount; j++) {
- offsets.push(int16(font.getBytes(2)));
+ for (j = 0; j < offsetsCount; j++) {
+ offsets.push(font.getUint16());
}
for (segIndex = 0; segIndex < segCount; segIndex++) {
- var segment = segments[segIndex];
- var start = segment.start, end = segment.end;
- var delta = segment.delta, offsetIndex = segment.offsetIndex;
+ segment = segments[segIndex];
+ start = segment.start;
+ var end = segment.end;
+ var delta = segment.delta;
+ offsetIndex = segment.offsetIndex;
- for (var j = start; j <= end; j++) {
+ for (j = start; j <= end; j++) {
if (j == 0xFFFF) {
continue;
}
- var glyphId = offsetIndex < 0 ? j :
- offsets[offsetIndex + j - start];
+ glyphId = (offsetIndex < 0 ?
+ j : offsets[offsetIndex + j - start]);
glyphId = (glyphId + delta) & 0xFFFF;
if (glyphId === 0) {
continue;
@@ -20060,13 +21835,11 @@ var Font = (function FontClosure() {
// table. (This looks weird, so I can have missed something), this
// works on Linux but seems to fails on Mac so let's rewrite the
// cmap table to a 3-1-4 style
- var firstCode = int16(font.getBytes(2));
- var entryCount = int16(font.getBytes(2));
+ var firstCode = font.getUint16();
+ var entryCount = font.getUint16();
- var glyphs = [];
- var ids = [];
- for (var j = 0; j < entryCount; j++) {
- var glyphId = int16(font.getBytes(2));
+ for (j = 0; j < entryCount; j++) {
+ glyphId = font.getUint16();
var charCode = firstCode + j;
mappings.push({
@@ -20082,7 +21855,7 @@ var Font = (function FontClosure() {
mappings.sort(function (a, b) {
return a.charCode - b.charCode;
});
- for (var i = 1; i < mappings.length; i++) {
+ for (i = 1; i < mappings.length; i++) {
if (mappings[i - 1].charCode === mappings[i].charCode) {
mappings.splice(i, 1);
i--;
@@ -20107,7 +21880,7 @@ var Font = (function FontClosure() {
font.pos = (font.start ? font.start : 0) + header.offset;
font.pos += header.length - 2;
- var numOfMetrics = int16(font.getBytes(2));
+ var numOfMetrics = font.getUint16();
if (numOfMetrics > numGlyphs) {
info('The numOfMetrics (' + numOfMetrics + ') should not be ' +
@@ -20122,13 +21895,16 @@ var Font = (function FontClosure() {
var numMissing = numOfSidebearings -
((metrics.length - numOfMetrics * 4) >> 1);
+ var i, ii;
if (numMissing > 0) {
font.pos = (font.start ? font.start : 0) + metrics.offset;
var entries = '';
- for (var i = 0, ii = metrics.length; i < ii; i++)
+ for (i = 0, ii = metrics.length; i < ii; i++) {
entries += String.fromCharCode(font.getByte());
- for (var i = 0; i < numMissing; i++)
+ }
+ for (i = 0; i < numMissing; i++) {
entries += '\x00\x00';
+ }
metrics.data = stringToArray(entries);
}
}
@@ -20147,8 +21923,8 @@ var Font = (function FontClosure() {
return glyf.length;
}
- var j = 10, flagsCount = 0;
- for (var i = 0; i < contoursCount; i++) {
+ var i, j = 10, flagsCount = 0;
+ for (i = 0; i < contoursCount; i++) {
var endPoint = (glyf[j] << 8) | glyf[j + 1];
flagsCount = endPoint + 1;
j += 2;
@@ -20160,7 +21936,7 @@ var Font = (function FontClosure() {
var instructionsEnd = j;
// validating flags
var coordinatesLength = 0;
- for (var i = 0; i < flagsCount; i++) {
+ for (i = 0; i < flagsCount; i++) {
var flag = glyf[j++];
if (flag & 0xC0) {
// reserved flags must be zero, cleaning up
@@ -20211,7 +21987,7 @@ var Font = (function FontClosure() {
// Validate version:
// Should always be 0x00010000
- var version = int32([data[0], data[1], data[2], data[3]]);
+ var version = int32(data[0], data[1], data[2], data[3]);
if (version >> 16 !== 1) {
info('Attempting to fix invalid version in head table: ' + version);
data[0] = 0;
@@ -20220,7 +21996,7 @@ var Font = (function FontClosure() {
data[3] = 0;
}
- var indexToLocFormat = int16([data[50], data[51]]);
+ var indexToLocFormat = int16(data[50], data[51]);
if (indexToLocFormat < 0 || indexToLocFormat > 1) {
info('Attempting to fix invalid indexToLocFormat in head table: ' +
indexToLocFormat);
@@ -20291,7 +22067,8 @@ var Font = (function FontClosure() {
var startOffset = itemDecode(locaData, 0);
var writeOffset = 0;
itemEncode(locaData, 0, writeOffset);
- for (var i = 0, j = itemSize; i < numGlyphs; i++, j += itemSize) {
+ var i, j;
+ for (i = 0, j = itemSize; i < numGlyphs; i++, j += itemSize) {
var endOffset = itemDecode(locaData, j);
if (endOffset > oldGlyfDataLength &&
((oldGlyfDataLength + 3) & ~3) === endOffset) {
@@ -20318,8 +22095,9 @@ var Font = (function FontClosure() {
// to have single glyph with one point
var simpleGlyph = new Uint8Array(
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 0]);
- for (var i = 0, j = itemSize; i < numGlyphs; i++, j += itemSize)
+ for (i = 0, j = itemSize; i < numGlyphs; i++, j += itemSize) {
itemEncode(locaData, j, simpleGlyph.length);
+ }
glyf.data = simpleGlyph;
return;
}
@@ -20345,25 +22123,27 @@ var Font = (function FontClosure() {
font.pos = start;
var length = post.length, end = start + length;
- var version = int32(font.getBytes(4));
+ var version = font.getInt32();
// skip rest to the tables
font.getBytes(28);
var glyphNames;
var valid = true;
+ var i;
+
switch (version) {
case 0x00010000:
glyphNames = MacStandardGlyphOrdering;
break;
case 0x00020000:
- var numGlyphs = int16(font.getBytes(2));
+ var numGlyphs = font.getUint16();
if (numGlyphs != maxpNumGlyphs) {
valid = false;
break;
}
var glyphNameIndexes = [];
- for (var i = 0; i < numGlyphs; ++i) {
- var index = int16(font.getBytes(2));
+ for (i = 0; i < numGlyphs; ++i) {
+ var index = font.getUint16();
if (index >= 32768) {
valid = false;
break;
@@ -20377,13 +22157,13 @@ var Font = (function FontClosure() {
while (font.pos < end) {
var stringLength = font.getByte();
var string = '';
- for (var i = 0; i < stringLength; ++i) {
+ for (i = 0; i < stringLength; ++i) {
string += String.fromCharCode(font.getByte());
}
customNames.push(string);
}
glyphNames = [];
- for (var i = 0; i < numGlyphs; ++i) {
+ for (i = 0; i < numGlyphs; ++i) {
var j = glyphNameIndexes[i];
if (j < 258) {
glyphNames.push(MacStandardGlyphOrdering[j]);
@@ -20409,25 +22189,27 @@ var Font = (function FontClosure() {
var names = [[], []];
var length = nameTable.length, end = start + length;
- var format = int16(font.getBytes(2));
+ var format = font.getUint16();
var FORMAT_0_HEADER_LENGTH = 6;
if (format !== 0 || length < FORMAT_0_HEADER_LENGTH) {
// unsupported name table format or table "too" small
return names;
}
- var numRecords = int16(font.getBytes(2));
- var stringsStart = int16(font.getBytes(2));
+ var numRecords = font.getUint16();
+ var stringsStart = font.getUint16();
var records = [];
var NAME_RECORD_LENGTH = 12;
- for (var i = 0; i < numRecords &&
+ var i, ii;
+
+ for (i = 0; i < numRecords &&
font.pos + NAME_RECORD_LENGTH <= end; i++) {
var r = {
- platform: int16(font.getBytes(2)),
- encoding: int16(font.getBytes(2)),
- language: int16(font.getBytes(2)),
- name: int16(font.getBytes(2)),
- length: int16(font.getBytes(2)),
- offset: int16(font.getBytes(2))
+ platform: font.getUint16(),
+ encoding: font.getUint16(),
+ language: font.getUint16(),
+ name: font.getUint16(),
+ length: font.getUint16(),
+ offset: font.getUint16()
};
// using only Macintosh and Windows platform/encoding names
if ((r.platform == 1 && r.encoding === 0 && r.language === 0) ||
@@ -20435,7 +22217,7 @@ var Font = (function FontClosure() {
records.push(r);
}
}
- for (var i = 0, ii = records.length; i < ii; i++) {
+ for (i = 0, ii = records.length; i < ii; i++) {
var record = records[i];
var pos = start + stringsStart + record.offset;
if (pos + record.length > end) {
@@ -20443,12 +22225,11 @@ var Font = (function FontClosure() {
}
font.pos = pos;
var nameIndex = record.name;
- var encoding = record.encoding ? 1 : 0;
if (record.encoding) {
// unicode
var str = '';
for (var j = 0, jj = record.length; j < jj; j += 2) {
- str += String.fromCharCode(int16(font.getBytes(2)));
+ str += String.fromCharCode(font.getUint16());
}
names[1][nameIndex] = str;
} else {
@@ -20472,7 +22253,7 @@ var Font = (function FontClosure() {
function sanitizeTTProgram(table, ttContext) {
var data = table.data;
- var i = 0, n, lastEndf = 0, lastDeff = 0;
+ var i = 0, j, n, b, funcId, pc, lastEndf = 0, lastDeff = 0;
var stack = [];
var callstack = [];
var functionsCalled = [];
@@ -20488,7 +22269,7 @@ var Font = (function FontClosure() {
if (inFDEF || inELSE) {
i += n;
} else {
- for (var j = 0; j < n; j++) {
+ for (j = 0; j < n; j++) {
stack.push(data[i++]);
}
}
@@ -20497,8 +22278,8 @@ var Font = (function FontClosure() {
if (inFDEF || inELSE) {
i += n * 2;
} else {
- for (var j = 0; j < n; j++) {
- var b = data[i++];
+ for (j = 0; j < n; j++) {
+ b = data[i++];
stack.push((b << 8) | data[i++]);
}
}
@@ -20507,7 +22288,7 @@ var Font = (function FontClosure() {
if (inFDEF || inELSE) {
i += n;
} else {
- for (var j = 0; j < n; j++) {
+ for (j = 0; j < n; j++) {
stack.push(data[i++]);
}
}
@@ -20516,15 +22297,15 @@ var Font = (function FontClosure() {
if (inFDEF || inELSE) {
i += n * 2;
} else {
- for (var j = 0; j < n; j++) {
- var b = data[i++];
+ for (j = 0; j < n; j++) {
+ b = data[i++];
stack.push((b << 8) | data[i++]);
}
}
} else if (op === 0x2B && !tooComplexToFollowFunctions) { // CALL
if (!inFDEF && !inELSE) {
// collecting inforamtion about which functions are used
- var funcId = stack[stack.length - 1];
+ funcId = stack[stack.length - 1];
ttContext.functionsUsed[funcId] = true;
if (funcId in ttContext.functionsStackDeltas) {
stack.length += ttContext.functionsStackDeltas[funcId];
@@ -20532,7 +22313,7 @@ var Font = (function FontClosure() {
functionsCalled.indexOf(funcId) < 0) {
callstack.push({data: data, i: i, stackTop: stack.length - 1});
functionsCalled.push(funcId);
- var pc = ttContext.functionsDefined[funcId];
+ pc = ttContext.functionsDefined[funcId];
if (!pc) {
warn('TT: CALL non-existent function');
ttContext.hintsValid = false;
@@ -20550,20 +22331,20 @@ var Font = (function FontClosure() {
inFDEF = true;
// collecting inforamtion about which functions are defined
lastDeff = i;
- var funcId = stack.pop();
+ funcId = stack.pop();
ttContext.functionsDefined[funcId] = {data: data, i: i};
} else if (op === 0x2D) { // ENDF - end of function
if (inFDEF) {
inFDEF = false;
lastEndf = i;
} else {
- var pc = callstack.pop();
+ pc = callstack.pop();
if (!pc) {
warn('TT: ENDF bad stack');
ttContext.hintsValid = false;
return;
}
- var funcId = functionsCalled.pop();
+ funcId = functionsCalled.pop();
data = pc.data;
i = pc.i;
ttContext.functionsStackDeltas[funcId] =
@@ -20590,7 +22371,9 @@ var Font = (function FontClosure() {
if (!inFDEF && !inELSE) {
var offset = stack[stack.length - 1];
// only jumping forward to prevent infinite loop
- if (offset > 0) { i += offset - 1; }
+ if (offset > 0) {
+ i += offset - 1;
+ }
}
}
// Adjusting stack not extactly, but just enough to get function id
@@ -20654,13 +22437,14 @@ var Font = (function FontClosure() {
if (content.length > 1) {
// concatenating the content items
var newLength = 0;
- for (var j = 0, jj = content.length; j < jj; j++) {
+ var j, jj;
+ for (j = 0, jj = content.length; j < jj; j++) {
newLength += content[j].length;
}
newLength = (newLength + 3) & ~3;
var result = new Uint8Array(newLength);
var pos = 0;
- for (var j = 0, jj = content.length; j < jj; j++) {
+ for (j = 0, jj = content.length; j < jj; j++) {
result.set(content[j], pos);
pos += content[j].length;
}
@@ -20702,11 +22486,13 @@ var Font = (function FontClosure() {
var header = readOpenTypeHeader(font);
var numTables = header.numTables;
+ var cff, cffFile;
var tables = { 'OS/2': null, cmap: null, head: null, hhea: null,
- hmtx: null, maxp: null, name: null, post: null};
+ hmtx: null, maxp: null, name: null, post: null };
+ var table, tableData;
for (var i = 0; i < numTables; i++) {
- var table = readTableEntry(font);
+ table = readTableEntry(font);
if (VALID_TABLES.indexOf(table.tag) < 0) {
continue; // skipping table if it's not a required or optional table
}
@@ -20721,8 +22507,8 @@ var Font = (function FontClosure() {
// OpenType font
if (!tables.head || !tables.hhea || !tables.maxp || !tables.post) {
// no major tables: throwing everything at CFFFont
- var cffFile = new Stream(tables['CFF '].data);
- var cff = new CFFFont(cffFile, properties);
+ cffFile = new Stream(tables['CFF '].data);
+ cff = new CFFFont(cffFile, properties);
return this.convert(name, cff, properties);
}
@@ -20743,19 +22529,19 @@ var Font = (function FontClosure() {
}
font.pos = (font.start || 0) + tables.maxp.offset;
- var version = int32(font.getBytes(4));
- var numGlyphs = int16(font.getBytes(2));
+ var version = font.getInt32();
+ var numGlyphs = font.getUint16();
var maxFunctionDefs = 0;
if (version >= 0x00010000 && tables.maxp.length >= 22) {
// maxZones can be invalid
font.pos += 8;
- var maxZones = int16(font.getBytes(2));
+ var maxZones = font.getUint16();
if (maxZones > 2) { // reset to 2 if font has invalid maxZones
tables.maxp.data[14] = 0;
tables.maxp.data[15] = 2;
}
font.pos += 4;
- maxFunctionDefs = int16(font.getBytes(2));
+ maxFunctionDefs = font.getUint16();
}
var dupFirstEntry = false;
@@ -20805,8 +22591,8 @@ var Font = (function FontClosure() {
sanitizeHead(tables.head, numGlyphs, isTrueType ? tables.loca.length : 0);
if (isTrueType) {
- var isGlyphLocationsLong = int16([tables.head.data[50],
- tables.head.data[51]]);
+ var isGlyphLocationsLong = int16(tables.head.data[50],
+ tables.head.data[51]);
sanitizeGlyphLocations(tables.loca, tables.glyf, numGlyphs,
isGlyphLocationsLong, hintsValid, dupFirstEntry);
}
@@ -20830,11 +22616,11 @@ var Font = (function FontClosure() {
}
}
- var charCodeToGlyphId = [];
+ var charCodeToGlyphId = [], charCode;
if (properties.type == 'CIDFontType2') {
var cidToGidMap = properties.cidToGidMap || [];
var cMap = properties.cMap.map;
- for (var charCode in cMap) {
+ for (charCode in cMap) {
charCode |= 0;
var cid = cMap[charCode];
assert(cid.length === 1, 'Max size of CID is 65,535');
@@ -20874,7 +22660,7 @@ var Font = (function FontClosure() {
properties.baseEncodingName === 'WinAnsiEncoding') {
baseEncoding = Encodings[properties.baseEncodingName];
}
- for (var charCode = 0; charCode < 256; charCode++) {
+ for (charCode = 0; charCode < 256; charCode++) {
var glyphName;
if (this.differences && charCode in this.differences) {
glyphName = this.differences[charCode];
@@ -20896,7 +22682,7 @@ var Font = (function FontClosure() {
}
var found = false;
- for (var i = 0; i < cmapMappingsLength; ++i) {
+ for (i = 0; i < cmapMappingsLength; ++i) {
if (cmapMappings[i].charCode === unicodeOrCharCode) {
charCodeToGlyphId[charCode] = cmapMappings[i].glyphId;
found = true;
@@ -20906,7 +22692,7 @@ var Font = (function FontClosure() {
if (!found && properties.glyphNames) {
// Try to map using the post table. There are currently no known
// pdfs that this fixes.
- var glyphId = properties.glyphNames.indexOf(glyphName);
+ glyphId = properties.glyphNames.indexOf(glyphName);
if (glyphId > 0) {
charCodeToGlyphId[charCode] = glyphId;
}
@@ -20926,8 +22712,8 @@ var Font = (function FontClosure() {
// associated glyph descriptions from the subtable'. This means
// charcodes in the cmap will be single bytes, so no-op since
// glyph.charCode & 0xFF === glyph.charCode
- for (var i = 0; i < cmapMappingsLength; ++i) {
- var charCode = cmapMappings[i].charCode & 0xFF;
+ for (i = 0; i < cmapMappingsLength; ++i) {
+ charCode = cmapMappings[i].charCode & 0xFF;
charCodeToGlyphId[charCode] = cmapMappings[i].glyphId;
}
}
@@ -20950,11 +22736,11 @@ var Font = (function FontClosure() {
// extract some more font properties from the OpenType head and
// hhea tables; yMin and descent value are always negative
var override = {
- unitsPerEm: int16([tables.head.data[18], tables.head.data[19]]),
- yMax: int16([tables.head.data[42], tables.head.data[43]]),
- yMin: int16([tables.head.data[38], tables.head.data[39]]) - 0x10000,
- ascent: int16([tables.hhea.data[4], tables.hhea.data[5]]),
- descent: int16([tables.hhea.data[6], tables.hhea.data[7]]) - 0x10000
+ unitsPerEm: int16(tables.head.data[18], tables.head.data[19]),
+ yMax: int16(tables.head.data[42], tables.head.data[43]),
+ yMin: int16(tables.head.data[38], tables.head.data[39]) - 0x10000,
+ ascent: int16(tables.hhea.data[4], tables.hhea.data[5]),
+ descent: int16(tables.hhea.data[6], tables.hhea.data[7]) - 0x10000
};
tables['OS/2'] = {
@@ -20976,9 +22762,9 @@ var Font = (function FontClosure() {
if (!isTrueType) {
try {
// Trying to repair CFF file
- var cffFile = new Stream(tables['CFF '].data);
+ cffFile = new Stream(tables['CFF '].data);
var parser = new CFFParser(cffFile, properties);
- var cff = parser.parse();
+ cff = parser.parse();
var compiler = new CFFCompiler(cff);
tables['CFF '].data = compiler.compile();
} catch (e) {
@@ -20999,25 +22785,27 @@ var Font = (function FontClosure() {
}
// rewrite the tables but tweak offsets
- for (var i = 0; i < numTables; i++) {
- var table = tables[tablesNames[i]];
+ for (i = 0; i < numTables; i++) {
+ table = tables[tablesNames[i]];
var data = [];
- var tableData = table.data;
- for (var j = 0, jj = tableData.length; j < jj; j++)
+ tableData = table.data;
+ for (var j = 0, jj = tableData.length; j < jj; j++) {
data.push(tableData[j]);
+ }
createTableEntry(ttf, table.tag, data);
}
// Add the table datas
- for (var i = 0; i < numTables; i++) {
- var table = tables[tablesNames[i]];
- var tableData = table.data;
- ttf.file += arrayToString(tableData);
+ for (i = 0; i < numTables; i++) {
+ table = tables[tablesNames[i]];
+ tableData = table.data;
+ ttf.file += bytesToString(new Uint8Array(tableData));
// 4-byte aligned data
- while (ttf.file.length & 3)
+ while (ttf.file.length & 3) {
ttf.file += String.fromCharCode(0);
+ }
}
return stringToArray(ttf.file);
@@ -21028,8 +22816,6 @@ var Font = (function FontClosure() {
// to write the table entry information about a table and another offset
// representing the offset where to draw the actual data of a particular
// table
- var REQ_TABLES_CNT = 9;
-
var otf = {
file: '',
virtualOffset: 9 * (4 * 4)
@@ -21045,18 +22831,25 @@ var Font = (function FontClosure() {
this.toFontChar = newMapping.toFontChar;
var numGlyphs = font.numGlyphs;
+ function getCharCode(charCodeToGlyphId, glyphId, addMap) {
+ for (var charCode in charCodeToGlyphId) {
+ if (glyphId === charCodeToGlyphId[charCode]) {
+ return charCode | 0;
+ }
+ }
+ if (addMap) {
+ newMapping.charCodeToGlyphId[newMapping.nextAvailableFontCharCode] =
+ glyphId;
+ return newMapping.nextAvailableFontCharCode++;
+ }
+ return null;
+ }
+
var seacs = font.seacs;
if (SEAC_ANALYSIS_ENABLED && seacs && seacs.length) {
var matrix = properties.fontMatrix || FONT_IDENTITY_MATRIX;
var charset = font.getCharset();
- var charCodeToGlyphId = mapping;
- var toFontChar = newMapping.toFontChar;
- var seacs = font.seacs;
var seacMap = Object.create(null);
- var glyphIdToCharCode = Object.create(null);
- for (var charCode in charCodeToGlyphId) {
- glyphIdToCharCode[charCodeToGlyphId[charCode]] = charCode | 0;
- }
for (var glyphId in seacs) {
glyphId |= 0;
var seac = seacs[glyphId];
@@ -21071,10 +22864,23 @@ var Font = (function FontClosure() {
x: seac[0] * matrix[0] + seac[1] * matrix[2] + matrix[4],
y: seac[0] * matrix[1] + seac[1] * matrix[3] + matrix[5]
};
- var charCode = glyphIdToCharCode[glyphId];
+
+ var charCode = getCharCode(mapping, glyphId);
+ if (charCode === null) {
+ // There's no point in mapping it if the char code was never mapped
+ // to begin with.
+ continue;
+ }
+ // Find a fontCharCode that maps to the base and accent glyphs. If one
+ // doesn't exists, create it.
+ var charCodeToGlyphId = newMapping.charCodeToGlyphId;
+ var baseFontCharCode = getCharCode(charCodeToGlyphId, baseGlyphId,
+ true);
+ var accentFontCharCode = getCharCode(charCodeToGlyphId, accentGlyphId,
+ true);
seacMap[charCode] = {
- baseFontCharCode: toFontChar[glyphIdToCharCode[baseGlyphId]],
- accentFontCharCode: toFontChar[glyphIdToCharCode[accentGlyphId]],
+ baseFontCharCode: baseFontCharCode,
+ accentFontCharCode: accentFontCharCode,
accentOffset: accentOffset
};
}
@@ -21097,56 +22903,56 @@ var Font = (function FontClosure() {
// Font header
'head': (function fontFieldsHead() {
return stringToArray(
- '\x00\x01\x00\x00' + // Version number
- '\x00\x00\x10\x00' + // fontRevision
- '\x00\x00\x00\x00' + // checksumAdjustement
- '\x5F\x0F\x3C\xF5' + // magicNumber
- '\x00\x00' + // Flags
- safeString16(unitsPerEm) + // unitsPerEM
- '\x00\x00\x00\x00\x9e\x0b\x7e\x27' + // creation date
- '\x00\x00\x00\x00\x9e\x0b\x7e\x27' + // modifification date
- '\x00\x00' + // xMin
- safeString16(properties.descent) + // yMin
- '\x0F\xFF' + // xMax
- safeString16(properties.ascent) + // yMax
- string16(properties.italicAngle ? 2 : 0) + // macStyle
- '\x00\x11' + // lowestRecPPEM
- '\x00\x00' + // fontDirectionHint
- '\x00\x00' + // indexToLocFormat
- '\x00\x00'); // glyphDataFormat
+ '\x00\x01\x00\x00' + // Version number
+ '\x00\x00\x10\x00' + // fontRevision
+ '\x00\x00\x00\x00' + // checksumAdjustement
+ '\x5F\x0F\x3C\xF5' + // magicNumber
+ '\x00\x00' + // Flags
+ safeString16(unitsPerEm) + // unitsPerEM
+ '\x00\x00\x00\x00\x9e\x0b\x7e\x27' + // creation date
+ '\x00\x00\x00\x00\x9e\x0b\x7e\x27' + // modifification date
+ '\x00\x00' + // xMin
+ safeString16(properties.descent) + // yMin
+ '\x0F\xFF' + // xMax
+ safeString16(properties.ascent) + // yMax
+ string16(properties.italicAngle ? 2 : 0) + // macStyle
+ '\x00\x11' + // lowestRecPPEM
+ '\x00\x00' + // fontDirectionHint
+ '\x00\x00' + // indexToLocFormat
+ '\x00\x00'); // glyphDataFormat
})(),
// Horizontal header
'hhea': (function fontFieldsHhea() {
return stringToArray(
- '\x00\x01\x00\x00' + // Version number
- safeString16(properties.ascent) + // Typographic Ascent
- safeString16(properties.descent) + // Typographic Descent
- '\x00\x00' + // Line Gap
- '\xFF\xFF' + // advanceWidthMax
- '\x00\x00' + // minLeftSidebearing
- '\x00\x00' + // minRightSidebearing
- '\x00\x00' + // xMaxExtent
- safeString16(properties.capHeight) + // caretSlopeRise
- safeString16(Math.tan(properties.italicAngle) *
- properties.xHeight) + // caretSlopeRun
- '\x00\x00' + // caretOffset
- '\x00\x00' + // -reserved-
- '\x00\x00' + // -reserved-
- '\x00\x00' + // -reserved-
- '\x00\x00' + // -reserved-
- '\x00\x00' + // metricDataFormat
- string16(numGlyphs + 1)); // Number of HMetrics
+ '\x00\x01\x00\x00' + // Version number
+ safeString16(properties.ascent) + // Typographic Ascent
+ safeString16(properties.descent) + // Typographic Descent
+ '\x00\x00' + // Line Gap
+ '\xFF\xFF' + // advanceWidthMax
+ '\x00\x00' + // minLeftSidebearing
+ '\x00\x00' + // minRightSidebearing
+ '\x00\x00' + // xMaxExtent
+ safeString16(properties.capHeight) + // caretSlopeRise
+ safeString16(Math.tan(properties.italicAngle) *
+ properties.xHeight) + // caretSlopeRun
+ '\x00\x00' + // caretOffset
+ '\x00\x00' + // -reserved-
+ '\x00\x00' + // -reserved-
+ '\x00\x00' + // -reserved-
+ '\x00\x00' + // -reserved-
+ '\x00\x00' + // metricDataFormat
+ string16(numGlyphs)); // Number of HMetrics
})(),
// Horizontal metrics
'hmtx': (function fontFieldsHmtx() {
var charstrings = font.charstrings;
var hmtx = '\x00\x00\x00\x00'; // Fake .notdef
- for (var i = 0, ii = numGlyphs; i < ii; i++) {
+ for (var i = 1, ii = numGlyphs; i < ii; i++) {
// TODO: For CFF fonts the width should technically match th x in
// the glyph, but it doesn't seem to matter.
- var charstring = charstrings ? charstrings[i] : {};
+ var charstring = charstrings ? charstrings[i - 1] : {};
var width = 'width' in charstring ? charstring.width : 0;
hmtx += string16(width) + string16(0);
}
@@ -21156,8 +22962,8 @@ var Font = (function FontClosure() {
// Maximum profile
'maxp': (function fontFieldsMaxp() {
return stringToArray(
- '\x00\x00\x50\x00' + // Version number
- string16(numGlyphs + 1)); // Num of glyphs
+ '\x00\x00\x50\x00' + // Version number
+ string16(numGlyphs)); // Num of glyphs
})(),
// Naming tables
@@ -21167,12 +22973,13 @@ var Font = (function FontClosure() {
'post': stringToArray(createPostTable(properties))
};
- for (var field in fields)
+ var field;
+ for (field in fields) {
createTableEntry(otf, field, fields[field]);
-
- for (var field in fields) {
+ }
+ for (field in fields) {
var table = fields[field];
- otf.file += arrayToString(table);
+ otf.file += bytesToString(new Uint8Array(table));
}
return stringToArray(otf.file);
@@ -21191,7 +22998,7 @@ var Font = (function FontClosure() {
toUnicode: null
};
// Section 9.10.2 Mapping Character Codes to Unicode Values
- if (properties.toUnicode) {
+ if (properties.toUnicode && properties.toUnicode.length !== 0) {
map.toUnicode = properties.toUnicode;
return map;
}
@@ -21200,20 +23007,36 @@ var Font = (function FontClosure() {
// the differences array only contains adobe standard or symbol set names,
// in pratice it seems better to always try to create a toUnicode
// map based of the default encoding.
+ var toUnicode, charcode;
if (!properties.composite /* is simple font */) {
- var toUnicode = [];
+ toUnicode = [];
var encoding = properties.defaultEncoding.slice();
// Merge in the differences array.
var differences = properties.differences;
- for (var charcode in differences) {
+ for (charcode in differences) {
encoding[charcode] = differences[charcode];
}
- for (var charcode in encoding) {
+ for (charcode in encoding) {
// a) Map the character code to a character name.
var glyphName = encoding[charcode];
// b) Look up the character name in the Adobe Glyph List (see the
// Bibliography) to obtain the corresponding Unicode value.
if (glyphName === '' || !(glyphName in GlyphsUnicode)) {
+ // (undocumented) c) Few heuristics to recognize unknown glyphs
+ // NOTE: Adobe Reader does not do this step, but OSX Preview does
+ var code;
+ // Gxx glyph
+ if (glyphName.length === 3 &&
+ glyphName[0] === 'G' &&
+ (code = parseInt(glyphName.substr(1), 16))) {
+ toUnicode[charcode] = String.fromCharCode(code);
+ }
+ // Cddd glyph
+ if (glyphName.length >= 3 &&
+ glyphName[0] === 'C' &&
+ (code = +glyphName.substr(1))) {
+ toUnicode[charcode] = String.fromCharCode(code);
+ }
continue;
}
toUnicode[charcode] = String.fromCharCode(GlyphsUnicode[glyphName]);
@@ -21247,10 +23070,11 @@ var Font = (function FontClosure() {
var ucs2CMapName = new Name(registry + '-' + ordering + '-UCS2');
// d) Obtain the CMap with the name constructed in step (c) (available
// from the ASN Web site; see the Bibliography).
- var ucs2CMap = CMapFactory.create(ucs2CMapName, PDFJS.cMapUrl, null);
+ var ucs2CMap = CMapFactory.create(ucs2CMapName,
+ { url: PDFJS.cMapUrl, packed: PDFJS.cMapPacked }, null);
var cMap = properties.cMap;
- var toUnicode = [];
- for (var charcode in cMap.map) {
+ toUnicode = [];
+ for (charcode in cMap.map) {
var cid = cMap.map[charcode];
assert(cid.length === 1, 'Max size of CID is 65,535');
// e) Map the CID obtained in step (a) according to the CMap obtained
@@ -21267,9 +23091,9 @@ var Font = (function FontClosure() {
}
// The viewer's choice, just use an identity map.
- var toUnicode = [];
+ toUnicode = [];
var firstChar = properties.firstChar, lastChar = properties.lastChar;
- for (var i = firstChar, ii = lastChar; i <= ii; i++) {
+ for (var i = firstChar; i <= lastChar; i++) {
toUnicode[i] = String.fromCharCode(i);
}
map.isIdentity = true;
@@ -21301,15 +23125,18 @@ var Font = (function FontClosure() {
}
}
// ... via toUnicode map
- if (!charcode && 'toUnicode' in this)
+ if (!charcode && 'toUnicode' in this) {
charcode = this.toUnicode.indexOf(glyphUnicode);
+ }
// setting it to unicode if negative or undefined
- if (charcode <= 0)
+ if (charcode <= 0) {
charcode = glyphUnicode;
+ }
// trying to get width via charcode
width = this.widths[charcode];
- if (width)
+ if (width) {
break; // the non-zero width found
+ }
}
width = width || this.defaultWidth;
// Do not shadow the property here. See discussion:
@@ -21319,19 +23146,19 @@ var Font = (function FontClosure() {
},
charToGlyph: function Font_charToGlyph(charcode) {
- var fontCharCode, width, operatorList;
+ var fontCharCode, width, operatorListId;
var widthCode = charcode;
if (this.cMap && charcode in this.cMap.map) {
widthCode = this.cMap.map[charcode].charCodeAt(0);
}
- var width = this.widths[widthCode];
+ width = this.widths[widthCode];
width = isNum(width) ? width : this.defaultWidth;
var vmetric = this.vmetrics && this.vmetrics[widthCode];
- var unicodeChars = this.toUnicode[charcode] || charcode;
- if (typeof unicodeChars === 'number') {
- unicodeChars = String.fromCharCode(unicodeChars);
+ var unicode = this.toUnicode[charcode] || charcode;
+ if (typeof unicode === 'number') {
+ unicode = String.fromCharCode(unicode);
}
// First try the toFontChar map, if it's not there then try falling
@@ -21341,9 +23168,9 @@ var Font = (function FontClosure() {
fontCharCode = mapSpecialUnicodeValues(fontCharCode);
}
- if (this.type === 'Type3') {
+ if (this.isType3Font) {
// Font char code in this case is actually a glyph name.
- operatorList = this.charProcOperatorList[fontCharCode];
+ operatorListId = fontCharCode;
}
var accent = null;
@@ -21356,44 +23183,49 @@ var Font = (function FontClosure() {
};
}
- return {
- fontChar: String.fromCharCode(fontCharCode),
- unicode: unicodeChars,
- accent: accent,
- width: width,
- vmetric: vmetric,
- operatorList: operatorList
- };
+ var fontChar = String.fromCharCode(fontCharCode);
+
+ var glyph = this.glyphCache[charcode];
+ if (!glyph ||
+ !glyph.matchesForCache(fontChar, unicode, accent, width, vmetric,
+ operatorListId)) {
+ glyph = new Glyph(fontChar, unicode, accent, width, vmetric,
+ operatorListId);
+ this.glyphCache[charcode] = glyph;
+ }
+ return glyph;
},
charsToGlyphs: function Font_charsToGlyphs(chars) {
var charsCache = this.charsCache;
- var glyphs;
+ var glyphs, glyph, charcode;
// if we translated this string before, just grab it from the cache
if (charsCache) {
glyphs = charsCache[chars];
- if (glyphs)
+ if (glyphs) {
return glyphs;
+ }
}
// lazily create the translation cache
- if (!charsCache)
+ if (!charsCache) {
charsCache = this.charsCache = Object.create(null);
+ }
glyphs = [];
var charsCacheKey = chars;
+ var i = 0, ii;
if (this.cMap) {
- var i = 0;
// composite fonts have multi-byte strings convert the string from
// single-byte to multi-byte
while (i < chars.length) {
var c = this.cMap.readCharCode(chars, i);
- var charcode = c[0];
+ charcode = c[0];
var length = c[1];
i += length;
- var glyph = this.charToGlyph(charcode);
+ glyph = this.charToGlyph(charcode);
glyphs.push(glyph);
// placing null after each word break charcode (ASCII SPACE)
// Ignore occurences of 0x20 in multiple-byte codes.
@@ -21402,12 +23234,13 @@ var Font = (function FontClosure() {
}
}
} else {
- for (var i = 0, ii = chars.length; i < ii; ++i) {
- var charcode = chars.charCodeAt(i);
- var glyph = this.charToGlyph(charcode);
+ for (i = 0, ii = chars.length; i < ii; ++i) {
+ charcode = chars.charCodeAt(i);
+ glyph = this.charToGlyph(charcode);
glyphs.push(glyph);
- if (charcode == 0x20)
+ if (charcode == 0x20) {
glyphs.push(null);
+ }
}
}
@@ -21422,6 +23255,8 @@ var Font = (function FontClosure() {
var ErrorFont = (function ErrorFontClosure() {
function ErrorFont(error) {
this.error = error;
+ this.loadedName = 'g_font_error';
+ this.loading = false;
}
ErrorFont.prototype = {
@@ -21447,12 +23282,14 @@ var ErrorFont = (function ErrorFontClosure() {
*/
function type1FontGlyphMapping(properties, builtInEncoding, glyphNames) {
var charCodeToGlyphId = Object.create(null);
+ var glyphId, charCode, baseEncoding;
+
if (properties.baseEncodingName) {
// If a valid base encoding name was used, the mapping is initialized with
// that.
- var baseEncoding = Encodings[properties.baseEncodingName];
- for (var charCode = 0; charCode < baseEncoding.length; charCode++) {
- var glyphId = glyphNames.indexOf(baseEncoding[charCode]);
+ baseEncoding = Encodings[properties.baseEncodingName];
+ for (charCode = 0; charCode < baseEncoding.length; charCode++) {
+ glyphId = glyphNames.indexOf(baseEncoding[charCode]);
if (glyphId >= 0) {
charCodeToGlyphId[charCode] = glyphId;
}
@@ -21460,15 +23297,15 @@ function type1FontGlyphMapping(properties, builtInEncoding, glyphNames) {
} else if (!!(properties.flags & FontFlags.Symbolic)) {
// For a symbolic font the encoding should be the fonts built-in
// encoding.
- for (var charCode in builtInEncoding) {
+ for (charCode in builtInEncoding) {
charCodeToGlyphId[charCode] = builtInEncoding[charCode];
}
} else {
// For non-symbolic fonts that don't have a base encoding the standard
// encoding should be used.
- var baseEncoding = Encodings.StandardEncoding;
- for (var charCode = 0; charCode < baseEncoding.length; charCode++) {
- var glyphId = glyphNames.indexOf(baseEncoding[charCode]);
+ baseEncoding = Encodings.StandardEncoding;
+ for (charCode = 0; charCode < baseEncoding.length; charCode++) {
+ glyphId = glyphNames.indexOf(baseEncoding[charCode]);
if (glyphId >= 0) {
charCodeToGlyphId[charCode] = glyphId;
}
@@ -21478,9 +23315,9 @@ function type1FontGlyphMapping(properties, builtInEncoding, glyphNames) {
// Lastly, merge in the differences.
var differences = properties.differences;
if (differences) {
- for (var charCode in differences) {
+ for (charCode in differences) {
var glyphName = differences[charCode];
- var glyphId = glyphNames.indexOf(glyphName);
+ glyphId = glyphNames.indexOf(glyphName);
if (glyphId >= 0) {
charCodeToGlyphId[charCode] = glyphId;
}
@@ -21558,6 +23395,7 @@ var Type1CharString = (function Type1CharStringClosure() {
convert: function Type1CharString_convert(encoded, subrs) {
var count = encoded.length;
var error = false;
+ var wx, sbx, subrNumber;
for (var i = 0; i < count; i++) {
var value = encoded[i];
if (value < 32) {
@@ -21615,7 +23453,7 @@ var Type1CharString = (function Type1CharStringClosure() {
error = true;
break;
}
- var subrNumber = this.stack.pop();
+ subrNumber = this.stack.pop();
error = this.convert(subrs[subrNumber], subrs);
break;
case 11: // return
@@ -21627,8 +23465,8 @@ var Type1CharString = (function Type1CharStringClosure() {
}
// To convert to type2 we have to move the width value to the
// first part of the charstring and then use hmoveto with lsb.
- var wx = this.stack.pop();
- var sbx = this.stack.pop();
+ wx = this.stack.pop();
+ sbx = this.stack.pop();
this.lsb = sbx;
this.width = wx;
this.stack.push(sbx);
@@ -21701,9 +23539,9 @@ var Type1CharString = (function Type1CharStringClosure() {
// (dx, dy). The height argument will not be used for vmtx and
// vhea tables reconstruction -- ignoring it.
var wy = this.stack.pop();
- var wx = this.stack.pop();
+ wx = this.stack.pop();
var sby = this.stack.pop();
- var sbx = this.stack.pop();
+ sbx = this.stack.pop();
this.lsb = sbx;
this.width = wx;
this.stack.push(sbx, sby);
@@ -21723,7 +23561,7 @@ var Type1CharString = (function Type1CharStringClosure() {
error = true;
break;
}
- var subrNumber = this.stack.pop();
+ subrNumber = this.stack.pop();
var numArgs = this.stack.pop();
if (subrNumber === 0 && numArgs === 3) {
var flexArgs = this.stack.splice(this.stack.length - 17, 17);
@@ -21804,7 +23642,7 @@ var Type1CharString = (function Type1CharStringClosure() {
if (keepStack) {
this.stack.splice(start, howManyArgs);
} else {
- this.stack = [];
+ this.stack.length = 0;
}
return false;
}
@@ -21830,18 +23668,46 @@ var Type1Parser = (function Type1ParserClosure() {
var EEXEC_ENCRYPT_KEY = 55665;
var CHAR_STRS_ENCRYPT_KEY = 4330;
- function decrypt(stream, key, discardNumber) {
- var r = key, c1 = 52845, c2 = 22719;
- var decryptedString = [];
+ function isHexDigit(code) {
+ return code >= 48 && code <= 57 || // '0'-'9'
+ code >= 65 && code <= 70 || // 'A'-'F'
+ code >= 97 && code <= 102; // 'a'-'f'
+ }
- var value = '';
- var count = stream.length;
+ function decrypt(data, key, discardNumber) {
+ var r = key | 0, c1 = 52845, c2 = 22719;
+ var count = data.length;
+ var decrypted = new Uint8Array(count);
for (var i = 0; i < count; i++) {
- value = stream[i];
- decryptedString[i] = value ^ (r >> 8);
+ var value = data[i];
+ decrypted[i] = value ^ (r >> 8);
r = ((value + r) * c1 + c2) & ((1 << 16) - 1);
}
- return decryptedString.slice(discardNumber);
+ return Array.prototype.slice.call(decrypted, discardNumber);
+ }
+
+ function decryptAscii(data, key, discardNumber) {
+ var r = key | 0, c1 = 52845, c2 = 22719;
+ var count = data.length, maybeLength = count >>> 1;
+ var decrypted = new Uint8Array(maybeLength);
+ var i, j;
+ for (i = 0, j = 0; i < count; i++) {
+ var digit1 = data[i];
+ if (!isHexDigit(digit1)) {
+ continue;
+ }
+ i++;
+ var digit2;
+ while (i < count && !isHexDigit(digit2 = data[i])) {
+ i++;
+ }
+ if (i < count) {
+ var value = parseInt(String.fromCharCode(digit1, digit2), 16);
+ decrypted[j++] = value ^ (r >> 8);
+ r = ((value + r) * c1 + c2) & ((1 << 16) - 1);
+ }
+ }
+ return Array.prototype.slice.call(decrypted, discardNumber, j);
}
function isSpecial(c) {
@@ -21853,7 +23719,11 @@ var Type1Parser = (function Type1ParserClosure() {
function Type1Parser(stream, encrypted) {
if (encrypted) {
- stream = new Stream(decrypt(stream.getBytes(), EEXEC_ENCRYPT_KEY, 4));
+ var data = stream.getBytes();
+ var isBinary = !(isHexDigit(data[0]) && isHexDigit(data[1]) &&
+ isHexDigit(data[2]) && isHexDigit(data[3]));
+ stream = new Stream(isBinary ? decrypt(data, EEXEC_ENCRYPT_KEY, 4) :
+ decryptAscii(data, EEXEC_ENCRYPT_KEY, 4));
}
this.stream = stream;
this.nextChar();
@@ -21945,7 +23815,7 @@ var Type1Parser = (function Type1ParserClosure() {
}
}
};
- var token;
+ var token, length, data, lenIV, encoded;
while ((token = this.getToken()) !== null) {
if (token !== '/') {
continue;
@@ -21969,12 +23839,11 @@ var Type1Parser = (function Type1ParserClosure() {
continue;
}
var glyph = this.getToken();
- var length = this.readInt();
+ length = this.readInt();
this.getToken(); // read in 'RD' or '-|'
- var data = stream.makeSubStream(stream.pos, length);
- var lenIV = program.properties.privateData['lenIV'];
- var encoded = decrypt(data.getBytes(), CHAR_STRS_ENCRYPT_KEY,
- lenIV);
+ data = stream.makeSubStream(stream.pos, length);
+ lenIV = program.properties.privateData['lenIV'];
+ encoded = decrypt(data.getBytes(), CHAR_STRS_ENCRYPT_KEY, lenIV);
// Skip past the required space and binary data.
stream.skip(length);
this.nextChar();
@@ -21993,12 +23862,11 @@ var Type1Parser = (function Type1ParserClosure() {
this.getToken(); // read in 'array'
while ((token = this.getToken()) === 'dup') {
var index = this.readInt();
- var length = this.readInt();
+ length = this.readInt();
this.getToken(); // read in 'RD' or '-|'
- var data = stream.makeSubStream(stream.pos, length);
- var lenIV = program.properties.privateData['lenIV'];
- var encoded = decrypt(data.getBytes(), CHAR_STRS_ENCRYPT_KEY,
- lenIV);
+ data = stream.makeSubStream(stream.pos, length);
+ lenIV = program.properties.privateData['lenIV'];
+ encoded = decrypt(data.getBytes(), CHAR_STRS_ENCRYPT_KEY, lenIV);
// Skip past the required space and binary data.
stream.skip(length);
this.nextChar();
@@ -22045,8 +23913,8 @@ var Type1Parser = (function Type1ParserClosure() {
}
for (var i = 0; i < charstrings.length; i++) {
- var glyph = charstrings[i].glyph;
- var encoded = charstrings[i].encoded;
+ glyph = charstrings[i].glyph;
+ encoded = charstrings[i].encoded;
var charString = new Type1CharString();
var error = charString.convert(encoded, subrs);
var output = charString.output;
@@ -22092,7 +23960,7 @@ var Type1Parser = (function Type1ParserClosure() {
this.getToken(); // read in 'array'
for (var j = 0; j < size; j++) {
- var token = this.getToken();
+ token = this.getToken();
// skipping till first dup or def (e.g. ignoring for statement)
while (token !== 'dup' && token !== 'def') {
token = this.getToken();
@@ -22230,8 +24098,9 @@ var Type1Font = function Type1Font(name, file, properties) {
var eexecBlock = new Stream(file.getBytes(eexecBlockLength));
var eexecBlockParser = new Type1Parser(eexecBlock, true);
var data = eexecBlockParser.extractFontProgram();
- for (var info in data.properties)
+ for (var info in data.properties) {
properties[info] = data.properties[info];
+ }
var charstrings = data.charstrings;
var type2Charstrings = this.getType2Charstrings(charstrings);
@@ -22245,7 +24114,7 @@ var Type1Font = function Type1Font(name, file, properties) {
Type1Font.prototype = {
get numGlyphs() {
- return this.charstrings.length;
+ return this.charstrings.length + 1;
},
getCharset: function Type1Font_getCharset() {
@@ -22259,15 +24128,15 @@ Type1Font.prototype = {
getGlyphMapping: function Type1Font_getGlyphMapping(properties) {
var charstrings = this.charstrings;
- var glyphNames = ['.notdef'];
- for (var glyphId = 0; glyphId < charstrings.length; glyphId++) {
+ var glyphNames = ['.notdef'], glyphId;
+ for (glyphId = 0; glyphId < charstrings.length; glyphId++) {
glyphNames.push(charstrings[glyphId].glyphName);
}
var encoding = properties.builtInEncoding;
if (encoding) {
var builtInEncoding = {};
for (var charCode in encoding) {
- var glyphId = glyphNames.indexOf(encoding[charCode]);
+ glyphId = glyphNames.indexOf(encoding[charCode]);
if (glyphId >= 0) {
builtInEncoding[charCode] = glyphId;
}
@@ -22302,19 +24171,22 @@ Type1Font.prototype = {
getType2Subrs: function Type1Font_getType2Subrs(type1Subrs) {
var bias = 0;
var count = type1Subrs.length;
- if (count < 1133)
+ if (count < 1133) {
bias = 107;
- else if (count < 33769)
+ } else if (count < 33769) {
bias = 1131;
- else
+ } else {
bias = 32768;
+ }
// Add a bunch of empty subrs to deal with the Type2 bias
var type2Subrs = [];
- for (var i = 0; i < bias; i++)
+ var i;
+ for (i = 0; i < bias; i++) {
type2Subrs.push([0x0B]);
+ }
- for (var i = 0; i < count; i++) {
+ for (i = 0; i < count; i++) {
type2Subrs.push(type1Subrs[i]);
}
@@ -22355,22 +24227,23 @@ Type1Font.prototype = {
var count = glyphs.length;
var charsetArray = [0];
- for (var i = 0; i < count; i++) {
+ var i, ii;
+ for (i = 0; i < count; i++) {
var index = CFFStandardStrings.indexOf(charstrings[i].glyphName);
// TODO: Insert the string and correctly map it. Previously it was
// thought mapping names that aren't in the standard strings to .notdef
// was fine, however in issue818 when mapping them all to .notdef the
// adieresis glyph no longer worked.
- if (index == -1)
+ if (index == -1) {
index = 0;
-
+ }
charsetArray.push((index >> 8) & 0xff, index & 0xff);
}
cff.charset = new CFFCharset(false, 0, [], charsetArray);
var charStringsIndex = new CFFIndex();
charStringsIndex.add([0x8B, 0x0E]); // .notdef
- for (var i = 0; i < count; i++) {
+ for (i = 0; i < count; i++) {
charStringsIndex.add(glyphs[i]);
}
cff.charStrings = charStringsIndex;
@@ -22393,10 +24266,11 @@ Type1Font.prototype = {
'StdHW',
'StdVW'
];
- for (var i = 0, ii = fields.length; i < ii; i++) {
+ for (i = 0, ii = fields.length; i < ii; i++) {
var field = fields[i];
- if (!properties.privateData.hasOwnProperty(field))
+ if (!properties.privateData.hasOwnProperty(field)) {
continue;
+ }
var value = properties.privateData[field];
if (isArray(value)) {
// All of the private dictionary array data in CFF must be stored as
@@ -22410,7 +24284,7 @@ Type1Font.prototype = {
cff.topDict.privateDict = privateDict;
var subrIndex = new CFFIndex();
- for (var i = 0, ii = subrs.length; i < ii; i++) {
+ for (i = 0, ii = subrs.length; i < ii; i++) {
subrIndex.add(subrs[i]);
}
privateDict.subrsIndex = subrIndex;
@@ -22447,22 +24321,25 @@ var CFFFont = (function CFFFontClosure() {
},
getGlyphMapping: function CFFFont_getGlyphMapping() {
var cff = this.cff;
+ var properties = this.properties;
var charsets = cff.charset.charset;
- var charCodeToGlyphId = Object.create(null);
+ var charCodeToGlyphId;
+ var glyphId;
- if (this.properties.composite) {
- if (this.cff.isCIDFont) {
+ if (properties.composite) {
+ charCodeToGlyphId = Object.create(null);
+ if (cff.isCIDFont) {
// If the font is actually a CID font then we should use the charset
// to map CIDs to GIDs.
- for (var glyphId = 0; glyphId < charsets.length; glyphId++) {
+ for (glyphId = 0; glyphId < charsets.length; glyphId++) {
var cidString = String.fromCharCode(charsets[glyphId]);
- var charCode = this.properties.cMap.map.indexOf(cidString);
+ var charCode = properties.cMap.map.indexOf(cidString);
charCodeToGlyphId[charCode] = glyphId;
}
} else {
// If it is NOT actually a CID font then CIDs should be mapped
// directly to GIDs.
- for (var glyphId = 0; glyphId < cff.charStrings.count; glyphId++) {
+ for (glyphId = 0; glyphId < cff.charStrings.count; glyphId++) {
charCodeToGlyphId[glyphId] = glyphId;
}
}
@@ -22470,7 +24347,8 @@ var CFFFont = (function CFFFontClosure() {
}
var encoding = cff.encoding ? cff.encoding.encoding : null;
- return type1FontGlyphMapping(this.properties, encoding, charsets);
+ charCodeToGlyphId = type1FontGlyphMapping(properties, encoding, charsets);
+ return charCodeToGlyphId;
}
};
@@ -22652,12 +24530,17 @@ var CFFParser = (function CFFParserClosure() {
},
parseHeader: function CFFParser_parseHeader() {
var bytes = this.bytes;
+ var bytesLength = bytes.length;
var offset = 0;
- while (bytes[offset] != 1)
+ // Prevent an infinite loop, by checking that the offset is within the
+ // bounds of the bytes array. Necessary in empty, or invalid, font files.
+ while (offset < bytesLength && bytes[offset] !== 1) {
++offset;
-
- if (offset !== 0) {
+ }
+ if (offset >= bytesLength) {
+ error('Invalid CFF header');
+ } else if (offset !== 0) {
info('cff data is shifted');
bytes = bytes.subarray(offset);
this.bytes = bytes;
@@ -22667,7 +24550,7 @@ var CFFParser = (function CFFParserClosure() {
var hdrSize = bytes[2];
var offSize = bytes[3];
var header = new CFFHeader(major, minor, hdrSize, offSize);
- return {obj: header, endPos: hdrSize};
+ return { obj: header, endPos: hdrSize };
},
parseDict: function CFFParser_parseDict(dict) {
var pos = 0;
@@ -22709,12 +24592,14 @@ var CFFParser = (function CFFParserClosure() {
var b1 = b >> 4;
var b2 = b & 15;
- if (b1 == eof)
+ if (b1 == eof) {
break;
+ }
str += lookup[b1];
- if (b2 == eof)
+ if (b2 == eof) {
break;
+ }
str += lookup[b2];
}
return parseFloat(str);
@@ -22723,13 +24608,14 @@ var CFFParser = (function CFFParserClosure() {
var operands = [];
var entries = [];
- var pos = 0;
+ pos = 0;
var end = dict.length;
while (pos < end) {
var b = dict[pos];
if (b <= 21) {
- if (b === 12)
+ if (b === 12) {
b = (b << 8) | dict[++pos];
+ }
entries.push([b, operands]);
operands = [];
++pos;
@@ -22744,15 +24630,15 @@ var CFFParser = (function CFFParserClosure() {
var bytes = this.bytes;
var count = (bytes[pos++] << 8) | bytes[pos++];
var offsets = [];
- var start = pos;
var end = pos;
+ var i, ii;
if (count !== 0) {
var offsetSize = bytes[pos++];
// add 1 for offset to determine size of last object
var startPos = pos + ((count + 1) * offsetSize) - 1;
- for (var i = 0, ii = count + 1; i < ii; ++i) {
+ for (i = 0, ii = count + 1; i < ii; ++i) {
var offset = 0;
for (var j = 0; j < offsetSize; ++j) {
offset <<= 8;
@@ -22762,7 +24648,7 @@ var CFFParser = (function CFFParserClosure() {
}
end = offsets[count];
}
- for (var i = 0, ii = offsets.length - 1; i < ii; ++i) {
+ for (i = 0, ii = offsets.length - 1; i < ii; ++i) {
var offsetStart = offsets[i];
var offsetEnd = offsets[i + 1];
cffIndex.add(bytes.subarray(offsetStart, offsetEnd));
@@ -22786,13 +24672,13 @@ var CFFParser = (function CFFParserClosure() {
if ((c < 33 || c > 126) || c === 91 /* [ */ || c === 93 /* ] */ ||
c === 40 /* ( */ || c === 41 /* ) */ || c === 123 /* { */ ||
c === 125 /* } */ || c === 60 /* < */ || c === 62 /* > */ ||
- c === 47 /* / */ || c === 37 /* % */) {
+ c === 47 /* / */ || c === 37 /* % */ || c === 35 /* # */) {
data[j] = 95;
continue;
}
data[j] = c;
}
- names.push(String.fromCharCode.apply(null, data));
+ names.push(bytesToString(data));
}
return names;
},
@@ -22800,14 +24686,12 @@ var CFFParser = (function CFFParserClosure() {
var strings = new CFFStrings();
for (var i = 0, ii = index.count; i < ii; ++i) {
var data = index.get(i);
- strings.add(String.fromCharCode.apply(null, data));
+ strings.add(bytesToString(data));
}
return strings;
},
createDict: function CFFParser_createDict(Type, dict, strings) {
var cffDict = new Type(strings);
- var types = cffDict.types;
-
for (var i = 0, ii = dict.length; i < ii; ++i) {
var pair = dict[i];
var key = pair[0];
@@ -22863,14 +24747,14 @@ var CFFParser = (function CFFParserClosure() {
stack[stackSize] = value - 139;
stackSize++;
} else if (value >= 247 && value <= 254) { // number (+1 bytes)
- stack[stackSize] = value < 251 ?
- ((value - 247) << 8) + data[j] + 108 :
- -((value - 251) << 8) - data[j] - 108;
+ stack[stackSize] = (value < 251 ?
+ ((value - 247) << 8) + data[j] + 108 :
+ -((value - 251) << 8) - data[j] - 108);
j++;
stackSize++;
} else if (value == 255) { // number (32 bit)
stack[stackSize] = ((data[j] << 24) | (data[j + 1] << 16) |
- (data[j + 2] << 8) | data[j + 3]) / 65536;
+ (data[j + 2] << 8) | data[j + 3]) / 65536;
j += 4;
stackSize++;
} else if (value == 19 || value == 20) {
@@ -22949,8 +24833,9 @@ var CFFParser = (function CFFParserClosure() {
parentDict.privateDict = privateDict;
// Parse the Subrs index also since it's relative to the private dict.
- if (!privateDict.getByName('Subrs'))
+ if (!privateDict.getByName('Subrs')) {
return;
+ }
var subrsOffset = privateDict.getByName('Subrs');
var relativeOffset = offset + subrsOffset;
// Validate the offset.
@@ -22977,31 +24862,34 @@ var CFFParser = (function CFFParserClosure() {
var start = pos;
var format = bytes[pos++];
var charset = ['.notdef'];
+ var id, count, i;
// subtract 1 for the .notdef glyph
length -= 1;
switch (format) {
case 0:
- for (var i = 0; i < length; i++) {
- var id = (bytes[pos++] << 8) | bytes[pos++];
+ for (i = 0; i < length; i++) {
+ id = (bytes[pos++] << 8) | bytes[pos++];
charset.push(cid ? id : strings.get(id));
}
break;
case 1:
while (charset.length <= length) {
- var id = (bytes[pos++] << 8) | bytes[pos++];
- var count = bytes[pos++];
- for (var i = 0; i <= count; i++)
+ id = (bytes[pos++] << 8) | bytes[pos++];
+ count = bytes[pos++];
+ for (i = 0; i <= count; i++) {
charset.push(cid ? id++ : strings.get(id++));
+ }
}
break;
case 2:
while (charset.length <= length) {
- var id = (bytes[pos++] << 8) | bytes[pos++];
- var count = (bytes[pos++] << 8) | bytes[pos++];
- for (var i = 0; i <= count; i++)
+ id = (bytes[pos++] << 8) | bytes[pos++];
+ count = (bytes[pos++] << 8) | bytes[pos++];
+ for (i = 0; i <= count; i++) {
charset.push(cid ? id++ : strings.get(id++));
+ }
}
break;
default:
@@ -23021,12 +24909,12 @@ var CFFParser = (function CFFParserClosure() {
var bytes = this.bytes;
var predefined = false;
var hasSupplement = false;
- var format;
+ var format, i, ii;
var raw = null;
function readSupplement() {
var supplementsCount = bytes[pos++];
- for (var i = 0; i < supplementsCount; i++) {
+ for (i = 0; i < supplementsCount; i++) {
var code = bytes[pos++];
var sid = (bytes[pos++] << 8) + (bytes[pos++] & 0xff);
encoding[code] = charset.indexOf(strings.get(sid));
@@ -23038,7 +24926,7 @@ var CFFParser = (function CFFParserClosure() {
format = pos;
var baseEncoding = pos ? Encodings.ExpertEncoding :
Encodings.StandardEncoding;
- for (var i = 0, ii = charset.length; i < ii; i++) {
+ for (i = 0, ii = charset.length; i < ii; i++) {
var index = baseEncoding.indexOf(charset[i]);
if (index != -1) {
encoding[index] = i;
@@ -23046,22 +24934,24 @@ var CFFParser = (function CFFParserClosure() {
}
} else {
var dataStart = pos;
- var format = bytes[pos++];
+ format = bytes[pos++];
switch (format & 0x7f) {
case 0:
var glyphsCount = bytes[pos++];
- for (var i = 1; i <= glyphsCount; i++)
+ for (i = 1; i <= glyphsCount; i++) {
encoding[bytes[pos++]] = i;
+ }
break;
case 1:
var rangesCount = bytes[pos++];
var gid = 1;
- for (var i = 0; i < rangesCount; i++) {
+ for (i = 0; i < rangesCount; i++) {
var start = bytes[pos++];
var left = bytes[pos++];
- for (var j = start; j <= start + left; j++)
+ for (var j = start; j <= start + left; j++) {
encoding[j] = gid++;
+ }
}
break;
@@ -23090,21 +24980,24 @@ var CFFParser = (function CFFParserClosure() {
var bytes = this.bytes;
var format = bytes[pos++];
var fdSelect = [];
+ var i;
+
switch (format) {
case 0:
- for (var i = 0; i < length; ++i) {
+ for (i = 0; i < length; ++i) {
var id = bytes[pos++];
fdSelect.push(id);
}
break;
case 3:
var rangesCount = (bytes[pos++] << 8) | bytes[pos++];
- for (var i = 0; i < rangesCount; ++i) {
+ for (i = 0; i < rangesCount; ++i) {
var first = (bytes[pos++] << 8) | bytes[pos++];
var fdIndex = bytes[pos++];
var next = (bytes[pos] << 8) | bytes[pos + 1];
- for (var j = first; j < next; ++j)
+ for (var j = first; j < next; ++j) {
fdSelect.push(fdIndex);
+ }
}
// Advance past the sentinel(next).
pos += 2;
@@ -23158,10 +25051,12 @@ var CFFStrings = (function CFFStringsClosure() {
}
CFFStrings.prototype = {
get: function CFFStrings_get(index) {
- if (index >= 0 && index <= 390)
+ if (index >= 0 && index <= 390) {
return CFFStandardStrings[index];
- if (index - 391 <= this.strings.length)
+ }
+ if (index - 391 <= this.strings.length) {
return this.strings[index - 391];
+ }
return CFFStandardStrings[0];
},
add: function CFFStrings_add(value) {
@@ -23212,15 +25107,18 @@ var CFFDict = (function CFFDictClosure() {
CFFDict.prototype = {
// value should always be an array
setByKey: function CFFDict_setByKey(key, value) {
- if (!(key in this.keyToNameMap))
+ if (!(key in this.keyToNameMap)) {
return false;
+ }
// ignore empty values
- if (value.length === 0)
+ if (value.length === 0) {
return true;
+ }
var type = this.types[key];
// remove the array wrapping these types of values
- if (type === 'num' || type === 'sid' || type === 'offset')
+ if (type === 'num' || type === 'sid' || type === 'offset') {
value = value[0];
+ }
this.values[key] = value;
return true;
},
@@ -23234,11 +25132,13 @@ var CFFDict = (function CFFDictClosure() {
return this.nameToKeyMap[name] in this.values;
},
getByName: function CFFDict_getByName(name) {
- if (!(name in this.nameToKeyMap))
+ if (!(name in this.nameToKeyMap)) {
error('Invalid dictionary name "' + name + '"');
+ }
var key = this.nameToKeyMap[name];
- if (!(key in this.values))
+ if (!(key in this.values)) {
return this.defaults[key];
+ }
return this.values[key];
},
removeByName: function CFFDict_removeByName(name) {
@@ -23311,8 +25211,9 @@ var CFFTopDict = (function CFFTopDictClosure() {
];
var tables = null;
function CFFTopDict(strings) {
- if (tables === null)
+ if (tables === null) {
tables = CFFDict.createTables(layout);
+ }
CFFDict.call(this, tables, strings);
this.privateDict = null;
}
@@ -23343,8 +25244,9 @@ var CFFPrivateDict = (function CFFPrivateDictClosure() {
];
var tables = null;
function CFFPrivateDict(strings) {
- if (tables === null)
+ if (tables === null) {
tables = CFFDict.createTables(layout);
+ }
CFFDict.call(this, tables, strings);
this.subrsIndex = null;
}
@@ -23357,11 +25259,6 @@ var CFFCharsetPredefinedTypes = {
EXPERT: 1,
EXPERT_SUBSET: 2
};
-var CFFCharsetEmbeddedTypes = {
- FORMAT0: 0,
- FORMAT1: 1,
- FORMAT2: 2
-};
var CFFCharset = (function CFFCharsetClosure() {
function CFFCharset(predefined, format, charset, raw) {
this.predefined = predefined;
@@ -23372,14 +25269,6 @@ var CFFCharset = (function CFFCharsetClosure() {
return CFFCharset;
})();
-var CFFEncodingPredefinedTypes = {
- STANDARD: 0,
- EXPERT: 1
-};
-var CFFCharsetEmbeddedTypes = {
- FORMAT0: 0,
- FORMAT1: 1
-};
var CFFEncoding = (function CFFEncodingClosure() {
function CFFEncoding(predefined, format, encoding, raw) {
this.predefined = predefined;
@@ -23409,8 +25298,9 @@ var CFFOffsetTracker = (function CFFOffsetTrackerClosure() {
return key in this.offsets;
},
track: function CFFOffsetTracker_track(key, location) {
- if (key in this.offsets)
+ if (key in this.offsets) {
error('Already tracking location of ' + key);
+ }
this.offsets[key] = location;
},
offset: function CFFOffsetTracker_offset(value) {
@@ -23421,8 +25311,9 @@ var CFFOffsetTracker = (function CFFOffsetTrackerClosure() {
setEntryLocation: function CFFOffsetTracker_setEntryLocation(key,
values,
output) {
- if (!(key in this.offsets))
+ if (!(key in this.offsets)) {
error('Not tracking location of ' + key);
+ }
var data = output.data;
var dataOffset = this.offsets[key];
var size = 5;
@@ -23434,8 +25325,9 @@ var CFFOffsetTracker = (function CFFOffsetTrackerClosure() {
var offset4 = offset0 + 4;
// It's easy to screw up offsets so perform this sanity check.
if (data[offset0] !== 0x1d || data[offset1] !== 0 ||
- data[offset2] !== 0 || data[offset3] !== 0 || data[offset4] !== 0)
+ data[offset2] !== 0 || data[offset3] !== 0 || data[offset4] !== 0) {
error('writing to an offset that is not empty');
+ }
var value = values[i];
data[offset0] = 0x1d;
data[offset1] = (value >> 24) & 0xFF;
@@ -23450,13 +25342,6 @@ var CFFOffsetTracker = (function CFFOffsetTrackerClosure() {
// Takes a CFF and converts it to the binary representation.
var CFFCompiler = (function CFFCompilerClosure() {
- function stringToArray(str) {
- var array = [];
- for (var i = 0, ii = str.length; i < ii; ++i)
- array[i] = str.charCodeAt(i);
-
- return array;
- }
function CFFCompiler(cff) {
this.cff = cff;
}
@@ -23553,7 +25438,7 @@ var CFFCompiler = (function CFFCompilerClosure() {
output.add(fdSelect);
// It is unclear if the sub font dictionary can have CID related
// dictionary keys, but the sanitizer doesn't like them so remove them.
- var compiled = this.compileTopDicts(cff.fdArray, output.length, true);
+ compiled = this.compileTopDicts(cff.fdArray, output.length, true);
topDictTracker.setEntryLocation('FDArray', [output.length], output);
output.add(compiled.output);
var fontDictTrackers = compiled.trackers;
@@ -23570,10 +25455,11 @@ var CFFCompiler = (function CFFCompilerClosure() {
return output.data;
},
encodeNumber: function CFFCompiler_encodeNumber(value) {
- if (parseFloat(value) == parseInt(value, 10) && !isNaN(value)) // isInt
+ if (parseFloat(value) == parseInt(value, 10) && !isNaN(value)) { // isInt
return this.encodeInteger(value);
- else
+ } else {
return this.encodeFloat(value);
+ }
},
encodeFloat: function CFFCompiler_encodeFloat(num) {
var value = num.toString();
@@ -23586,7 +25472,8 @@ var CFFCompiler = (function CFFCompilerClosure() {
}
var nibbles = '';
- for (var i = 0, ii = value.length; i < ii; ++i) {
+ var i, ii;
+ for (i = 0, ii = value.length; i < ii; ++i) {
var a = value[i];
if (a === 'e') {
nibbles += value[++i] === '-' ? 'c' : 'b';
@@ -23600,7 +25487,7 @@ var CFFCompiler = (function CFFCompilerClosure() {
}
nibbles += (nibbles.length & 1) ? 'f' : 'ff';
var out = [30];
- for (var i = 0, ii = nibbles.length; i < ii; i += 2) {
+ for (i = 0, ii = nibbles.length; i < ii; i += 2) {
out.push(parseInt(nibbles.substr(i, 2), 16));
}
return out;
@@ -23636,8 +25523,9 @@ var CFFCompiler = (function CFFCompilerClosure() {
},
compileNameIndex: function CFFCompiler_compileNameIndex(names) {
var nameIndex = new CFFIndex();
- for (var i = 0, ii = names.length; i < ii; ++i)
+ for (var i = 0, ii = names.length; i < ii; ++i) {
nameIndex.add(stringToArray(names[i]));
+ }
return this.compileIndex(nameIndex);
},
compileTopDicts: function CFFCompiler_compileTopDicts(dicts,
@@ -23705,16 +25593,22 @@ var CFFCompiler = (function CFFCompilerClosure() {
var order = dict.order;
for (var i = 0; i < order.length; ++i) {
var key = order[i];
- if (!(key in dict.values))
+ if (!(key in dict.values)) {
continue;
+ }
var values = dict.values[key];
var types = dict.types[key];
- if (!isArray(types)) types = [types];
- if (!isArray(values)) values = [values];
+ if (!isArray(types)) {
+ types = [types];
+ }
+ if (!isArray(values)) {
+ values = [values];
+ }
// Remove any empty dict values.
- if (values.length === 0)
+ if (values.length === 0) {
continue;
+ }
for (var j = 0, jj = types.length; j < jj; ++j) {
var type = types[j];
@@ -23731,15 +25625,17 @@ var CFFCompiler = (function CFFCompilerClosure() {
var name = dict.keyToNameMap[key];
// Some offsets have the offset and the length, so just record the
// position of the first one.
- if (!offsetTracker.isTracking(name))
+ if (!offsetTracker.isTracking(name)) {
offsetTracker.track(name, out.length);
+ }
out = out.concat([0x1d, 0, 0, 0, 0]);
break;
case 'array':
case 'delta':
out = out.concat(this.encodeNumber(value));
- for (var k = 1, kk = values.length; k < kk; ++k)
+ for (var k = 1, kk = values.length; k < kk; ++k) {
out = out.concat(this.encodeNumber(values[k]));
+ }
break;
default:
error('Unknown data type of ' + type);
@@ -23752,8 +25648,9 @@ var CFFCompiler = (function CFFCompilerClosure() {
},
compileStringIndex: function CFFCompiler_compileStringIndex(strings) {
var stringIndex = new CFFIndex();
- for (var i = 0, ii = strings.length; i < ii; ++i)
+ for (var i = 0, ii = strings.length; i < ii; ++i) {
stringIndex.add(stringToArray(strings[i]));
+ }
return this.compileIndex(stringIndex);
},
compileGlobalSubrIndex: function CFFCompiler_compileGlobalSubrIndex() {
@@ -23774,8 +25671,9 @@ var CFFCompiler = (function CFFCompilerClosure() {
},
compileTypedArray: function CFFCompiler_compileTypedArray(data) {
var out = [];
- for (var i = 0, ii = data.length; i < ii; ++i)
+ for (var i = 0, ii = data.length; i < ii; ++i) {
out[i] = data[i];
+ }
return out;
},
compileIndex: function CFFCompiler_compileIndex(index, trackers) {
@@ -23786,31 +25684,34 @@ var CFFCompiler = (function CFFCompilerClosure() {
// If there is no object, just create an index. This technically
// should just be [0, 0] but OTS has an issue with that.
- if (count === 0)
+ if (count === 0) {
return [0, 0, 0];
+ }
var data = [(count >> 8) & 0xFF, count & 0xff];
- var lastOffset = 1;
- for (var i = 0; i < count; ++i)
+ var lastOffset = 1, i;
+ for (i = 0; i < count; ++i) {
lastOffset += objects[i].length;
+ }
var offsetSize;
- if (lastOffset < 0x100)
+ if (lastOffset < 0x100) {
offsetSize = 1;
- else if (lastOffset < 0x10000)
+ } else if (lastOffset < 0x10000) {
offsetSize = 2;
- else if (lastOffset < 0x1000000)
+ } else if (lastOffset < 0x1000000) {
offsetSize = 3;
- else
+ } else {
offsetSize = 4;
+ }
// Next byte contains the offset size use to reference object in the file
data.push(offsetSize);
// Add another offset after this one because we need a new offset
var relativeOffset = 1;
- for (var i = 0; i < count + 1; i++) {
+ for (i = 0; i < count + 1; i++) {
if (offsetSize === 1) {
data.push(relativeOffset & 0xFF);
} else if (offsetSize === 2) {
@@ -23827,17 +25728,19 @@ var CFFCompiler = (function CFFCompilerClosure() {
relativeOffset & 0xFF);
}
- if (objects[i])
+ if (objects[i]) {
relativeOffset += objects[i].length;
+ }
}
- var offset = data.length;
- for (var i = 0; i < count; i++) {
+ for (i = 0; i < count; i++) {
// Notify the tracker where the object will be offset in the data.
- if (trackers[i])
+ if (trackers[i]) {
trackers[i].offset(data.length);
- for (var j = 0, jj = objects[i].length; j < jj; j++)
+ }
+ for (var j = 0, jj = objects[i].length; j < jj; j++) {
data.push(objects[i][j]);
+ }
}
return data;
}
@@ -23873,25 +25776,26 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
}
function parseCmap(data, start, end) {
- var offset = getUshort(data, start + 2) === 1 ? getLong(data, start + 8) :
- getLong(data, start + 16);
+ var offset = (getUshort(data, start + 2) === 1 ?
+ getLong(data, start + 8) : getLong(data, start + 16));
var format = getUshort(data, start + offset);
+ var length, ranges, p, i;
if (format === 4) {
- var length = getUshort(data, start + offset + 2);
+ length = getUshort(data, start + offset + 2);
var segCount = getUshort(data, start + offset + 6) >> 1;
- var p = start + offset + 14;
- var ranges = [];
- for (var i = 0; i < segCount; i++, p += 2) {
+ p = start + offset + 14;
+ ranges = [];
+ for (i = 0; i < segCount; i++, p += 2) {
ranges[i] = {end: getUshort(data, p)};
}
p += 2;
- for (var i = 0; i < segCount; i++, p += 2) {
+ for (i = 0; i < segCount; i++, p += 2) {
ranges[i].start = getUshort(data, p);
}
- for (var i = 0; i < segCount; i++, p += 2) {
+ for (i = 0; i < segCount; i++, p += 2) {
ranges[i].idDelta = getUshort(data, p);
}
- for (var i = 0; i < segCount; i++, p += 2) {
+ for (i = 0; i < segCount; i++, p += 2) {
var idOffset = getUshort(data, p);
if (idOffset === 0) {
continue;
@@ -23904,11 +25808,11 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
}
return ranges;
} else if (format === 12) {
- var length = getLong(data, start + offset + 4);
+ length = getLong(data, start + offset + 4);
var groups = getLong(data, start + offset + 12);
- var p = start + offset + 16;
- var ranges = [];
- for (var i = 0; i < groups; i++) {
+ p = start + offset + 16;
+ ranges = [];
+ for (i = 0; i < groups; i++) {
ranges.push({
start: getLong(data, p),
end: getLong(data, p + 4),
@@ -23923,13 +25827,13 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
function parseCff(data, start, end) {
var properties = {};
- var parser = new CFFParser(
- new Stream(data, start, end - start), properties);
+ var parser = new CFFParser(new Stream(data, start, end - start),
+ properties);
var cff = parser.parse();
return {
glyphs: cff.charStrings.objects,
- subrs: cff.topDict.privateDict && cff.topDict.privateDict.subrsIndex &&
- cff.topDict.privateDict.subrsIndex.objects,
+ subrs: (cff.topDict.privateDict && cff.topDict.privateDict.subrsIndex &&
+ cff.topDict.privateDict.subrsIndex.objects),
gsubrs: cff.globalSubrIndex && cff.globalSubrIndex.objects
};
}
@@ -23990,16 +25894,13 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
var i = 0;
var numberOfContours = ((code[i] << 24) | (code[i + 1] << 16)) >> 16;
- var xMin = ((code[i + 2] << 24) | (code[i + 3] << 16)) >> 16;
- var yMin = ((code[i + 4] << 24) | (code[i + 5] << 16)) >> 16;
- var xMax = ((code[i + 6] << 24) | (code[i + 7] << 16)) >> 16;
- var yMax = ((code[i + 8] << 24) | (code[i + 9] << 16)) >> 16;
+ var flags;
+ var x = 0, y = 0;
i += 10;
if (numberOfContours < 0) {
// composite glyph
- var x = 0, y = 0;
do {
- var flags = (code[i] << 8) | code[i + 1];
+ flags = (code[i] << 8) | code[i + 1];
var glyphIndex = (code[i + 2] << 8) | code[i + 3];
i += 4;
var arg1, arg2;
@@ -24044,7 +25945,8 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
} else {
// simple glyph
var endPtsOfContours = [];
- for (var j = 0; j < numberOfContours; j++) {
+ var j, jj;
+ for (j = 0; j < numberOfContours; j++) {
endPtsOfContours.push((code[i] << 8) | code[i + 1]);
i += 2;
}
@@ -24053,7 +25955,8 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
var numberOfPoints = endPtsOfContours[endPtsOfContours.length - 1] + 1;
var points = [];
while (points.length < numberOfPoints) {
- var flags = code[i++], repeat = 1;
+ flags = code[i++];
+ var repeat = 1;
if ((flags & 0x08)) {
repeat += code[i++];
}
@@ -24061,8 +25964,7 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
points.push({flags: flags});
}
}
- var x = 0, y = 0;
- for (var j = 0; j < numberOfPoints; j++) {
+ for (j = 0; j < numberOfPoints; j++) {
switch (points[j].flags & 0x12) {
case 0x00:
x += ((code[i] << 24) | (code[i + 1] << 16)) >> 16;
@@ -24077,7 +25979,7 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
}
points[j].x = x;
}
- for (var j = 0; j < numberOfPoints; j++) {
+ for (j = 0; j < numberOfPoints; j++) {
switch (points[j].flags & 0x24) {
case 0x00:
y += ((code[i] << 24) | (code[i + 1] << 16)) >> 16;
@@ -24094,7 +25996,7 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
}
var startPoint = 0;
- for (var i = 0; i < numberOfContours; i++) {
+ for (i = 0; i < numberOfContours; i++) {
var endPoint = endPtsOfContours[i];
// contours might have implicit points, which is located in the middle
// between two neighboring off-curve points
@@ -24115,7 +26017,7 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
contour.push(p);
}
moveTo(contour[0].x, contour[0].y);
- for (var j = 1, jj = contour.length; j < jj; j++) {
+ for (j = 1, jj = contour.length; j < jj; j++) {
if ((contour[j].flags & 1)) {
lineTo(contour[j].x, contour[j].y);
} else if ((contour[j + 1].flags & 1)){
@@ -24154,6 +26056,7 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
while (i < code.length) {
var stackClean = false;
var v = code[i++];
+ var xa, xb, ya, yb, y1, y2, y3, n, subrCode;
switch (v) {
case 1: // hstem
stems += stack.length >> 1;
@@ -24199,15 +26102,15 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
break;
case 8: // rrcurveto
while (stack.length > 0) {
- var xa = x + stack.shift(), ya = y + stack.shift();
- var xb = xa + stack.shift(), yb = ya + stack.shift();
+ xa = x + stack.shift(); ya = y + stack.shift();
+ xb = xa + stack.shift(); yb = ya + stack.shift();
x = xb + stack.shift(); y = yb + stack.shift();
bezierCurveTo(xa, ya, xb, yb, x, y);
}
break;
case 10: // callsubr
- var n = stack.pop() + font.subrsBias;
- var subrCode = font.subrs[n];
+ n = stack.pop() + font.subrsBias;
+ subrCode = font.subrs[n];
if (subrCode) {
parse(subrCode);
}
@@ -24218,49 +26121,50 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
v = code[i++];
switch (v) {
case 34: // flex
- var xa = x + stack.shift();
- var xb = xa + stack.shift(), y1 = y + stack.shift();
+ xa = x + stack.shift();
+ xb = xa + stack.shift(); y1 = y + stack.shift();
x = xb + stack.shift();
bezierCurveTo(xa, y, xb, y1, x, y1);
- var xa = x + stack.shift();
- var xb = xa + stack.shift();
+ xa = x + stack.shift();
+ xb = xa + stack.shift();
x = xb + stack.shift();
bezierCurveTo(xa, y1, xb, y, x, y);
break;
case 35: // flex
- var xa = x + stack.shift(), ya = y + stack.shift();
- var xb = xa + stack.shift(), yb = ya + stack.shift();
+ xa = x + stack.shift(); ya = y + stack.shift();
+ xb = xa + stack.shift(); yb = ya + stack.shift();
x = xb + stack.shift(); y = yb + stack.shift();
bezierCurveTo(xa, ya, xb, yb, x, y);
- var xa = x + stack.shift(), ya = y + stack.shift();
- var xb = xa + stack.shift(), yb = ya + stack.shift();
+ xa = x + stack.shift(); ya = y + stack.shift();
+ xb = xa + stack.shift(); yb = ya + stack.shift();
x = xb + stack.shift(); y = yb + stack.shift();
bezierCurveTo(xa, ya, xb, yb, x, y);
stack.pop(); // fd
break;
case 36: // hflex1
- var xa = x + stack.shift(), y1 = y + stack.shift();
- var xb = xa + stack.shift(), y2 = y1 + stack.shift();
+ xa = x + stack.shift(); y1 = y + stack.shift();
+ xb = xa + stack.shift(); y2 = y1 + stack.shift();
x = xb + stack.shift();
bezierCurveTo(xa, y1, xb, y2, x, y2);
- var xa = x + stack.shift();
- var xb = xa + stack.shift(), y3 = y2 + stack.shift();
+ xa = x + stack.shift();
+ xb = xa + stack.shift(); y3 = y2 + stack.shift();
x = xb + stack.shift();
bezierCurveTo(xa, y2, xb, y3, x, y);
break;
case 37: // flex1
var x0 = x, y0 = y;
- var xa = x + stack.shift(), ya = y + stack.shift();
- var xb = xa + stack.shift(), yb = ya + stack.shift();
+ xa = x + stack.shift(); ya = y + stack.shift();
+ xb = xa + stack.shift(); yb = ya + stack.shift();
x = xb + stack.shift(); y = yb + stack.shift();
bezierCurveTo(xa, ya, xb, yb, x, y);
- var xa = x + stack.shift(), ya = y + stack.shift();
- var xb = xa + stack.shift(), yb = ya + stack.shift();
+ xa = x + stack.shift(); ya = y + stack.shift();
+ xb = xa + stack.shift(); yb = ya + stack.shift();
x = xb; y = yb;
- if (Math.abs(x - x0) > Math.abs(y - y0))
+ if (Math.abs(x - x0) > Math.abs(y - y0)) {
x += stack.shift();
- else
+ } else {
y += stack.shift();
+ }
bezierCurveTo(xa, ya, xb, yb, x, y);
break;
default:
@@ -24316,8 +26220,8 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
break;
case 24: // rcurveline
while (stack.length > 2) {
- var xa = x + stack.shift(), ya = y + stack.shift();
- var xb = xa + stack.shift(), yb = ya + stack.shift();
+ xa = x + stack.shift(); ya = y + stack.shift();
+ xb = xa + stack.shift(); yb = ya + stack.shift();
x = xb + stack.shift(); y = yb + stack.shift();
bezierCurveTo(xa, ya, xb, yb, x, y);
}
@@ -24331,8 +26235,8 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
y += stack.shift();
lineTo(x, y);
}
- var xa = x + stack.shift(), ya = y + stack.shift();
- var xb = xa + stack.shift(), yb = ya + stack.shift();
+ xa = x + stack.shift(); ya = y + stack.shift();
+ xb = xa + stack.shift(); yb = ya + stack.shift();
x = xb + stack.shift(); y = yb + stack.shift();
bezierCurveTo(xa, ya, xb, yb, x, y);
break;
@@ -24341,8 +26245,8 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
x += stack.shift();
}
while (stack.length > 0) {
- var xa = x, ya = y + stack.shift();
- var xb = xa + stack.shift(), yb = ya + stack.shift();
+ xa = x; ya = y + stack.shift();
+ xb = xa + stack.shift(); yb = ya + stack.shift();
x = xb; y = yb + stack.shift();
bezierCurveTo(xa, ya, xb, yb, x, y);
}
@@ -24352,8 +26256,8 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
y += stack.shift();
}
while (stack.length > 0) {
- var xa = x + stack.shift(), ya = y;
- var xb = xa + stack.shift(), yb = ya + stack.shift();
+ xa = x + stack.shift(); ya = y;
+ xb = xa + stack.shift(); yb = ya + stack.shift();
x = xb + stack.shift(); y = yb;
bezierCurveTo(xa, ya, xb, yb, x, y);
}
@@ -24363,16 +26267,16 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
i += 2;
break;
case 29: // callgsubr
- var n = stack.pop() + font.gsubrsBias;
- var subrCode = font.gsubrs[n];
+ n = stack.pop() + font.gsubrsBias;
+ subrCode = font.gsubrs[n];
if (subrCode) {
parse(subrCode);
}
break;
case 30: // vhcurveto
while (stack.length > 0) {
- var xa = x, ya = y + stack.shift();
- var xb = xa + stack.shift(), yb = ya + stack.shift();
+ xa = x; ya = y + stack.shift();
+ xb = xa + stack.shift(); yb = ya + stack.shift();
x = xb + stack.shift();
y = yb + (stack.length === 1 ? stack.shift() : 0);
bezierCurveTo(xa, ya, xb, yb, x, y);
@@ -24380,8 +26284,8 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
break;
}
- var xa = x + stack.shift(), ya = y;
- var xb = xa + stack.shift(), yb = ya + stack.shift();
+ xa = x + stack.shift(); ya = y;
+ xb = xa + stack.shift(); yb = ya + stack.shift();
y = yb + stack.shift();
x = xb + (stack.length === 1 ? stack.shift() : 0);
bezierCurveTo(xa, ya, xb, yb, x, y);
@@ -24389,8 +26293,8 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
break;
case 31: // hvcurveto
while (stack.length > 0) {
- var xa = x + stack.shift(), ya = y;
- var xb = xa + stack.shift(), yb = ya + stack.shift();
+ xa = x + stack.shift(); ya = y;
+ xb = xa + stack.shift(); yb = ya + stack.shift();
y = yb + stack.shift();
x = xb + (stack.length === 1 ? stack.shift() : 0);
bezierCurveTo(xa, ya, xb, yb, x, y);
@@ -24398,23 +26302,24 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
break;
}
- var xa = x, ya = y + stack.shift();
- var xb = xa + stack.shift(), yb = ya + stack.shift();
+ xa = x; ya = y + stack.shift();
+ xb = xa + stack.shift(); yb = ya + stack.shift();
x = xb + stack.shift();
y = yb + (stack.length === 1 ? stack.shift() : 0);
bezierCurveTo(xa, ya, xb, yb, x, y);
}
break;
default:
- if (v < 32)
+ if (v < 32) {
error('unknown operator: ' + v);
- if (v < 247)
+ }
+ if (v < 247) {
stack.push(v - 139);
- else if (v < 251)
+ } else if (v < 251) {
stack.push((v - 247) * 256 + code[i++] + 108);
- else if (v < 255)
+ } else if (v < 255) {
stack.push(-(v - 251) * 256 - code[i++] - 108);
- else {
+ } else {
stack.push(((code[i] << 24) | (code[i + 1] << 16) |
(code[i + 2] << 8) | code[i + 3]) / 65536);
i += 4;
@@ -24498,10 +26403,10 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
this.glyphNameMap = glyphNameMap || GlyphsUnicode;
this.compiledGlyphs = [];
- this.gsubrsBias = this.gsubrs.length < 1240 ? 107 :
- this.gsubrs.length < 33900 ? 1131 : 32768;
- this.subrsBias = this.subrs.length < 1240 ? 107 :
- this.subrs.length < 33900 ? 1131 : 32768;
+ this.gsubrsBias = (this.gsubrs.length < 1240 ?
+ 107 : (this.gsubrs.length < 33900 ? 1131 : 32768));
+ this.subrsBias = (this.subrs.length < 1240 ?
+ 107 : (this.subrs.length < 33900 ? 1131 : 32768));
}
Util.inherit(Type2Compiled, CompiledFont, {
@@ -24517,7 +26422,7 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
var cmap, glyf, loca, cff, indexToLocFormat, unitsPerEm;
var numTables = getUshort(data, 4);
for (var i = 0, p = 12; i < numTables; i++, p += 16) {
- var tag = String.fromCharCode.apply(null, data.subarray(p, p + 4));
+ var tag = bytesToString(data.subarray(p, p + 4));
var offset = getLong(data, p + 8);
var length = getLong(data, p + 12);
switch (tag) {
@@ -24541,8 +26446,8 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
}
if (glyf) {
- var fontMatrix = !unitsPerEm ? font.fontMatrix :
- [1 / unitsPerEm, 0, 0, 1 / unitsPerEm, 0, 0];
+ var fontMatrix = (!unitsPerEm ? font.fontMatrix :
+ [1 / unitsPerEm, 0, 0, 1 / unitsPerEm, 0, 0]);
return new TrueTypeCompiled(
parseGlyfTable(glyf, loca, indexToLocFormat), cmap, fontMatrix);
} else {
@@ -28768,22 +30673,24 @@ var PDFImage = (function PDFImageClosure() {
* 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) {
+ function handleImageData(handler, xref, res, image) {
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('JpegDecode', [image.getIR(), numComps], function(message) {
+ var decodePromise = handler.sendWithPromise('JpegDecode',
+ [image.getIR(), numComps]);
+ return decodePromise.then(function (message) {
var data = message.data;
- var stream = new Stream(data, 0, data.length, image.dict);
- promise.resolve(stream);
+ return new Stream(data, 0, data.length, image.dict);
});
} else {
- promise.resolve(image);
+ return 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.
@@ -28791,20 +30698,27 @@ var PDFImage = (function PDFImageClosure() {
function decodeAndClamp(value, addend, coefficient, max) {
value = addend + value * coefficient;
// Clamp the value to the range
- return value < 0 ? 0 : value > max ? max : value;
+ return (value < 0 ? 0 : (value > max ? max : value));
}
+
function PDFImage(xref, res, image, inline, smask, mask, isMask) {
this.image = image;
- if (image.getParams) {
- // JPX/JPEG2000 streams directly contain bits per component
- // and color space mode information.
- warn('get params from actual stream');
- // var bits = ...
- // var colorspace = ...
+ var dict = image.dict;
+ if (dict.has('Filter')) {
+ var filter = dict.get('Filter').name;
+ if (filter === 'JPXDecode') {
+ var jpxImage = new JpxImage();
+ jpxImage.parseImageProperties(image.stream);
+ image.stream.reset();
+ image.bitsPerComponent = jpxImage.bitsPerComponent;
+ image.numComps = jpxImage.componentsCount;
+ } else if (filter === 'JBIG2Decode') {
+ image.bitsPerComponent = 1;
+ image.numComps = 1;
+ }
}
// TODO cache rendered images?
- var dict = image.dict;
this.width = dict.get('Width', 'W');
this.height = dict.get('Height', 'H');
@@ -28833,8 +30747,21 @@ var PDFImage = (function PDFImageClosure() {
if (!this.imageMask) {
var colorSpace = dict.get('ColorSpace', 'CS');
if (!colorSpace) {
- warn('JPX images (which don"t require color spaces');
- colorSpace = Name.get('DeviceRGB');
+ info('JPX images (which do not require color spaces)');
+ switch (image.numComps) {
+ case 1:
+ colorSpace = Name.get('DeviceGray');
+ break;
+ case 3:
+ colorSpace = Name.get('DeviceRGB');
+ break;
+ case 4:
+ colorSpace = Name.get('DeviceCMYK');
+ break;
+ default:
+ error('JPX images with ' + this.numComps +
+ ' color components not supported.');
+ }
}
this.colorSpace = ColorSpace.parse(colorSpace, xref, res);
this.numComps = this.colorSpace.numComps;
@@ -28870,51 +30797,47 @@ var PDFImage = (function PDFImageClosure() {
}
}
/**
- * Handles processing of image data and calls the callback with an argument
- * of a PDFImage when the image is ready to be used.
+ * Handles processing of image data and returns the Promise that is resolved
+ * with a PDFImage when the image is ready to be used.
*/
- PDFImage.buildImage = function PDFImage_buildImage(callback, handler, xref,
+ PDFImage.buildImage = function PDFImage_buildImage(handler, xref,
res, image, inline) {
- var imageDataPromise = new LegacyPromise();
- var smaskPromise = new LegacyPromise();
- var maskPromise = new LegacyPromise();
- // The image data and smask data may not be ready yet, wait till both are
- // resolved.
- Promise.all([imageDataPromise, smaskPromise, maskPromise]).then(
- function(results) {
- var imageData = results[0], smaskData = results[1], maskData = results[2];
- var image = new PDFImage(xref, res, imageData, inline, smaskData,
- maskData);
- callback(image);
- });
-
- handleImageData(handler, xref, res, image, imageDataPromise);
+ var imagePromise = handleImageData(handler, xref, res, image);
+ var smaskPromise;
+ var maskPromise;
var smask = image.dict.get('SMask');
var mask = image.dict.get('Mask');
if (smask) {
- handleImageData(handler, xref, res, smask, smaskPromise);
- maskPromise.resolve(null);
+ smaskPromise = handleImageData(handler, xref, res, smask);
+ maskPromise = Promise.resolve(null);
} else {
- smaskPromise.resolve(null);
+ smaskPromise = Promise.resolve(null);
if (mask) {
if (isStream(mask)) {
- handleImageData(handler, xref, res, mask, maskPromise);
+ maskPromise = handleImageData(handler, xref, res, mask);
} else if (isArray(mask)) {
- maskPromise.resolve(mask);
+ maskPromise = Promise.resolve(mask);
} else {
warn('Unsupported mask format.');
- maskPromise.resolve(null);
+ maskPromise = Promise.resolve(null);
}
} else {
- maskPromise.resolve(null);
+ maskPromise = Promise.resolve(null);
}
}
+ return Promise.all([imagePromise, smaskPromise, maskPromise]).then(
+ function(results) {
+ var imageData = results[0];
+ var smaskData = results[1];
+ var maskData = results[2];
+ return new PDFImage(xref, res, imageData, inline, smaskData, maskData);
+ });
};
/**
- * Resize an image using the nearest neighbor algorithm. Currently only
+ * 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.
@@ -28923,30 +30846,50 @@ var PDFImage = (function PDFImageClosure() {
* @param {Number} h1 Original height.
* @param {Number} w2 New width.
* @param {Number} h2 New height.
+ * @param {TypedArray} dest (Optional) The destination buffer.
+ * @param {Number} alpha01 (Optional) Size reserved for the alpha channel.
* @return {TypedArray} Resized image data.
*/
PDFImage.resize = function PDFImage_resize(pixels, bpc, components,
- w1, h1, w2, h2) {
+ w1, h1, w2, h2, dest, alpha01) {
+
+ if (components !== 1 && components !== 3) {
+ error('Unsupported component count for resizing.');
+ }
+
var length = w2 * h2 * components;
- var temp = bpc <= 8 ? new Uint8Array(length) :
- bpc <= 16 ? new Uint16Array(length) : new Uint32Array(length);
+ var temp = dest ? dest : (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];
+ var i, j, py, newIndex = 0, oldIndex;
+ var xScaled = new Uint16Array(w2);
+ var w1Scanline = w1 * components;
+ if (alpha01 !== 1) {
+ alpha01 = 0;
+ }
+
+ for (j = 0; j < w2; j++) {
+ xScaled[j] = Math.floor(j * xRatio) * components;
+ }
+
+ if (components === 1) {
+ for (i = 0; i < h2; i++) {
+ py = Math.floor(i * yRatio) * w1Scanline;
+ for (j = 0; j < w2; j++) {
+ oldIndex = py + xScaled[j];
+ temp[newIndex++] = pixels[oldIndex];
+ }
+ }
+ } else if (components === 3) {
+ for (i = 0; i < h2; i++) {
+ py = Math.floor(i * yRatio) * w1Scanline;
+ for (j = 0; j < w2; j++) {
+ oldIndex = py + xScaled[j];
+ temp[newIndex++] = pixels[oldIndex++];
+ temp[newIndex++] = pixels[oldIndex++];
+ temp[newIndex++] = pixels[oldIndex++];
+ newIndex += alpha01;
}
}
}
@@ -28984,37 +30927,39 @@ var PDFImage = (function PDFImageClosure() {
this.smask && this.smask.width || 0,
this.mask && this.mask.width || 0);
},
+
get drawHeight() {
return Math.max(this.height,
this.smask && this.smask.height || 0,
this.mask && this.mask.height || 0);
},
+
decodeBuffer: function PDFImage_decodeBuffer(buffer) {
var bpc = this.bpc;
- var decodeMap = this.decode;
var numComps = this.numComps;
- var decodeAddends, decodeCoefficients;
var decodeAddends = this.decodeAddends;
var decodeCoefficients = this.decodeCoefficients;
var max = (1 << bpc) - 1;
+ var i, ii;
if (bpc === 1) {
// If the buffer needed decode that means it just needs to be inverted.
- for (var i = 0, ii = buffer.length; i < ii; i++) {
+ for (i = 0, ii = buffer.length; i < ii; i++) {
buffer[i] = +!(buffer[i]);
}
return;
}
var index = 0;
- for (var i = 0, ii = this.width * this.height; i < ii; i++) {
+ for (i = 0, ii = this.width * this.height; i < ii; i++) {
for (var j = 0; j < numComps; j++) {
buffer[index] = decodeAndClamp(buffer[index], decodeAddends[j],
- decodeCoefficients[j], max);
+ decodeCoefficients[j], max);
index++;
}
}
},
+
getComponents: function PDFImage_getComponents(buffer) {
var bpc = this.bpc;
@@ -29029,15 +30974,16 @@ var PDFImage = (function PDFImageClosure() {
var length = width * height * numComps;
var bufferPos = 0;
- var output = bpc <= 8 ? new Uint8Array(length) :
- bpc <= 16 ? new Uint16Array(length) : new Uint32Array(length);
+ var output = (bpc <= 8 ? new Uint8Array(length) :
+ (bpc <= 16 ? new Uint16Array(length) : new Uint32Array(length)));
var rowComps = width * numComps;
var max = (1 << bpc) - 1;
+ var i = 0, ii, buf;
if (bpc === 1) {
// Optimization for reading 1 bpc images.
- var i = 0, buf, mask, loop1End, loop2End;
+ var mask, loop1End, loop2End;
for (var j = 0; j < height; j++) {
loop1End = i + (rowComps & ~7);
loop2End = i + rowComps;
@@ -29068,8 +31014,9 @@ var PDFImage = (function PDFImageClosure() {
}
} else {
// The general case that handles all other bpc values.
- var bits = 0, buf = 0;
- for (var i = 0, ii = length; i < ii; ++i) {
+ var bits = 0;
+ buf = 0;
+ for (i = 0, ii = length; i < ii; ++i) {
if (i % rowComps === 0) {
buf = 0;
bits = 0;
@@ -29082,22 +31029,23 @@ var PDFImage = (function PDFImageClosure() {
var remainingBits = bits - bpc;
var value = buf >> remainingBits;
- output[i] = value < 0 ? 0 : value > max ? max : value;
+ output[i] = (value < 0 ? 0 : (value > max ? max : value));
buf = buf & ((1 << remainingBits) - 1);
bits = remainingBits;
}
}
return output;
},
+
fillOpacity: function PDFImage_fillOpacity(rgbaBuf, width, height,
actualHeight, image) {
var smask = this.smask;
var mask = this.mask;
- var alphaBuf;
+ var alphaBuf, sw, sh, i, ii, j;
if (smask) {
- var sw = smask.width;
- var sh = smask.height;
+ sw = smask.width;
+ sh = smask.height;
alphaBuf = new Uint8Array(sw * sh);
smask.fillGrayBuffer(alphaBuf);
if (sw != width || sh != height) {
@@ -29106,14 +31054,14 @@ var PDFImage = (function PDFImageClosure() {
}
} else if (mask) {
if (mask instanceof PDFImage) {
- var sw = mask.width;
- var sh = mask.height;
+ sw = mask.width;
+ sh = mask.height;
alphaBuf = new Uint8Array(sw * sh);
mask.numComps = 1;
mask.fillGrayBuffer(alphaBuf);
// Need to invert values in rgbaBuf
- for (var i = 0, ii = sw * sh; i < ii; ++i) {
+ for (i = 0, ii = sw * sh; i < ii; ++i) {
alphaBuf[i] = 255 - alphaBuf[i];
}
@@ -29126,10 +31074,10 @@ var PDFImage = (function PDFImageClosure() {
// then they should be painted.
alphaBuf = new Uint8Array(width * height);
var numComps = this.numComps;
- for (var i = 0, ii = width * height; i < ii; ++i) {
+ for (i = 0, ii = width * height; i < ii; ++i) {
var opacity = 0;
var imageOffset = i * numComps;
- for (var j = 0; j < numComps; ++j) {
+ for (j = 0; j < numComps; ++j) {
var color = image[imageOffset + j];
var maskOffset = j * 2;
if (color < mask[maskOffset] || color > mask[maskOffset + 1]) {
@@ -29145,48 +31093,52 @@ var PDFImage = (function PDFImageClosure() {
}
if (alphaBuf) {
- for (var i = 0, j = 3, ii = width * actualHeight; i < ii; ++i, j += 4) {
+ for (i = 0, j = 3, ii = width * actualHeight; i < ii; ++i, j += 4) {
rgbaBuf[j] = alphaBuf[i];
}
} else {
// No mask.
- for (var i = 0, j = 3, ii = width * actualHeight; i < ii; ++i, j += 4) {
+ for (i = 0, j = 3, ii = width * actualHeight; i < ii; ++i, j += 4) {
rgbaBuf[j] = 255;
}
}
},
+
undoPreblend: function PDFImage_undoPreblend(buffer, width, height) {
var matte = this.smask && this.smask.matte;
if (!matte) {
return;
}
-
- function clamp(value) {
- return (value < 0 ? 0 : value > 255 ? 255 : value) | 0;
- }
-
var matteRgb = this.colorSpace.getRgb(matte, 0);
+ var matteR = matteRgb[0];
+ var matteG = matteRgb[1];
+ var matteB = matteRgb[2];
var length = width * height * 4;
+ var r, g, b;
for (var i = 0; i < length; i += 4) {
var alpha = buffer[i + 3];
if (alpha === 0) {
// according formula we have to get Infinity in all components
- // making it as white (tipical paper color) should be okay
+ // making it white (typical paper color) should be okay
buffer[i] = 255;
buffer[i + 1] = 255;
buffer[i + 2] = 255;
continue;
}
var k = 255 / alpha;
- buffer[i] = clamp((buffer[i] - matteRgb[0]) * k + matteRgb[0]);
- buffer[i + 1] = clamp((buffer[i + 1] - matteRgb[1]) * k + matteRgb[1]);
- buffer[i + 2] = clamp((buffer[i + 2] - matteRgb[2]) * k + matteRgb[2]);
+ r = (buffer[i] - matteR) * k + matteR;
+ g = (buffer[i + 1] - matteG) * k + matteG;
+ b = (buffer[i + 2] - matteB) * k + matteB;
+ buffer[i] = r <= 0 ? 0 : r >= 255 ? 255 : r | 0;
+ buffer[i + 1] = g <= 0 ? 0 : g >= 255 ? 255 : g | 0;
+ buffer[i + 2] = b <= 0 ? 0 : b >= 255 ? 255 : b | 0;
}
},
+
createImageData: function PDFImage_createImageData(forceRGBA) {
var drawWidth = this.drawWidth;
var drawHeight = this.drawHeight;
- var imgData = { // other fields are filled in below
+ var imgData = { // other fields are filled in below
width: drawWidth,
height: drawHeight
};
@@ -29198,7 +31150,7 @@ var PDFImage = (function PDFImageClosure() {
// Rows start at byte boundary.
var rowBytes = (originalWidth * numComps * bpc + 7) >> 3;
- var imgArray = this.getImageBytes(originalHeight * rowBytes);
+ var imgArray;
if (!forceRGBA) {
// If it is a 1-bit-per-pixel grayscale (i.e. black-and-white) image
@@ -29218,6 +31170,7 @@ var PDFImage = (function PDFImageClosure() {
drawWidth === originalWidth && drawHeight === originalHeight) {
imgData.kind = kind;
+ imgArray = this.getImageBytes(originalHeight * rowBytes);
// If imgArray came from a DecodeStream, we're safe to transfer it
// (and thus neuter it) because it will constitute the entire
// DecodeStream's data. But if it came from a Stream, we need to
@@ -29233,7 +31186,14 @@ var PDFImage = (function PDFImageClosure() {
return imgData;
}
}
+ if (this.image instanceof JpegStream) {
+ imgData.kind = ImageKind.RGB_24BPP;
+ imgData.data = this.getImageBytes(originalHeight * rowBytes,
+ drawWidth, drawHeight);
+ return imgData;
+ }
+ imgArray = this.getImageBytes(originalHeight * rowBytes);
// imgArray can be incomplete (e.g. after CCITT fax encoding).
var actualHeight = 0 | (imgArray.length / rowBytes *
drawHeight / originalHeight);
@@ -29271,32 +31231,35 @@ var PDFImage = (function PDFImageClosure() {
return imgData;
},
+
fillGrayBuffer: function PDFImage_fillGrayBuffer(buffer) {
var numComps = this.numComps;
- if (numComps != 1)
+ if (numComps != 1) {
error('Reading gray scale from a color image: ' + numComps);
+ }
var width = this.width;
var height = this.height;
var bpc = this.bpc;
- // rows start at byte boundary;
+ // rows start at byte boundary
var rowBytes = (width * numComps * bpc + 7) >> 3;
var imgArray = this.getImageBytes(height * rowBytes);
var comps = this.getComponents(imgArray);
+ var i, length;
if (bpc === 1) {
// inline decoding (= inversion) for 1 bpc images
- var length = width * height;
+ length = width * height;
if (this.needsDecode) {
- // invert and scale to {0, 255}
- for (var i = 0; i < length; ++i) {
+ // invert and scale to {0, 255}
+ for (i = 0; i < length; ++i) {
buffer[i] = (comps[i] - 1) & 255;
}
} else {
// scale to {0, 255}
- for (var i = 0; i < length; ++i) {
+ for (i = 0; i < length; ++i) {
buffer[i] = (-comps[i]) & 255;
}
}
@@ -29306,15 +31269,19 @@ var PDFImage = (function PDFImageClosure() {
if (this.needsDecode) {
this.decodeBuffer(comps);
}
- var length = width * height;
+ 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 (i = 0; i < length; ++i) {
buffer[i] = (scale * comps[i]) | 0;
}
},
- getImageBytes: function PDFImage_getImageBytes(length) {
+
+ getImageBytes: function PDFImage_getImageBytes(length,
+ drawWidth, drawHeight) {
this.image.reset();
+ this.image.drawWidth = drawWidth;
+ this.image.drawHeight = drawHeight;
return this.image.getBytes(length);
}
};
@@ -32269,7 +34236,7 @@ var Metrics = {
var EOF = {};
function isEOF(v) {
- return v == EOF;
+ return (v === EOF);
}
var Parser = (function ParserClosure() {
@@ -32300,51 +34267,58 @@ var Parser = (function ParserClosure() {
}
},
getObj: function Parser_getObj(cipherTransform) {
- if (isCmd(this.buf1, 'BI')) { // inline image
- this.shift();
- return this.makeInlineImage(cipherTransform);
- }
- if (isCmd(this.buf1, '[')) { // array
- this.shift();
- var array = [];
- while (!isCmd(this.buf1, ']') && !isEOF(this.buf1))
- array.push(this.getObj(cipherTransform));
- if (isEOF(this.buf1))
- error('End of file inside array');
- this.shift();
- return array;
- }
- if (isCmd(this.buf1, '<<')) { // dictionary or stream
- this.shift();
- var dict = new Dict(this.xref);
- while (!isCmd(this.buf1, '>>') && !isEOF(this.buf1)) {
- if (!isName(this.buf1)) {
- info('Malformed dictionary, key must be a name object');
+ var buf1 = this.buf1;
+ this.shift();
+
+ if (buf1 instanceof Cmd) {
+ switch (buf1.cmd) {
+ case 'BI': // inline image
+ return this.makeInlineImage(cipherTransform);
+ case '[': // array
+ var array = [];
+ while (!isCmd(this.buf1, ']') && !isEOF(this.buf1)) {
+ array.push(this.getObj(cipherTransform));
+ }
+ if (isEOF(this.buf1)) {
+ error('End of file inside array');
+ }
this.shift();
- continue;
- }
+ return array;
+ case '<<': // dictionary or stream
+ var dict = new Dict(this.xref);
+ while (!isCmd(this.buf1, '>>') && !isEOF(this.buf1)) {
+ if (!isName(this.buf1)) {
+ info('Malformed dictionary: key must be a name object');
+ this.shift();
+ continue;
+ }
- var key = this.buf1.name;
- this.shift();
- if (isEOF(this.buf1))
- break;
- dict.set(key, this.getObj(cipherTransform));
- }
- if (isEOF(this.buf1))
- error('End of file inside dictionary');
+ var key = this.buf1.name;
+ this.shift();
+ if (isEOF(this.buf1)) {
+ break;
+ }
+ dict.set(key, this.getObj(cipherTransform));
+ }
+ if (isEOF(this.buf1)) {
+ error('End of file inside dictionary');
+ }
- // stream objects are not allowed inside content streams or
- // object streams
- if (isCmd(this.buf2, 'stream')) {
- return this.allowStreams ?
- this.makeStream(dict, cipherTransform) : dict;
+ // Stream objects are not allowed inside content streams or
+ // object streams.
+ if (isCmd(this.buf2, 'stream')) {
+ return (this.allowStreams ?
+ this.makeStream(dict, cipherTransform) : dict);
+ }
+ this.shift();
+ return dict;
+ default: // simple object
+ return buf1;
}
- this.shift();
- return dict;
}
- if (isInt(this.buf1)) { // indirect reference or integer
- var num = this.buf1;
- this.shift();
+
+ if (isInt(buf1)) { // indirect reference or integer
+ var num = buf1;
if (isInt(this.buf1) && isCmd(this.buf2, 'R')) {
var ref = new Ref(num, this.buf1);
this.shift();
@@ -32353,33 +34327,34 @@ var Parser = (function ParserClosure() {
}
return num;
}
- if (isString(this.buf1)) { // string
- var str = this.buf1;
- this.shift();
- if (cipherTransform)
+
+ if (isString(buf1)) { // string
+ var str = buf1;
+ if (cipherTransform) {
str = cipherTransform.decryptString(str);
+ }
return str;
}
// simple object
- var obj = this.buf1;
- this.shift();
- return obj;
+ return buf1;
},
makeInlineImage: function Parser_makeInlineImage(cipherTransform) {
var lexer = this.lexer;
var stream = lexer.stream;
// parse dictionary
- var dict = new Dict();
+ var dict = new Dict(null);
while (!isCmd(this.buf1, 'ID') && !isEOF(this.buf1)) {
- if (!isName(this.buf1))
+ if (!isName(this.buf1)) {
error('Dictionary key must be a name object');
+ }
var key = this.buf1.name;
this.shift();
- if (isEOF(this.buf1))
+ if (isEOF(this.buf1)) {
break;
+ }
dict.set(key, this.getObj(cipherTransform));
}
@@ -32403,13 +34378,13 @@ var Parser = (function ParserClosure() {
break; // some binary stuff found, resetting the state
}
}
- state = state === 3 ? 4 : 0;
+ state = (state === 3 ? 4 : 0);
break;
case 0x45:
state = 2;
break;
case 0x49:
- state = state === 2 ? 3 : 0;
+ state = (state === 2 ? 3 : 0);
break;
default:
state = 0;
@@ -32430,7 +34405,7 @@ var Parser = (function ParserClosure() {
var a = 1;
var b = 0;
- for (var i = 0, ii = imageBytes.length; i < ii; ++i) {
+ for (i = 0, ii = imageBytes.length; i < ii; ++i) {
a = (a + (imageBytes[i] & 0xff)) % 65521;
b = (b + a) % 65521;
}
@@ -32469,7 +34444,7 @@ var Parser = (function ParserClosure() {
},
fetchIfRef: function Parser_fetchIfRef(obj) {
// not relying on the xref.fetchIfRef -- xref might not be set
- return isRef(obj) ? this.xref.fetch(obj) : obj;
+ return (isRef(obj) ? this.xref.fetch(obj) : obj);
},
makeStream: function Parser_makeStream(dict, cipherTransform) {
var lexer = this.lexer;
@@ -32499,11 +34474,11 @@ var Parser = (function ParserClosure() {
var ENDSTREAM_SIGNATURE_LENGTH = 9;
var ENDSTREAM_SIGNATURE = [0x65, 0x6E, 0x64, 0x73, 0x74, 0x72, 0x65,
0x61, 0x6D];
- var skipped = 0, found = false;
+ var skipped = 0, found = false, i, j;
while (stream.pos < stream.end) {
var scanBytes = stream.peekBytes(SCAN_BLOCK_SIZE);
var scanLength = scanBytes.length - ENDSTREAM_SIGNATURE_LENGTH;
- var found = false, i, j;
+ found = false;
for (i = 0, j = 0; i < scanLength; i++) {
var b = scanBytes[i];
if (b !== ENDSTREAM_SIGNATURE[j]) {
@@ -32538,8 +34513,9 @@ var Parser = (function ParserClosure() {
this.shift(); // 'endstream'
stream = stream.makeSubStream(pos, length, dict);
- if (cipherTransform)
+ if (cipherTransform) {
stream = cipherTransform.createStream(stream, length);
+ }
stream = this.filter(stream, dict, length);
stream.dict = dict;
return stream;
@@ -32547,8 +34523,9 @@ var Parser = (function ParserClosure() {
filter: function Parser_filter(stream, dict, length) {
var filter = this.fetchIfRef(dict.get('Filter', 'F'));
var params = this.fetchIfRef(dict.get('DecodeParms', 'DP'));
- if (isName(filter))
+ if (isName(filter)) {
return this.makeFilter(stream, filter.name, length, params);
+ }
var maybeLength = length;
if (isArray(filter)) {
@@ -32556,12 +34533,14 @@ var Parser = (function ParserClosure() {
var paramsArray = params;
for (var i = 0, ii = filterArray.length; i < ii; ++i) {
filter = filterArray[i];
- if (!isName(filter))
+ if (!isName(filter)) {
error('Bad filter name: ' + filter);
+ }
params = null;
- if (isArray(paramsArray) && (i in paramsArray))
+ if (isArray(paramsArray) && (i in paramsArray)) {
params = paramsArray[i];
+ }
stream = this.makeFilter(stream, filter.name, maybeLength, params);
// after the first stream the length variable is invalid
maybeLength = null;
@@ -32583,11 +34562,12 @@ var Parser = (function ParserClosure() {
if (name == 'LZWDecode' || name == 'LZW') {
var earlyChange = 1;
if (params) {
- if (params.has('EarlyChange'))
+ if (params.has('EarlyChange')) {
earlyChange = params.get('EarlyChange');
+ }
return new PredictorStream(
new LZWStream(stream, maybeLength, earlyChange),
- maybeLength, params);
+ maybeLength, params);
}
return new LZWStream(stream, maybeLength, earlyChange);
}
@@ -32643,29 +34623,29 @@ var Lexer = (function LexerClosure() {
}
Lexer.isSpace = function Lexer_isSpace(ch) {
- // space is one of the following characters: SPACE, TAB, CR, or LF
- return ch === 0x20 || ch === 0x09 || ch === 0x0D || ch === 0x0A;
+ // Space is one of the following characters: SPACE, TAB, CR or LF.
+ return (ch === 0x20 || ch === 0x09 || ch === 0x0D || ch === 0x0A);
};
- // A '1' in this array means the character is white space. A '1' or
+ // A '1' in this array means the character is white space. A '1' or
// '2' means the character ends a name or command.
var specialChars = [
- 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 1, 0, 0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, // 2x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, // 3x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 5x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ax
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // bx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // cx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // dx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ex
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // fx
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, // 0x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
+ 1, 0, 0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, // 2x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, // 3x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 5x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 7x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ax
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // bx
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // cx
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // dx
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ex
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // fx
];
function toHexDigit(ch) {
@@ -32690,10 +34670,8 @@ var Lexer = (function LexerClosure() {
var ch = this.currentChar;
var eNotation = false;
var divideBy = 0; // different from 0 if it's a floating point value
-
var sign = 1;
-
if (ch === 0x2D) { // '-'
sign = -1;
ch = this.nextChar();
@@ -32704,7 +34682,6 @@ var Lexer = (function LexerClosure() {
divideBy = 10;
ch = this.nextChar();
}
-
if (ch < 0x30 || ch > 0x39) { // '0' - '9'
error('Invalid number: ' + String.fromCharCode(ch));
return 0;
@@ -32739,7 +34716,6 @@ var Lexer = (function LexerClosure() {
} else if (ch === 0x45 || ch === 0x65) { // 'E', 'e'
// 'E' can be either a scientific notation or the beginning of a new
// operator
- var hasE = true;
ch = this.peekChar();
if (ch === 0x2B || ch === 0x2D) { // '+', '-'
powerValueSign = (ch === 0x2D) ? -1 : 1;
@@ -32829,10 +34805,14 @@ var Lexer = (function LexerClosure() {
x = (x << 3) + (ch & 0x0F);
}
}
-
strBuf.push(String.fromCharCode(x));
break;
- case 0x0A: case 0x0D: // LF, CR
+ case 0x0D: // CR
+ if (this.peekChar() === 0x0A) { // LF
+ this.nextChar();
+ }
+ break;
+ case 0x0A: // LF
break;
default:
strBuf.push(String.fromCharCode(ch));
@@ -32862,8 +34842,9 @@ var Lexer = (function LexerClosure() {
var x = toHexDigit(ch);
if (x != -1) {
var x2 = toHexDigit(this.nextChar());
- if (x2 == -1)
+ if (x2 === -1) {
error('Illegal digit in hex char in name: ' + x2);
+ }
strBuf.push(String.fromCharCode((x << 4) | x2));
} else {
strBuf.push('#', String.fromCharCode(ch));
@@ -32927,8 +34908,9 @@ var Lexer = (function LexerClosure() {
return EOF;
}
if (comment) {
- if (ch === 0x0A || ch == 0x0D) // LF, CR
+ if (ch === 0x0A || ch === 0x0D) { // LF, CR
comment = false;
+ }
} else if (ch === 0x25) { // '%'
comment = true;
} else if (specialChars[ch] !== 1) {
@@ -32993,21 +34975,24 @@ var Lexer = (function LexerClosure() {
if (knownCommandFound && !(possibleCommand in knownCommands)) {
break;
}
- if (str.length == 128)
+ if (str.length === 128) {
error('Command token too long: ' + str.length);
+ }
str = possibleCommand;
knownCommandFound = knownCommands && (str in knownCommands);
}
- if (str == 'true')
+ if (str === 'true') {
return true;
- if (str == 'false')
+ }
+ if (str === 'false') {
return false;
- if (str == 'null')
+ }
+ if (str === 'null') {
return null;
+ }
return Cmd.get(str);
},
skipToNextLine: function Lexer_skipToNextLine() {
- var stream = this.stream;
var ch = this.currentChar;
while (ch >= 0) {
if (ch === 0x0D) { // CR
@@ -33038,8 +35023,9 @@ var Linearization = (function LinearizationClosure() {
if (isInt(obj1) && isInt(obj2) && isCmd(obj3, 'obj') &&
isDict(this.linDict)) {
var obj = this.linDict.get('Linearized');
- if (!(isNum(obj) && obj > 0))
+ if (!(isNum(obj) && obj > 0)) {
this.linDict = null;
+ }
}
}
@@ -33047,9 +35033,7 @@ var Linearization = (function LinearizationClosure() {
getInt: function Linearization_getInt(name) {
var linDict = this.linDict;
var obj;
- if (isDict(linDict) &&
- isInt(obj = linDict.get(name)) &&
- obj > 0) {
+ if (isDict(linDict) && isInt(obj = linDict.get(name)) && obj > 0) {
return obj;
}
error('"' + name + '" field in linearization table is invalid');
@@ -33057,18 +35041,16 @@ var Linearization = (function LinearizationClosure() {
getHint: function Linearization_getHint(index) {
var linDict = this.linDict;
var obj1, obj2;
- if (isDict(linDict) &&
- isArray(obj1 = linDict.get('H')) &&
- obj1.length >= 2 &&
- isInt(obj2 = obj1[index]) &&
- obj2 > 0) {
+ if (isDict(linDict) && isArray(obj1 = linDict.get('H')) &&
+ obj1.length >= 2 && isInt(obj2 = obj1[index]) && obj2 > 0) {
return obj2;
}
error('Hints table in linearization table is invalid: ' + index);
},
get length() {
- if (!isDict(this.linDict))
+ if (!isDict(this.linDict)) {
return 0;
+ }
return this.getInt('L');
},
get hintsOffset() {
@@ -33230,7 +35212,6 @@ var PostScriptLexer = (function PostScriptLexerClosure() {
return (this.currentChar = this.stream.getByte());
},
getToken: function PostScriptLexer_getToken() {
- var s = '';
var comment = false;
var ch = this.currentChar;
@@ -33303,8 +35284,8 @@ var PostScriptLexer = (function PostScriptLexerClosure() {
var Stream = (function StreamClosure() {
function Stream(arrayBuffer, start, length, dict) {
- this.bytes = arrayBuffer instanceof Uint8Array ? arrayBuffer :
- new Uint8Array(arrayBuffer);
+ this.bytes = (arrayBuffer instanceof Uint8Array ?
+ arrayBuffer : new Uint8Array(arrayBuffer));
this.start = start || 0;
this.pos = this.start;
this.end = (start + length) || this.bytes.length;
@@ -33317,11 +35298,27 @@ var Stream = (function StreamClosure() {
get length() {
return this.end - this.start;
},
+ get isEmpty() {
+ return this.length === 0;
+ },
getByte: function Stream_getByte() {
- if (this.pos >= this.end)
+ if (this.pos >= this.end) {
return -1;
+ }
return this.bytes[this.pos++];
},
+ getUint16: function Stream_getUint16() {
+ var b0 = this.getByte();
+ var b1 = this.getByte();
+ return (b0 << 8) + b1;
+ },
+ getInt32: function Stream_getInt32() {
+ var b0 = this.getByte();
+ var b1 = this.getByte();
+ var b2 = this.getByte();
+ var b3 = this.getByte();
+ return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3;
+ },
// returns subarray of original buffer
// should only be read
getBytes: function Stream_getBytes(length) {
@@ -33329,13 +35326,13 @@ var Stream = (function StreamClosure() {
var pos = this.pos;
var strEnd = this.end;
- if (!length)
+ if (!length) {
return bytes.subarray(pos, strEnd);
-
+ }
var end = pos + length;
- if (end > strEnd)
+ if (end > strEnd) {
end = strEnd;
-
+ }
this.pos = end;
return bytes.subarray(pos, end);
},
@@ -33345,8 +35342,9 @@ var Stream = (function StreamClosure() {
return bytes;
},
skip: function Stream_skip(n) {
- if (!n)
+ if (!n) {
n = 1;
+ }
this.pos += n;
},
reset: function Stream_reset() {
@@ -33368,8 +35366,9 @@ var StringStream = (function StringStreamClosure() {
function StringStream(str) {
var length = str.length;
var bytes = new Uint8Array(length);
- for (var n = 0; n < length; ++n)
+ for (var n = 0; n < length; ++n) {
bytes[n] = str.charCodeAt(n);
+ }
Stream.call(this, bytes);
}
@@ -33395,6 +35394,12 @@ var DecodeStream = (function DecodeStreamClosure() {
}
DecodeStream.prototype = {
+ get isEmpty() {
+ while (!this.eof && this.bufferLength === 0) {
+ this.readBlock();
+ }
+ return this.bufferLength === 0;
+ },
ensureBuffer: function DecodeStream_ensureBuffer(requested) {
var buffer = this.buffer;
var current;
@@ -33411,20 +35416,33 @@ var DecodeStream = (function DecodeStreamClosure() {
size *= 2;
}
var buffer2 = new Uint8Array(size);
- for (var i = 0; i < current; ++i) {
- buffer2[i] = buffer[i];
+ if (buffer) {
+ buffer2.set(buffer);
}
return (this.buffer = buffer2);
},
getByte: function DecodeStream_getByte() {
var pos = this.pos;
while (this.bufferLength <= pos) {
- if (this.eof)
+ if (this.eof) {
return -1;
+ }
this.readBlock();
}
return this.buffer[this.pos++];
},
+ getUint16: function DecodeStream_getUint16() {
+ var b0 = this.getByte();
+ var b1 = this.getByte();
+ return (b0 << 8) + b1;
+ },
+ getInt32: function DecodeStream_getInt32() {
+ var b0 = this.getByte();
+ var b1 = this.getByte();
+ var b2 = this.getByte();
+ var b3 = this.getByte();
+ return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3;
+ },
getBytes: function DecodeStream_getBytes(length) {
var end, pos = this.pos;
@@ -33432,22 +35450,24 @@ var DecodeStream = (function DecodeStreamClosure() {
this.ensureBuffer(pos + length);
end = pos + length;
- while (!this.eof && this.bufferLength < end)
+ while (!this.eof && this.bufferLength < end) {
this.readBlock();
-
+ }
var bufEnd = this.bufferLength;
- if (end > bufEnd)
+ if (end > bufEnd) {
end = bufEnd;
+ }
} else {
- while (!this.eof)
+ while (!this.eof) {
this.readBlock();
-
+ }
end = this.bufferLength;
// checking if bufferLength is still 0 then
// the buffer has to be initialized
- if (!end)
+ if (!end) {
this.buffer = new Uint8Array(0);
+ }
}
this.pos = end;
@@ -33460,13 +35480,15 @@ var DecodeStream = (function DecodeStreamClosure() {
},
makeSubStream: function DecodeStream_makeSubStream(start, length, dict) {
var end = start + length;
- while (this.bufferLength <= end && !this.eof)
+ while (this.bufferLength <= end && !this.eof) {
this.readBlock();
+ }
return new Stream(this.buffer, start, length, dict);
},
- skip: function Stream_skip(n) {
- if (!n)
+ skip: function DecodeStream_skip(n) {
+ if (!n) {
n = 1;
+ }
this.pos += n;
},
reset: function DecodeStream_reset() {
@@ -33492,7 +35514,7 @@ var StreamsSequenceStream = (function StreamsSequenceStreamClosure() {
StreamsSequenceStream.prototype = Object.create(DecodeStream.prototype);
StreamsSequenceStream.prototype.readBlock =
- function streamSequenceStreamReadBlock() {
+ function streamSequenceStreamReadBlock() {
var streams = this.streams;
if (streams.length === 0) {
@@ -33623,14 +35645,18 @@ var FlateStream = (function FlateStreamClosure() {
var cmf = str.getByte();
var flg = str.getByte();
- if (cmf == -1 || flg == -1)
+ if (cmf == -1 || flg == -1) {
error('Invalid header in flate stream: ' + cmf + ', ' + flg);
- if ((cmf & 0x0f) != 0x08)
+ }
+ if ((cmf & 0x0f) != 0x08) {
error('Unknown compression method in flate stream: ' + cmf + ', ' + flg);
- if ((((cmf << 8) + flg) % 31) !== 0)
+ }
+ if ((((cmf << 8) + flg) % 31) !== 0) {
error('Bad FCHECK in flate stream: ' + cmf + ', ' + flg);
- if (flg & 0x20)
+ }
+ if (flg & 0x20) {
error('FDICT bit set in flate stream: ' + cmf + ', ' + flg);
+ }
this.codeSize = 0;
this.codeBuf = 0;
@@ -33678,8 +35704,9 @@ var FlateStream = (function FlateStreamClosure() {
var code = codes[codeBuf & ((1 << maxLen) - 1)];
var codeLen = code >> 16;
var codeVal = code & 0xffff;
- if (codeSize === 0 || codeSize < codeLen || codeLen === 0)
+ if (codeSize === 0 || codeSize < codeLen || codeLen === 0) {
error('Bad encoding in flate stream');
+ }
this.codeBuf = (codeBuf >> codeLen);
this.codeSize = (codeSize - codeLen);
return codeVal;
@@ -33691,9 +35718,11 @@ var FlateStream = (function FlateStreamClosure() {
// find max code length
var maxLen = 0;
- for (var i = 0; i < n; ++i) {
- if (lengths[i] > maxLen)
+ var i;
+ for (i = 0; i < n; ++i) {
+ if (lengths[i] > maxLen) {
maxLen = lengths[i];
+ }
}
// build the table
@@ -33707,15 +35736,15 @@ var FlateStream = (function FlateStreamClosure() {
// bit-reverse the code
var code2 = 0;
var t = code;
- for (var i = 0; i < len; ++i) {
+ for (i = 0; i < len; ++i) {
code2 = (code2 << 1) | (t & 1);
t >>= 1;
}
// fill the table entries
- for (var i = code2; i < size; i += skip)
+ for (i = code2; i < size; i += skip) {
codes[i] = (len << 16) | val;
-
+ }
++code;
}
}
@@ -33725,11 +35754,13 @@ var FlateStream = (function FlateStreamClosure() {
};
FlateStream.prototype.readBlock = function FlateStream_readBlock() {
+ var buffer, len;
var str = this.str;
// read block header
var hdr = this.getBits(3);
- if (hdr & 1)
+ if (hdr & 1) {
this.eof = true;
+ }
hdr >>= 1;
if (hdr === 0) { // uncompressed block
@@ -33761,7 +35792,7 @@ var FlateStream = (function FlateStreamClosure() {
this.codeSize = 0;
var bufferLength = this.bufferLength;
- var buffer = this.ensureBuffer(bufferLength + blockLen);
+ buffer = this.ensureBuffer(bufferLength + blockLen);
var end = bufferLength + blockLen;
this.bufferLength = end;
if (blockLen === 0) {
@@ -33793,31 +35824,35 @@ var FlateStream = (function FlateStreamClosure() {
// build the code lengths code table
var codeLenCodeLengths = new Uint8Array(codeLenCodeMap.length);
- for (var i = 0; i < numCodeLenCodes; ++i)
+ var i;
+ for (i = 0; i < numCodeLenCodes; ++i) {
codeLenCodeLengths[codeLenCodeMap[i]] = this.getBits(3);
+ }
var codeLenCodeTab = this.generateHuffmanTable(codeLenCodeLengths);
// build the literal and distance code tables
- var len = 0;
- var i = 0;
+ len = 0;
+ i = 0;
var codes = numLitCodes + numDistCodes;
var codeLengths = new Uint8Array(codes);
+ var bitsLength, bitsOffset, what;
while (i < codes) {
var code = this.getCode(codeLenCodeTab);
if (code == 16) {
- var bitsLength = 2, bitsOffset = 3, what = len;
+ bitsLength = 2; bitsOffset = 3; what = len;
} else if (code == 17) {
- var bitsLength = 3, bitsOffset = 3, what = (len = 0);
+ bitsLength = 3; bitsOffset = 3; what = (len = 0);
} else if (code == 18) {
- var bitsLength = 7, bitsOffset = 11, what = (len = 0);
+ bitsLength = 7; bitsOffset = 11; what = (len = 0);
} else {
codeLengths[i++] = len = code;
continue;
}
var repeatLength = this.getBits(bitsLength) + bitsOffset;
- while (repeatLength-- > 0)
+ while (repeatLength-- > 0) {
codeLengths[i++] = what;
+ }
}
litCodeTable =
@@ -33828,7 +35863,7 @@ var FlateStream = (function FlateStreamClosure() {
error('Unknown block type in flate stream');
}
- var buffer = this.buffer;
+ buffer = this.buffer;
var limit = buffer ? buffer.length : 0;
var pos = this.bufferLength;
while (true) {
@@ -33848,21 +35883,24 @@ var FlateStream = (function FlateStreamClosure() {
code1 -= 257;
code1 = lengthDecode[code1];
var code2 = code1 >> 16;
- if (code2 > 0)
+ if (code2 > 0) {
code2 = this.getBits(code2);
- var len = (code1 & 0xffff) + code2;
+ }
+ len = (code1 & 0xffff) + code2;
code1 = this.getCode(distCodeTable);
code1 = distDecode[code1];
code2 = code1 >> 16;
- if (code2 > 0)
+ if (code2 > 0) {
code2 = this.getBits(code2);
+ }
var dist = (code1 & 0xffff) + code2;
if (pos + len >= limit) {
buffer = this.ensureBuffer(pos + len);
limit = buffer.length;
}
- for (var k = 0; k < len; ++k, ++pos)
+ for (var k = 0; k < len; ++k, ++pos) {
buffer[pos] = buffer[pos - dist];
+ }
}
};
@@ -33873,15 +35911,18 @@ var PredictorStream = (function PredictorStreamClosure() {
function PredictorStream(str, maybeLength, params) {
var predictor = this.predictor = params.get('Predictor') || 1;
- if (predictor <= 1)
+ if (predictor <= 1) {
return str; // no prediction
- if (predictor !== 2 && (predictor < 10 || predictor > 15))
+ }
+ if (predictor !== 2 && (predictor < 10 || predictor > 15)) {
error('Unsupported predictor: ' + predictor);
+ }
- if (predictor === 2)
+ if (predictor === 2) {
this.readBlock = this.readBlockTiff;
- else
+ } else {
this.readBlock = this.readBlockPng;
+ }
this.str = str;
this.dict = str.dict;
@@ -33900,7 +35941,7 @@ var PredictorStream = (function PredictorStreamClosure() {
PredictorStream.prototype = Object.create(DecodeStream.prototype);
PredictorStream.prototype.readBlockTiff =
- function predictorStreamReadBlockTiff() {
+ function predictorStreamReadBlockTiff() {
var rowBytes = this.rowBytes;
var bufferLength = this.bufferLength;
@@ -33918,9 +35959,10 @@ var PredictorStream = (function PredictorStreamClosure() {
var inbuf = 0, outbuf = 0;
var inbits = 0, outbits = 0;
var pos = bufferLength;
+ var i;
if (bits === 1) {
- for (var i = 0; i < rowBytes; ++i) {
+ for (i = 0; i < rowBytes; ++i) {
var c = rawBytes[i];
inbuf = (inbuf << 8) | c;
// bitwise addition is exclusive or
@@ -33930,8 +35972,9 @@ var PredictorStream = (function PredictorStreamClosure() {
inbuf &= 0xFFFF;
}
} else if (bits === 8) {
- for (var i = 0; i < colors; ++i)
+ for (i = 0; i < colors; ++i) {
buffer[pos++] = rawBytes[i];
+ }
for (; i < rowBytes; ++i) {
buffer[pos] = buffer[pos - colors] + rawBytes[i];
pos++;
@@ -33941,7 +35984,7 @@ var PredictorStream = (function PredictorStreamClosure() {
var bitMask = (1 << bits) - 1;
var j = 0, k = bufferLength;
var columns = this.columns;
- for (var i = 0; i < columns; ++i) {
+ for (i = 0; i < columns; ++i) {
for (var kk = 0; kk < colors; ++kk) {
if (inbits < bits) {
inbuf = (inbuf << 8) | (rawBytes[j++] & 0xFF);
@@ -33960,14 +36003,14 @@ var PredictorStream = (function PredictorStreamClosure() {
}
if (outbits > 0) {
buffer[k++] = (outbuf << (8 - outbits)) +
- (inbuf & ((1 << (8 - outbits)) - 1));
+ (inbuf & ((1 << (8 - outbits)) - 1));
}
}
this.bufferLength += rowBytes;
};
PredictorStream.prototype.readBlockPng =
- function predictorStreamReadBlockPng() {
+ function predictorStreamReadBlockPng() {
var rowBytes = this.rowBytes;
var pixBytes = this.pixBytes;
@@ -33983,30 +36026,35 @@ var PredictorStream = (function PredictorStreamClosure() {
var buffer = this.ensureBuffer(bufferLength + rowBytes);
var prevRow = buffer.subarray(bufferLength - rowBytes, bufferLength);
- if (prevRow.length === 0)
+ if (prevRow.length === 0) {
prevRow = new Uint8Array(rowBytes);
+ }
- var j = bufferLength;
+ var i, j = bufferLength, up, c;
switch (predictor) {
case 0:
- for (var i = 0; i < rowBytes; ++i)
+ for (i = 0; i < rowBytes; ++i) {
buffer[j++] = rawBytes[i];
+ }
break;
case 1:
- for (var i = 0; i < pixBytes; ++i)
+ for (i = 0; i < pixBytes; ++i) {
buffer[j++] = rawBytes[i];
+ }
for (; i < rowBytes; ++i) {
buffer[j] = (buffer[j - pixBytes] + rawBytes[i]) & 0xFF;
j++;
}
break;
case 2:
- for (var i = 0; i < rowBytes; ++i)
+ for (i = 0; i < rowBytes; ++i) {
buffer[j++] = (prevRow[i] + rawBytes[i]) & 0xFF;
+ }
break;
case 3:
- for (var i = 0; i < pixBytes; ++i)
+ for (i = 0; i < pixBytes; ++i) {
buffer[j++] = (prevRow[i] >> 1) + rawBytes[i];
+ }
for (; i < rowBytes; ++i) {
buffer[j] = (((prevRow[i] + buffer[j - pixBytes]) >> 1) +
rawBytes[i]) & 0xFF;
@@ -34016,34 +36064,38 @@ var PredictorStream = (function PredictorStreamClosure() {
case 4:
// we need to save the up left pixels values. the simplest way
// is to create a new buffer
- for (var i = 0; i < pixBytes; ++i) {
- var up = prevRow[i];
- var c = rawBytes[i];
+ for (i = 0; i < pixBytes; ++i) {
+ up = prevRow[i];
+ c = rawBytes[i];
buffer[j++] = up + c;
}
for (; i < rowBytes; ++i) {
- var up = prevRow[i];
+ up = prevRow[i];
var upLeft = prevRow[i - pixBytes];
var left = buffer[j - pixBytes];
var p = left + up - upLeft;
var pa = p - left;
- if (pa < 0)
+ if (pa < 0) {
pa = -pa;
+ }
var pb = p - up;
- if (pb < 0)
+ if (pb < 0) {
pb = -pb;
+ }
var pc = p - upLeft;
- if (pc < 0)
+ if (pc < 0) {
pc = -pc;
+ }
- var c = rawBytes[i];
- if (pa <= pb && pa <= pc)
+ c = rawBytes[i];
+ if (pa <= pb && pa <= pc) {
buffer[j++] = left + c;
- else if (pb <= pc)
+ } else if (pb <= pc) {
buffer[j++] = up + c;
- else
+ } else {
buffer[j++] = upLeft + c;
+ }
}
break;
default:
@@ -34084,16 +36136,17 @@ var JpegStream = (function JpegStreamClosure() {
});
JpegStream.prototype.ensureBuffer = function JpegStream_ensureBuffer(req) {
- if (this.bufferLength)
+ if (this.bufferLength) {
return;
+ }
try {
var jpegImage = new JpegImage();
- if (this.colorTransform != -1)
+ 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);
+ var data = jpegImage.getData(this.drawWidth, this.drawHeight,
+ /* forceRGBoutput = */true);
this.buffer = data;
this.bufferLength = data.length;
this.eof = true;
@@ -34101,6 +36154,12 @@ var JpegStream = (function JpegStreamClosure() {
error('JPEG error: ' + e);
}
};
+
+ JpegStream.prototype.getBytes = function JpegStream_getBytes(length) {
+ this.ensureBuffer();
+ return this.buffer;
+ };
+
JpegStream.prototype.getIR = function JpegStream_getIR() {
return PDFJS.createObjectURL(this.bytes, 'image/jpeg');
};
@@ -34109,7 +36168,7 @@ var JpegStream = (function JpegStreamClosure() {
* further processing such as color space conversions.
*/
JpegStream.prototype.isNativelySupported =
- function JpegStream_isNativelySupported(xref, res) {
+ function JpegStream_isNativelySupported(xref, res) {
var cs = ColorSpace.parse(this.dict.get('ColorSpace', 'CS'), xref, res);
return cs.name === 'DeviceGray' || cs.name === 'DeviceRGB';
};
@@ -34117,7 +36176,7 @@ var JpegStream = (function JpegStreamClosure() {
* Checks if the image can be decoded by the browser.
*/
JpegStream.prototype.isNativelyDecodable =
- function JpegStream_isNativelyDecodable(xref, res) {
+ function JpegStream_isNativelyDecodable(xref, res) {
var cs = ColorSpace.parse(this.dict.get('ColorSpace', 'CS'), xref, res);
var numComps = cs.numComps;
return numComps == 1 || numComps == 3;
@@ -34150,8 +36209,9 @@ var JpxStream = (function JpxStreamClosure() {
});
JpxStream.prototype.ensureBuffer = function JpxStream_ensureBuffer(req) {
- if (this.bufferLength)
+ if (this.bufferLength) {
return;
+ }
var jpxImage = new JpxImage();
jpxImage.parse(this.bytes);
@@ -34159,75 +36219,35 @@ var JpxStream = (function JpxStreamClosure() {
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 tileCount = jpxImage.tiles.length;
+ if (tileCount === 1) {
+ this.buffer = jpxImage.tiles[0].items;
+ } else {
+ var data = new Uint8Array(width * height * componentsCount);
- var dataPosition, sourcePosition, data0, data1, data2, data3, rowFeed;
- switch (componentsCount) {
- case 1:
- data0 = tileCompoments[0].items;
+ for (var k = 0; k < tileCount; k++) {
+ var tileComponents = jpxImage.tiles[k];
+ var tileWidth = tileComponents.width;
+ var tileHeight = tileComponents.height;
+ var tileLeft = tileComponents.left;
+ var tileTop = tileComponents.top;
- 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;
+ var src = tileComponents.items;
+ var srcPosition = 0;
+ var dataPosition = (width * tileTop + tileLeft) * componentsCount;
+ var imgRowSize = width * componentsCount;
+ var tileRowSize = tileWidth * componentsCount;
- 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;
+ for (var j = 0; j < tileHeight; j++) {
+ var rowBytes = src.subarray(srcPosition, srcPosition + tileRowSize);
+ data.set(rowBytes, dataPosition);
+ srcPosition += tileRowSize;
+ dataPosition += imgRowSize;
+ }
}
+ this.buffer = data;
}
-
- this.buffer = data;
- this.bufferLength = data.length;
+ this.bufferLength = this.buffer.length;
this.eof = true;
};
@@ -34258,8 +36278,9 @@ var Jbig2Stream = (function Jbig2StreamClosure() {
});
Jbig2Stream.prototype.ensureBuffer = function Jbig2Stream_ensureBuffer(req) {
- if (this.bufferLength)
+ if (this.bufferLength) {
return;
+ }
var jbig2Image = new Jbig2Image();
@@ -34284,8 +36305,9 @@ var Jbig2Stream = (function Jbig2StreamClosure() {
var dataLength = data.length;
// JBIG2 had black as 1 and white as 0, inverting the colors
- for (var i = 0; i < dataLength; i++)
+ for (var i = 0; i < dataLength; i++) {
data[i] ^= 0xFF;
+ }
this.buffer = data;
this.bufferLength = dataLength;
@@ -34331,8 +36353,9 @@ var DecryptStream = (function DecryptStreamClosure() {
var bufferLength = this.bufferLength;
var i, n = chunk.length;
var buffer = this.ensureBuffer(bufferLength + n);
- for (i = 0; i < n; i++)
+ for (i = 0; i < n; i++) {
buffer[bufferLength++] = chunk[i];
+ }
this.bufferLength = bufferLength;
};
@@ -34373,17 +36396,19 @@ var Ascii85Stream = (function Ascii85StreamClosure() {
}
var bufferLength = this.bufferLength, buffer;
+ var i;
// special code for z
if (c == Z_LOWER_CHAR) {
buffer = this.ensureBuffer(bufferLength + 4);
- for (var i = 0; i < 4; ++i)
+ for (i = 0; i < 4; ++i) {
buffer[bufferLength + i] = 0;
+ }
this.bufferLength += 4;
} else {
var input = this.input;
input[0] = c;
- for (var i = 1; i < 5; ++i) {
+ for (i = 1; i < 5; ++i) {
c = str.getByte();
while (Lexer.isSpace(c)) {
c = str.getByte();
@@ -34391,23 +36416,26 @@ var Ascii85Stream = (function Ascii85StreamClosure() {
input[i] = c;
- if (c === EOF || c == TILDA_CHAR)
+ if (c === EOF || c == TILDA_CHAR) {
break;
+ }
}
buffer = this.ensureBuffer(bufferLength + i - 1);
this.bufferLength += i - 1;
// partial ending;
if (i < 5) {
- for (; i < 5; ++i)
+ for (; i < 5; ++i) {
input[i] = 0x21 + 84;
+ }
this.eof = true;
}
var t = 0;
- for (var i = 0; i < 5; ++i)
+ for (i = 0; i < 5; ++i) {
t = t * 85 + (input[i] - 0x21);
+ }
- for (var i = 3; i >= 0; --i) {
+ for (i = 3; i >= 0; --i) {
buffer[bufferLength + i] = t & 0xFF;
t >>= 8;
}
@@ -34500,11 +36528,12 @@ var RunLengthStream = (function RunLengthStreamClosure() {
return;
}
+ var buffer;
var bufferLength = this.bufferLength;
var n = repeatHeader[0];
if (n < 128) {
// copy n bytes
- var buffer = this.ensureBuffer(bufferLength + n + 1);
+ buffer = this.ensureBuffer(bufferLength + n + 1);
buffer[bufferLength++] = repeatHeader[1];
if (n > 0) {
var source = this.str.getBytes(n);
@@ -34514,9 +36543,10 @@ var RunLengthStream = (function RunLengthStreamClosure() {
} else {
n = 257 - n;
var b = repeatHeader[1];
- var buffer = this.ensureBuffer(bufferLength + n + 1);
- for (var i = 0; i < n; i++)
+ buffer = this.ensureBuffer(bufferLength + n + 1);
+ for (var i = 0; i < n; i++) {
buffer[bufferLength++] = b;
+ }
}
this.bufferLength = bufferLength;
};
@@ -34956,7 +36986,7 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
this.str = str;
this.dict = str.dict;
- params = params || new Dict();
+ params = params || Dict.empty;
this.encoding = params.get('K') || 0;
this.eoline = params.get('EndOfLine') || false;
@@ -34964,8 +36994,9 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
this.columns = params.get('Columns') || 1728;
this.rows = params.get('Rows') || 0;
var eoblock = params.get('EndOfBlock');
- if (eoblock === null || eoblock === undefined)
+ if (eoblock === null || eoblock === undefined) {
eoblock = true;
+ }
this.eoblock = eoblock;
this.black = params.get('BlackIs1') || false;
@@ -35007,7 +37038,7 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
};
CCITTFaxStream.prototype.addPixels =
- function ccittFaxStreamAddPixels(a1, blackPixels) {
+ function ccittFaxStreamAddPixels(a1, blackPixels) {
var codingLine = this.codingLine;
var codingPos = this.codingPos;
@@ -35027,7 +37058,7 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
};
CCITTFaxStream.prototype.addPixelsNeg =
- function ccittFaxStreamAddPixelsNeg(a1, blackPixels) {
+ function ccittFaxStreamAddPixelsNeg(a1, blackPixels) {
var codingLine = this.codingLine;
var codingPos = this.codingPos;
@@ -35037,8 +37068,9 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
this.err = true;
a1 = this.columns;
}
- if ((codingPos & 1) ^ blackPixels)
+ if ((codingPos & 1) ^ blackPixels) {
++codingPos;
+ }
codingLine[codingPos] = a1;
} else if (a1 < codingLine[codingPos]) {
@@ -35047,8 +37079,9 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
this.err = true;
a1 = 0;
}
- while (codingPos > 0 && a1 < codingLine[codingPos - 1])
+ while (codingPos > 0 && a1 < codingLine[codingPos - 1]) {
--codingPos;
+ }
codingLine[codingPos] = a1;
}
@@ -35060,19 +37093,19 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
var codingLine = this.codingLine;
var columns = this.columns;
- var refPos, blackPixels, bits;
+ var refPos, blackPixels, bits, i;
if (this.outputBits === 0) {
- if (this.eof)
+ if (this.eof) {
return null;
-
+ }
this.err = false;
var code1, code2, code3;
if (this.nextLine2D) {
- for (var i = 0; codingLine[i] < columns; ++i)
+ for (i = 0; codingLine[i] < columns; ++i) {
refLine[i] = codingLine[i];
-
+ }
refLine[i++] = columns;
refLine[i] = columns;
codingLine[0] = 0;
@@ -35085,8 +37118,9 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
switch (code1) {
case twoDimPass:
this.addPixels(refLine[refPos + 1], blackPixels);
- if (refLine[refPos + 1] < columns)
+ if (refLine[refPos + 1] < columns) {
refPos += 2;
+ }
break;
case twoDimHoriz:
code1 = code2 = 0;
@@ -35122,8 +37156,9 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
if (codingLine[this.codingPos] < columns) {
++refPos;
while (refLine[refPos] <= codingLine[this.codingPos] &&
- refLine[refPos] < columns)
+ refLine[refPos] < columns) {
refPos += 2;
+ }
}
break;
case twoDimVertR2:
@@ -35143,8 +37178,9 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
if (codingLine[this.codingPos] < columns) {
++refPos;
while (refLine[refPos] <= codingLine[this.codingPos] &&
- refLine[refPos] < columns)
+ refLine[refPos] < columns) {
refPos += 2;
+ }
}
break;
case twoDimVert0:
@@ -35153,48 +37189,54 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
if (codingLine[this.codingPos] < columns) {
++refPos;
while (refLine[refPos] <= codingLine[this.codingPos] &&
- refLine[refPos] < columns)
+ refLine[refPos] < columns) {
refPos += 2;
+ }
}
break;
case twoDimVertL3:
this.addPixelsNeg(refLine[refPos] - 3, blackPixels);
blackPixels ^= 1;
if (codingLine[this.codingPos] < columns) {
- if (refPos > 0)
+ if (refPos > 0) {
--refPos;
- else
+ } else {
++refPos;
+ }
while (refLine[refPos] <= codingLine[this.codingPos] &&
- refLine[refPos] < columns)
+ refLine[refPos] < columns) {
refPos += 2;
+ }
}
break;
case twoDimVertL2:
this.addPixelsNeg(refLine[refPos] - 2, blackPixels);
blackPixels ^= 1;
if (codingLine[this.codingPos] < columns) {
- if (refPos > 0)
+ if (refPos > 0) {
--refPos;
- else
+ } else {
++refPos;
+ }
while (refLine[refPos] <= codingLine[this.codingPos] &&
- refLine[refPos] < columns)
+ refLine[refPos] < columns) {
refPos += 2;
+ }
}
break;
case twoDimVertL1:
this.addPixelsNeg(refLine[refPos] - 1, blackPixels);
blackPixels ^= 1;
if (codingLine[this.codingPos] < columns) {
- if (refPos > 0)
+ if (refPos > 0) {
--refPos;
- else
+ } else {
++refPos;
-
+ }
while (refLine[refPos] <= codingLine[this.codingPos] &&
- refLine[refPos] < columns)
+ refLine[refPos] < columns) {
refPos += 2;
+ }
}
break;
case EOF:
@@ -35227,8 +37269,9 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
}
}
- if (this.byteAlign)
+ if (this.byteAlign) {
this.inputBits &= ~7;
+ }
var gotEOL = false;
@@ -35262,10 +37305,11 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
this.eatBits(1);
}
if (this.encoding >= 0) {
- for (var i = 0; i < 4; ++i) {
+ for (i = 0; i < 4; ++i) {
code1 = this.lookBits(12);
- if (code1 != 1)
+ if (code1 != 1) {
info('bad rtc code: ' + code1);
+ }
this.eatBits(12);
if (this.encoding > 0) {
this.lookBits(1);
@@ -35294,10 +37338,11 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
}
}
- if (codingLine[0] > 0)
+ if (codingLine[0] > 0) {
this.outputBits = codingLine[this.codingPos = 0];
- else
+ } else {
this.outputBits = codingLine[this.codingPos = 1];
+ }
this.row++;
}
@@ -35311,7 +37356,7 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
codingLine[this.codingPos - 1]);
}
} else {
- var bits = 8;
+ bits = 8;
c = 0;
do {
if (this.outputBits > bits) {
@@ -35352,15 +37397,17 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
// returned. The second array element is the actual code. The third array
// element indicates whether EOF was reached.
CCITTFaxStream.prototype.findTableCode =
- function ccittFaxStreamFindTableCode(start, end, table, limit) {
+ function ccittFaxStreamFindTableCode(start, end, table, limit) {
var limitValue = limit || 0;
for (var i = start; i <= end; ++i) {
var code = this.lookBits(i);
- if (code == EOF)
+ if (code == EOF) {
return [true, 1, false];
- if (i < end)
+ }
+ if (i < end) {
code <<= end - i;
+ }
if (!limitValue || code >= limitValue) {
var p = table[code - limitValue];
if (p[0] == i) {
@@ -35373,7 +37420,7 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
};
CCITTFaxStream.prototype.getTwoDimCode =
- function ccittFaxStreamGetTwoDimCode() {
+ function ccittFaxStreamGetTwoDimCode() {
var code = 0;
var p;
@@ -35386,28 +37433,30 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
}
} else {
var result = this.findTableCode(1, 7, twoDimTable);
- if (result[0] && result[2])
+ if (result[0] && result[2]) {
return result[1];
+ }
}
info('Bad two dim code');
return EOF;
};
CCITTFaxStream.prototype.getWhiteCode =
- function ccittFaxStreamGetWhiteCode() {
+ function ccittFaxStreamGetWhiteCode() {
var code = 0;
var p;
- var n;
if (this.eoblock) {
code = this.lookBits(12);
- if (code == EOF)
+ if (code == EOF) {
return 1;
+ }
- if ((code >> 5) === 0)
+ if ((code >> 5) === 0) {
p = whiteTable1[code];
- else
+ } else {
p = whiteTable2[code >> 3];
+ }
if (p[0] > 0) {
this.eatBits(p[0]);
@@ -35415,12 +37464,14 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
}
} else {
var result = this.findTableCode(1, 9, whiteTable2);
- if (result[0])
+ if (result[0]) {
return result[1];
+ }
result = this.findTableCode(11, 12, whiteTable1);
- if (result[0])
+ if (result[0]) {
return result[1];
+ }
}
info('bad white code');
this.eatBits(1);
@@ -35428,19 +37479,21 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
};
CCITTFaxStream.prototype.getBlackCode =
- function ccittFaxStreamGetBlackCode() {
+ function ccittFaxStreamGetBlackCode() {
var code, p;
if (this.eoblock) {
code = this.lookBits(13);
- if (code == EOF)
+ if (code == EOF) {
return 1;
- if ((code >> 7) === 0)
+ }
+ if ((code >> 7) === 0) {
p = blackTable1[code];
- else if ((code >> 9) === 0 && (code >> 7) !== 0)
+ } else if ((code >> 9) === 0 && (code >> 7) !== 0) {
p = blackTable2[(code >> 1) - 64];
- else
+ } else {
p = blackTable3[code >> 7];
+ }
if (p[0] > 0) {
this.eatBits(p[0]);
@@ -35448,16 +37501,19 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
}
} else {
var result = this.findTableCode(2, 6, blackTable3);
- if (result[0])
+ if (result[0]) {
return result[1];
+ }
result = this.findTableCode(7, 12, blackTable2, 64);
- if (result[0])
+ if (result[0]) {
return result[1];
+ }
result = this.findTableCode(10, 13, blackTable1);
- if (result[0])
+ if (result[0]) {
return result[1];
+ }
}
info('bad black code');
this.eatBits(1);
@@ -35468,8 +37524,9 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
var c;
while (this.inputBits < n) {
if ((c = this.str.getByte()) === -1) {
- if (this.inputBits === 0)
+ if (this.inputBits === 0) {
return EOF;
+ }
return ((this.inputBuf << (n - this.inputBits)) &
(0xFFFF >> (16 - n)));
}
@@ -35480,8 +37537,9 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
};
CCITTFaxStream.prototype.eatBits = function CCITTFaxStream_eatBits(n) {
- if ((this.inputBits -= n) < 0)
+ if ((this.inputBits -= n) < 0) {
this.inputBits = 0;
+ }
};
return CCITTFaxStream;
@@ -35540,8 +37598,9 @@ var LZWStream = (function LZWStreamClosure() {
var i, j, q;
var lzwState = this.lzwState;
- if (!lzwState)
+ if (!lzwState) {
return; // eof was found
+ }
var earlyChange = lzwState.earlyChange;
var nextCode = lzwState.nextCode;
@@ -35602,8 +37661,9 @@ var LZWStream = (function LZWStreamClosure() {
} while (estimatedDecodedSize < decodedLength);
buffer = this.ensureBuffer(this.bufferLength + estimatedDecodedSize);
}
- for (j = 0; j < currentSequenceLength; j++)
+ for (j = 0; j < currentSequenceLength; j++) {
buffer[currentBufferLength++] = currentSequence[j];
+ }
}
lzwState.nextCode = nextCode;
lzwState.codeLength = codeLength;
@@ -35632,70 +37692,59 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = {
var pdfManager;
function loadDocument(recoveryMode) {
- var loadDocumentPromise = new LegacyPromise();
+ var loadDocumentCapability = createPromiseCapability();
var parseSuccess = function parseSuccess() {
- var numPagesPromise = pdfManager.ensureModel('numPages');
- var fingerprintPromise = pdfManager.ensureModel('fingerprint');
- var outlinePromise = pdfManager.ensureCatalog('documentOutline');
- var infoPromise = pdfManager.ensureModel('documentInfo');
- var metadataPromise = pdfManager.ensureCatalog('metadata');
+ var numPagesPromise = pdfManager.ensureDoc('numPages');
+ var fingerprintPromise = pdfManager.ensureDoc('fingerprint');
var encryptedPromise = pdfManager.ensureXRef('encrypt');
- var javaScriptPromise = pdfManager.ensureCatalog('javaScript');
- Promise.all([numPagesPromise, fingerprintPromise, outlinePromise,
- infoPromise, metadataPromise, encryptedPromise,
- javaScriptPromise]).then(
- function onDocReady(results) {
-
+ Promise.all([numPagesPromise, fingerprintPromise,
+ encryptedPromise]).then(function onDocReady(results) {
var doc = {
numPages: results[0],
fingerprint: results[1],
- outline: results[2],
- info: results[3],
- metadata: results[4],
- encrypted: !!results[5],
- javaScript: results[6]
+ encrypted: !!results[2],
};
- loadDocumentPromise.resolve(doc);
+ loadDocumentCapability.resolve(doc);
},
parseFailure);
};
var parseFailure = function parseFailure(e) {
- loadDocumentPromise.reject(e);
+ loadDocumentCapability.reject(e);
};
- pdfManager.ensureModel('checkHeader', []).then(function() {
- pdfManager.ensureModel('parseStartXRef', []).then(function() {
- pdfManager.ensureModel('parse', [recoveryMode]).then(
- parseSuccess, parseFailure);
+ pdfManager.ensureDoc('checkHeader', []).then(function() {
+ pdfManager.ensureDoc('parseStartXRef', []).then(function() {
+ pdfManager.ensureDoc('parse', [recoveryMode]).then(
+ parseSuccess, parseFailure);
}, parseFailure);
}, parseFailure);
- return loadDocumentPromise;
+ return loadDocumentCapability.promise;
}
function getPdfManager(data) {
- var pdfManagerPromise = new LegacyPromise();
+ var pdfManagerCapability = createPromiseCapability();
var source = data.source;
var disableRange = data.disableRange;
if (source.data) {
try {
pdfManager = new LocalPdfManager(source.data, source.password);
- pdfManagerPromise.resolve();
+ pdfManagerCapability.resolve();
} catch (ex) {
- pdfManagerPromise.reject(ex);
+ pdfManagerCapability.reject(ex);
}
- return pdfManagerPromise;
+ return pdfManagerCapability.promise;
} else if (source.chunkedViewerLoading) {
try {
pdfManager = new NetworkPdfManager(source, handler);
- pdfManagerPromise.resolve();
+ pdfManagerCapability.resolve();
} catch (ex) {
- pdfManagerPromise.reject(ex);
+ pdfManagerCapability.reject(ex);
}
- return pdfManagerPromise;
+ return pdfManagerCapability.promise;
}
var networkManager = new NetworkManager(source.url, {
@@ -35740,9 +37789,9 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = {
try {
pdfManager = new NetworkPdfManager(source, handler);
- pdfManagerPromise.resolve(pdfManager);
+ pdfManagerCapability.resolve(pdfManager);
} catch (ex) {
- pdfManagerPromise.reject(ex);
+ pdfManagerCapability.reject(ex);
}
},
@@ -35750,21 +37799,21 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = {
// the data is array, instantiating directly from it
try {
pdfManager = new LocalPdfManager(args.chunk, source.password);
- pdfManagerPromise.resolve();
+ pdfManagerCapability.resolve();
} catch (ex) {
- pdfManagerPromise.reject(ex);
+ pdfManagerCapability.reject(ex);
}
},
onError: function onError(status) {
if (status == 404) {
- var exception = new MissingPDFException( 'Missing PDF "' +
- source.url + '".');
+ var exception = new MissingPDFException('Missing PDF "' +
+ source.url + '".');
handler.send('MissingPDF', { exception: exception });
} else {
handler.send('DocError', 'Unexpected server response (' +
- status + ') while retrieving PDF "' +
- source.url + '".');
+ status + ') while retrieving PDF "' +
+ source.url + '".');
}
},
@@ -35776,7 +37825,7 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = {
}
});
- return pdfManagerPromise;
+ return pdfManagerCapability.promise;
}
handler.on('test', function wphSetupTest(data) {
@@ -35846,6 +37895,7 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = {
PDFJS.verbosity = data.verbosity;
PDFJS.cMapUrl = data.cMapUrl === undefined ?
null : data.cMapUrl;
+ PDFJS.cMapPacked = data.cMapPacked === true;
getPdfManager(data).then(function () {
pdfManager.onLoadedStream().then(function(stream) {
@@ -35858,9 +37908,7 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = {
if (ex instanceof PasswordException) {
// after password exception prepare to receive a new password
// to repeat loading
- pdfManager.passwordChangedPromise =
- new LegacyPromise();
- pdfManager.passwordChangedPromise.then(pdfManagerReady);
+ pdfManager.passwordChanged().then(pdfManagerReady);
}
onFailure(ex);
@@ -35875,46 +37923,64 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = {
}, onFailure);
});
- handler.on('GetPageRequest', function wphSetupGetPage(data) {
- var pageIndex = data.pageIndex;
- pdfManager.getPage(pageIndex).then(function(page) {
+ handler.on('GetPage', function wphSetupGetPage(data) {
+ return pdfManager.getPage(data.pageIndex).then(function(page) {
var rotatePromise = pdfManager.ensure(page, 'rotate');
var refPromise = pdfManager.ensure(page, 'ref');
var viewPromise = pdfManager.ensure(page, 'view');
- Promise.all([rotatePromise, refPromise, viewPromise]).then(
+ return Promise.all([rotatePromise, refPromise, viewPromise]).then(
function(results) {
- var page = {
- pageIndex: data.pageIndex,
+ return {
rotate: results[0],
ref: results[1],
view: results[2]
};
-
- handler.send('GetPage', { pageInfo: page });
});
});
});
- handler.on('GetPageIndex', function wphSetupGetPageIndex(data, deferred) {
+ handler.on('GetPageIndex', function wphSetupGetPageIndex(data) {
var ref = new Ref(data.ref.num, data.ref.gen);
- pdfManager.pdfModel.catalog.getPageIndex(ref).then(function (pageIndex) {
- deferred.resolve(pageIndex);
- }, deferred.reject);
+ var catalog = pdfManager.pdfDocument.catalog;
+ return catalog.getPageIndex(ref);
});
handler.on('GetDestinations',
- function wphSetupGetDestinations(data, deferred) {
- pdfManager.ensureCatalog('destinations').then(function(destinations) {
- deferred.resolve(destinations);
- });
+ function wphSetupGetDestinations(data) {
+ return pdfManager.ensureCatalog('destinations');
+ }
+ );
+
+ handler.on('GetAttachments',
+ function wphSetupGetAttachments(data) {
+ return pdfManager.ensureCatalog('attachments');
+ }
+ );
+
+ handler.on('GetJavaScript',
+ function wphSetupGetJavaScript(data) {
+ return pdfManager.ensureCatalog('javaScript');
+ }
+ );
+
+ handler.on('GetOutline',
+ function wphSetupGetOutline(data) {
+ return pdfManager.ensureCatalog('documentOutline');
}
);
- handler.on('GetData', function wphSetupGetData(data, deferred) {
+ handler.on('GetMetadata',
+ function wphSetupGetMetadata(data) {
+ return Promise.all([pdfManager.ensureDoc('documentInfo'),
+ pdfManager.ensureCatalog('metadata')]);
+ }
+ );
+
+ handler.on('GetData', function wphSetupGetData(data) {
pdfManager.requestLoadedStream();
- pdfManager.onLoadedStream().then(function(stream) {
- deferred.resolve(stream.bytes);
+ return pdfManager.onLoadedStream().then(function(stream) {
+ return stream.bytes;
});
});
@@ -35922,16 +37988,9 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = {
pdfManager.updatePassword(data);
});
- handler.on('GetAnnotationsRequest', function wphSetupGetAnnotations(data) {
- pdfManager.getPage(data.pageIndex).then(function(page) {
- pdfManager.ensure(page, 'getAnnotationsData', []).then(
- function(annotationsData) {
- handler.send('GetAnnotations', {
- pageIndex: data.pageIndex,
- annotations: annotationsData
- });
- }
- );
+ handler.on('GetAnnotations', function wphSetupGetAnnotations(data) {
+ return pdfManager.getPage(data.pageIndex).then(function(page) {
+ return pdfManager.ensure(page, 'getAnnotationsData', []);
});
});
@@ -35949,7 +38008,7 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = {
}, function(e) {
var minimumStackMessage =
- 'worker.js: while trying to getPage() and getOperatorList()';
+ 'worker.js: while trying to getPage() and getOperatorList()';
var wrappedException;
@@ -35980,29 +38039,24 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = {
});
}, this);
- handler.on('GetTextContent', function wphExtractText(data, deferred) {
- pdfManager.getPage(data.pageIndex).then(function(page) {
+ handler.on('GetTextContent', function wphExtractText(data) {
+ return pdfManager.getPage(data.pageIndex).then(function(page) {
var pageNum = data.pageIndex + 1;
var start = Date.now();
- page.extractTextContent().then(function(textContent) {
- deferred.resolve(textContent);
+ return page.extractTextContent().then(function(textContent) {
info('text indexing: page=' + pageNum + ' - time=' +
(Date.now() - start) + 'ms');
- }, function (e) {
- // Skip errored pages
- deferred.reject(e);
+ return textContent;
});
});
});
- handler.on('Cleanup', function wphCleanup(data, deferred) {
- pdfManager.cleanup();
- deferred.resolve(true);
+ handler.on('Cleanup', function wphCleanup(data) {
+ return pdfManager.cleanup();
});
- handler.on('Terminate', function wphTerminate(data, deferred) {
+ handler.on('Terminate', function wphTerminate(data) {
pdfManager.terminate();
- deferred.resolve();
});
}
};
@@ -36228,6 +38282,990 @@ var ArithmeticDecoder = (function ArithmeticDecoderClosure() {
})();
+var JpegImage = (function jpegImage() {
+ var dctZigZag = new Int32Array([
+ 0,
+ 1, 8,
+ 16, 9, 2,
+ 3, 10, 17, 24,
+ 32, 25, 18, 11, 4,
+ 5, 12, 19, 26, 33, 40,
+ 48, 41, 34, 27, 20, 13, 6,
+ 7, 14, 21, 28, 35, 42, 49, 56,
+ 57, 50, 43, 36, 29, 22, 15,
+ 23, 30, 37, 44, 51, 58,
+ 59, 52, 45, 38, 31,
+ 39, 46, 53, 60,
+ 61, 54, 47,
+ 55, 62,
+ 63
+ ]);
+
+ var dctCos1 = 4017; // cos(pi/16)
+ var dctSin1 = 799; // sin(pi/16)
+ var dctCos3 = 3406; // cos(3*pi/16)
+ var dctSin3 = 2276; // sin(3*pi/16)
+ var dctCos6 = 1567; // cos(6*pi/16)
+ var dctSin6 = 3784; // sin(6*pi/16)
+ var dctSqrt2 = 5793; // sqrt(2)
+ var dctSqrt1d2 = 2896; // sqrt(2) / 2
+
+ function constructor() {
+ }
+
+ function buildHuffmanTable(codeLengths, values) {
+ var k = 0, code = [], i, j, length = 16;
+ while (length > 0 && !codeLengths[length - 1]) {
+ length--;
+ }
+ code.push({children: [], index: 0});
+ var p = code[0], q;
+ for (i = 0; i < length; i++) {
+ for (j = 0; j < codeLengths[i]; j++) {
+ p = code.pop();
+ p.children[p.index] = values[k];
+ while (p.index > 0) {
+ p = code.pop();
+ }
+ p.index++;
+ code.push(p);
+ while (code.length <= i) {
+ code.push(q = {children: [], index: 0});
+ p.children[p.index] = q.children;
+ p = q;
+ }
+ k++;
+ }
+ if (i + 1 < length) {
+ // p here points to last code
+ code.push(q = {children: [], index: 0});
+ p.children[p.index] = q.children;
+ p = q;
+ }
+ }
+ return code[0].children;
+ }
+
+ function getBlockBufferOffset(component, row, col) {
+ return 64 * ((component.blocksPerLine + 1) * row + col);
+ }
+
+ function decodeScan(data, offset,
+ frame, components, resetInterval,
+ spectralStart, spectralEnd,
+ successivePrev, successive) {
+ var precision = frame.precision;
+ var samplesPerLine = frame.samplesPerLine;
+ var scanLines = frame.scanLines;
+ var mcusPerLine = frame.mcusPerLine;
+ var progressive = frame.progressive;
+ var maxH = frame.maxH, maxV = frame.maxV;
+
+ var startOffset = offset, bitsData = 0, bitsCount = 0;
+
+ function readBit() {
+ if (bitsCount > 0) {
+ bitsCount--;
+ return (bitsData >> bitsCount) & 1;
+ }
+ bitsData = data[offset++];
+ if (bitsData == 0xFF) {
+ var nextByte = data[offset++];
+ if (nextByte) {
+ throw 'unexpected marker: ' +
+ ((bitsData << 8) | nextByte).toString(16);
+ }
+ // unstuff 0
+ }
+ bitsCount = 7;
+ return bitsData >>> 7;
+ }
+
+ function decodeHuffman(tree) {
+ var node = tree;
+ var bit;
+ while ((bit = readBit()) !== null) {
+ node = node[bit];
+ if (typeof node === 'number') {
+ return node;
+ }
+ if (typeof node !== 'object') {
+ throw 'invalid huffman sequence';
+ }
+ }
+ return null;
+ }
+
+ function receive(length) {
+ var n = 0;
+ while (length > 0) {
+ var bit = readBit();
+ if (bit === null) {
+ return;
+ }
+ n = (n << 1) | bit;
+ length--;
+ }
+ return n;
+ }
+
+ function receiveAndExtend(length) {
+ var n = receive(length);
+ if (n >= 1 << (length - 1)) {
+ return n;
+ }
+ return n + (-1 << length) + 1;
+ }
+
+ function decodeBaseline(component, offset) {
+ var t = decodeHuffman(component.huffmanTableDC);
+ var diff = t === 0 ? 0 : receiveAndExtend(t);
+ component.blockData[offset] = (component.pred += diff);
+ var k = 1;
+ while (k < 64) {
+ var rs = decodeHuffman(component.huffmanTableAC);
+ var s = rs & 15, r = rs >> 4;
+ if (s === 0) {
+ if (r < 15) {
+ break;
+ }
+ k += 16;
+ continue;
+ }
+ k += r;
+ var z = dctZigZag[k];
+ component.blockData[offset + z] = receiveAndExtend(s);
+ k++;
+ }
+ }
+
+ function decodeDCFirst(component, offset) {
+ var t = decodeHuffman(component.huffmanTableDC);
+ var diff = t === 0 ? 0 : (receiveAndExtend(t) << successive);
+ component.blockData[offset] = (component.pred += diff);
+ }
+
+ function decodeDCSuccessive(component, offset) {
+ component.blockData[offset] |= readBit() << successive;
+ }
+
+ var eobrun = 0;
+ function decodeACFirst(component, offset) {
+ if (eobrun > 0) {
+ eobrun--;
+ return;
+ }
+ var k = spectralStart, e = spectralEnd;
+ while (k <= e) {
+ var rs = decodeHuffman(component.huffmanTableAC);
+ var s = rs & 15, r = rs >> 4;
+ if (s === 0) {
+ if (r < 15) {
+ eobrun = receive(r) + (1 << r) - 1;
+ break;
+ }
+ k += 16;
+ continue;
+ }
+ k += r;
+ var z = dctZigZag[k];
+ component.blockData[offset + z] =
+ receiveAndExtend(s) * (1 << successive);
+ k++;
+ }
+ }
+
+ var successiveACState = 0, successiveACNextValue;
+ function decodeACSuccessive(component, offset) {
+ var k = spectralStart;
+ var e = spectralEnd;
+ var r = 0;
+ var s;
+ var rs;
+ while (k <= e) {
+ var z = dctZigZag[k];
+ switch (successiveACState) {
+ case 0: // initial state
+ rs = decodeHuffman(component.huffmanTableAC);
+ s = rs & 15;
+ r = rs >> 4;
+ if (s === 0) {
+ if (r < 15) {
+ eobrun = receive(r) + (1 << r);
+ successiveACState = 4;
+ } else {
+ r = 16;
+ successiveACState = 1;
+ }
+ } else {
+ if (s !== 1) {
+ throw 'invalid ACn encoding';
+ }
+ successiveACNextValue = receiveAndExtend(s);
+ successiveACState = r ? 2 : 3;
+ }
+ continue;
+ case 1: // skipping r zero items
+ case 2:
+ if (component.blockData[offset + z]) {
+ component.blockData[offset + z] += (readBit() << successive);
+ } else {
+ r--;
+ if (r === 0) {
+ successiveACState = successiveACState == 2 ? 3 : 0;
+ }
+ }
+ break;
+ case 3: // set value for a zero item
+ if (component.blockData[offset + z]) {
+ component.blockData[offset + z] += (readBit() << successive);
+ } else {
+ component.blockData[offset + z] =
+ successiveACNextValue << successive;
+ successiveACState = 0;
+ }
+ break;
+ case 4: // eob
+ if (component.blockData[offset + z]) {
+ component.blockData[offset + z] += (readBit() << successive);
+ }
+ break;
+ }
+ k++;
+ }
+ if (successiveACState === 4) {
+ eobrun--;
+ if (eobrun === 0) {
+ successiveACState = 0;
+ }
+ }
+ }
+
+ function decodeMcu(component, decode, mcu, row, col) {
+ var mcuRow = (mcu / mcusPerLine) | 0;
+ var mcuCol = mcu % mcusPerLine;
+ var blockRow = mcuRow * component.v + row;
+ var blockCol = mcuCol * component.h + col;
+ var offset = getBlockBufferOffset(component, blockRow, blockCol);
+ decode(component, offset);
+ }
+
+ function decodeBlock(component, decode, mcu) {
+ var blockRow = (mcu / component.blocksPerLine) | 0;
+ var blockCol = mcu % component.blocksPerLine;
+ var offset = getBlockBufferOffset(component, blockRow, blockCol);
+ decode(component, offset);
+ }
+
+ var componentsLength = components.length;
+ var component, i, j, k, n;
+ var decodeFn;
+ if (progressive) {
+ if (spectralStart === 0) {
+ decodeFn = successivePrev === 0 ? decodeDCFirst : decodeDCSuccessive;
+ } else {
+ decodeFn = successivePrev === 0 ? decodeACFirst : decodeACSuccessive;
+ }
+ } else {
+ decodeFn = decodeBaseline;
+ }
+
+ var mcu = 0, marker;
+ var mcuExpected;
+ if (componentsLength == 1) {
+ mcuExpected = components[0].blocksPerLine * components[0].blocksPerColumn;
+ } else {
+ mcuExpected = mcusPerLine * frame.mcusPerColumn;
+ }
+ if (!resetInterval) {
+ resetInterval = mcuExpected;
+ }
+
+ var h, v;
+ while (mcu < mcuExpected) {
+ // reset interval stuff
+ for (i = 0; i < componentsLength; i++) {
+ components[i].pred = 0;
+ }
+ eobrun = 0;
+
+ if (componentsLength == 1) {
+ component = components[0];
+ for (n = 0; n < resetInterval; n++) {
+ decodeBlock(component, decodeFn, mcu);
+ mcu++;
+ }
+ } else {
+ for (n = 0; n < resetInterval; n++) {
+ for (i = 0; i < componentsLength; i++) {
+ component = components[i];
+ h = component.h;
+ v = component.v;
+ for (j = 0; j < v; j++) {
+ for (k = 0; k < h; k++) {
+ decodeMcu(component, decodeFn, mcu, j, k);
+ }
+ }
+ }
+ mcu++;
+ }
+ }
+
+ // find marker
+ bitsCount = 0;
+ marker = (data[offset] << 8) | data[offset + 1];
+ if (marker <= 0xFF00) {
+ throw 'marker was not found';
+ }
+
+ if (marker >= 0xFFD0 && marker <= 0xFFD7) { // RSTx
+ offset += 2;
+ } else {
+ break;
+ }
+ }
+
+ return offset - startOffset;
+ }
+
+ // A port of poppler's IDCT method which in turn is taken from:
+ // Christoph Loeffler, Adriaan Ligtenberg, George S. Moschytz,
+ // 'Practical Fast 1-D DCT Algorithms with 11 Multiplications',
+ // IEEE Intl. Conf. on Acoustics, Speech & Signal Processing, 1989,
+ // 988-991.
+ function quantizeAndInverse(component, blockBufferOffset, p) {
+ var qt = component.quantizationTable;
+ var v0, v1, v2, v3, v4, v5, v6, v7, t;
+ var i;
+
+ // dequant
+ for (i = 0; i < 64; i++) {
+ p[i] = component.blockData[blockBufferOffset + i] * qt[i];
+ }
+
+ // inverse DCT on rows
+ for (i = 0; i < 8; ++i) {
+ var row = 8 * i;
+
+ // check for all-zero AC coefficients
+ if (p[1 + row] === 0 && p[2 + row] === 0 && p[3 + row] === 0 &&
+ p[4 + row] === 0 && p[5 + row] === 0 && p[6 + row] === 0 &&
+ p[7 + row] === 0) {
+ t = (dctSqrt2 * p[0 + row] + 512) >> 10;
+ p[0 + row] = t;
+ p[1 + row] = t;
+ p[2 + row] = t;
+ p[3 + row] = t;
+ p[4 + row] = t;
+ p[5 + row] = t;
+ p[6 + row] = t;
+ p[7 + row] = t;
+ continue;
+ }
+
+ // stage 4
+ v0 = (dctSqrt2 * p[0 + row] + 128) >> 8;
+ v1 = (dctSqrt2 * p[4 + row] + 128) >> 8;
+ v2 = p[2 + row];
+ v3 = p[6 + row];
+ v4 = (dctSqrt1d2 * (p[1 + row] - p[7 + row]) + 128) >> 8;
+ v7 = (dctSqrt1d2 * (p[1 + row] + p[7 + row]) + 128) >> 8;
+ v5 = p[3 + row] << 4;
+ v6 = p[5 + row] << 4;
+
+ // stage 3
+ t = (v0 - v1+ 1) >> 1;
+ v0 = (v0 + v1 + 1) >> 1;
+ v1 = t;
+ t = (v2 * dctSin6 + v3 * dctCos6 + 128) >> 8;
+ v2 = (v2 * dctCos6 - v3 * dctSin6 + 128) >> 8;
+ v3 = t;
+ t = (v4 - v6 + 1) >> 1;
+ v4 = (v4 + v6 + 1) >> 1;
+ v6 = t;
+ t = (v7 + v5 + 1) >> 1;
+ v5 = (v7 - v5 + 1) >> 1;
+ v7 = t;
+
+ // stage 2
+ t = (v0 - v3 + 1) >> 1;
+ v0 = (v0 + v3 + 1) >> 1;
+ v3 = t;
+ t = (v1 - v2 + 1) >> 1;
+ v1 = (v1 + v2 + 1) >> 1;
+ v2 = t;
+ t = (v4 * dctSin3 + v7 * dctCos3 + 2048) >> 12;
+ v4 = (v4 * dctCos3 - v7 * dctSin3 + 2048) >> 12;
+ v7 = t;
+ t = (v5 * dctSin1 + v6 * dctCos1 + 2048) >> 12;
+ v5 = (v5 * dctCos1 - v6 * dctSin1 + 2048) >> 12;
+ v6 = t;
+
+ // stage 1
+ p[0 + row] = v0 + v7;
+ p[7 + row] = v0 - v7;
+ p[1 + row] = v1 + v6;
+ p[6 + row] = v1 - v6;
+ p[2 + row] = v2 + v5;
+ p[5 + row] = v2 - v5;
+ p[3 + row] = v3 + v4;
+ p[4 + row] = v3 - v4;
+ }
+
+ // inverse DCT on columns
+ for (i = 0; i < 8; ++i) {
+ var col = i;
+
+ // check for all-zero AC coefficients
+ if (p[1*8 + col] === 0 && p[2*8 + col] === 0 && p[3*8 + col] === 0 &&
+ p[4*8 + col] === 0 && p[5*8 + col] === 0 && p[6*8 + col] === 0 &&
+ p[7*8 + col] === 0) {
+ t = (dctSqrt2 * p[i+0] + 8192) >> 14;
+ p[0*8 + col] = t;
+ p[1*8 + col] = t;
+ p[2*8 + col] = t;
+ p[3*8 + col] = t;
+ p[4*8 + col] = t;
+ p[5*8 + col] = t;
+ p[6*8 + col] = t;
+ p[7*8 + col] = t;
+ continue;
+ }
+
+ // stage 4
+ v0 = (dctSqrt2 * p[0*8 + col] + 2048) >> 12;
+ v1 = (dctSqrt2 * p[4*8 + col] + 2048) >> 12;
+ v2 = p[2*8 + col];
+ v3 = p[6*8 + col];
+ v4 = (dctSqrt1d2 * (p[1*8 + col] - p[7*8 + col]) + 2048) >> 12;
+ v7 = (dctSqrt1d2 * (p[1*8 + col] + p[7*8 + col]) + 2048) >> 12;
+ v5 = p[3*8 + col];
+ v6 = p[5*8 + col];
+
+ // stage 3
+ t = (v0 - v1 + 1) >> 1;
+ v0 = (v0 + v1 + 1) >> 1;
+ v1 = t;
+ t = (v2 * dctSin6 + v3 * dctCos6 + 2048) >> 12;
+ v2 = (v2 * dctCos6 - v3 * dctSin6 + 2048) >> 12;
+ v3 = t;
+ t = (v4 - v6 + 1) >> 1;
+ v4 = (v4 + v6 + 1) >> 1;
+ v6 = t;
+ t = (v7 + v5 + 1) >> 1;
+ v5 = (v7 - v5 + 1) >> 1;
+ v7 = t;
+
+ // stage 2
+ t = (v0 - v3 + 1) >> 1;
+ v0 = (v0 + v3 + 1) >> 1;
+ v3 = t;
+ t = (v1 - v2 + 1) >> 1;
+ v1 = (v1 + v2 + 1) >> 1;
+ v2 = t;
+ t = (v4 * dctSin3 + v7 * dctCos3 + 2048) >> 12;
+ v4 = (v4 * dctCos3 - v7 * dctSin3 + 2048) >> 12;
+ v7 = t;
+ t = (v5 * dctSin1 + v6 * dctCos1 + 2048) >> 12;
+ v5 = (v5 * dctCos1 - v6 * dctSin1 + 2048) >> 12;
+ v6 = t;
+
+ // stage 1
+ p[0*8 + col] = v0 + v7;
+ p[7*8 + col] = v0 - v7;
+ p[1*8 + col] = v1 + v6;
+ p[6*8 + col] = v1 - v6;
+ p[2*8 + col] = v2 + v5;
+ p[5*8 + col] = v2 - v5;
+ p[3*8 + col] = v3 + v4;
+ p[4*8 + col] = v3 - v4;
+ }
+
+ // convert to 8-bit integers
+ for (i = 0; i < 64; ++i) {
+ var index = blockBufferOffset + i;
+ var q = p[i];
+ q = (q <= -2056) ? 0 : (q >= 2024) ? 255 : (q + 2056) >> 4;
+ component.blockData[index] = q;
+ }
+ }
+
+ function buildComponentData(frame, component) {
+ var lines = [];
+ var blocksPerLine = component.blocksPerLine;
+ var blocksPerColumn = component.blocksPerColumn;
+ var samplesPerLine = blocksPerLine << 3;
+ var computationBuffer = new Int32Array(64);
+
+ var i, j, ll = 0;
+ for (var blockRow = 0; blockRow < blocksPerColumn; blockRow++) {
+ for (var blockCol = 0; blockCol < blocksPerLine; blockCol++) {
+ var offset = getBlockBufferOffset(component, blockRow, blockCol);
+ quantizeAndInverse(component, offset, computationBuffer);
+ }
+ }
+ return component.blockData;
+ }
+
+ function clamp0to255(a) {
+ return a <= 0 ? 0 : a >= 255 ? 255 : a;
+ }
+
+ constructor.prototype = {
+ parse: function parse(data) {
+
+ function readUint16() {
+ var value = (data[offset] << 8) | data[offset + 1];
+ offset += 2;
+ return value;
+ }
+
+ function readDataBlock() {
+ var length = readUint16();
+ var array = data.subarray(offset, offset + length - 2);
+ offset += array.length;
+ return array;
+ }
+
+ function prepareComponents(frame) {
+ var mcusPerLine = Math.ceil(frame.samplesPerLine / 8 / frame.maxH);
+ var mcusPerColumn = Math.ceil(frame.scanLines / 8 / frame.maxV);
+ for (var i = 0; i < frame.components.length; i++) {
+ component = frame.components[i];
+ var blocksPerLine = Math.ceil(Math.ceil(frame.samplesPerLine / 8) *
+ component.h / frame.maxH);
+ var blocksPerColumn = Math.ceil(Math.ceil(frame.scanLines / 8) *
+ component.v / frame.maxV);
+ var blocksPerLineForMcu = mcusPerLine * component.h;
+ var blocksPerColumnForMcu = mcusPerColumn * component.v;
+
+ var blocksBufferSize = 64 * blocksPerColumnForMcu *
+ (blocksPerLineForMcu + 1);
+ component.blockData = new Int16Array(blocksBufferSize);
+ component.blocksPerLine = blocksPerLine;
+ component.blocksPerColumn = blocksPerColumn;
+ }
+ frame.mcusPerLine = mcusPerLine;
+ frame.mcusPerColumn = mcusPerColumn;
+ }
+
+ var offset = 0, length = data.length;
+ var jfif = null;
+ var adobe = null;
+ var pixels = null;
+ var frame, resetInterval;
+ var quantizationTables = [];
+ var huffmanTablesAC = [], huffmanTablesDC = [];
+ var fileMarker = readUint16();
+ if (fileMarker != 0xFFD8) { // SOI (Start of Image)
+ throw 'SOI not found';
+ }
+
+ fileMarker = readUint16();
+ while (fileMarker != 0xFFD9) { // EOI (End of image)
+ var i, j, l;
+ switch(fileMarker) {
+ case 0xFFE0: // APP0 (Application Specific)
+ case 0xFFE1: // APP1
+ case 0xFFE2: // APP2
+ case 0xFFE3: // APP3
+ case 0xFFE4: // APP4
+ case 0xFFE5: // APP5
+ case 0xFFE6: // APP6
+ case 0xFFE7: // APP7
+ case 0xFFE8: // APP8
+ case 0xFFE9: // APP9
+ case 0xFFEA: // APP10
+ case 0xFFEB: // APP11
+ case 0xFFEC: // APP12
+ case 0xFFED: // APP13
+ case 0xFFEE: // APP14
+ case 0xFFEF: // APP15
+ case 0xFFFE: // COM (Comment)
+ var appData = readDataBlock();
+
+ if (fileMarker === 0xFFE0) {
+ if (appData[0] === 0x4A && appData[1] === 0x46 &&
+ appData[2] === 0x49 && appData[3] === 0x46 &&
+ appData[4] === 0) { // 'JFIF\x00'
+ jfif = {
+ version: { major: appData[5], minor: appData[6] },
+ densityUnits: appData[7],
+ xDensity: (appData[8] << 8) | appData[9],
+ yDensity: (appData[10] << 8) | appData[11],
+ thumbWidth: appData[12],
+ thumbHeight: appData[13],
+ thumbData: appData.subarray(14, 14 +
+ 3 * appData[12] * appData[13])
+ };
+ }
+ }
+ // TODO APP1 - Exif
+ if (fileMarker === 0xFFEE) {
+ if (appData[0] === 0x41 && appData[1] === 0x64 &&
+ appData[2] === 0x6F && appData[3] === 0x62 &&
+ appData[4] === 0x65 && appData[5] === 0) { // 'Adobe\x00'
+ adobe = {
+ version: appData[6],
+ flags0: (appData[7] << 8) | appData[8],
+ flags1: (appData[9] << 8) | appData[10],
+ transformCode: appData[11]
+ };
+ }
+ }
+ break;
+
+ case 0xFFDB: // DQT (Define Quantization Tables)
+ var quantizationTablesLength = readUint16();
+ var quantizationTablesEnd = quantizationTablesLength + offset - 2;
+ var z;
+ while (offset < quantizationTablesEnd) {
+ var quantizationTableSpec = data[offset++];
+ var tableData = new Int32Array(64);
+ if ((quantizationTableSpec >> 4) === 0) { // 8 bit values
+ for (j = 0; j < 64; j++) {
+ z = dctZigZag[j];
+ tableData[z] = data[offset++];
+ }
+ } else if ((quantizationTableSpec >> 4) === 1) { //16 bit
+ for (j = 0; j < 64; j++) {
+ z = dctZigZag[j];
+ tableData[z] = readUint16();
+ }
+ } else {
+ throw 'DQT: invalid table spec';
+ }
+ quantizationTables[quantizationTableSpec & 15] = tableData;
+ }
+ break;
+
+ case 0xFFC0: // SOF0 (Start of Frame, Baseline DCT)
+ case 0xFFC1: // SOF1 (Start of Frame, Extended DCT)
+ case 0xFFC2: // SOF2 (Start of Frame, Progressive DCT)
+ if (frame) {
+ throw 'Only single frame JPEGs supported';
+ }
+ readUint16(); // skip data length
+ frame = {};
+ frame.extended = (fileMarker === 0xFFC1);
+ frame.progressive = (fileMarker === 0xFFC2);
+ frame.precision = data[offset++];
+ frame.scanLines = readUint16();
+ frame.samplesPerLine = readUint16();
+ frame.components = [];
+ frame.componentIds = {};
+ var componentsCount = data[offset++], componentId;
+ var maxH = 0, maxV = 0;
+ for (i = 0; i < componentsCount; i++) {
+ componentId = data[offset];
+ var h = data[offset + 1] >> 4;
+ var v = data[offset + 1] & 15;
+ if (maxH < h) {
+ maxH = h;
+ }
+ if (maxV < v) {
+ maxV = v;
+ }
+ var qId = data[offset + 2];
+ l = frame.components.push({
+ h: h,
+ v: v,
+ quantizationTable: quantizationTables[qId]
+ });
+ frame.componentIds[componentId] = l - 1;
+ offset += 3;
+ }
+ frame.maxH = maxH;
+ frame.maxV = maxV;
+ prepareComponents(frame);
+ break;
+
+ case 0xFFC4: // DHT (Define Huffman Tables)
+ var huffmanLength = readUint16();
+ for (i = 2; i < huffmanLength;) {
+ var huffmanTableSpec = data[offset++];
+ var codeLengths = new Uint8Array(16);
+ var codeLengthSum = 0;
+ for (j = 0; j < 16; j++, offset++) {
+ codeLengthSum += (codeLengths[j] = data[offset]);
+ }
+ var huffmanValues = new Uint8Array(codeLengthSum);
+ for (j = 0; j < codeLengthSum; j++, offset++) {
+ huffmanValues[j] = data[offset];
+ }
+ i += 17 + codeLengthSum;
+
+ ((huffmanTableSpec >> 4) === 0 ?
+ huffmanTablesDC : huffmanTablesAC)[huffmanTableSpec & 15] =
+ buildHuffmanTable(codeLengths, huffmanValues);
+ }
+ break;
+
+ case 0xFFDD: // DRI (Define Restart Interval)
+ readUint16(); // skip data length
+ resetInterval = readUint16();
+ break;
+
+ case 0xFFDA: // SOS (Start of Scan)
+ var scanLength = readUint16();
+ var selectorsCount = data[offset++];
+ var components = [], component;
+ for (i = 0; i < selectorsCount; i++) {
+ var componentIndex = frame.componentIds[data[offset++]];
+ component = frame.components[componentIndex];
+ var tableSpec = data[offset++];
+ component.huffmanTableDC = huffmanTablesDC[tableSpec >> 4];
+ component.huffmanTableAC = huffmanTablesAC[tableSpec & 15];
+ components.push(component);
+ }
+ var spectralStart = data[offset++];
+ var spectralEnd = data[offset++];
+ var successiveApproximation = data[offset++];
+ var processed = decodeScan(data, offset,
+ frame, components, resetInterval,
+ spectralStart, spectralEnd,
+ successiveApproximation >> 4, successiveApproximation & 15);
+ offset += processed;
+ break;
+ default:
+ if (data[offset - 3] == 0xFF &&
+ data[offset - 2] >= 0xC0 && data[offset - 2] <= 0xFE) {
+ // could be incorrect encoding -- last 0xFF byte of the previous
+ // block was eaten by the encoder
+ offset -= 3;
+ break;
+ }
+ throw 'unknown JPEG marker ' + fileMarker.toString(16);
+ }
+ fileMarker = readUint16();
+ }
+
+ this.width = frame.samplesPerLine;
+ this.height = frame.scanLines;
+ this.jfif = jfif;
+ this.adobe = adobe;
+ this.components = [];
+ for (i = 0; i < frame.components.length; i++) {
+ component = frame.components[i];
+ this.components.push({
+ output: buildComponentData(frame, component),
+ scaleX: component.h / frame.maxH,
+ scaleY: component.v / frame.maxV,
+ blocksPerLine: component.blocksPerLine,
+ blocksPerColumn: component.blocksPerColumn
+ });
+ }
+ this.numComponents = this.components.length;
+ },
+
+ _getLinearizedBlockData: function getLinearizedBlockData(width, height) {
+ var scaleX = this.width / width, scaleY = this.height / height;
+
+ var component, componentScaleX, componentScaleY, blocksPerScanline;
+ var x, y, i, j;
+ var index;
+ var offset = 0;
+ var output;
+ var numComponents = this.components.length;
+ var dataLength = width * height * numComponents;
+ var data = new Uint8Array(dataLength);
+ var xScaleBlockOffset = new Uint32Array(width);
+ var mask3LSB = 0xfffffff8; // used to clear the 3 LSBs
+
+ for (i = 0; i < numComponents; i++) {
+ component = this.components[i];
+ componentScaleX = component.scaleX * scaleX;
+ componentScaleY = component.scaleY * scaleY;
+ offset = i;
+ output = component.output;
+ blocksPerScanline = (component.blocksPerLine + 1) << 3;
+ // precalculate the xScaleBlockOffset
+ for (x = 0; x < width; x++) {
+ j = 0 | (x * componentScaleX);
+ xScaleBlockOffset[x] = ((j & mask3LSB) << 3) | (j & 7);
+ }
+ // linearize the blocks of the component
+ for (y = 0; y < height; y++) {
+ j = 0 | (y * componentScaleY);
+ index = blocksPerScanline * (j & mask3LSB) | ((j & 7) << 3);
+ for (x = 0; x < width; x++) {
+ data[offset] = output[index + xScaleBlockOffset[x]];
+ offset += numComponents;
+ }
+ }
+ }
+ return data;
+ },
+
+ _isColorConversionNeeded: function isColorConversionNeeded() {
+ if (this.adobe && this.adobe.transformCode) {
+ // The adobe transform marker overrides any previous setting
+ return true;
+ } else if (this.numComponents == 3) {
+ return true;
+ } else if (typeof this.colorTransform !== 'undefined') {
+ return !!this.colorTransform;
+ } else {
+ return false;
+ }
+ },
+
+ _convertYccToRgb: function convertYccToRgb(data) {
+ var Y, Cb, Cr;
+ for (var i = 0; i < data.length; i += this.numComponents) {
+ Y = data[i ];
+ Cb = data[i + 1];
+ Cr = data[i + 2];
+ data[i ] = clamp0to255(Y - 179.456 + 1.402 * Cr);
+ data[i + 1] = clamp0to255(Y + 135.459 - 0.344 * Cb - 0.714 * Cr);
+ data[i + 2] = clamp0to255(Y - 226.816 + 1.772 * Cb);
+ }
+ return data;
+ },
+
+ _convertYcckToRgb: function convertYcckToRgb(data) {
+ var Y, Cb, Cr, k, CbCb, CbCr, CbY, Cbk, CrCr, Crk, CrY, YY, Yk, kk;
+ var offset = 0;
+ for (var i = 0; i < data.length; i += this.numComponents) {
+ Y = data[i];
+ Cb = data[i + 1];
+ Cr = data[i + 2];
+ k = data[i + 3];
+
+ CbCb = Cb * Cb;
+ CbCr = Cb * Cr;
+ CbY = Cb * Y;
+ Cbk = Cb * k;
+ CrCr = Cr * Cr;
+ Crk = Cr * k;
+ CrY = Cr * Y;
+ YY = Y * Y;
+ Yk = Y * k;
+ kk = k * k;
+
+ var r = - 122.67195406894 -
+ 6.60635669420364e-5 * CbCb + 0.000437130475926232 * CbCr -
+ 5.4080610064599e-5* CbY + 0.00048449797120281* Cbk -
+ 0.154362151871126 * Cb - 0.000957964378445773 * CrCr +
+ 0.000817076911346625 * CrY - 0.00477271405408747 * Crk +
+ 1.53380253221734 * Cr + 0.000961250184130688 * YY -
+ 0.00266257332283933 * Yk + 0.48357088451265 * Y -
+ 0.000336197177618394 * kk + 0.484791561490776 * k;
+
+ var g = 107.268039397724 +
+ 2.19927104525741e-5 * CbCb - 0.000640992018297945 * CbCr +
+ 0.000659397001245577* CbY + 0.000426105652938837* Cbk -
+ 0.176491792462875 * Cb - 0.000778269941513683 * CrCr +
+ 0.00130872261408275 * CrY + 0.000770482631801132 * Crk -
+ 0.151051492775562 * Cr + 0.00126935368114843 * YY -
+ 0.00265090189010898 * Yk + 0.25802910206845 * Y -
+ 0.000318913117588328 * kk - 0.213742400323665 * k;
+
+ var b = - 20.810012546947 -
+ 0.000570115196973677 * CbCb - 2.63409051004589e-5 * CbCr +
+ 0.0020741088115012* CbY - 0.00288260236853442* Cbk +
+ 0.814272968359295 * Cb - 1.53496057440975e-5 * CrCr -
+ 0.000132689043961446 * CrY + 0.000560833691242812 * Crk -
+ 0.195152027534049 * Cr + 0.00174418132927582 * YY -
+ 0.00255243321439347 * Yk + 0.116935020465145 * Y -
+ 0.000343531996510555 * kk + 0.24165260232407 * k;
+
+ data[offset++] = clamp0to255(r);
+ data[offset++] = clamp0to255(g);
+ data[offset++] = clamp0to255(b);
+ }
+ return data;
+ },
+
+ _convertYcckToCmyk: function convertYcckToCmyk(data) {
+ var Y, Cb, Cr;
+ for (var i = 0; i < data.length; i += this.numComponents) {
+ Y = data[i];
+ Cb = data[i + 1];
+ Cr = data[i + 2];
+ data[i ] = clamp0to255(434.456 - Y - 1.402 * Cr);
+ data[i + 1] = clamp0to255(119.541 - Y + 0.344 * Cb + 0.714 * Cr);
+ data[i + 2] = clamp0to255(481.816 - Y - 1.772 * Cb);
+ // K in data[i + 3] is unchanged
+ }
+ return data;
+ },
+
+ _convertCmykToRgb: function convertCmykToRgb(data) {
+ var c, m, y, k;
+ var offset = 0;
+ var length = data.length;
+ var min = -255 * 255 * 255;
+ var scale = 1 / 255 / 255;
+ for (var i = 0; i < length;) {
+ c = data[i++];
+ m = data[i++];
+ y = data[i++];
+ k = data[i++];
+
+ var r =
+ c * (-4.387332384609988 * c + 54.48615194189176 * m +
+ 18.82290502165302 * y + 212.25662451639585 * k -
+ 72734.4411664936) +
+ m * (1.7149763477362134 * m - 5.6096736904047315 * y -
+ 17.873870861415444 * k - 1401.7366389350734) +
+ y * (-2.5217340131683033 * y - 21.248923337353073 * k +
+ 4465.541406466231) -
+ k * (21.86122147463605 * k + 48317.86113160301);
+ var g =
+ c * (8.841041422036149 * c + 60.118027045597366 * m +
+ 6.871425592049007 * y + 31.159100130055922 * k -
+ 20220.756542821975) +
+ m * (-15.310361306967817 * m + 17.575251261109482 * y +
+ 131.35250912493976 * k - 48691.05921601825) +
+ y * (4.444339102852739 * y + 9.8632861493405 * k -
+ 6341.191035517494) -
+ k * (20.737325471181034 * k + 47890.15695978492);
+ var b =
+ c * (0.8842522430003296 * c + 8.078677503112928 * m +
+ 30.89978309703729 * y - 0.23883238689178934 * k -
+ 3616.812083916688) +
+ m * (10.49593273432072 * m + 63.02378494754052 * y +
+ 50.606957656360734 * k - 28620.90484698408) +
+ y * (0.03296041114873217 * y + 115.60384449646641 * k -
+ 49363.43385999684) -
+ k * (22.33816807309886 * k + 45932.16563550634);
+
+ data[offset++] = r >= 0 ? 255 : r <= min ? 0 : 255 + r * scale | 0;
+ data[offset++] = g >= 0 ? 255 : g <= min ? 0 : 255 + g * scale | 0;
+ data[offset++] = b >= 0 ? 255 : b <= min ? 0 : 255 + b * scale | 0;
+ }
+ return data;
+ },
+
+ getData: function getData(width, height, forceRGBoutput) {
+ if (this.numComponents > 4) {
+ throw 'Unsupported color mode';
+ }
+ // type of data: Uint8Array(width * height * numComponents)
+ var data = this._getLinearizedBlockData(width, height);
+
+ if (this.numComponents === 3) {
+ return this._convertYccToRgb(data);
+ } else if (this.numComponents === 4) {
+ if (this._isColorConversionNeeded()) {
+ if (forceRGBoutput) {
+ return this._convertYcckToRgb(data);
+ } else {
+ return this._convertYcckToCmyk(data);
+ }
+ } else {
+ return this._convertCmykToRgb(data);
+ }
+ }
+ return data;
+ }
+ };
+
+ return constructor;
+})();
+
+
var JpxImage = (function JpxImageClosure() {
// Table E.1
var SubbandsGainLog2 = {
@@ -36236,10 +39274,6 @@ var JpxImage = (function JpxImageClosure() {
'HL': 1,
'HH': 2
};
- var TransformType = {
- IRREVERSIBLE: 0,
- REVERSIBLE: 1
- };
function JpxImage() {
this.failOnCorruptedImage = false;
}
@@ -36259,15 +39293,8 @@ var JpxImage = (function JpxImageClosure() {
xhr.send(null);
},
parse: function JpxImage_parse(data) {
- function readUint(data, offset, bytes) {
- var n = 0;
- for (var i = 0; i < bytes; i++) {
- n = n * 256 + (data[offset + i] & 0xFF);
- }
- return n;
- }
- var head = readUint(data, 0, 2);
+ var head = readUint16(data, 0);
// No box header, immediate start of codestream (SOC)
if (head === 0xFF4F) {
this.parseCodestream(data, 0, data.length);
@@ -36277,11 +39304,14 @@ var JpxImage = (function JpxImageClosure() {
var position = 0, length = data.length;
while (position < length) {
var headerSize = 8;
- var lbox = readUint(data, position, 4);
- var tbox = readUint(data, position + 4, 4);
+ var lbox = readUint32(data, position);
+ var tbox = readUint32(data, position + 4);
position += headerSize;
- if (lbox == 1) {
- lbox = readUint(data, position, 8);
+ if (lbox === 1) {
+ // XLBox: read UInt64 according to spec.
+ // JavaScript's int precision of 53 bit should be sufficient here.
+ lbox = readUint32(data, position) * 4294967296 +
+ readUint32(data, position + 4);
position += 8;
headerSize += 8;
}
@@ -36312,15 +39342,48 @@ var JpxImage = (function JpxImageClosure() {
}
}
},
+ parseImageProperties: function JpxImage_parseImageProperties(stream) {
+ try {
+ var newByte = stream.getByte();
+ while (newByte >= 0) {
+ var oldByte = newByte;
+ newByte = stream.getByte();
+ var code = (oldByte << 8) | newByte;
+ // Image and tile size (SIZ)
+ if (code == 0xFF51) {
+ stream.skip(4);
+ var Xsiz = stream.getInt32() >>> 0; // Byte 4
+ var Ysiz = stream.getInt32() >>> 0; // Byte 8
+ var XOsiz = stream.getInt32() >>> 0; // Byte 12
+ var YOsiz = stream.getInt32() >>> 0; // Byte 16
+ stream.skip(16);
+ var Csiz = stream.getUint16(); // Byte 36
+ this.width = Xsiz - XOsiz;
+ this.height = Ysiz - YOsiz;
+ this.componentsCount = Csiz;
+ // Results are always returned as Uint8Arrays
+ this.bitsPerComponent = 8;
+ return;
+ }
+ }
+ throw 'No size marker found in JPX stream';
+ } catch (e) {
+ if (this.failOnCorruptedImage) {
+ error('JPX error: ' + e);
+ } else {
+ warn('JPX error: ' + e + '. Trying to recover');
+ }
+ }
+ },
parseCodestream: function JpxImage_parseCodestream(data, start, end) {
var context = {};
try {
var position = start;
- while (position < end) {
+ while (position + 1 < end) {
var code = readUint16(data, position);
position += 2;
- var length = 0, j;
+ var length = 0, j, sqcd, spqcds, spqcdSize, scalarExpounded, tile;
switch (code) {
case 0xFF4F: // Start of codestream (SOC)
context.mainHeader = true;
@@ -36362,8 +39425,7 @@ var JpxImage = (function JpxImageClosure() {
length = readUint16(data, position);
var qcd = {};
j = position + 2;
- var sqcd = data[j++];
- var spqcdSize, scalarExpounded;
+ sqcd = data[j++];
switch (sqcd & 0x1F) {
case 0:
spqcdSize = 8;
@@ -36383,7 +39445,7 @@ var JpxImage = (function JpxImageClosure() {
qcd.noQuantization = (spqcdSize == 8);
qcd.scalarExpounded = scalarExpounded;
qcd.guardBits = sqcd >> 5;
- var spqcds = [];
+ spqcds = [];
while (j < length + position) {
var spqcd = {};
if (spqcdSize == 8) {
@@ -36415,8 +39477,7 @@ var JpxImage = (function JpxImageClosure() {
cqcc = readUint16(data, j);
j += 2;
}
- var sqcd = data[j++];
- var spqcdSize, scalarExpounded;
+ sqcd = data[j++];
switch (sqcd & 0x1F) {
case 0:
spqcdSize = 8;
@@ -36436,9 +39497,9 @@ var JpxImage = (function JpxImageClosure() {
qcc.noQuantization = (spqcdSize == 8);
qcc.scalarExpounded = scalarExpounded;
qcc.guardBits = sqcd >> 5;
- var spqcds = [];
+ spqcds = [];
while (j < (length + position)) {
- var spqcd = {};
+ spqcd = {};
if (spqcdSize == 8) {
spqcd.epsilon = data[j++] >> 3;
spqcd.mu = 0;
@@ -36464,7 +39525,6 @@ var JpxImage = (function JpxImageClosure() {
cod.entropyCoderWithCustomPrecincts = !!(scod & 1);
cod.sopMarkerUsed = !!(scod & 2);
cod.ephMarkerUsed = !!(scod & 4);
- var codingStyle = {};
cod.progressionOrder = data[j++];
cod.layersCount = readUint16(data, j);
j += 2;
@@ -36480,7 +39540,7 @@ var JpxImage = (function JpxImageClosure() {
cod.verticalyStripe = !!(blockStyle & 8);
cod.predictableTermination = !!(blockStyle & 16);
cod.segmentationSymbolUsed = !!(blockStyle & 32);
- cod.transformation = data[j++];
+ cod.reversibleTransformation = data[j++];
if (cod.entropyCoderWithCustomPrecincts) {
var precinctsSizes = [];
while (j < length + position) {
@@ -36511,7 +39571,7 @@ var JpxImage = (function JpxImageClosure() {
break;
case 0xFF90: // Start of tile-part (SOT)
length = readUint16(data, position);
- var tile = {};
+ tile = {};
tile.index = readUint16(data, position + 2);
tile.length = readUint32(data, position + 4);
tile.dataEnd = tile.length + position - 2;
@@ -36529,7 +39589,7 @@ var JpxImage = (function JpxImageClosure() {
context.currentTile = tile;
break;
case 0xFF93: // Start of data (SOD)
- var tile = context.currentTile;
+ tile = context.currentTile;
if (tile.partIndex === 0) {
initializeTile(context, tile.index);
buildPackets(context);
@@ -36543,6 +39603,8 @@ var JpxImage = (function JpxImageClosure() {
length = readUint16(data, position);
// skipping content
break;
+ case 0xFF53: // Coding style component (COC)
+ throw 'Codestream code 0xFF53 (COC) is not implemented';
default:
throw 'Unknown codestream code: ' + code.toString(16);
}
@@ -36561,21 +39623,6 @@ var JpxImage = (function JpxImageClosure() {
this.componentsCount = context.SIZ.Csiz;
}
};
- function readUint32(data, offset) {
- return (data[offset] << 24) | (data[offset + 1] << 16) |
- (data[offset + 2] << 8) | data[offset + 3];
- }
- function readUint16(data, offset) {
- return (data[offset] << 8) | data[offset + 1];
- }
- function log2(x) {
- var n = 1, i = 0;
- while (x > n) {
- n <<= 1;
- i++;
- }
- return i;
- }
function calculateComponentDimensions(component, siz) {
// Section B.2 Component mapping
component.x0 = Math.ceil(siz.XOsiz / component.XRsiz);
@@ -36588,12 +39635,12 @@ var JpxImage = (function JpxImageClosure() {
function calculateTileGrids(context, components) {
var siz = context.SIZ;
// Section B.3 Division into tile and tile-components
- var tiles = [];
+ var tile, tiles = [];
var numXtiles = Math.ceil((siz.Xsiz - siz.XTOsiz) / siz.XTsiz);
var numYtiles = Math.ceil((siz.Ysiz - siz.YTOsiz) / siz.YTsiz);
for (var q = 0; q < numYtiles; q++) {
for (var p = 0; p < numXtiles; p++) {
- var tile = {};
+ tile = {};
tile.tx0 = Math.max(siz.XTOsiz + p * siz.XTsiz, siz.XOsiz);
tile.ty0 = Math.max(siz.YTOsiz + q * siz.YTsiz, siz.YOsiz);
tile.tx1 = Math.min(siz.XTOsiz + (p + 1) * siz.XTsiz, siz.Xsiz);
@@ -36609,9 +39656,9 @@ var JpxImage = (function JpxImageClosure() {
var componentsCount = siz.Csiz;
for (var i = 0, ii = componentsCount; i < ii; i++) {
var component = components[i];
- var tileComponents = [];
for (var j = 0, jj = tiles.length; j < jj; j++) {
- var tileComponent = {}, tile = tiles[j];
+ var tileComponent = {};
+ tile = tiles[j];
tileComponent.tcx0 = Math.ceil(tile.tx0 / component.XRsiz);
tileComponent.tcy0 = Math.ceil(tile.ty0 / component.YRsiz);
tileComponent.tcx1 = Math.ceil(tile.tx1 / component.XRsiz);
@@ -36670,16 +39717,17 @@ var JpxImage = (function JpxImageClosure() {
var ycb_ = dimensions.ycb_;
var codeblockWidth = 1 << xcb_;
var codeblockHeight = 1 << ycb_;
- var cbx0 = Math.floor(subband.tbx0 / codeblockWidth);
- var cby0 = Math.floor(subband.tby0 / codeblockHeight);
- var cbx1 = Math.ceil(subband.tbx1 / codeblockWidth);
- var cby1 = Math.ceil(subband.tby1 / codeblockHeight);
+ var cbx0 = subband.tbx0 >> xcb_;
+ var cby0 = subband.tby0 >> ycb_;
+ var cbx1 = (subband.tbx1 + codeblockWidth - 1) >> xcb_;
+ var cby1 = (subband.tby1 + codeblockHeight - 1) >> ycb_;
var precinctParameters = subband.resolution.precinctParameters;
var codeblocks = [];
var precincts = [];
- for (var j = cby0; j < cby1; j++) {
- for (var i = cbx0; i < cbx1; i++) {
- var codeblock = {
+ var i, j, codeblock, precinctNumber;
+ for (j = cby0; j < cby1; j++) {
+ for (i = cbx0; i < cbx1; i++) {
+ codeblock = {
cbx: i,
cby: j,
tbx0: codeblockWidth * i,
@@ -36694,26 +39742,28 @@ var JpxImage = (function JpxImageClosure() {
var pj = Math.floor((codeblock.tby0 -
precinctParameters.precinctYOffset) /
precinctParameters.precinctHeight);
- var precinctNumber = pj +
- pi * precinctParameters.numprecinctswide;
+ precinctNumber = pj + pi * precinctParameters.numprecinctswide;
codeblock.tbx0_ = Math.max(subband.tbx0, codeblock.tbx0);
codeblock.tby0_ = Math.max(subband.tby0, codeblock.tby0);
codeblock.tbx1_ = Math.min(subband.tbx1, codeblock.tbx1);
codeblock.tby1_ = Math.min(subband.tby1, codeblock.tby1);
codeblock.precinctNumber = precinctNumber;
codeblock.subbandType = subband.type;
- var coefficientsLength = (codeblock.tbx1_ - codeblock.tbx0_) *
- (codeblock.tby1_ - codeblock.tby0_);
codeblock.Lblock = 3;
codeblocks.push(codeblock);
// building precinct for the sub-band
- var precinct;
- if (precinctNumber in precincts) {
- precinct = precincts[precinctNumber];
- precinct.cbxMin = Math.min(precinct.cbxMin, i);
- precinct.cbyMin = Math.min(precinct.cbyMin, j);
- precinct.cbxMax = Math.max(precinct.cbxMax, i);
- precinct.cbyMax = Math.max(precinct.cbyMax, j);
+ var precinct = precincts[precinctNumber];
+ if (precinct !== undefined) {
+ if (i < precinct.cbxMin) {
+ precinct.cbxMin = i;
+ } else if (i > precinct.cbxMax) {
+ precinct.cbxMax = i;
+ }
+ if (j < precinct.cbyMin) {
+ precinct.cbxMin = j;
+ } else if (j > precinct.cbyMax) {
+ precinct.cbyMax = j;
+ }
} else {
precincts[precinctNumber] = precinct = {
cbxMin: i,
@@ -36732,10 +39782,6 @@ var JpxImage = (function JpxImageClosure() {
numcodeblockhigh: cby1 - cby1 + 1
};
subband.codeblocks = codeblocks;
- for (var i = 0, ii = codeblocks.length; i < ii; i++) {
- var codeblock = codeblocks[i];
- var precinctNumber = codeblock.precinctNumber;
- }
subband.precincts = precincts;
}
function createPacket(resolution, precinctNumber, layerNumber) {
@@ -36921,7 +39967,6 @@ var JpxImage = (function JpxImageClosure() {
}
// Generate the packets sequence
var progressionOrder = tile.codingStyleDefaultParameters.progressionOrder;
- var packetsIterator;
switch (progressionOrder) {
case 0:
tile.packetsIterator =
@@ -36965,24 +40010,22 @@ var JpxImage = (function JpxImageClosure() {
}
}
function readCodingpasses() {
- var value = readBits(1);
- if (value === 0) {
+ if (readBits(1) === 0) {
return 1;
}
- value = (value << 1) | readBits(1);
- if (value == 0x02) {
+ if (readBits(1) === 0) {
return 2;
}
- value = (value << 2) | readBits(2);
- if (value <= 0x0E) {
- return (value & 0x03) + 3;
+ var value = readBits(2);
+ if (value < 3) {
+ return value + 3;
}
- value = (value << 5) | readBits(5);
- if (value <= 0x1FE) {
- return (value & 0x1F) + 6;
+ value = readBits(5);
+ if (value < 31) {
+ return value + 6;
}
- value = (value << 7) | readBits(7);
- return (value & 0x7F) + 37;
+ value = readBits(7);
+ return value + 37;
}
var tileIndex = context.currentTile.index;
var tile = context.tiles[tileIndex];
@@ -36994,19 +40037,20 @@ var JpxImage = (function JpxImageClosure() {
continue;
}
var layerNumber = packet.layerNumber;
- var queue = [];
+ var queue = [], codeblock;
for (var i = 0, ii = packet.codeblocks.length; i < ii; i++) {
- var codeblock = packet.codeblocks[i];
+ codeblock = packet.codeblocks[i];
var precinct = codeblock.precinct;
var codeblockColumn = codeblock.cbx - precinct.cbxMin;
var codeblockRow = codeblock.cby - precinct.cbyMin;
var codeblockIncluded = false;
var firstTimeInclusion = false;
+ var valueReady;
if ('included' in codeblock) {
codeblockIncluded = !!readBits(1);
} else {
// reading inclusion tree
- var precinct = codeblock.precinct;
+ precinct = codeblock.precinct;
var inclusionTree, zeroBitPlanesTree;
if ('inclusionTree' in precinct) {
inclusionTree = precinct.inclusionTree;
@@ -37023,7 +40067,7 @@ var JpxImage = (function JpxImageClosure() {
if (inclusionTree.reset(codeblockColumn, codeblockRow, layerNumber)) {
while (true) {
if (readBits(1)) {
- var valueReady = !inclusionTree.nextLevel();
+ valueReady = !inclusionTree.nextLevel();
if (valueReady) {
codeblock.included = true;
codeblockIncluded = firstTimeInclusion = true;
@@ -37044,7 +40088,7 @@ var JpxImage = (function JpxImageClosure() {
zeroBitPlanesTree.reset(codeblockColumn, codeblockRow);
while (true) {
if (readBits(1)) {
- var valueReady = !zeroBitPlanesTree.nextLevel();
+ valueReady = !zeroBitPlanesTree.nextLevel();
if (valueReady) {
break;
}
@@ -37072,7 +40116,7 @@ var JpxImage = (function JpxImageClosure() {
alignToByte();
while (queue.length > 0) {
var packetItem = queue.shift();
- var codeblock = packetItem.codeblock;
+ codeblock = packetItem.codeblock;
if (!('data' in codeblock)) {
codeblock.data = [];
}
@@ -37087,9 +40131,15 @@ var JpxImage = (function JpxImageClosure() {
}
return position;
}
- function copyCoefficients(coefficients, x0, y0, width, height,
- delta, mb, codeblocks, transformation,
- segmentationSymbolUsed) {
+ function copyCoefficients(coefficients, levelWidth, levelHeight, subband,
+ delta, mb, reversible, segmentationSymbolUsed) {
+ var x0 = subband.tbx0;
+ var y0 = subband.tby0;
+ var width = subband.tbx1 - subband.tbx0;
+ var codeblocks = subband.codeblocks;
+ var right = subband.type.charAt(0) === 'H' ? 1 : 0;
+ var bottom = subband.type.charAt(1) === 'H' ? levelWidth : 0;
+
for (var i = 0, ii = codeblocks.length; i < ii; ++i) {
var codeblock = codeblocks[i];
var blockWidth = codeblock.tbx1_ - codeblock.tbx0_;
@@ -37103,28 +40153,30 @@ var JpxImage = (function JpxImageClosure() {
var bitModel, currentCodingpassType;
bitModel = new BitModel(blockWidth, blockHeight, codeblock.subbandType,
- codeblock.zeroBitPlanes);
+ codeblock.zeroBitPlanes, mb);
currentCodingpassType = 2; // first bit plane starts from cleanup
// collect data
var data = codeblock.data, totalLength = 0, codingpasses = 0;
- for (var q = 0, qq = data.length; q < qq; q++) {
- var dataItem = data[q];
+ var j, jj, dataItem;
+ for (j = 0, jj = data.length; j < jj; j++) {
+ dataItem = data[j];
totalLength += dataItem.end - dataItem.start;
codingpasses += dataItem.codingpasses;
}
- var encodedData = new Uint8Array(totalLength), k = 0;
- for (var q = 0, qq = data.length; q < qq; q++) {
- var dataItem = data[q];
+ var encodedData = new Uint8Array(totalLength);
+ var position = 0;
+ for (j = 0, jj = data.length; j < jj; j++) {
+ dataItem = data[j];
var chunk = dataItem.data.subarray(dataItem.start, dataItem.end);
- encodedData.set(chunk, k);
- k += chunk.length;
+ encodedData.set(chunk, position);
+ position += chunk.length;
}
// decoding the item
var decoder = new ArithmeticDecoder(encodedData, 0, totalLength);
bitModel.setDecoder(decoder);
- for (var q = 0; q < codingpasses; q++) {
+ for (j = 0; j < codingpasses; j++) {
switch (currentCodingpassType) {
case 0:
bitModel.runSignificancePropogationPass();
@@ -37143,17 +40195,34 @@ var JpxImage = (function JpxImageClosure() {
}
var offset = (codeblock.tbx0_ - x0) + (codeblock.tby0_ - y0) * width;
- var n, nb, correction, position = 0;
- var irreversible = (transformation === TransformType.IRREVERSIBLE);
var sign = bitModel.coefficentsSign;
var magnitude = bitModel.coefficentsMagnitude;
var bitsDecoded = bitModel.bitsDecoded;
- for (var j = 0; j < blockHeight; j++) {
- for (var k = 0; k < blockWidth; k++) {
- n = (sign[position] ? -1 : 1) * magnitude[position];
- nb = bitsDecoded[position];
- correction = (irreversible || mb > nb) ? 1 << (mb - nb) : 1;
- coefficients[offset++] = n * correction * delta;
+ var magnitudeCorrection = reversible ? 0 : 0.5;
+ var k, n, nb;
+ position = 0;
+ // Do the interleaving of Section F.3.3 here, so we do not need
+ // to copy later. LL level is not interleaved, just copied.
+ var interleave = (subband.type !== 'LL');
+ for (j = 0; j < blockHeight; j++) {
+ var row = (offset / width) | 0; // row in the non-interleaved subband
+ var levelOffset = 2 * row * (levelWidth - width) + right + bottom;
+ for (k = 0; k < blockWidth; k++) {
+ n = magnitude[position];
+ if (n !== 0) {
+ n = (n + magnitudeCorrection) * delta;
+ if (sign[position] !== 0) {
+ n = -n;
+ }
+ nb = bitsDecoded[position];
+ var pos = interleave ? (levelOffset + (offset << 1)) : offset;
+ if (reversible && (nb >= mb)) {
+ coefficients[pos] = n;
+ } else {
+ coefficients[pos] = n * (1 << (mb - nb));
+ }
+ }
+ offset++;
position++;
}
offset += width - blockWidth;
@@ -37169,19 +40238,23 @@ var JpxImage = (function JpxImageClosure() {
var spqcds = quantizationParameters.SPqcds;
var scalarExpounded = quantizationParameters.scalarExpounded;
var guardBits = quantizationParameters.guardBits;
- var transformation = codingStyleParameters.transformation;
var segmentationSymbolUsed = codingStyleParameters.segmentationSymbolUsed;
var precision = context.components[c].precision;
- var transformation = codingStyleParameters.transformation;
- var transform = (transformation === TransformType.IRREVERSIBLE ?
- new IrreversibleTransform() : new ReversibleTransform());
+ var reversible = codingStyleParameters.reversibleTransformation;
+ var transform = (reversible ? new ReversibleTransform() :
+ new IrreversibleTransform());
var subbandCoefficients = [];
- var k = 0, b = 0;
+ var b = 0;
for (var i = 0; i <= decompositionLevelsCount; i++) {
var resolution = component.resolutions[i];
+ var width = resolution.trx1 - resolution.trx0;
+ var height = resolution.try1 - resolution.try0;
+ // Allocate space for the whole sublevel.
+ var coefficients = new Float32Array(width * height);
+
for (var j = 0, jj = resolution.subbands.length; j < jj; j++) {
var mu, epsilon;
if (!scalarExpounded) {
@@ -37191,31 +40264,30 @@ var JpxImage = (function JpxImageClosure() {
} else {
mu = spqcds[b].mu;
epsilon = spqcds[b].epsilon;
+ b++;
}
var subband = resolution.subbands[j];
- var width = subband.tbx1 - subband.tbx0;
- var height = subband.tby1 - subband.tby0;
var gainLog2 = SubbandsGainLog2[subband.type];
// calulate quantization coefficient (Section E.1.1.1)
- var delta = (transformation === TransformType.IRREVERSIBLE ?
- Math.pow(2, precision + gainLog2 - epsilon) * (1 + mu / 2048) : 1);
+ var delta = (reversible ? 1 :
+ Math.pow(2, precision + gainLog2 - epsilon) * (1 + mu / 2048));
var mb = (guardBits + epsilon - 1);
- var coefficients = new Float32Array(width * height);
- copyCoefficients(coefficients, subband.tbx0, subband.tby0,
- width, height, delta, mb, subband.codeblocks, transformation,
- segmentationSymbolUsed);
-
- subbandCoefficients.push({
- width: width,
- height: height,
- items: coefficients
- });
-
- b++;
+ // In the first resolution level, copyCoefficients will fill the
+ // whole array with coefficients. In the succeding passes,
+ // copyCoefficients will consecutively fill in the values that belong
+ // to the interleaved positions of the HL, LH, and HH coefficients.
+ // The LL coefficients will then be interleaved in Transform.iterate().
+ copyCoefficients(coefficients, width, height, subband, delta, mb,
+ reversible, segmentationSymbolUsed);
}
+ subbandCoefficients.push({
+ width: width,
+ height: height,
+ items: coefficients
+ });
}
var result = transform.calculate(subbandCoefficients,
@@ -37235,72 +40307,91 @@ var JpxImage = (function JpxImageClosure() {
var resultImages = [];
for (var i = 0, ii = context.tiles.length; i < ii; i++) {
var tile = context.tiles[i];
- var result = [];
- for (var c = 0; c < componentsCount; c++) {
- var image = transformTile(context, tile, c);
- result.push(image);
+ var transformedTiles = [];
+ var c;
+ for (c = 0; c < componentsCount; c++) {
+ transformedTiles[c] = transformTile(context, tile, c);
}
+ var tile0 = transformedTiles[0];
+ var out = new Uint8Array(tile0.items.length * componentsCount);
+ var result = {
+ left: tile0.left,
+ top: tile0.top,
+ width: tile0.width,
+ height: tile0.height,
+ items: out
+ };
// Section G.2.2 Inverse multi component transform
+ var shift, offset, max, min, maxK;
+ var pos = 0, j, jj, y0, y1, y2, r, g, b, k, val;
if (tile.codingStyleDefaultParameters.multipleComponentTransform) {
+ var fourComponents = componentsCount === 4;
+ var y0items = transformedTiles[0].items;
+ var y1items = transformedTiles[1].items;
+ var y2items = transformedTiles[2].items;
+ var y3items = fourComponents ? transformedTiles[3].items : null;
+
+ // HACK: The multiple component transform formulas below assume that
+ // all components have the same precision. With this in mind, we
+ // compute shift and offset only once.
+ shift = components[0].precision - 8;
+ offset = (128 << shift) + 0.5;
+ max = 255 * (1 << shift);
+ maxK = max * 0.5;
+ min = -maxK;
+
var component0 = tile.components[0];
- var transformation = component0.codingStyleParameters.transformation;
- if (transformation === TransformType.IRREVERSIBLE) {
+ var alpha01 = componentsCount - 3;
+ jj = y0items.length;
+ if (!component0.codingStyleParameters.reversibleTransformation) {
// inverse irreversible multiple component transform
- var y0items = result[0].items;
- var y1items = result[1].items;
- var y2items = result[2].items;
- for (var j = 0, jj = y0items.length; j < jj; ++j) {
- var y0 = y0items[j], y1 = y1items[j], y2 = y2items[j];
- y0items[j] = y0 + 1.402 * y2 + 0.5;
- y1items[j] = y0 - 0.34413 * y1 - 0.71414 * y2 + 0.5;
- y2items[j] = y0 + 1.772 * y1 + 0.5;
+ for (j = 0; j < jj; j++, pos += alpha01) {
+ y0 = y0items[j] + offset;
+ y1 = y1items[j];
+ y2 = y2items[j];
+ r = y0 + 1.402 * y2;
+ g = y0 - 0.34413 * y1 - 0.71414 * y2;
+ b = y0 + 1.772 * y1;
+ out[pos++] = r <= 0 ? 0 : r >= max ? 255 : r >> shift;
+ out[pos++] = g <= 0 ? 0 : g >= max ? 255 : g >> shift;
+ out[pos++] = b <= 0 ? 0 : b >= max ? 255 : b >> shift;
}
} else {
// inverse reversible multiple component transform
- var y0items = result[0].items;
- var y1items = result[1].items;
- var y2items = result[2].items;
- for (var j = 0, jj = y0items.length; j < jj; ++j) {
- var y0 = y0items[j], y1 = y1items[j], y2 = y2items[j];
- var i1 = y0 - ((y2 + y1) >> 2);
- y1items[j] = i1;
- y0items[j] = y2 + i1;
- y2items[j] = y1 + i1;
+ for (j = 0; j < jj; j++, pos += alpha01) {
+ y0 = y0items[j] + offset;
+ y1 = y1items[j];
+ y2 = y2items[j];
+ g = y0 - ((y2 + y1) >> 2);
+ r = g + y2;
+ b = g + y1;
+ out[pos++] = r <= 0 ? 0 : r >= max ? 255 : r >> shift;
+ out[pos++] = g <= 0 ? 0 : g >= max ? 255 : g >> shift;
+ out[pos++] = b <= 0 ? 0 : b >= max ? 255 : b >> shift;
}
}
- }
-
- // Section G.1 DC level shifting to unsigned component values
- for (var c = 0; c < componentsCount; c++) {
- var component = components[c];
- if (component.isSigned) {
- continue;
- }
-
- var offset = 1 << (component.precision - 1);
- var tileImage = result[c];
- var items = tileImage.items;
- for (var j = 0, jj = items.length; j < jj; j++) {
- items[j] += offset;
+ if (fourComponents) {
+ for (j = 0, pos = 3; j < jj; j++, pos += 4) {
+ k = y3items[j];
+ out[pos] = k <= min ? 0 : k >= maxK ? 255 : (k + offset) >> shift;
+ }
}
- }
-
- // To simplify things: shift and clamp output to 8 bit unsigned
- for (var c = 0; c < componentsCount; c++) {
- var component = components[c];
- var offset = component.isSigned ? 128 : 0;
- var shift = component.precision - 8;
- var tileImage = result[c];
- var items = tileImage.items;
- var data = new Uint8Array(items.length);
- for (var j = 0, jj = items.length; j < jj; j++) {
- var value = (items[j] >> shift) + offset;
- data[j] = value < 0 ? 0 : value > 255 ? 255 : value;
+ } else { // no multi-component transform
+ for (c = 0; c < componentsCount; c++) {
+ var items = transformedTiles[c].items;
+ shift = components[c].precision - 8;
+ offset = (128 << shift) + 0.5;
+ max = (127.5 * (1 << shift));
+ min = -max;
+ for (pos = c, j = 0, jj = items.length; j < jj; j++) {
+ val = items[j];
+ out[pos] = val <= min ? 0 :
+ val >= max ? 255 : (val + offset) >> shift;
+ pos += componentsCount;
+ }
}
- result[c].items = data;
}
-
resultImages.push(result);
}
return resultImages;
@@ -37309,7 +40400,6 @@ var JpxImage = (function JpxImageClosure() {
var siz = context.SIZ;
var componentsCount = siz.Csiz;
var tile = context.tiles[tileIndex];
- var resultTiles = [];
for (var c = 0; c < componentsCount; c++) {
var component = tile.components[c];
var qcdOrQcc = (c in context.currentTile.QCC ?
@@ -37340,9 +40430,9 @@ var JpxImage = (function JpxImageClosure() {
}
TagTree.prototype = {
reset: function TagTree_reset(i, j) {
- var currentLevel = 0, value = 0;
+ var currentLevel = 0, value = 0, level;
while (currentLevel < this.levels.length) {
- var level = this.levels[currentLevel];
+ level = this.levels[currentLevel];
var index = i + j * level.width;
if (index in level.items) {
value = level.items[index];
@@ -37354,7 +40444,7 @@ var JpxImage = (function JpxImageClosure() {
currentLevel++;
}
currentLevel--;
- var level = this.levels[currentLevel];
+ level = this.levels[currentLevel];
level.items[level.index] = value;
this.currentLevel = currentLevel;
delete this.value;
@@ -37374,7 +40464,7 @@ var JpxImage = (function JpxImageClosure() {
}
this.currentLevel = currentLevel;
- var level = this.levels[currentLevel];
+ level = this.levels[currentLevel];
level.items[level.index] = value;
return true;
}
@@ -37440,7 +40530,7 @@ var JpxImage = (function JpxImageClosure() {
var level = this.levels[levelIndex];
var currentValue = level.items[level.index];
while (--levelIndex >= 0) {
- var level = this.levels[levelIndex];
+ level = this.levels[levelIndex];
level.items[level.index] = currentValue;
}
},
@@ -37455,7 +40545,7 @@ var JpxImage = (function JpxImageClosure() {
}
this.currentLevel = currentLevel;
- var level = this.levels[currentLevel];
+ level = this.levels[currentLevel];
level.items[level.index] = value;
return true;
}
@@ -37486,32 +40576,7 @@ var JpxImage = (function JpxImageClosure() {
8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 0, 0, 0, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8
]);
- // Table D-2
- function calcSignContribution(significance0, sign0, significance1, sign1) {
- if (significance1) {
- if (!sign1) {
- return significance0 ? (!sign0 ? 1 : 0) : 1;
- } else {
- return significance0 ? (!sign0 ? 0 : -1) : -1;
- }
- } else {
- return significance0 ? (!sign0 ? 1 : -1) : 0;
- }
- }
- // Table D-3
- var SignContextLabels = [
- {contextLabel: 13, xorBit: 0},
- {contextLabel: 12, xorBit: 0},
- {contextLabel: 11, xorBit: 0},
- {contextLabel: 10, xorBit: 0},
- {contextLabel: 9, xorBit: 0},
- {contextLabel: 10, xorBit: 1},
- {contextLabel: 11, xorBit: 1},
- {contextLabel: 12, xorBit: 1},
- {contextLabel: 13, xorBit: 1}
- ];
-
- function BitModel(width, height, subband, zeroBitPlanes) {
+ function BitModel(width, height, subband, zeroBitPlanes, mb) {
this.width = width;
this.height = height;
@@ -37524,12 +40589,16 @@ var JpxImage = (function JpxImageClosure() {
// add border state cells for significanceState
this.neighborsSignificance = new Uint8Array(coefficientCount);
this.coefficentsSign = new Uint8Array(coefficientCount);
- this.coefficentsMagnitude = new Uint32Array(coefficientCount);
+ this.coefficentsMagnitude = mb > 14 ? new Uint32Array(coefficientCount) :
+ mb > 6 ? new Uint16Array(coefficientCount) :
+ new Uint8Array(coefficientCount);
this.processingFlags = new Uint8Array(coefficientCount);
- var bitsDecoded = new Uint8Array(this.width * this.height);
- for (var i = 0, ii = bitsDecoded.length; i < ii; i++) {
- bitsDecoded[i] = zeroBitPlanes;
+ var bitsDecoded = new Uint8Array(coefficientCount);
+ if (zeroBitPlanes !== 0) {
+ for (var i = 0; i < coefficientCount; i++) {
+ bitsDecoded[i] = zeroBitPlanes;
+ }
}
this.bitsDecoded = bitsDecoded;
@@ -37541,7 +40610,7 @@ var JpxImage = (function JpxImageClosure() {
this.decoder = decoder;
},
reset: function BitModel_reset() {
- // We have 17 contexts that are accessed via context labels,
+ // We have 17 contexts that are accessed via context labels,
// plus the uniform and runlength context.
this.contexts = new Int8Array(19);
@@ -37552,32 +40621,39 @@ var JpxImage = (function JpxImageClosure() {
this.contexts[RUNLENGTH_CONTEXT] = (3 << 1) | 0;
},
setNeighborsSignificance:
- function BitModel_setNeighborsSignificance(row, column) {
+ function BitModel_setNeighborsSignificance(row, column, index) {
var neighborsSignificance = this.neighborsSignificance;
var width = this.width, height = this.height;
- var index = row * width + column;
+ var left = (column > 0);
+ var right = (column + 1 < width);
+ var i;
+
if (row > 0) {
- if (column > 0) {
- neighborsSignificance[index - width - 1] += 0x10;
+ i = index - width;
+ if (left) {
+ neighborsSignificance[i - 1] += 0x10;
}
- if (column + 1 < width) {
- neighborsSignificance[index - width + 1] += 0x10;
+ if (right) {
+ neighborsSignificance[i + 1] += 0x10;
}
- neighborsSignificance[index - width] += 0x04;
+ neighborsSignificance[i] += 0x04;
}
+
if (row + 1 < height) {
- if (column > 0) {
- neighborsSignificance[index + width - 1] += 0x10;
+ i = index + width;
+ if (left) {
+ neighborsSignificance[i - 1] += 0x10;
}
- if (column + 1 < width) {
- neighborsSignificance[index + width + 1] += 0x10;
+ if (right) {
+ neighborsSignificance[i + 1] += 0x10;
}
- neighborsSignificance[index + width] += 0x04;
+ neighborsSignificance[i] += 0x04;
}
- if (column > 0) {
+
+ if (left) {
neighborsSignificance[index - 1] += 0x01;
}
- if (column + 1 < width) {
+ if (right) {
neighborsSignificance[index + 1] += 0x01;
}
neighborsSignificance[index] |= 0x80;
@@ -37588,19 +40664,14 @@ var JpxImage = (function JpxImageClosure() {
var width = this.width, height = this.height;
var coefficentsMagnitude = this.coefficentsMagnitude;
var coefficentsSign = this.coefficentsSign;
- var contextLabels = this.contextLabels;
var neighborsSignificance = this.neighborsSignificance;
var processingFlags = this.processingFlags;
var contexts = this.contexts;
var labels = this.contextLabelTable;
var bitsDecoded = this.bitsDecoded;
- // clear processed flag
var processedInverseMask = ~1;
var processedMask = 1;
var firstMagnitudeBitMask = 2;
- for (var q = 0, qq = width * height; q < qq; q++) {
- processingFlags[q] &= processedInverseMask;
- }
for (var i0 = 0; i0 < height; i0 += 4) {
for (var j = 0; j < width; j++) {
@@ -37610,6 +40681,8 @@ var JpxImage = (function JpxImageClosure() {
if (i >= height) {
break;
}
+ // clear processed flag first
+ processingFlags[index] &= processedInverseMask;
if (coefficentsMagnitude[index] ||
!neighborsSignificance[index]) {
@@ -37619,10 +40692,10 @@ var JpxImage = (function JpxImageClosure() {
var contextLabel = labels[neighborsSignificance[index]];
var decision = decoder.readBit(contexts, contextLabel);
if (decision) {
- var sign = this.decodeSignBit(i, j);
+ var sign = this.decodeSignBit(i, j, index);
coefficentsSign[index] = sign;
coefficentsMagnitude[index] = 1;
- this.setNeighborsSignificance(i, j);
+ this.setNeighborsSignificance(i, j, index);
processingFlags[index] |= firstMagnitudeBitMask;
}
bitsDecoded[index]++;
@@ -37631,27 +40704,56 @@ var JpxImage = (function JpxImageClosure() {
}
}
},
- decodeSignBit: function BitModel_decodeSignBit(row, column) {
+ decodeSignBit: function BitModel_decodeSignBit(row, column, index) {
var width = this.width, height = this.height;
- var index = row * width + column;
var coefficentsMagnitude = this.coefficentsMagnitude;
var coefficentsSign = this.coefficentsSign;
- var horizontalContribution = calcSignContribution(
- column > 0 && coefficentsMagnitude[index - 1],
- coefficentsSign[index - 1],
- column + 1 < width && coefficentsMagnitude[index + 1],
- coefficentsSign[index + 1]);
- var verticalContribution = calcSignContribution(
- row > 0 && coefficentsMagnitude[index - width],
- coefficentsSign[index - width],
- row + 1 < height && coefficentsMagnitude[index + width],
- coefficentsSign[index + width]);
+ var contribution, sign0, sign1, significance1;
+ var contextLabel, decoded;
+
+ // calculate horizontal contribution
+ significance1 = (column > 0 && coefficentsMagnitude[index - 1] !== 0);
+ if (column + 1 < width && coefficentsMagnitude[index + 1] !== 0) {
+ sign1 = coefficentsSign[index + 1];
+ if (significance1) {
+ sign0 = coefficentsSign[index - 1];
+ contribution = 1 - sign1 - sign0;
+ } else {
+ contribution = 1 - sign1 - sign1;
+ }
+ } else if (significance1) {
+ sign0 = coefficentsSign[index - 1];
+ contribution = 1 - sign0 - sign0;
+ } else {
+ contribution = 0;
+ }
+ var horizontalContribution = 3 * contribution;
- var contextLabelAndXor = SignContextLabels[
- 3 * (1 - horizontalContribution) + (1 - verticalContribution)];
- var contextLabel = contextLabelAndXor.contextLabel;
- var decoded = this.decoder.readBit(this.contexts, contextLabel);
- return decoded ^ contextLabelAndXor.xorBit;
+ // calculate vertical contribution and combine with the horizontal
+ significance1 = (row > 0 && coefficentsMagnitude[index - width] !== 0);
+ if (row + 1 < height && coefficentsMagnitude[index + width] !== 0) {
+ sign1 = coefficentsSign[index + width];
+ if (significance1) {
+ sign0 = coefficentsSign[index - width];
+ contribution = 1 - sign1 - sign0 + horizontalContribution;
+ } else {
+ contribution = 1 - sign1 - sign1 + horizontalContribution;
+ }
+ } else if (significance1) {
+ sign0 = coefficentsSign[index - width];
+ contribution = 1 - sign0 - sign0 + horizontalContribution;
+ } else {
+ contribution = horizontalContribution;
+ }
+
+ if (contribution >= 0) {
+ contextLabel = 9 + contribution;
+ decoded = this.decoder.readBit(this.contexts, contextLabel);
+ } else {
+ contextLabel = 9 - contribution;
+ decoded = this.decoder.readBit(this.contexts, contextLabel) ^ 1;
+ }
+ return decoded;
},
runMagnitudeRefinementPass:
function BitModel_runMagnitudeRefinementPass() {
@@ -37664,14 +40766,13 @@ var JpxImage = (function JpxImageClosure() {
var processingFlags = this.processingFlags;
var processedMask = 1;
var firstMagnitudeBitMask = 2;
- for (var i0 = 0; i0 < height; i0 += 4) {
+ var length = width * height;
+ var width4 = width * 4;
+
+ for (var index0 = 0, indexNext; index0 < length; index0 = indexNext) {
+ indexNext = Math.min(length, index0 + width4);
for (var j = 0; j < width; j++) {
- for (var i1 = 0; i1 < 4; i1++) {
- var i = i0 + i1;
- if (i >= height) {
- break;
- }
- var index = i * width + j;
+ for (var index = index0 + j; index < indexNext; index += width) {
// significant but not those that have just become
if (!coefficentsMagnitude[index] ||
@@ -37681,12 +40782,10 @@ var JpxImage = (function JpxImageClosure() {
var contextLabel = 16;
if ((processingFlags[index] & firstMagnitudeBitMask) !== 0) {
- processingFlags[i * width + j] ^= firstMagnitudeBitMask;
+ processingFlags[index] ^= firstMagnitudeBitMask;
// first refinement
- var significance = neighborsSignificance[index];
- var sumOfSignificance = (significance & 3) +
- ((significance >> 2) & 3) + ((significance >> 4) & 7);
- contextLabel = sumOfSignificance >= 1 ? 15 : 14;
+ var significance = neighborsSignificance[index] & 127;
+ contextLabel = significance === 0 ? 15 : 14;
}
var bit = decoder.readBit(contexts, contextLabel);
@@ -37702,7 +40801,6 @@ var JpxImage = (function JpxImageClosure() {
var decoder = this.decoder;
var width = this.width, height = this.height;
var neighborsSignificance = this.neighborsSignificance;
- var significanceState = this.significanceState;
var coefficentsMagnitude = this.coefficentsMagnitude;
var coefficentsSign = this.coefficentsSign;
var contexts = this.contexts;
@@ -37714,12 +40812,16 @@ var JpxImage = (function JpxImageClosure() {
var oneRowDown = width;
var twoRowsDown = width * 2;
var threeRowsDown = width * 3;
- for (var i0 = 0; i0 < height; i0 += 4) {
+ var iNext;
+ for (var i0 = 0; i0 < height; i0 = iNext) {
+ iNext = Math.min(i0 + 4, height);
+ var indexBase = i0 * width;
+ var checkAllEmpty = i0 + 3 < height;
for (var j = 0; j < width; j++) {
- var index0 = i0 * width + j;
+ var index0 = indexBase + j;
// using the property: labels[neighborsSignificance[index]] == 0
// when neighborsSignificance[index] == 0
- var allEmpty = (i0 + 3 < height &&
+ var allEmpty = (checkAllEmpty &&
processingFlags[index0] === 0 &&
processingFlags[index0 + oneRowDown] === 0 &&
processingFlags[index0 + twoRowsDown] === 0 &&
@@ -37729,7 +40831,7 @@ var JpxImage = (function JpxImageClosure() {
neighborsSignificance[index0 + twoRowsDown] === 0 &&
neighborsSignificance[index0 + threeRowsDown] === 0);
var i1 = 0, index = index0;
- var i;
+ var i = i0, sign;
if (allEmpty) {
var hasSignificantCoefficent =
decoder.readBit(contexts, RUNLENGTH_CONTEXT);
@@ -37742,13 +40844,15 @@ var JpxImage = (function JpxImageClosure() {
}
i1 = (decoder.readBit(contexts, UNIFORM_CONTEXT) << 1) |
decoder.readBit(contexts, UNIFORM_CONTEXT);
- i = i0 + i1;
- index += i1 * width;
+ if (i1 !== 0) {
+ i = i0 + i1;
+ index += i1 * width;
+ }
- var sign = this.decodeSignBit(i, j);
+ sign = this.decodeSignBit(i, j, index);
coefficentsSign[index] = sign;
coefficentsMagnitude[index] = 1;
- this.setNeighborsSignificance(i, j);
+ this.setNeighborsSignificance(i, j, index);
processingFlags[index] |= firstMagnitudeBitMask;
index = index0;
@@ -37758,12 +40862,7 @@ var JpxImage = (function JpxImageClosure() {
i1++;
}
- for (; i1 < 4; i1++, index += width) {
- i = i0 + i1;
- if (i >= height) {
- break;
- }
-
+ for (i = i0 + i1; i < iNext; i++, index += width) {
if (coefficentsMagnitude[index] ||
(processingFlags[index] & processedMask) !== 0) {
continue;
@@ -37771,11 +40870,11 @@ var JpxImage = (function JpxImageClosure() {
var contextLabel = labels[neighborsSignificance[index]];
var decision = decoder.readBit(contexts, contextLabel);
- if (decision == 1) {
- var sign = this.decodeSignBit(i, j);
+ if (decision === 1) {
+ sign = this.decodeSignBit(i, j, index);
coefficentsSign[index] = sign;
coefficentsMagnitude[index] = 1;
- this.setNeighborsSignificance(i, j);
+ this.setNeighborsSignificance(i, j, index);
processingFlags[index] |= firstMagnitudeBitMask;
}
bitsDecoded[index]++;
@@ -37806,9 +40905,8 @@ var JpxImage = (function JpxImageClosure() {
Transform.prototype.calculate =
function transformCalculate(subbands, u0, v0) {
var ll = subbands[0];
- for (var i = 1, ii = subbands.length, j = 1; i < ii; i += 3, j++) {
- ll = this.iterate(ll, subbands[i], subbands[i + 1],
- subbands[i + 2], u0, v0);
+ for (var i = 1, ii = subbands.length; i < ii; i++) {
+ ll = this.iterate(ll, subbands[i], u0, v0);
}
return ll;
};
@@ -37825,63 +40923,46 @@ var JpxImage = (function JpxImageClosure() {
buffer[i1] = buffer[j1];
buffer[j2] = buffer[i2];
};
- Transform.prototype.iterate = function Transform_iterate(ll, hl, lh, hh,
- u0, v0) {
+ Transform.prototype.iterate = function Transform_iterate(ll, hl_lh_hh,
+ u0, v0) {
var llWidth = ll.width, llHeight = ll.height, llItems = ll.items;
- var hlWidth = hl.width, hlHeight = hl.height, hlItems = hl.items;
- var lhWidth = lh.width, lhHeight = lh.height, lhItems = lh.items;
- var hhWidth = hh.width, hhHeight = hh.height, hhItems = hh.items;
+ var width = hl_lh_hh.width;
+ var height = hl_lh_hh.height;
+ var items = hl_lh_hh.items;
+ var i, j, k, l, u, v;
- // Section F.3.3 interleave
- var width = llWidth + hlWidth;
- var height = llHeight + lhHeight;
- var items = new Float32Array(width * height);
- var i, j, k, l;
-
- for (i = 0; i < llHeight; i++) {
- var k = i * llWidth, l = i * 2 * width;
- for (var j = 0; j < llWidth; j++, k++, l += 2) {
+ // Interleave LL according to Section F.3.3
+ for (k = 0, i = 0; i < llHeight; i++) {
+ l = i * 2 * width;
+ for (j = 0; j < llWidth; j++, k++, l += 2) {
items[l] = llItems[k];
}
}
- for (i = 0; i < hlHeight; i++) {
- k = i * hlWidth; l = i * 2 * width + 1;
- for (j = 0; j < hlWidth; j++, k++, l += 2) {
- items[l] = hlItems[k];
- }
- }
- for (i = 0; i < lhHeight; i++) {
- k = i * lhWidth; l = (i * 2 + 1) * width;
- for (j = 0; j < lhWidth; j++, k++, l += 2) {
- items[l] = lhItems[k];
- }
- }
- for (i = 0; i < hhHeight; i++) {
- k = i * hhWidth; l = (i * 2 + 1) * width + 1;
- for (j = 0; j < hhWidth; j++, k++, l += 2) {
- items[l] = hhItems[k];
- }
- }
+ // The LL band is not needed anymore.
+ llItems = ll.items = null;
var bufferPadding = 4;
var rowBuffer = new Float32Array(width + 2 * bufferPadding);
// Section F.3.4 HOR_SR
- for (var v = 0; v < height; v++) {
- if (width == 1) {
- // if width = 1, when u0 even keep items as is, when odd divide by 2
- if ((u0 % 1) !== 0) {
- items[v * width] /= 2;
+ if (width === 1) {
+ // if width = 1, when u0 even keep items as is, when odd divide by 2
+ if ((u0 & 1) !== 0) {
+ for (v = 0, k = 0; v < height; v++, k += width) {
+ items[k] *= 0.5;
}
- continue;
}
- k = v * width;
- rowBuffer.set(items.subarray(k, k + width), bufferPadding);
+ } else {
+ for (v = 0, k = 0; v < height; v++, k += width) {
+ rowBuffer.set(items.subarray(k, k + width), bufferPadding);
- this.extend(rowBuffer, bufferPadding, width);
- this.filter(rowBuffer, bufferPadding, width, u0, rowBuffer);
+ this.extend(rowBuffer, bufferPadding, width);
+ this.filter(rowBuffer, bufferPadding, width);
- items.set(rowBuffer.subarray(bufferPadding, bufferPadding + width), k);
+ items.set(
+ rowBuffer.subarray(bufferPadding, bufferPadding + width),
+ k);
+ }
}
// Accesses to the items array can take long, because it may not fit into
@@ -37895,40 +40976,42 @@ var JpxImage = (function JpxImageClosure() {
for (i = 0; i < numBuffers; i++) {
colBuffers.push(new Float32Array(height + 2 * bufferPadding));
}
- var b, currentBuffer = 0, ll = bufferPadding + height;
+ var b, currentBuffer = 0;
+ ll = bufferPadding + height;
// Section F.3.5 VER_SR
- for (var u = 0; u < width; u++) {
- if (height == 1) {
+ if (height === 1) {
// if height = 1, when v0 even keep items as is, when odd divide by 2
- if ((v0 % 1) !== 0) {
- items[u] /= 2;
+ if ((v0 & 1) !== 0) {
+ for (u = 0; u < width; u++) {
+ items[u] *= 0.5;
}
- continue;
}
-
- // if we ran out of buffers, copy several image columns at once
- if (currentBuffer === 0) {
- numBuffers = Math.min(width - u, numBuffers);
- for (k = u, l = bufferPadding; l < ll; k += width, l++) {
- for (b = 0; b < numBuffers; b++) {
- colBuffers[b][l] = items[k + b];
+ } else {
+ for (u = 0; u < width; u++) {
+ // if we ran out of buffers, copy several image columns at once
+ if (currentBuffer === 0) {
+ numBuffers = Math.min(width - u, numBuffers);
+ for (k = u, l = bufferPadding; l < ll; k += width, l++) {
+ for (b = 0; b < numBuffers; b++) {
+ colBuffers[b][l] = items[k + b];
+ }
}
+ currentBuffer = numBuffers;
}
- currentBuffer = numBuffers;
- }
- currentBuffer--;
- var buffer = colBuffers[currentBuffer];
- this.extend(buffer, bufferPadding, height);
- this.filter(buffer, bufferPadding, height, v0, buffer);
+ currentBuffer--;
+ var buffer = colBuffers[currentBuffer];
+ this.extend(buffer, bufferPadding, height);
+ this.filter(buffer, bufferPadding, height);
- // If this is last buffer in this group of buffers, flush all buffers.
- if (currentBuffer === 0) {
- k = u - numBuffers + 1;
- for (l = bufferPadding; l < ll; k += width, l++) {
- for (b = 0; b < numBuffers; b++) {
- items[k + b] = colBuffers[b][l];
+ // If this is last buffer in this group of buffers, flush all buffers.
+ if (currentBuffer === 0) {
+ k = u - numBuffers + 1;
+ for (l = bufferPadding; l < ll; k += width, l++) {
+ for (b = 0; b < numBuffers; b++) {
+ items[k + b] = colBuffers[b][l];
+ }
}
}
}
@@ -37951,10 +41034,10 @@ var JpxImage = (function JpxImageClosure() {
IrreversibleTransform.prototype = Object.create(Transform.prototype);
IrreversibleTransform.prototype.filter =
- function irreversibleTransformFilter(y, offset, length, i0, x) {
- var i0_ = Math.floor(i0 / 2);
- var i1_ = Math.floor((i0 + length) / 2);
- var offset_ = offset - (i0 % 1);
+ function irreversibleTransformFilter(x, offset, length) {
+ var len = length >> 1;
+ offset = offset | 0;
+ var j, n, current, next;
var alpha = -1.586134342059924;
var beta = -0.052980118572961;
@@ -37963,40 +41046,74 @@ var JpxImage = (function JpxImageClosure() {
var K = 1.230174104914001;
var K_ = 1 / K;
- // step 1
- var j = offset_ - 2;
- for (var n = i0_ - 1, nn = i1_ + 2; n < nn; n++, j += 2) {
- x[j] = K * y[j];
- }
+ // step 1 is combined with step 3
// step 2
- var j = offset_ - 3;
- for (var n = i0_ - 2, nn = i1_ + 2; n < nn; n++, j += 2) {
- x[j] = K_ * y[j];
+ j = offset - 3;
+ for (n = len + 4; n--; j += 2) {
+ x[j] *= K_;
}
- // step 3
- var j = offset_ - 2;
- for (var n = i0_ - 1, nn = i1_ + 2; n < nn; n++, j += 2) {
- x[j] -= delta * (x[j - 1] + x[j + 1]);
+ // step 1 & 3
+ j = offset - 2;
+ current = delta * x[j -1];
+ for (n = len + 3; n--; j += 2) {
+ next = delta * x[j + 1];
+ x[j] = K * x[j] - current - next;
+ if (n--) {
+ j += 2;
+ current = delta * x[j + 1];
+ x[j] = K * x[j] - current - next;
+ } else {
+ break;
+ }
}
// step 4
- var j = offset_ - 1;
- for (var n = i0_ - 1, nn = i1_ + 1; n < nn; n++, j += 2) {
- x[j] -= gamma * (x[j - 1] + x[j + 1]);
+ j = offset - 1;
+ current = gamma * x[j - 1];
+ for (n = len + 2; n--; j += 2) {
+ next = gamma * x[j + 1];
+ x[j] -= current + next;
+ if (n--) {
+ j += 2;
+ current = gamma * x[j + 1];
+ x[j] -= current + next;
+ } else {
+ break;
+ }
}
// step 5
- var j = offset_;
- for (var n = i0_, nn = i1_ + 1; n < nn; n++, j += 2) {
- x[j] -= beta * (x[j - 1] + x[j + 1]);
+ j = offset;
+ current = beta * x[j - 1];
+ for (n = len + 1; n--; j += 2) {
+ next = beta * x[j + 1];
+ x[j] -= current + next;
+ if (n--) {
+ j += 2;
+ current = beta * x[j + 1];
+ x[j] -= current + next;
+ } else {
+ break;
+ }
}
// step 6
- var j = offset_ + 1;
- for (var n = i0_, nn = i1_; n < nn; n++, j += 2) {
- x[j] -= alpha * (x[j - 1] + x[j + 1]);
+ if (len !== 0) {
+ j = offset + 1;
+ current = alpha * x[j - 1];
+ for (n = len; n--; j += 2) {
+ next = alpha * x[j + 1];
+ x[j] -= current + next;
+ if (n--) {
+ j += 2;
+ current = alpha * x[j + 1];
+ x[j] -= current + next;
+ } else {
+ break;
+ }
+ }
}
};
@@ -38011,17 +41128,17 @@ var JpxImage = (function JpxImageClosure() {
ReversibleTransform.prototype = Object.create(Transform.prototype);
ReversibleTransform.prototype.filter =
- function reversibleTransformFilter(y, offset, length, i0, x) {
- var i0_ = Math.floor(i0 / 2);
- var i1_ = Math.floor((i0 + length) / 2);
- var offset_ = offset - (i0 % 1);
+ function reversibleTransformFilter(x, offset, length) {
+ var len = length >> 1;
+ offset = offset | 0;
+ var j, n;
- for (var n = i0_, nn = i1_ + 1, j = offset_; n < nn; n++, j += 2) {
- x[j] = y[j] - Math.floor((y[j - 1] + y[j + 1] + 2) / 4);
+ for (j = offset, n = len + 1; n--; j += 2) {
+ x[j] -= (x[j - 1] + x[j + 1] + 2) >> 2;
}
- for (var n = i0_, nn = i1_, j = offset_ + 1; n < nn; n++, j += 2) {
- x[j] = y[j] + Math.floor((x[j - 1] + x[j + 1]) / 2);
+ for (j = offset + 1, n = len; n--; j += 2) {
+ x[j] += (x[j - 1] + x[j + 1]) >> 1;
}
};
@@ -38042,7 +41159,7 @@ var Jbig2Image = (function Jbig2ImageClosure() {
if (id in this) {
return this[id];
}
- return (this[id] = new Int8Array(1<<16));
+ return (this[id] = new Int8Array(1 << 16));
}
};
@@ -38067,69 +41184,32 @@ var Jbig2Image = (function Jbig2ImageClosure() {
// A.2 Procedure for decoding values
function decodeInteger(contextCache, procedure, decoder) {
var contexts = contextCache.getContexts(procedure);
-
var prev = 1;
- var state = 1, v = 0, s;
- var toRead = 32, offset = 4436; // defaults for state 7
- while (state) {
- var bit = decoder.readBit(contexts, prev);
- prev = (prev < 256 ? (prev << 1) | bit :
- (((prev << 1) | bit) & 511) | 256);
- switch (state) {
- case 1:
- s = !!bit;
- break;
- case 2:
- if (bit) {
- break;
- }
- state = 7;
- toRead = 2;
- offset = 0;
- break;
- case 3:
- if (bit) {
- break;
- }
- state = 7;
- toRead = 4;
- offset = 4;
- break;
- case 4:
- if (bit) {
- break;
- }
- state = 7;
- toRead = 6;
- offset = 20;
- break;
- case 5:
- if (bit) {
- break;
- }
- state = 7;
- toRead = 8;
- offset = 84;
- break;
- case 6:
- if (bit) {
- break;
- }
- state = 7;
- toRead = 12;
- offset = 340;
- break;
- default:
- v = ((v << 1) | bit) >>> 0;
- if (--toRead === 0) {
- state = 0;
- }
- continue;
+
+ function readBits(length) {
+ var v = 0;
+ for (var i = 0; i < length; i++) {
+ var bit = decoder.readBit(contexts, prev);
+ prev = (prev < 256 ? (prev << 1) | bit :
+ (((prev << 1) | bit) & 511) | 256);
+ v = (v << 1) | bit;
}
- state++;
+ return v >>> 0;
}
- v += offset;
- return (!s ? v : (v > 0 ? -v : null));
+
+ var sign = readBits(1);
+ var value = readBits(1) ?
+ (readBits(1) ?
+ (readBits(1) ?
+ (readBits(1) ?
+ (readBits(1) ?
+ (readBits(32) + 4436) :
+ readBits(12) + 340) :
+ readBits(8) + 84) :
+ readBits(6) + 20) :
+ readBits(4) + 4) :
+ readBits(2);
+ return (sign === 0 ? value : (value > 0 ? -value : null));
}
// A.3 The IAID decoding procedure
@@ -38203,33 +41283,6 @@ var Jbig2Image = (function Jbig2ImageClosure() {
0x0008 // '0000' + '001000'
];
- function log2(x) {
- var n = 1, i = 0;
- while (x > n) {
- n <<= 1;
- i++;
- }
- return i;
- }
-
- function readInt32(data, start) {
- return (data[start] << 24) | (data[start + 1] << 16) |
- (data[start + 2] << 8) | data[start + 3];
- }
-
- function readUint32(data, start) {
- var value = readInt32(data, start);
- return value & 0x80000000 ? (value + 4294967296) : value;
- }
-
- function readUint16(data, start) {
- return (data[start] << 8) | data[start + 1];
- }
-
- function readInt8(data, start) {
- return (data[start] << 24) >> 24;
- }
-
// 6.2 Generic Region Decoding Procedure
function decodeBitmap(mmr, width, height, templateIndex, prediction, skip, at,
decodingContext) {
@@ -38252,8 +41305,9 @@ var Jbig2Image = (function Jbig2ImageClosure() {
var templateY = new Int8Array(templateLength);
var changingTemplateEntries = [];
var reuseMask = 0, minX = 0, maxX = 0, minY = 0;
+ var c, k;
- for (var k = 0; k < templateLength; k++) {
+ for (k = 0; k < templateLength; k++) {
templateX[k] = template[k].x;
templateY[k] = template[k].y;
minX = Math.min(minX, template[k].x);
@@ -38275,7 +41329,7 @@ var Jbig2Image = (function Jbig2ImageClosure() {
var changingTemplateX = new Int8Array(changingEntriesLength);
var changingTemplateY = new Int8Array(changingEntriesLength);
var changingTemplateBit = new Uint16Array(changingEntriesLength);
- for (var c = 0; c < changingEntriesLength; c++) {
+ for (c = 0; c < changingEntriesLength; c++) {
k = changingTemplateEntries[c];
changingTemplateX[c] = template[k].x;
changingTemplateY[c] = template[k].y;
@@ -38294,7 +41348,7 @@ var Jbig2Image = (function Jbig2ImageClosure() {
var decoder = decodingContext.decoder;
var contexts = decodingContext.contextCache.getContexts('GB');
- var ltp = 0, c, j, i0, j0, k, contextLabel = 0, bit, shift;
+ var ltp = 0, j, i0, j0, contextLabel = 0, bit, shift;
for (var i = 0; i < height; i++) {
if (prediction) {
var sltp = decoder.readBit(contexts, pseudoPixelContext);
@@ -38361,7 +41415,8 @@ var Jbig2Image = (function Jbig2ImageClosure() {
var codingTemplateLength = codingTemplate.length;
var codingTemplateX = new Int32Array(codingTemplateLength);
var codingTemplateY = new Int32Array(codingTemplateLength);
- for (var k = 0; k < codingTemplateLength; k++) {
+ var k;
+ for (k = 0; k < codingTemplateLength; k++) {
codingTemplateX[k] = codingTemplate[k].x;
codingTemplateY[k] = codingTemplate[k].y;
}
@@ -38373,7 +41428,7 @@ var Jbig2Image = (function Jbig2ImageClosure() {
var referenceTemplateLength = referenceTemplate.length;
var referenceTemplateX = new Int32Array(referenceTemplateLength);
var referenceTemplateY = new Int32Array(referenceTemplateLength);
- for (var k = 0; k < referenceTemplateLength; k++) {
+ for (k = 0; k < referenceTemplateLength; k++) {
referenceTemplateX[k] = referenceTemplate[k].x;
referenceTemplateY[k] = referenceTemplate[k].y;
}
@@ -38398,19 +41453,20 @@ var Jbig2Image = (function Jbig2ImageClosure() {
var row = new Uint8Array(width);
bitmap.push(row);
for (var j = 0; j < width; j++) {
-
+ var i0, j0;
var contextLabel = 0;
- for (var k = 0; k < codingTemplateLength; k++) {
- var i0 = i + codingTemplateY[k], j0 = j + codingTemplateX[k];
+ for (k = 0; k < codingTemplateLength; k++) {
+ i0 = i + codingTemplateY[k];
+ j0 = j + codingTemplateX[k];
if (i0 < 0 || j0 < 0 || j0 >= width) {
contextLabel <<= 1; // out of bound pixel
} else {
contextLabel = (contextLabel << 1) | bitmap[i0][j0];
}
}
- for (var k = 0; k < referenceTemplateLength; k++) {
- var i0 = i + referenceTemplateY[k] + offsetY;
- var j0 = j + referenceTemplateX[k] + offsetX;
+ for (k = 0; k < referenceTemplateLength; k++) {
+ i0 = i + referenceTemplateY[k] + offsetY;
+ j0 = j + referenceTemplateX[k] + offsetX;
if (i0 < 0 || i0 >= referenceHeight || j0 < 0 ||
j0 >= referenceWidth) {
contextLabel <<= 1; // out of bound pixel
@@ -38460,16 +41516,28 @@ var Jbig2Image = (function Jbig2ImageClosure() {
// 6.5.8.2 Refinement/aggregate-coded symbol bitmap
var numberOfInstances = decodeInteger(contextCache, 'IAAI', decoder);
if (numberOfInstances > 1) {
- error('JBIG2 error: number of instances > 1 is not supported');
- }
- var symbolId = decodeIAID(contextCache, decoder, symbolCodeLength);
- var rdx = decodeInteger(contextCache, 'IARDX', decoder); // 6.4.11.3
- var rdy = decodeInteger(contextCache, 'IARDY', decoder); // 6.4.11.4
- var symbol = (symbolId < symbols.length ? symbols[symbolId] :
- newSymbols[symbolId - symbols.length]);
- bitmap = decodeRefinement(currentWidth, currentHeight,
+ bitmap = decodeTextRegion(huffman, refinement,
+ currentWidth, currentHeight, 0,
+ numberOfInstances, 1, //strip size
+ symbols.concat(newSymbols),
+ symbolCodeLength,
+ 0, //transposed
+ 0, //ds offset
+ 1, //top left 7.4.3.1.1
+ 0, //OR operator
+ huffmanTables,
+ refinementTemplateIndex, refinementAt,
+ decodingContext);
+ } else {
+ var symbolId = decodeIAID(contextCache, decoder, symbolCodeLength);
+ var rdx = decodeInteger(contextCache, 'IARDX', decoder); // 6.4.11.3
+ var rdy = decodeInteger(contextCache, 'IARDY', decoder); // 6.4.11.4
+ var symbol = (symbolId < symbols.length ? symbols[symbolId] :
+ newSymbols[symbolId - symbols.length]);
+ bitmap = decodeRefinement(currentWidth, currentHeight,
refinementTemplateIndex, symbol, rdx, rdy, false, refinementAt,
decodingContext);
+ }
} else {
// 6.5.8.1 Direct-coded symbol bitmap
bitmap = decodeBitmap(false, currentWidth, currentHeight,
@@ -38515,8 +41583,9 @@ var Jbig2Image = (function Jbig2ImageClosure() {
// Prepare bitmap
var bitmap = [];
- for (var i = 0; i < height; i++) {
- var row = new Uint8Array(width);
+ var i, row;
+ for (i = 0; i < height; i++) {
+ row = new Uint8Array(width);
if (defaultPixelValue) {
for (var j = 0; j < width; j++) {
row[j] = defaultPixelValue;
@@ -38529,7 +41598,7 @@ var Jbig2Image = (function Jbig2ImageClosure() {
var contextCache = decodingContext.contextCache;
var stripT = -decodeInteger(contextCache, 'IADT', decoder); // 6.4.6
var firstS = 0;
- var i = 0;
+ i = 0;
while (i < numberOfSymbolInstances) {
var deltaT = decodeInteger(contextCache, 'IADT', decoder); // 6.4.6
stripT += deltaT;
@@ -38538,12 +41607,12 @@ var Jbig2Image = (function Jbig2ImageClosure() {
firstS += deltaFirstS;
var currentS = firstS;
do {
- var currentT = stripSize == 1 ? 0 :
- decodeInteger(contextCache, 'IAIT', decoder); // 6.4.9
+ var currentT = (stripSize == 1 ? 0 :
+ decodeInteger(contextCache, 'IAIT', decoder)); // 6.4.9
var t = stripSize * stripT + currentT;
var symbolId = decodeIAID(contextCache, decoder, symbolCodeLength);
- var applyRefinement = refinement &&
- decodeInteger(contextCache, 'IARI', decoder);
+ var applyRefinement = (refinement &&
+ decodeInteger(contextCache, 'IARI', decoder));
var symbolBitmap = inputSymbols[symbolId];
var symbolWidth = symbolBitmap[0].length;
var symbolHeight = symbolBitmap.length;
@@ -38561,25 +41630,26 @@ var Jbig2Image = (function Jbig2ImageClosure() {
}
var offsetT = t - ((referenceCorner & 1) ? 0 : symbolHeight);
var offsetS = currentS - ((referenceCorner & 2) ? symbolWidth : 0);
+ var s2, t2, symbolRow;
if (transposed) {
// Place Symbol Bitmap from T1,S1
- for (var s2 = 0; s2 < symbolHeight; s2++) {
- var row = bitmap[offsetS + s2];
+ for (s2 = 0; s2 < symbolHeight; s2++) {
+ row = bitmap[offsetS + s2];
if (!row) {
continue;
}
- var symbolRow = symbolBitmap[s2];
+ symbolRow = symbolBitmap[s2];
// To ignore Parts of Symbol bitmap which goes
// outside bitmap region
var maxWidth = Math.min(width - offsetT, symbolWidth);
switch (combinationOperator) {
case 0: // OR
- for (var t2 = 0; t2 < maxWidth; t2++) {
+ for (t2 = 0; t2 < maxWidth; t2++) {
row[offsetT + t2] |= symbolRow[t2];
}
break;
case 2: // XOR
- for (var t2 = 0; t2 < maxWidth; t2++) {
+ for (t2 = 0; t2 < maxWidth; t2++) {
row[offsetT + t2] ^= symbolRow[t2];
}
break;
@@ -38590,20 +41660,20 @@ var Jbig2Image = (function Jbig2ImageClosure() {
}
currentS += symbolHeight - 1;
} else {
- for (var t2 = 0; t2 < symbolHeight; t2++) {
- var row = bitmap[offsetT + t2];
+ for (t2 = 0; t2 < symbolHeight; t2++) {
+ row = bitmap[offsetT + t2];
if (!row) {
continue;
}
- var symbolRow = symbolBitmap[t2];
+ symbolRow = symbolBitmap[t2];
switch (combinationOperator) {
case 0: // OR
- for (var s2 = 0; s2 < symbolWidth; s2++) {
+ for (s2 = 0; s2 < symbolWidth; s2++) {
row[offsetS + s2] |= symbolRow[s2];
}
break;
case 2: // XOR
- for (var s2 = 0; s2 < symbolWidth; s2++) {
+ for (s2 = 0; s2 < symbolWidth; s2++) {
row[offsetS + s2] ^= symbolRow[s2];
}
break;
@@ -38643,7 +41713,7 @@ var Jbig2Image = (function Jbig2ImageClosure() {
var retainBits = [referredFlags & 31];
var position = start + 6;
if (referredFlags == 7) {
- referredToCount = readInt32(data, position - 1) & 0x1FFFFFFF;
+ referredToCount = readUint32(data, position - 1) & 0x1FFFFFFF;
position += 3;
var bytes = (referredToCount + 7) >> 3;
retainBits[0] = data[position++];
@@ -38658,7 +41728,8 @@ var Jbig2Image = (function Jbig2ImageClosure() {
var referredToSegmentNumberSize = (segmentHeader.number <= 256 ? 1 :
(segmentHeader.number <= 65536 ? 2 : 4));
var referredTo = [];
- for (var i = 0; i < referredToCount; i++) {
+ var i, ii;
+ for (i = 0; i < referredToCount; i++) {
var number = (referredToSegmentNumberSize == 1 ? data[position] :
(referredToSegmentNumberSize == 2 ? readUint16(data, position) :
readUint32(data, position)));
@@ -38693,7 +41764,7 @@ var Jbig2Image = (function Jbig2ImageClosure() {
searchPattern[3] = (genericRegionInfo.height >> 16) & 0xFF;
searchPattern[4] = (genericRegionInfo.height >> 8) & 0xFF;
searchPattern[5] = genericRegionInfo.height & 0xFF;
- for (var i = position, ii = data.length; i < ii; i++) {
+ for (i = position, ii = data.length; i < ii; i++) {
var j = 0;
while (j < searchPatternLength && searchPattern[j] === data[i + j]) {
j++;
@@ -38760,7 +41831,7 @@ var Jbig2Image = (function Jbig2ImageClosure() {
var header = segment.header;
var data = segment.data, position = segment.start, end = segment.end;
- var args;
+ var args, at, i, atLength;
switch (header.type) {
case 0: // SymbolDictionary
// 7.4.2 Symbol dictionary segment syntax
@@ -38778,9 +41849,9 @@ var Jbig2Image = (function Jbig2ImageClosure() {
dictionary.refinementTemplate = (dictionaryFlags >> 12) & 1;
position += 2;
if (!dictionary.huffman) {
- var atLength = dictionary.template === 0 ? 4 : 1;
- var at = [];
- for (var i = 0; i < atLength; i++) {
+ atLength = dictionary.template === 0 ? 4 : 1;
+ at = [];
+ for (i = 0; i < atLength; i++) {
at.push({
x: readInt8(data, position),
y: readInt8(data, position + 1)
@@ -38790,8 +41861,8 @@ var Jbig2Image = (function Jbig2ImageClosure() {
dictionary.at = at;
}
if (dictionary.refinement && !dictionary.refinementTemplate) {
- var at = [];
- for (var i = 0; i < 2; i++) {
+ at = [];
+ for (i = 0; i < 2; i++) {
at.push({
x: readInt8(data, position),
y: readInt8(data, position + 1)
@@ -38837,8 +41908,8 @@ var Jbig2Image = (function Jbig2ImageClosure() {
!!(textRegionHuffmanFlags & 14);
}
if (textRegion.refinement && !textRegion.refinementTemplate) {
- var at = [];
- for (var i = 0; i < 2; i++) {
+ at = [];
+ for (i = 0; i < 2; i++) {
at.push({
x: readInt8(data, position),
y: readInt8(data, position + 1)
@@ -38865,9 +41936,9 @@ var Jbig2Image = (function Jbig2ImageClosure() {
genericRegion.template = (genericRegionSegmentFlags >> 1) & 3;
genericRegion.prediction = !!(genericRegionSegmentFlags & 8);
if (!genericRegion.mmr) {
- var atLength = genericRegion.template === 0 ? 4 : 1;
- var at = [];
- for (var i = 0; i < atLength; i++) {
+ atLength = genericRegion.template === 0 ? 4 : 1;
+ at = [];
+ for (i = 0; i < atLength; i++) {
at.push({
x: readInt8(data, position),
y: readInt8(data, position + 1)
@@ -38979,12 +42050,13 @@ var Jbig2Image = (function Jbig2ImageClosure() {
var buffer = this.buffer;
var mask0 = 128 >> (regionInfo.x & 7);
var offset0 = regionInfo.y * rowSize + (regionInfo.x >> 3);
+ var i, j, mask, offset;
switch (combinationOperator) {
case 0: // OR
- for (var i = 0; i < height; i++) {
- var mask = mask0;
- var offset = offset0;
- for (var j = 0; j < width; j++) {
+ for (i = 0; i < height; i++) {
+ mask = mask0;
+ offset = offset0;
+ for (j = 0; j < width; j++) {
if (bitmap[i][j]) {
buffer[offset] |= mask;
}
@@ -38998,10 +42070,10 @@ var Jbig2Image = (function Jbig2ImageClosure() {
}
break;
case 2: // XOR
- for (var i = 0; i < height; i++) {
- var mask = mask0;
- var offset = offset0;
- for (var j = 0; j < width; j++) {
+ for (i = 0; i < height; i++) {
+ mask = mask0;
+ offset = offset0;
+ for (j = 0; j < width; j++) {
if (bitmap[i][j]) {
buffer[offset] ^= mask;
}
@@ -39163,7 +42235,6 @@ var bidi = PDFJS.bidi = (function bidiClosure() {
}
function findUnequal(arr, start, value) {
- var j;
for (var j = start, jj = arr.length; j < jj; ++j) {
if (arr[j] != value) {
return j;
@@ -39186,64 +42257,32 @@ var bidi = PDFJS.bidi = (function bidiClosure() {
}
}
- 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 createBidiText(str, isLTR, vertical) {
+ return {
+ str: str,
+ dir: (vertical ? 'ttb' : (isLTR ? 'ltr' : 'rtl'))
+ };
}
- function BidiResult(str, isLTR, vertical) {
- this.str = str;
- this.dir = (vertical ? 'ttb' : (isLTR ? 'ltr' : 'rtl'));
- }
+ // These are used in bidi(), which is called frequently. We re-use them on
+ // each call to avoid unnecessary allocations.
+ var chars = [];
+ var types = [];
function bidi(str, startLevel, vertical) {
var isLTR = true;
var strLength = str.length;
if (strLength === 0 || vertical) {
- return new BidiResult(str, isLTR, vertical);
+ return createBidiText(str, isLTR, vertical);
}
// Get types and fill arrays
- var chars = [];
- var types = [];
+ chars.length = 0;
+ types.length = 0;
var numBidi = 0;
- for (var i = 0; i < strLength; ++i) {
+ var i, ii;
+ for (i = 0; i < strLength; ++i) {
chars[i] = str.charAt(i);
var charCode = str.charCodeAt(i);
@@ -39269,7 +42308,7 @@ var bidi = PDFJS.bidi = (function bidiClosure() {
// - If more than 30% chars are rtl then string is primarily rtl
if (numBidi === 0) {
isLTR = true;
- return new BidiResult(str, isLTR);
+ return createBidiText(str, isLTR);
}
if (startLevel == -1) {
@@ -39283,7 +42322,7 @@ var bidi = PDFJS.bidi = (function bidiClosure() {
}
var levels = [];
- for (var i = 0; i < strLength; ++i) {
+ for (i = 0; i < strLength; ++i) {
levels[i] = startLevel;
}
@@ -39300,7 +42339,7 @@ var bidi = PDFJS.bidi = (function bidiClosure() {
start of the level run, it will get the type of sor.
*/
var lastType = sor;
- for (var i = 0; i < strLength; ++i) {
+ for (i = 0; i < strLength; ++i) {
if (types[i] == 'NSM') {
types[i] = lastType;
} else {
@@ -39313,9 +42352,10 @@ var bidi = PDFJS.bidi = (function bidiClosure() {
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];
+ lastType = sor;
+ var t;
+ for (i = 0; i < strLength; ++i) {
+ t = types[i];
if (t == 'EN') {
types[i] = (lastType == 'AL') ? 'AN' : 'EN';
} else if (t == 'R' || t == 'L' || t == 'AL') {
@@ -39326,8 +42366,8 @@ var bidi = PDFJS.bidi = (function bidiClosure() {
/*
W3. Change all ALs to R.
*/
- for (var i = 0; i < strLength; ++i) {
- var t = types[i];
+ for (i = 0; i < strLength; ++i) {
+ t = types[i];
if (t == 'AL') {
types[i] = 'R';
}
@@ -39338,7 +42378,7 @@ var bidi = PDFJS.bidi = (function bidiClosure() {
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) {
+ for (i = 1; i < strLength - 1; ++i) {
if (types[i] == 'ES' && types[i - 1] == 'EN' && types[i + 1] == 'EN') {
types[i] = 'EN';
}
@@ -39352,17 +42392,18 @@ var bidi = PDFJS.bidi = (function bidiClosure() {
W5. A sequence of European terminators adjacent to European numbers changes
to all European numbers:
*/
- for (var i = 0; i < strLength; ++i) {
+ for (i = 0; i < strLength; ++i) {
if (types[i] == 'EN') {
// do before
- for (var j = i - 1; j >= 0; --j) {
+ var j;
+ for (j = i - 1; j >= 0; --j) {
if (types[j] != 'ET') {
break;
}
types[j] = 'EN';
}
// do after
- for (var j = i + 1; j < strLength; --j) {
+ for (j = i + 1; j < strLength; --j) {
if (types[j] != 'ET') {
break;
}
@@ -39374,8 +42415,8 @@ var bidi = PDFJS.bidi = (function bidiClosure() {
/*
W6. Otherwise, separators and terminators change to Other Neutral:
*/
- for (var i = 0; i < strLength; ++i) {
- var t = types[i];
+ for (i = 0; i < strLength; ++i) {
+ t = types[i];
if (t == 'WS' || t == 'ES' || t == 'ET' || t == 'CS') {
types[i] = 'ON';
}
@@ -39386,9 +42427,9 @@ var bidi = PDFJS.bidi = (function bidiClosure() {
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];
+ lastType = sor;
+ for (i = 0; i < strLength; ++i) {
+ t = types[i];
if (t == 'EN') {
types[i] = ((lastType == 'L') ? 'L' : 'EN');
} else if (t == 'R' || t == 'L') {
@@ -39402,7 +42443,7 @@ var bidi = PDFJS.bidi = (function bidiClosure() {
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) {
+ for (i = 0; i < strLength; ++i) {
if (types[i] == 'ON') {
var end = findUnequal(types, i + 1, 'ON');
var before = sor;
@@ -39430,7 +42471,7 @@ var bidi = PDFJS.bidi = (function bidiClosure() {
/*
N2. Any remaining neutrals take the embedding direction.
*/
- for (var i = 0; i < strLength; ++i) {
+ for (i = 0; i < strLength; ++i) {
if (types[i] == 'ON') {
types[i] = e;
}
@@ -39443,8 +42484,8 @@ var bidi = PDFJS.bidi = (function bidiClosure() {
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];
+ for (i = 0; i < strLength; ++i) {
+ t = types[i];
if (isEven(levels[i])) {
if (t == 'R') {
levels[i] += 1;
@@ -39480,8 +42521,9 @@ var bidi = PDFJS.bidi = (function bidiClosure() {
// 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];
+ var level;
+ for (i = 0, ii = levels.length; i < ii; ++i) {
+ level = levels[i];
if (highestLevel < level) {
highestLevel = level;
}
@@ -39491,10 +42533,10 @@ var bidi = PDFJS.bidi = (function bidiClosure() {
}
// now reverse between those limits
- for (var level = highestLevel; level >= lowestOddLevel; --level) {
+ for (level = highestLevel; level >= lowestOddLevel; --level) {
// find segments to reverse
var start = -1;
- for (var i = 0, ii = levels.length; i < ii; ++i) {
+ for (i = 0, ii = levels.length; i < ii; ++i) {
if (levels[i] < level) {
if (start >= 0) {
reverseValues(chars, start, i);
@@ -39528,1439 +42570,182 @@ var bidi = PDFJS.bidi = (function bidiClosure() {
// Finally, return string
var result = '';
- for (var i = 0, ii = chars.length; i < ii; ++i) {
+ for (i = 0, ii = chars.length; i < ii; ++i) {
var ch = chars[i];
if (ch != '<' && ch != '>') {
result += ch;
}
}
- return new BidiResult(result, isLTR);
+ return createBidiText(result, isLTR);
}
return bidi;
})();
-
-var BUILT_IN_CMAPS = [
-// << Start unicode maps.
-'Adobe-GB1-UCS2',
-'Adobe-CNS1-UCS2',
-'Adobe-Japan1-UCS2',
-'Adobe-Korea1-UCS2',
-// >> End unicode maps.
-'78-EUC-H',
-'78-EUC-V',
-'78-H',
-'78-RKSJ-H',
-'78-RKSJ-V',
-'78-V',
-'78ms-RKSJ-H',
-'78ms-RKSJ-V',
-'83pv-RKSJ-H',
-'90ms-RKSJ-H',
-'90ms-RKSJ-V',
-'90msp-RKSJ-H',
-'90msp-RKSJ-V',
-'90pv-RKSJ-H',
-'90pv-RKSJ-V',
-'Add-H',
-'Add-RKSJ-H',
-'Add-RKSJ-V',
-'Add-V',
-'Adobe-CNS1-0',
-'Adobe-CNS1-1',
-'Adobe-CNS1-2',
-'Adobe-CNS1-3',
-'Adobe-CNS1-4',
-'Adobe-CNS1-5',
-'Adobe-CNS1-6',
-'Adobe-GB1-0',
-'Adobe-GB1-1',
-'Adobe-GB1-2',
-'Adobe-GB1-3',
-'Adobe-GB1-4',
-'Adobe-GB1-5',
-'Adobe-Japan1-0',
-'Adobe-Japan1-1',
-'Adobe-Japan1-2',
-'Adobe-Japan1-3',
-'Adobe-Japan1-4',
-'Adobe-Japan1-5',
-'Adobe-Japan1-6',
-'Adobe-Korea1-0',
-'Adobe-Korea1-1',
-'Adobe-Korea1-2',
-'B5-H',
-'B5-V',
-'B5pc-H',
-'B5pc-V',
-'CNS-EUC-H',
-'CNS-EUC-V',
-'CNS1-H',
-'CNS1-V',
-'CNS2-H',
-'CNS2-V',
-'ETHK-B5-H',
-'ETHK-B5-V',
-'ETen-B5-H',
-'ETen-B5-V',
-'ETenms-B5-H',
-'ETenms-B5-V',
-'EUC-H',
-'EUC-V',
-'Ext-H',
-'Ext-RKSJ-H',
-'Ext-RKSJ-V',
-'Ext-V',
-'GB-EUC-H',
-'GB-EUC-V',
-'GB-H',
-'GB-V',
-'GBK-EUC-H',
-'GBK-EUC-V',
-'GBK2K-H',
-'GBK2K-V',
-'GBKp-EUC-H',
-'GBKp-EUC-V',
-'GBT-EUC-H',
-'GBT-EUC-V',
-'GBT-H',
-'GBT-V',
-'GBTpc-EUC-H',
-'GBTpc-EUC-V',
-'GBpc-EUC-H',
-'GBpc-EUC-V',
-'H',
-'HKdla-B5-H',
-'HKdla-B5-V',
-'HKdlb-B5-H',
-'HKdlb-B5-V',
-'HKgccs-B5-H',
-'HKgccs-B5-V',
-'HKm314-B5-H',
-'HKm314-B5-V',
-'HKm471-B5-H',
-'HKm471-B5-V',
-'HKscs-B5-H',
-'HKscs-B5-V',
-'Hankaku',
-'Hiragana',
-'KSC-EUC-H',
-'KSC-EUC-V',
-'KSC-H',
-'KSC-Johab-H',
-'KSC-Johab-V',
-'KSC-V',
-'KSCms-UHC-H',
-'KSCms-UHC-HW-H',
-'KSCms-UHC-HW-V',
-'KSCms-UHC-V',
-'KSCpc-EUC-H',
-'KSCpc-EUC-V',
-'Katakana',
-'NWP-H',
-'NWP-V',
-'RKSJ-H',
-'RKSJ-V',
-'Roman',
-'UniCNS-UCS2-H',
-'UniCNS-UCS2-V',
-'UniCNS-UTF16-H',
-'UniCNS-UTF16-V',
-'UniCNS-UTF32-H',
-'UniCNS-UTF32-V',
-'UniCNS-UTF8-H',
-'UniCNS-UTF8-V',
-'UniGB-UCS2-H',
-'UniGB-UCS2-V',
-'UniGB-UTF16-H',
-'UniGB-UTF16-V',
-'UniGB-UTF32-H',
-'UniGB-UTF32-V',
-'UniGB-UTF8-H',
-'UniGB-UTF8-V',
-'UniJIS-UCS2-H',
-'UniJIS-UCS2-HW-H',
-'UniJIS-UCS2-HW-V',
-'UniJIS-UCS2-V',
-'UniJIS-UTF16-H',
-'UniJIS-UTF16-V',
-'UniJIS-UTF32-H',
-'UniJIS-UTF32-V',
-'UniJIS-UTF8-H',
-'UniJIS-UTF8-V',
-'UniJIS2004-UTF16-H',
-'UniJIS2004-UTF16-V',
-'UniJIS2004-UTF32-H',
-'UniJIS2004-UTF32-V',
-'UniJIS2004-UTF8-H',
-'UniJIS2004-UTF8-V',
-'UniJISPro-UCS2-HW-V',
-'UniJISPro-UCS2-V',
-'UniJISPro-UTF8-V',
-'UniJISX0213-UTF32-H',
-'UniJISX0213-UTF32-V',
-'UniJISX02132004-UTF32-H',
-'UniJISX02132004-UTF32-V',
-'UniKS-UCS2-H',
-'UniKS-UCS2-V',
-'UniKS-UTF16-H',
-'UniKS-UTF16-V',
-'UniKS-UTF32-H',
-'UniKS-UTF32-V',
-'UniKS-UTF8-H',
-'UniKS-UTF8-V',
-'V',
-'WP-Symbol'];
-
-// CMap, not to be confused with TrueType's cmap.
-var CMap = (function CMapClosure() {
- function CMap(builtInCMap) {
- // Codespace ranges are stored as follows:
- // [[1BytePairs], [2BytePairs], [3BytePairs], [4BytePairs]]
- // where nBytePairs are ranges e.g. [low1, high1, low2, high2, ...]
- this.codespaceRanges = [[], [], [], []];
- this.numCodespaceRanges = 0;
- this.map = [];
- this.vertical = false;
- this.useCMap = null;
- this.builtInCMap = builtInCMap;
- }
- CMap.prototype = {
- addCodespaceRange: function(n, low, high) {
- this.codespaceRanges[n - 1].push(low, high);
- this.numCodespaceRanges++;
- },
-
- mapRange: function(low, high, dstLow) {
- var lastByte = dstLow.length - 1;
- while (low <= high) {
- this.map[low] = dstLow;
- // Only the last byte has to be incremented.
- dstLow = dstLow.substr(0, lastByte) +
- String.fromCharCode(dstLow.charCodeAt(lastByte) + 1);
- ++low;
- }
- },
-
- mapRangeToArray: function(low, high, array) {
- var i = 0;
- while (low <= high) {
- this.map[low] = array[i++];
- ++low;
- }
- },
-
- mapOne: function(src, dst) {
- this.map[src] = dst;
- },
-
- lookup: function(code) {
- return this.map[code];
- },
-
- readCharCode: function(str, offset) {
- var c = 0;
- var codespaceRanges = this.codespaceRanges;
- var codespaceRangesLen = this.codespaceRanges.length;
- // 9.7.6.2 CMap Mapping
- // The code length is at most 4.
- for (var n = 0; n < codespaceRangesLen; n++) {
- c = ((c << 8) | str.charCodeAt(offset + n)) >>> 0;
- // Check each codespace range to see if it falls within.
- var codespaceRange = codespaceRanges[n];
- for (var k = 0, kk = codespaceRange.length; k < kk;) {
- var low = codespaceRange[k++];
- var high = codespaceRange[k++];
- if (c >= low && c <= high) {
- return [c, n + 1];
- }
- }
- }
-
- return [0, 1];
- }
-
- };
- return CMap;
-})();
-
-var IdentityCMap = (function IdentityCMapClosure() {
- function IdentityCMap(vertical, n) {
- CMap.call(this);
- this.vertical = vertical;
- this.addCodespaceRange(n, 0, 0xffff);
- this.mapRange(0, 0xffff, '\u0000');
- }
- Util.inherit(IdentityCMap, CMap, {});
-
- return IdentityCMap;
-})();
-
-var CMapFactory = (function CMapFactoryClosure() {
- function strToInt(str) {
- var a = 0;
- for (var i = 0; i < str.length; i++) {
- a = (a << 8) | str.charCodeAt(i);
- }
- return a >>> 0;
- }
-
- function expectString(obj) {
- if (!isString(obj)) {
- error('Malformed CMap: expected string.');
- }
- }
-
- function expectInt(obj) {
- if (!isInt(obj)) {
- error('Malformed CMap: expected int.');
- }
- }
-
- function parseBfChar(cMap, lexer) {
- while (true) {
- var obj = lexer.getObj();
- if (isEOF(obj)) {
- break;
- }
- if (isCmd(obj, 'endbfchar')) {
- return;
- }
- expectString(obj);
- var src = strToInt(obj);
- obj = lexer.getObj();
- // TODO are /dstName used?
- expectString(obj);
- var dst = obj;
- cMap.mapOne(src, dst);
- }
- }
-
- function parseBfRange(cMap, lexer) {
- while (true) {
- var obj = lexer.getObj();
- if (isEOF(obj)) {
- break;
- }
- if (isCmd(obj, 'endbfrange')) {
- return;
- }
- expectString(obj);
- var low = strToInt(obj);
- obj = lexer.getObj();
- expectString(obj);
- var high = strToInt(obj);
- obj = lexer.getObj();
- if (isInt(obj) || isString(obj)) {
- var dstLow = isInt(obj) ? String.fromCharCode(obj) : obj;
- cMap.mapRange(low, high, dstLow);
- } else if (isCmd(obj, '[')) {
- obj = lexer.getObj();
- var array = [];
- while (!isCmd(obj, ']') && !isEOF(obj)) {
- array.push(obj);
- obj = lexer.getObj();
- }
- cMap.mapRangeToArray(low, high, array);
- } else {
- break;
- }
- }
- error('Invalid bf range.');
- }
-
- function parseCidChar(cMap, lexer) {
- while (true) {
- var obj = lexer.getObj();
- if (isEOF(obj)) {
- break;
- }
- if (isCmd(obj, 'endcidchar')) {
- return;
- }
- expectString(obj);
- var src = strToInt(obj);
- obj = lexer.getObj();
- expectInt(obj);
- var dst = String.fromCharCode(obj);
- cMap.mapOne(src, dst);
- }
- }
-
- function parseCidRange(cMap, lexer) {
- while (true) {
- var obj = lexer.getObj();
- if (isEOF(obj)) {
- break;
- }
- if (isCmd(obj, 'endcidrange')) {
- return;
- }
- expectString(obj);
- var low = strToInt(obj);
- obj = lexer.getObj();
- expectString(obj);
- var high = strToInt(obj);
- obj = lexer.getObj();
- expectInt(obj);
- var dstLow = String.fromCharCode(obj);
- cMap.mapRange(low, high, dstLow);
- }
- }
-
- function parseCodespaceRange(cMap, lexer) {
- while (true) {
- var obj = lexer.getObj();
- if (isEOF(obj)) {
- break;
- }
- if (isCmd(obj, 'endcodespacerange')) {
- return;
- }
- if (!isString(obj)) {
- break;
- }
- var low = strToInt(obj);
- obj = lexer.getObj();
- if (!isString(obj)) {
- break;
- }
- var high = strToInt(obj);
- cMap.addCodespaceRange(obj.length, low, high);
- }
- error('Invalid codespace range.');
- }
-
- function parseWMode(cMap, lexer) {
- var obj = lexer.getObj();
- if (isInt(obj)) {
- cMap.vertical = !!obj;
- }
- }
-
- function parseCMap(cMap, lexer, builtInCMapUrl, useCMap) {
- var previous;
- var embededUseCMap;
- objLoop: while (true) {
- var obj = lexer.getObj();
- if (isEOF(obj)) {
- break;
- } else if (isName(obj)) {
- if (obj.name === 'WMode') {
- parseWMode(cMap, lexer);
- }
- previous = obj;
- } else if (isCmd(obj)) {
- switch (obj.cmd) {
- case 'endcmap':
- break objLoop;
- case 'usecmap':
- if (isName(previous)) {
- embededUseCMap = previous.name;
- }
- break;
- case 'begincodespacerange':
- parseCodespaceRange(cMap, lexer);
- break;
- case 'beginbfchar':
- parseBfChar(cMap, lexer);
- break;
- case 'begincidchar':
- parseCidChar(cMap, lexer);
- break;
- case 'beginbfrange':
- parseBfRange(cMap, lexer);
- break;
- case 'begincidrange':
- parseCidRange(cMap, lexer);
- break;
- }
- }
- }
-
- if (!useCMap && embededUseCMap) {
- // Load the usecmap definition from the file only if there wasn't one
- // specified.
- useCMap = embededUseCMap;
- }
- if (useCMap) {
- cMap.useCMap = createBuiltInCMap(useCMap, builtInCMapUrl);
- // If there aren't any code space ranges defined clone all the parent ones
- // into this cMap.
- if (cMap.numCodespaceRanges === 0) {
- var useCodespaceRanges = cMap.useCMap.codespaceRanges;
- for (var i = 0; i < useCodespaceRanges.length; i++) {
- cMap.codespaceRanges[i] = useCodespaceRanges[i].slice();
- }
- cMap.numCodespaceRanges = cMap.useCMap.numCodespaceRanges;
- }
- // Merge the map into the current one, making sure not to override
- // any previously defined entries.
- for (var key in cMap.useCMap.map) {
- if (key in cMap.map) {
- continue;
- }
- cMap.map[key] = cMap.useCMap.map[key];
- }
- }
- }
-
- function createBuiltInCMap(name, builtInCMapUrl) {
- if (name === 'Identity-H') {
- return new IdentityCMap(false, 2);
- } else if (name === 'Identity-V') {
- return new IdentityCMap(true, 2);
- }
- if (BUILT_IN_CMAPS.indexOf(name) === -1) {
- error('Unknown cMap name: ' + name);
- }
-
- var request = new XMLHttpRequest();
- var url = builtInCMapUrl + name;
- request.open('GET', url, false);
- request.send(null);
- if (request.status === 0 && /^https?:/i.test(url)) {
- error('Unable to get cMap at: ' + url);
- }
- var cMap = new CMap(true);
- var lexer = new Lexer(new StringStream(request.responseText));
- parseCMap(cMap, lexer, builtInCMapUrl, null);
- return cMap;
- }
-
- return {
- create: function (encoding, builtInCMapUrl, useCMap) {
- if (isName(encoding)) {
- return createBuiltInCMap(encoding.name, builtInCMapUrl);
- } else if (isStream(encoding)) {
- var cMap = new CMap();
- var lexer = new Lexer(encoding);
- try {
- parseCMap(cMap, lexer, builtInCMapUrl, useCMap);
- } catch (e) {
- warn('Invalid CMap data. ' + e);
- }
- return cMap;
- }
- error('Encoding required.');
- }
- };
-})();
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
+/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
-/*
- Copyright 2011 notmasteryet
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-// - The JPEG specification can be found in the ITU CCITT Recommendation T.81
-// (www.w3.org/Graphics/JPEG/itu-t81.pdf)
-// - The JFIF specification can be found in the JPEG File Interchange Format
-// (www.w3.org/Graphics/JPEG/jfif3.pdf)
-// - The Adobe Application-Specific JPEG markers in the Supporting the DCT Filters
-// in PostScript Level 2, Technical Note #5116
-// (partners.adobe.com/public/developer/en/ps/sdk/5116.DCT_Filter.pdf)
+/* Copyright 2014 Opera Software ASA
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *
+ * Based on https://code.google.com/p/smhasher/wiki/MurmurHash3.
+ * Hashes roughly 100 KB per millisecond on i7 3.4 GHz.
+ */
+/* globals Uint32ArrayView */
-var JpegImage = (function jpegImage() {
- "use strict";
- var dctZigZag = new Int32Array([
- 0,
- 1, 8,
- 16, 9, 2,
- 3, 10, 17, 24,
- 32, 25, 18, 11, 4,
- 5, 12, 19, 26, 33, 40,
- 48, 41, 34, 27, 20, 13, 6,
- 7, 14, 21, 28, 35, 42, 49, 56,
- 57, 50, 43, 36, 29, 22, 15,
- 23, 30, 37, 44, 51, 58,
- 59, 52, 45, 38, 31,
- 39, 46, 53, 60,
- 61, 54, 47,
- 55, 62,
- 63
- ]);
+'use strict';
- var dctCos1 = 4017 // cos(pi/16)
- var dctSin1 = 799 // sin(pi/16)
- var dctCos3 = 3406 // cos(3*pi/16)
- var dctSin3 = 2276 // sin(3*pi/16)
- var dctCos6 = 1567 // cos(6*pi/16)
- var dctSin6 = 3784 // sin(6*pi/16)
- var dctSqrt2 = 5793 // sqrt(2)
- var dctSqrt1d2 = 2896 // sqrt(2) / 2
+var MurmurHash3_64 = (function MurmurHash3_64Closure (seed) {
+ // Workaround for missing math precison in JS.
+ var MASK_HIGH = 0xffff0000;
+ var MASK_LOW = 0xffff;
- function constructor() {
+ function MurmurHash3_64 (seed) {
+ var SEED = 0xc3d2e1f0;
+ this.h1 = seed ? seed & 0xffffffff : SEED;
+ this.h2 = seed ? seed & 0xffffffff : SEED;
}
- function buildHuffmanTable(codeLengths, values) {
- var k = 0, code = [], i, j, length = 16;
- while (length > 0 && !codeLengths[length - 1])
- length--;
- code.push({children: [], index: 0});
- var p = code[0], q;
- for (i = 0; i < length; i++) {
- for (j = 0; j < codeLengths[i]; j++) {
- p = code.pop();
- p.children[p.index] = values[k];
- while (p.index > 0) {
- p = code.pop();
- }
- p.index++;
- code.push(p);
- while (code.length <= i) {
- code.push(q = {children: [], index: 0});
- p.children[p.index] = q.children;
- p = q;
- }
- k++;
- }
- if (i + 1 < length) {
- // p here points to last code
- code.push(q = {children: [], index: 0});
- p.children[p.index] = q.children;
- p = q;
- }
- }
- return code[0].children;
+ var alwaysUseUint32ArrayView = false;
+ // old webkits have issues with non-aligned arrays
+ try {
+ new Uint32Array(new Uint8Array(5).buffer, 0, 1);
+ } catch (e) {
+ alwaysUseUint32ArrayView = true;
}
- function decodeScan(data, offset,
- frame, components, resetInterval,
- spectralStart, spectralEnd,
- successivePrev, successive) {
- var precision = frame.precision;
- var samplesPerLine = frame.samplesPerLine;
- var scanLines = frame.scanLines;
- var mcusPerLine = frame.mcusPerLine;
- var progressive = frame.progressive;
- var maxH = frame.maxH, maxV = frame.maxV;
-
- var startOffset = offset, bitsData = 0, bitsCount = 0;
- function readBit() {
- if (bitsCount > 0) {
- bitsCount--;
- return (bitsData >> bitsCount) & 1;
- }
- bitsData = data[offset++];
- if (bitsData == 0xFF) {
- var nextByte = data[offset++];
- if (nextByte) {
- throw "unexpected marker: " + ((bitsData << 8) | nextByte).toString(16);
- }
- // unstuff 0
- }
- bitsCount = 7;
- return bitsData >>> 7;
- }
- function decodeHuffman(tree) {
- var node = tree, bit;
- while ((bit = readBit()) !== null) {
- node = node[bit];
- if (typeof node === 'number')
- return node;
- if (typeof node !== 'object')
- throw "invalid huffman sequence";
- }
- return null;
- }
- function receive(length) {
- var n = 0;
- while (length > 0) {
- var bit = readBit();
- if (bit === null) return;
- n = (n << 1) | bit;
- length--;
- }
- return n;
- }
- function receiveAndExtend(length) {
- var n = receive(length);
- if (n >= 1 << (length - 1))
- return n;
- return n + (-1 << length) + 1;
- }
- function decodeBaseline(component, zz) {
- var t = decodeHuffman(component.huffmanTableDC);
- var diff = t === 0 ? 0 : receiveAndExtend(t);
- zz[0]= (component.pred += diff);
- var k = 1;
- while (k < 64) {
- var rs = decodeHuffman(component.huffmanTableAC);
- var s = rs & 15, r = rs >> 4;
- if (s === 0) {
- if (r < 15)
- break;
- k += 16;
- continue;
- }
- k += r;
- var z = dctZigZag[k];
- zz[z] = receiveAndExtend(s);
- k++;
- }
- }
- function decodeDCFirst(component, zz) {
- var t = decodeHuffman(component.huffmanTableDC);
- var diff = t === 0 ? 0 : (receiveAndExtend(t) << successive);
- zz[0] = (component.pred += diff);
- }
- function decodeDCSuccessive(component, zz) {
- zz[0] |= readBit() << successive;
- }
- var eobrun = 0;
- function decodeACFirst(component, zz) {
- if (eobrun > 0) {
- eobrun--;
- return;
- }
- var k = spectralStart, e = spectralEnd;
- while (k <= e) {
- var rs = decodeHuffman(component.huffmanTableAC);
- var s = rs & 15, r = rs >> 4;
- if (s === 0) {
- if (r < 15) {
- eobrun = receive(r) + (1 << r) - 1;
- break;
- }
- k += 16;
- continue;
- }
- k += r;
- var z = dctZigZag[k];
- zz[z] = receiveAndExtend(s) * (1 << successive);
- k++;
- }
- }
- var successiveACState = 0, successiveACNextValue;
- function decodeACSuccessive(component, zz) {
- var k = spectralStart, e = spectralEnd, r = 0;
- while (k <= e) {
- var z = dctZigZag[k];
- switch (successiveACState) {
- case 0: // initial state
- var rs = decodeHuffman(component.huffmanTableAC);
- var s = rs & 15, r = rs >> 4;
- if (s === 0) {
- if (r < 15) {
- eobrun = receive(r) + (1 << r);
- successiveACState = 4;
- } else {
- r = 16;
- successiveACState = 1;
- }
- } else {
- if (s !== 1)
- throw "invalid ACn encoding";
- successiveACNextValue = receiveAndExtend(s);
- successiveACState = r ? 2 : 3;
- }
- continue;
- case 1: // skipping r zero items
- case 2:
- if (zz[z])
- zz[z] += (readBit() << successive);
- else {
- r--;
- if (r === 0)
- successiveACState = successiveACState == 2 ? 3 : 0;
+ MurmurHash3_64.prototype = {
+ update: function MurmurHash3_64_update(input) {
+ var useUint32ArrayView = alwaysUseUint32ArrayView;
+ var i;
+ if (typeof input == 'string') {
+ var data = new Uint8Array(input.length * 2);
+ var length = 0;
+ for (i = 0; i < input.length; i++) {
+ var code = input.charCodeAt(i);
+ if (code <= 0xff) {
+ data[length++] = code;
}
- break;
- case 3: // set value for a zero item
- if (zz[z])
- zz[z] += (readBit() << successive);
else {
- zz[z] = successiveACNextValue << successive;
- successiveACState = 0;
+ data[length++] = code >>> 8;
+ data[length++] = code & 0xff;
}
- break;
- case 4: // eob
- if (zz[z])
- zz[z] += (readBit() << successive);
- break;
- }
- k++;
- }
- if (successiveACState === 4) {
- eobrun--;
- if (eobrun === 0)
- successiveACState = 0;
- }
- }
- function decodeMcu(component, decode, mcu, row, col) {
- var mcuRow = (mcu / mcusPerLine) | 0;
- var mcuCol = mcu % mcusPerLine;
- var blockRow = mcuRow * component.v + row;
- var blockCol = mcuCol * component.h + col;
- decode(component, component.blocks[blockRow][blockCol]);
- }
- function decodeBlock(component, decode, mcu) {
- var blockRow = (mcu / component.blocksPerLine) | 0;
- var blockCol = mcu % component.blocksPerLine;
- decode(component, component.blocks[blockRow][blockCol]);
- }
-
- var componentsLength = components.length;
- var component, i, j, k, n;
- var decodeFn;
- if (progressive) {
- if (spectralStart === 0)
- decodeFn = successivePrev === 0 ? decodeDCFirst : decodeDCSuccessive;
- else
- decodeFn = successivePrev === 0 ? decodeACFirst : decodeACSuccessive;
- } else {
- decodeFn = decodeBaseline;
- }
-
- var mcu = 0, marker;
- var mcuExpected;
- if (componentsLength == 1) {
- mcuExpected = components[0].blocksPerLine * components[0].blocksPerColumn;
- } else {
- mcuExpected = mcusPerLine * frame.mcusPerColumn;
- }
- if (!resetInterval) resetInterval = mcuExpected;
-
- var h, v;
- while (mcu < mcuExpected) {
- // reset interval stuff
- for (i = 0; i < componentsLength; i++)
- components[i].pred = 0;
- eobrun = 0;
-
- if (componentsLength == 1) {
- component = components[0];
- for (n = 0; n < resetInterval; n++) {
- decodeBlock(component, decodeFn, mcu);
- mcu++;
}
+ } else if (input instanceof Uint8Array) {
+ data = input;
+ length = data.length;
+ } else if (typeof input === 'object' && ('length' in input)) {
+ // processing regular arrays as well, e.g. for IE9
+ data = input;
+ length = data.length;
+ useUint32ArrayView = true;
} else {
- for (n = 0; n < resetInterval; n++) {
- for (i = 0; i < componentsLength; i++) {
- component = components[i];
- h = component.h;
- v = component.v;
- for (j = 0; j < v; j++) {
- for (k = 0; k < h; k++) {
- decodeMcu(component, decodeFn, mcu, j, k);
- }
- }
- }
- mcu++;
- }
- }
-
- // find marker
- bitsCount = 0;
- marker = (data[offset] << 8) | data[offset + 1];
- if (marker <= 0xFF00) {
- throw "marker was not found";
- }
-
- if (marker >= 0xFFD0 && marker <= 0xFFD7) { // RSTx
- offset += 2;
- }
- else
- break;
- }
-
- return offset - startOffset;
- }
-
- function buildComponentData(frame, component) {
- var lines = [];
- var blocksPerLine = component.blocksPerLine;
- var blocksPerColumn = component.blocksPerColumn;
- var samplesPerLine = blocksPerLine << 3;
- var R = new Int32Array(64);
-
- // A port of poppler's IDCT method which in turn is taken from:
- // Christoph Loeffler, Adriaan Ligtenberg, George S. Moschytz,
- // "Practical Fast 1-D DCT Algorithms with 11 Multiplications",
- // IEEE Intl. Conf. on Acoustics, Speech & Signal Processing, 1989,
- // 988-991.
- function quantizeAndInverse(zz, p) {
- var qt = component.quantizationTable;
- var v0, v1, v2, v3, v4, v5, v6, v7, t;
- var i;
-
- // dequant
- for (i = 0; i < 64; i++)
- p[i] = zz[i] * qt[i];
-
- // inverse DCT on rows
- for (i = 0; i < 8; ++i) {
- var row = 8 * i;
-
- // check for all-zero AC coefficients
- if (p[1 + row] == 0 && p[2 + row] == 0 && p[3 + row] == 0 &&
- p[4 + row] == 0 && p[5 + row] == 0 && p[6 + row] == 0 &&
- p[7 + row] == 0) {
- t = (dctSqrt2 * p[0 + row] + 512) >> 10;
- p[0 + row] = t;
- p[1 + row] = t;
- p[2 + row] = t;
- p[3 + row] = t;
- p[4 + row] = t;
- p[5 + row] = t;
- p[6 + row] = t;
- p[7 + row] = t;
- continue;
- }
-
- // stage 4
- v0 = (dctSqrt2 * p[0 + row] + 128) >> 8;
- v1 = (dctSqrt2 * p[4 + row] + 128) >> 8;
- v2 = p[2 + row];
- v3 = p[6 + row];
- v4 = (dctSqrt1d2 * (p[1 + row] - p[7 + row]) + 128) >> 8;
- v7 = (dctSqrt1d2 * (p[1 + row] + p[7 + row]) + 128) >> 8;
- v5 = p[3 + row] << 4;
- v6 = p[5 + row] << 4;
-
- // stage 3
- t = (v0 - v1+ 1) >> 1;
- v0 = (v0 + v1 + 1) >> 1;
- v1 = t;
- t = (v2 * dctSin6 + v3 * dctCos6 + 128) >> 8;
- v2 = (v2 * dctCos6 - v3 * dctSin6 + 128) >> 8;
- v3 = t;
- t = (v4 - v6 + 1) >> 1;
- v4 = (v4 + v6 + 1) >> 1;
- v6 = t;
- t = (v7 + v5 + 1) >> 1;
- v5 = (v7 - v5 + 1) >> 1;
- v7 = t;
-
- // stage 2
- t = (v0 - v3 + 1) >> 1;
- v0 = (v0 + v3 + 1) >> 1;
- v3 = t;
- t = (v1 - v2 + 1) >> 1;
- v1 = (v1 + v2 + 1) >> 1;
- v2 = t;
- t = (v4 * dctSin3 + v7 * dctCos3 + 2048) >> 12;
- v4 = (v4 * dctCos3 - v7 * dctSin3 + 2048) >> 12;
- v7 = t;
- t = (v5 * dctSin1 + v6 * dctCos1 + 2048) >> 12;
- v5 = (v5 * dctCos1 - v6 * dctSin1 + 2048) >> 12;
- v6 = t;
-
- // stage 1
- p[0 + row] = v0 + v7;
- p[7 + row] = v0 - v7;
- p[1 + row] = v1 + v6;
- p[6 + row] = v1 - v6;
- p[2 + row] = v2 + v5;
- p[5 + row] = v2 - v5;
- p[3 + row] = v3 + v4;
- p[4 + row] = v3 - v4;
+ throw new Error('Wrong data format in MurmurHash3_64_update. ' +
+ 'Input must be a string or array.');
}
- // inverse DCT on columns
- for (i = 0; i < 8; ++i) {
- var col = i;
+ var blockCounts = length >> 2;
+ var tailLength = length - blockCounts * 4;
+ // we don't care about endianness here
+ var dataUint32 = useUint32ArrayView ?
+ new Uint32ArrayView(data, blockCounts) :
+ new Uint32Array(data.buffer, 0, blockCounts);
+ var k1 = 0;
+ var k2 = 0;
+ var h1 = this.h1;
+ var h2 = this.h2;
+ var C1 = 0xcc9e2d51;
+ var C2 = 0x1b873593;
+ var C1_LOW = C1 & MASK_LOW;
+ var C2_LOW = C2 & MASK_LOW;
- // check for all-zero AC coefficients
- if (p[1*8 + col] == 0 && p[2*8 + col] == 0 && p[3*8 + col] == 0 &&
- p[4*8 + col] == 0 && p[5*8 + col] == 0 && p[6*8 + col] == 0 &&
- p[7*8 + col] == 0) {
- t = (dctSqrt2 * p[i+0] + 8192) >> 14;
- p[0*8 + col] = t;
- p[1*8 + col] = t;
- p[2*8 + col] = t;
- p[3*8 + col] = t;
- p[4*8 + col] = t;
- p[5*8 + col] = t;
- p[6*8 + col] = t;
- p[7*8 + col] = t;
- continue;
+ for (i = 0; i < blockCounts; i++) {
+ if (i & 1) {
+ k1 = dataUint32[i];
+ k1 = (k1 * C1 & MASK_HIGH) | (k1 * C1_LOW & MASK_LOW);
+ k1 = k1 << 15 | k1 >>> 17;
+ k1 = (k1 * C2 & MASK_HIGH) | (k1 * C2_LOW & MASK_LOW);
+ h1 ^= k1;
+ h1 = h1 << 13 | h1 >>> 19;
+ h1 = h1 * 5 + 0xe6546b64;
+ } else {
+ k2 = dataUint32[i];
+ k2 = (k2 * C1 & MASK_HIGH) | (k2 * C1_LOW & MASK_LOW);
+ k2 = k2 << 15 | k2 >>> 17;
+ k2 = (k2 * C2 & MASK_HIGH) | (k2 * C2_LOW & MASK_LOW);
+ h2 ^= k2;
+ h2 = h2 << 13 | h2 >>> 19;
+ h2 = h2 * 5 + 0xe6546b64;
}
-
- // stage 4
- v0 = (dctSqrt2 * p[0*8 + col] + 2048) >> 12;
- v1 = (dctSqrt2 * p[4*8 + col] + 2048) >> 12;
- v2 = p[2*8 + col];
- v3 = p[6*8 + col];
- v4 = (dctSqrt1d2 * (p[1*8 + col] - p[7*8 + col]) + 2048) >> 12;
- v7 = (dctSqrt1d2 * (p[1*8 + col] + p[7*8 + col]) + 2048) >> 12;
- v5 = p[3*8 + col];
- v6 = p[5*8 + col];
-
- // stage 3
- t = (v0 - v1 + 1) >> 1;
- v0 = (v0 + v1 + 1) >> 1;
- v1 = t;
- t = (v2 * dctSin6 + v3 * dctCos6 + 2048) >> 12;
- v2 = (v2 * dctCos6 - v3 * dctSin6 + 2048) >> 12;
- v3 = t;
- t = (v4 - v6 + 1) >> 1;
- v4 = (v4 + v6 + 1) >> 1;
- v6 = t;
- t = (v7 + v5 + 1) >> 1;
- v5 = (v7 - v5 + 1) >> 1;
- v7 = t;
-
- // stage 2
- t = (v0 - v3 + 1) >> 1;
- v0 = (v0 + v3 + 1) >> 1;
- v3 = t;
- t = (v1 - v2 + 1) >> 1;
- v1 = (v1 + v2 + 1) >> 1;
- v2 = t;
- t = (v4 * dctSin3 + v7 * dctCos3 + 2048) >> 12;
- v4 = (v4 * dctCos3 - v7 * dctSin3 + 2048) >> 12;
- v7 = t;
- t = (v5 * dctSin1 + v6 * dctCos1 + 2048) >> 12;
- v5 = (v5 * dctCos1 - v6 * dctSin1 + 2048) >> 12;
- v6 = t;
-
- // stage 1
- p[0*8 + col] = v0 + v7;
- p[7*8 + col] = v0 - v7;
- p[1*8 + col] = v1 + v6;
- p[6*8 + col] = v1 - v6;
- p[2*8 + col] = v2 + v5;
- p[5*8 + col] = v2 - v5;
- p[3*8 + col] = v3 + v4;
- p[4*8 + col] = v3 - v4;
}
- // convert to 8-bit integers
- for (i = 0; i < 64; ++i) {
- p[i] = clampTo8bit((p[i] + 2056) >> 4);
- }
- }
-
- var i, j;
- for (var blockRow = 0; blockRow < blocksPerColumn; blockRow++) {
- var scanLine = blockRow << 3;
- for (i = 0; i < 8; i++)
- lines.push(new Uint8Array(samplesPerLine));
- for (var blockCol = 0; blockCol < blocksPerLine; blockCol++) {
- quantizeAndInverse(component.blocks[blockRow][blockCol], R);
+ k1 = 0;
- var offset = 0, sample = blockCol << 3;
- for (j = 0; j < 8; j++) {
- var line = lines[scanLine + j];
- for (i = 0; i < 8; i++)
- line[sample + i] = R[offset++];
+ switch (tailLength) {
+ case 3:
+ k1 ^= data[blockCounts * 4 + 2] << 16;
+ /* falls through */
+ case 2:
+ k1 ^= data[blockCounts * 4 + 1] << 8;
+ /* falls through */
+ case 1:
+ k1 ^= data[blockCounts * 4];
+ /* falls through */
+ k1 = (k1 * C1 & MASK_HIGH) | (k1 * C1_LOW & MASK_LOW);
+ k1 = k1 << 15 | k1 >>> 17;
+ k1 = (k1 * C2 & MASK_HIGH) | (k1 * C2_LOW & MASK_LOW);
+ if (blockCounts & 1) {
+ h1 ^= k1;
+ } else {
+ h2 ^= k1;
}
}
- }
- return lines;
- }
-
- function clampTo8bit(a) {
- return a < 0 ? 0 : a > 255 ? 255 : a;
- }
- constructor.prototype = {
- load: function load(path) {
- var xhr = new XMLHttpRequest();
- xhr.open("GET", path, true);
- xhr.responseType = "arraybuffer";
- xhr.onload = (function() {
- // TODO catch parse error
- var data = new Uint8Array(xhr.response || xhr.mozResponseArrayBuffer);
- this.parse(data);
- if (this.onload)
- this.onload();
- }).bind(this);
- xhr.send(null);
+ this.h1 = h1;
+ this.h2 = h2;
+ return this;
},
- parse: function parse(data) {
- var offset = 0, length = data.length;
- function readUint16() {
- var value = (data[offset] << 8) | data[offset + 1];
- offset += 2;
- return value;
- }
- function readDataBlock() {
- var length = readUint16();
- var array = data.subarray(offset, offset + length - 2);
- offset += array.length;
- return array;
- }
- function prepareComponents(frame) {
- var maxH = 0, maxV = 0;
- var component, componentId;
- for (componentId in frame.components) {
- if (frame.components.hasOwnProperty(componentId)) {
- component = frame.components[componentId];
- if (maxH < component.h) maxH = component.h;
- if (maxV < component.v) maxV = component.v;
- }
- }
- var mcusPerLine = Math.ceil(frame.samplesPerLine / 8 / maxH);
- var mcusPerColumn = Math.ceil(frame.scanLines / 8 / maxV);
- for (componentId in frame.components) {
- if (frame.components.hasOwnProperty(componentId)) {
- component = frame.components[componentId];
- var blocksPerLine = Math.ceil(Math.ceil(frame.samplesPerLine / 8) * component.h / maxH);
- var blocksPerColumn = Math.ceil(Math.ceil(frame.scanLines / 8) * component.v / maxV);
- var blocksPerLineForMcu = mcusPerLine * component.h;
- var blocksPerColumnForMcu = mcusPerColumn * component.v;
- var blocks = [];
- for (var i = 0; i < blocksPerColumnForMcu; i++) {
- var row = [];
- for (var j = 0; j < blocksPerLineForMcu; j++)
- row.push(new Int16Array(64));
- blocks.push(row);
- }
- component.blocksPerLine = blocksPerLine;
- component.blocksPerColumn = blocksPerColumn;
- component.blocks = blocks;
- }
- }
- frame.maxH = maxH;
- frame.maxV = maxV;
- frame.mcusPerLine = mcusPerLine;
- frame.mcusPerColumn = mcusPerColumn;
- }
- var jfif = null;
- var adobe = null;
- var pixels = null;
- var frame, resetInterval;
- var quantizationTables = [], frames = [];
- var huffmanTablesAC = [], huffmanTablesDC = [];
- var fileMarker = readUint16();
- if (fileMarker != 0xFFD8) { // SOI (Start of Image)
- throw "SOI not found";
- }
-
- fileMarker = readUint16();
- while (fileMarker != 0xFFD9) { // EOI (End of image)
- var i, j, l;
- switch(fileMarker) {
- case 0xFFE0: // APP0 (Application Specific)
- case 0xFFE1: // APP1
- case 0xFFE2: // APP2
- case 0xFFE3: // APP3
- case 0xFFE4: // APP4
- case 0xFFE5: // APP5
- case 0xFFE6: // APP6
- case 0xFFE7: // APP7
- case 0xFFE8: // APP8
- case 0xFFE9: // APP9
- case 0xFFEA: // APP10
- case 0xFFEB: // APP11
- case 0xFFEC: // APP12
- case 0xFFED: // APP13
- case 0xFFEE: // APP14
- case 0xFFEF: // APP15
- case 0xFFFE: // COM (Comment)
- var appData = readDataBlock();
-
- if (fileMarker === 0xFFE0) {
- if (appData[0] === 0x4A && appData[1] === 0x46 && appData[2] === 0x49 &&
- appData[3] === 0x46 && appData[4] === 0) { // 'JFIF\x00'
- jfif = {
- version: { major: appData[5], minor: appData[6] },
- densityUnits: appData[7],
- xDensity: (appData[8] << 8) | appData[9],
- yDensity: (appData[10] << 8) | appData[11],
- thumbWidth: appData[12],
- thumbHeight: appData[13],
- thumbData: appData.subarray(14, 14 + 3 * appData[12] * appData[13])
- };
- }
- }
- // TODO APP1 - Exif
- if (fileMarker === 0xFFEE) {
- if (appData[0] === 0x41 && appData[1] === 0x64 && appData[2] === 0x6F &&
- appData[3] === 0x62 && appData[4] === 0x65 && appData[5] === 0) { // 'Adobe\x00'
- adobe = {
- version: appData[6],
- flags0: (appData[7] << 8) | appData[8],
- flags1: (appData[9] << 8) | appData[10],
- transformCode: appData[11]
- };
- }
- }
- break;
-
- case 0xFFDB: // DQT (Define Quantization Tables)
- var quantizationTablesLength = readUint16();
- var quantizationTablesEnd = quantizationTablesLength + offset - 2;
- while (offset < quantizationTablesEnd) {
- var quantizationTableSpec = data[offset++];
- var tableData = new Int32Array(64);
- if ((quantizationTableSpec >> 4) === 0) { // 8 bit values
- for (j = 0; j < 64; j++) {
- var z = dctZigZag[j];
- tableData[z] = data[offset++];
- }
- } else if ((quantizationTableSpec >> 4) === 1) { //16 bit
- for (j = 0; j < 64; j++) {
- var z = dctZigZag[j];
- tableData[z] = readUint16();
- }
- } else
- throw "DQT: invalid table spec";
- quantizationTables[quantizationTableSpec & 15] = tableData;
- }
- break;
-
- case 0xFFC0: // SOF0 (Start of Frame, Baseline DCT)
- case 0xFFC1: // SOF1 (Start of Frame, Extended DCT)
- case 0xFFC2: // SOF2 (Start of Frame, Progressive DCT)
- readUint16(); // skip data length
- frame = {};
- frame.extended = (fileMarker === 0xFFC1);
- frame.progressive = (fileMarker === 0xFFC2);
- frame.precision = data[offset++];
- frame.scanLines = readUint16();
- frame.samplesPerLine = readUint16();
- frame.components = {};
- frame.componentsOrder = [];
- var componentsCount = data[offset++], componentId;
- var maxH = 0, maxV = 0;
- for (i = 0; i < componentsCount; i++) {
- componentId = data[offset];
- var h = data[offset + 1] >> 4;
- var v = data[offset + 1] & 15;
- var qId = data[offset + 2];
- frame.componentsOrder.push(componentId);
- frame.components[componentId] = {
- h: h,
- v: v,
- quantizationTable: quantizationTables[qId]
- };
- offset += 3;
- }
- prepareComponents(frame);
- frames.push(frame);
- break;
-
- case 0xFFC4: // DHT (Define Huffman Tables)
- var huffmanLength = readUint16();
- for (i = 2; i < huffmanLength;) {
- var huffmanTableSpec = data[offset++];
- var codeLengths = new Uint8Array(16);
- var codeLengthSum = 0;
- for (j = 0; j < 16; j++, offset++)
- codeLengthSum += (codeLengths[j] = data[offset]);
- var huffmanValues = new Uint8Array(codeLengthSum);
- for (j = 0; j < codeLengthSum; j++, offset++)
- huffmanValues[j] = data[offset];
- i += 17 + codeLengthSum;
- ((huffmanTableSpec >> 4) === 0 ?
- huffmanTablesDC : huffmanTablesAC)[huffmanTableSpec & 15] =
- buildHuffmanTable(codeLengths, huffmanValues);
- }
- break;
+ hexdigest: function MurmurHash3_64_hexdigest () {
+ var h1 = this.h1;
+ var h2 = this.h2;
- case 0xFFDD: // DRI (Define Restart Interval)
- readUint16(); // skip data length
- resetInterval = readUint16();
- break;
+ h1 ^= h2 >>> 1;
+ h1 = (h1 * 0xed558ccd & MASK_HIGH) | (h1 * 0x8ccd & MASK_LOW);
+ h2 = (h2 * 0xff51afd7 & MASK_HIGH) |
+ (((h2 << 16 | h1 >>> 16) * 0xafd7ed55 & MASK_HIGH) >>> 16);
+ h1 ^= h2 >>> 1;
+ h1 = (h1 * 0x1a85ec53 & MASK_HIGH) | (h1 * 0xec53 & MASK_LOW);
+ h2 = (h2 * 0xc4ceb9fe & MASK_HIGH) |
+ (((h2 << 16 | h1 >>> 16) * 0xb9fe1a85 & MASK_HIGH) >>> 16);
+ h1 ^= h2 >>> 1;
- case 0xFFDA: // SOS (Start of Scan)
- var scanLength = readUint16();
- var selectorsCount = data[offset++];
- var components = [], component;
- for (i = 0; i < selectorsCount; i++) {
- component = frame.components[data[offset++]];
- var tableSpec = data[offset++];
- component.huffmanTableDC = huffmanTablesDC[tableSpec >> 4];
- component.huffmanTableAC = huffmanTablesAC[tableSpec & 15];
- components.push(component);
- }
- var spectralStart = data[offset++];
- var spectralEnd = data[offset++];
- var successiveApproximation = data[offset++];
- var processed = decodeScan(data, offset,
- frame, components, resetInterval,
- spectralStart, spectralEnd,
- successiveApproximation >> 4, successiveApproximation & 15);
- offset += processed;
- break;
- default:
- if (data[offset - 3] == 0xFF &&
- data[offset - 2] >= 0xC0 && data[offset - 2] <= 0xFE) {
- // could be incorrect encoding -- last 0xFF byte of the previous
- // block was eaten by the encoder
- offset -= 3;
- break;
- }
- throw "unknown JPEG marker " + fileMarker.toString(16);
+ for (var i = 0, arr = [h1, h2], str = ''; i < arr.length; i++) {
+ var hex = (arr[i] >>> 0).toString(16);
+ while (hex.length < 8) {
+ hex = '0' + hex;
}
- fileMarker = readUint16();
+ str += hex;
}
- if (frames.length != 1)
- throw "only single frame JPEGs supported";
- this.width = frame.samplesPerLine;
- this.height = frame.scanLines;
- this.jfif = jfif;
- this.adobe = adobe;
- this.components = [];
- for (var i = 0; i < frame.componentsOrder.length; i++) {
- var component = frame.components[frame.componentsOrder[i]];
- this.components.push({
- lines: buildComponentData(frame, component),
- scaleX: component.h / frame.maxH,
- scaleY: component.v / frame.maxV
- });
- }
- },
- getData: function getData(width, height) {
- var scaleX = this.width / width, scaleY = this.height / height;
-
- var component, componentLine, componentScaleX, componentScaleY;
- var x, y, i;
- var offset = 0;
- var Y, Cb, Cr, K, C, M, Ye, R, G, B;
- var colorTransform;
- var numComponents = this.components.length;
- var dataLength = width * height * numComponents;
- var data = new Uint8Array(dataLength);
-
- // First construct image data ...
- for (i = 0; i < numComponents; i++) {
- component = this.components[i];
- componentScaleX = component.scaleX * scaleX;
- componentScaleY = component.scaleY * scaleY;
- offset = i;
- for (y = 0; y < height; y++) {
- componentLine = component.lines[0 | (y * componentScaleY)];
- for (x = 0; x < width; x++) {
- data[offset] = componentLine[0 | (x * componentScaleX)];
- offset += numComponents;
- }
- }
- }
-
- // ... then transform colors, if necessary
- switch (numComponents) {
- case 1: case 2: break;
- // no color conversion for one or two compoenents
-
- case 3:
- // The default transform for three components is true
- colorTransform = true;
- // The adobe transform marker overrides any previous setting
- if (this.adobe && this.adobe.transformCode)
- colorTransform = true;
- else if (typeof this.colorTransform !== 'undefined')
- colorTransform = !!this.colorTransform;
-
- if (colorTransform) {
- for (i = 0; i < dataLength; i += numComponents) {
- Y = data[i ];
- Cb = data[i + 1];
- Cr = data[i + 2];
-
- R = clampTo8bit(Y + 1.402 * (Cr - 128));
- G = clampTo8bit(Y - 0.3441363 * (Cb - 128) - 0.71413636 * (Cr - 128));
- B = clampTo8bit(Y + 1.772 * (Cb - 128));
-
- data[i ] = R;
- data[i + 1] = G;
- data[i + 2] = B;
- }
- }
- break;
- case 4:
- // The default transform for four components is false
- colorTransform = false;
- // The adobe transform marker overrides any previous setting
- if (this.adobe && this.adobe.transformCode)
- colorTransform = true;
- else if (typeof this.colorTransform !== 'undefined')
- colorTransform = !!this.colorTransform;
-
- if (colorTransform) {
- for (i = 0; i < dataLength; i += numComponents) {
- Y = data[i];
- Cb = data[i + 1];
- Cr = data[i + 2];
-
- C = 255 - clampTo8bit(Y + 1.402 * (Cr - 128));
- M = 255 - clampTo8bit(Y - 0.3441363 * (Cb - 128) - 0.71413636 * (Cr - 128));
- Ye = 255 - clampTo8bit(Y + 1.772 * (Cb - 128));
-
- data[i ] = C;
- data[i + 1] = M;
- data[i + 2] = Ye;
- // K is unchanged
- }
- }
- break;
- default:
- throw 'Unsupported color mode';
- }
- return data;
- },
- copyToImageData: function copyToImageData(imageData) {
- var width = imageData.width, height = imageData.height;
- var imageDataBytes = width * height * 4;
- var imageDataArray = imageData.data;
- var data = this.getData(width, height);
- var i = 0, j = 0;
- var Y, K, C, M, R, G, B;
- switch (this.components.length) {
- case 1:
- while (j < imageDataBytes) {
- Y = data[i++];
-
- imageDataArray[j++] = Y;
- imageDataArray[j++] = Y;
- imageDataArray[j++] = Y;
- imageDataArray[j++] = 255;
- }
- break;
- case 3:
- while (j < imageDataBytes) {
- R = data[i++];
- G = data[i++];
- B = data[i++];
-
- imageDataArray[j++] = R;
- imageDataArray[j++] = G;
- imageDataArray[j++] = B;
- imageDataArray[j++] = 255;
- }
- break;
- case 4:
- while (j < imageDataBytes) {
- C = data[i++];
- M = data[i++];
- Y = data[i++];
- K = data[i++];
-
- R = 255 - clampTo8bit(C * (1 - K / 255) + K);
- G = 255 - clampTo8bit(M * (1 - K / 255) + K);
- B = 255 - clampTo8bit(Y * (1 - K / 255) + K);
-
- imageDataArray[j++] = R;
- imageDataArray[j++] = G;
- imageDataArray[j++] = B;
- imageDataArray[j++] = 255;
- }
- break;
- default:
- throw 'Unsupported color mode';
- }
+ return str;
}
};
- return constructor;
+ return MurmurHash3_64;
})();