diff --git a/Makefile b/Makefile
index 62565670a..3cc423350 100644
--- a/Makefile
+++ b/Makefile
@@ -39,6 +39,7 @@ PDF_JS_FILES = \
../external/jpgjs/jpg.js \
jpx.js \
bidi.js \
+ metadata.js \
$(NULL)
# make server
diff --git a/README.md b/README.md
index 2c706f4ac..bd5d2c784 100644
--- a/README.md
+++ b/README.md
@@ -122,41 +122,14 @@ Our Github contributors so far:
You can add your name to it! :)
-
# Running the tests
-pdf.js comes with browser-level regression tests that allow one to probe
+pdf.js comes with browser-level regression tests that allow one to probe
whether it's able to successfully parse PDFs, as well as compare its output
against reference images, pixel-by-pixel.
-To run the tests, first configure the browser manifest file at:
-
- test/resources/browser_manifests/browser_manifest.json
-
-Sample manifests for different platforms are provided in that directory.
-
-To run all the bundled tests, type:
-
- $ make test
-
-and cross your fingers. Different types of tests are available, see the test
-manifest file at:
-
- test/test_manifest.json
-
-The test type `eq` tests whether the output images are identical to reference
-images. The test type `load` simply tests whether the file loads without
-raising any errors.
-
-
-### Running tests through our bot
-
-If you are a reviewer, you can use our remote bot to issue comprehensive tests
-against reference images before merging pull requests.
-
-See the bot repo for details:
-
-+ https://github.com/mozilla/pdf.js-bot
+More information about running the tests can be found on the
+[contributor wiki page](https://github.com/mozilla/pdf.js/wiki/Contributing).
# Additional resources
diff --git a/extensions/firefox/install.rdf.in b/extensions/firefox/install.rdf.in
index 3f8f87cda..feab3e7ad 100644
--- a/extensions/firefox/install.rdf.in
+++ b/extensions/firefox/install.rdf.in
@@ -20,7 +20,7 @@
true
Mozilla
Uses HTML5 to display PDF files directly in Firefox.
- http://support.mozilla.org/kb/using-mozilla-pdf-viewer
+ https://support.mozilla.org/kb/Opening%20PDF%20files%20within%20Firefox
2
diff --git a/external/shelljs/ChangeLog b/external/shelljs/ChangeLog
new file mode 100644
index 000000000..23ca5d0e0
--- /dev/null
+++ b/external/shelljs/ChangeLog
@@ -0,0 +1,22 @@
+2012.03.22, Version 0.0.4
+
+* ls() and find() return arrays instead of hashes (Artur Adib)
+* exec({silent:...}) overrides global silent() state (Artur Adib)
+
+
+2012.03.21, Version 0.0.3
+
+* Wildcard bug fix (Artur Adib)
+* execSync() now uses dummy file I/O op to reduce CPU usage (Artur Adib)
+* Minor fixes
+
+
+2012.03.15, Version 0.0.2
+
+* New methods: find(), test() (Artur Adib)
+* Deprecated non-Unix methods: exists(), verbose()
+
+
+2012.03.03, Version 0.0.2pre1
+
+* First public release
diff --git a/external/shelljs/README.md b/external/shelljs/README.md
index 82f53533b..af5f05127 100644
--- a/external/shelljs/README.md
+++ b/external/shelljs/README.md
@@ -1,6 +1,7 @@
# ShellJS - Unix shell commands for Node.js [](http://travis-ci.org/arturadib/shelljs)
-_This project is young and experimental. Use at your own risk._
++ _This project is young and experimental. Use at your own risk._
++ _Major API change as of v0.0.4: `ls()` and `find()` now return arrays._
ShellJS is a **portable** (Windows included) implementation of Unix shell commands on top of the Node.js API. You can use it to eliminate your shell script's dependency on Unix while still keeping its familiar and powerful commands.
@@ -18,11 +19,11 @@ cp('-R', 'stuff/*', 'out/Release');
// Replace macros in each .js file
cd('lib');
-for (file in ls('*.js')) {
+ls('*.js').forEach(function(file) {
sed('-i', 'BUILD_VERSION', 'v0.1.2', file);
sed('-i', /.*REMOVE_THIS_LINE.*\n/, '', file);
sed('-i', /.*REPLACE_LINE_WITH_MACRO.*\n/, cat('macro.js'), file);
-}
+});
cd('..');
// Run external tool synchronously
@@ -73,11 +74,11 @@ target.docs = function() {
cd(__dirname);
mkdir('docs');
cd('lib');
- for (file in ls('*.js')) {
+ ls('*.js').forEach(function(file){
var text = grep('//@', file); // extract special comments
text.replace('//@', ''); // remove comment tags
text.to('docs/my_docs.md');
- }
+ });
}
```
@@ -128,9 +129,7 @@ ls('-R', '/users/me', '/tmp');
ls('-R', ['/users/me', '/tmp']); // same as above
```
-Returns list of files in the given path, or in current directory if no path provided.
-For convenient iteration via `for (file in ls())`, the format returned is a hash object:
-`{ 'file1':null, 'dir1/file2':null, ...}`.
+Returns array of files in the given path, or in current directory if no path provided.
#### find(path [,path ...])
#### find(path_array)
@@ -139,18 +138,12 @@ Examples:
```javascript
find('src', 'lib');
find(['src', 'lib']); // same as above
-for (file in find('.')) {
-if (!file.match(/\.js$/))
-continue;
-// all files at this point end in '.js'
-}
+find('.').filter(function(file) { return file.match(/\.js$/); });
```
-Returns list of all files (however deep) in the given paths. For convenient iteration
-via `for (file in find(...))`, the format returned is a hash object:
-`{ 'file1':null, 'dir1/file2':null, ...}`.
+Returns array of all files (however deep) in the given paths.
-The main difference with respect to `ls('-R', path)` is that the resulting file names
+The main difference from `ls('-R', path)` is that the resulting file names
include the base directories, e.g. `lib/resources/file1` instead of just `file1`.
#### cp('[options ,] source [,source ...], dest')
@@ -332,6 +325,10 @@ When in synchronous mode returns the object `{ code:..., output:... }`, containi
`output` (stdout + stderr) and its exit `code`. Otherwise the `callback` gets the
arguments `(code, output)`.
+**Note:** For long-lived processes, it's best to run `exec()` asynchronously as
+the current synchronous implementation uses a lot of CPU. This should be getting
+fixed soon.
+
## Non-Unix commands
@@ -339,16 +336,35 @@ arguments `(code, output)`.
Searches and returns string containing a writeable, platform-dependent temporary directory.
Follows Python's [tempfile algorithm](http://docs.python.org/library/tempfile.html#tempfile.tempdir).
-#### exists(path [, path ...])
-#### exists(path_array)
-Returns true if all the given paths exist.
-
#### error()
Tests if error occurred in the last command. Returns `null` if no error occurred,
otherwise returns string explaining the error
+#### silent([state])
+Example:
+
+```javascript
+var silentState = silent();
+silent(true);
+/* ... */
+silent(silentState); // restore old silent state
+```
+
+Suppresses all command output if `state = true`, except for `echo()` calls.
+Returns state if no arguments given.
+
+## Deprecated
+
+
+#### exists(path [, path ...])
+#### exists(path_array)
+
+_This function is being deprecated. Use `test()` instead._
+
+Returns true if all the given paths exist.
+
#### verbose()
-Enables all output (default)
-#### silent()
-Suppresses all output, except for explict `echo()` calls
+_This function is being deprecated. Use `silent(false) instead.`_
+
+Enables all output (default)
diff --git a/external/shelljs/make.js b/external/shelljs/make.js
index 9c92dadc8..c495735bf 100644
--- a/external/shelljs/make.js
+++ b/external/shelljs/make.js
@@ -23,7 +23,7 @@ setTimeout(function() {
if (oldTarget.done && !force)
return;
oldTarget.done = true;
- return oldTarget(arguments);
+ return oldTarget.apply(oldTarget, arguments);
}
})(t, target[t]);
diff --git a/external/shelljs/package.json b/external/shelljs/package.json
index 9499680e9..4d2830cb9 100644
--- a/external/shelljs/package.json
+++ b/external/shelljs/package.json
@@ -1,12 +1,29 @@
-{ "name": "shelljs"
-, "version": "0.0.2pre1"
-, "author": "Artur Adib "
-, "description": "Portable Unix shell commands for Node.js"
-, "keywords": ["unix", "shell", "makefile", "make", "jake", "synchronous"]
-, "repository": "git://github.com/arturadib/shelljs"
-, "homepage": "http://github.com/arturadib/shelljs"
-, "main": "./shell.js"
-, "scripts": {
+{
+ "name": "shelljs",
+ "version": "0.0.5pre4",
+ "author": "Artur Adib ",
+ "description": "Portable Unix shell commands for Node.js",
+ "keywords": [
+ "unix",
+ "shell",
+ "makefile",
+ "make",
+ "jake",
+ "synchronous"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/arturadib/shelljs.git"
+ },
+ "homepage": "http://github.com/arturadib/shelljs",
+ "main": "./shell.js",
+ "scripts": {
"test": "node scripts/run-tests"
+ },
+ "dependencies": {},
+ "devDependencies": {},
+ "optionalDependencies": {},
+ "engines": {
+ "node": "*"
}
}
diff --git a/external/shelljs/shell.js b/external/shelljs/shell.js
index 95ddaa067..92c49c54d 100644
--- a/external/shelljs/shell.js
+++ b/external/shelljs/shell.js
@@ -74,9 +74,7 @@ exports.pwd = wrap('pwd', _pwd);
//@ ls('-R', ['/users/me', '/tmp']); // same as above
//@ ```
//@
-//@ Returns list of files in the given path, or in current directory if no path provided.
-//@ For convenient iteration via `for (file in ls())`, the format returned is a hash object:
-//@ `{ 'file1':null, 'dir1/file2':null, ...}`.
+//@ Returns array of files in the given path, or in current directory if no path provided.
function _ls(options, paths) {
options = parseOptions(options, {
'R': 'recursive',
@@ -90,24 +88,30 @@ function _ls(options, paths) {
else if (typeof paths === 'string')
paths = [].slice.call(arguments, 1);
- var hash = {};
+ var list = [];
- function pushHash(file, query) {
+ // Conditionally pushes file to list - returns true if pushed, false otherwise
+ // (e.g. prevents hidden files to be included unless explicitly told so)
+ function pushFile(file, query) {
// hidden file?
if (path.basename(file)[0] === '.') {
// not explicitly asking for hidden files?
if (!options.all && !(path.basename(query)[0] === '.' && path.basename(query).length > 1))
- return;
+ return false;
}
- hash[file] = null;
+ if (platform === 'win')
+ file = file.replace(/\\/g, '/');
+
+ list.push(file);
+ return true;
}
paths.forEach(function(p) {
if (fs.existsSync(p)) {
// Simple file?
if (fs.statSync(p).isFile()) {
- pushHash(p, p);
+ pushFile(p, p);
return; // continue
}
@@ -115,14 +119,17 @@ function _ls(options, paths) {
if (fs.statSync(p).isDirectory()) {
// Iterate over p contents
fs.readdirSync(p).forEach(function(file) {
- pushHash(file, p);
-
- // Recursive
- var oldDir = _pwd();
- _cd('', p);
- if (fs.statSync(file).isDirectory() && options.recursive)
- hash = extend(hash, _ls('-R', file+'/*'));
- _cd('', oldDir);
+ if (!pushFile(file, p))
+ return;
+
+ // Recursive?
+ if (options.recursive) {
+ var oldDir = _pwd();
+ _cd('', p);
+ if (fs.statSync(file).isDirectory())
+ list = list.concat(_ls('-R'+(options.all?'a':''), file+'/*'));
+ _cd('', oldDir);
+ }
});
return; // continue
}
@@ -137,17 +144,20 @@ function _ls(options, paths) {
// Escape special regular expression chars
var regexp = basename.replace(/(\^|\$|\(|\)|\<|\>|\[|\]|\{|\}|\.|\+|\?)/g, '\\$1');
// Translates wildcard into regex
- regexp = '^' + regexp.replace(/\*/g, '.*');
+ regexp = '^' + regexp.replace(/\*/g, '.*') + '$';
// Iterate over directory contents
fs.readdirSync(dirname).forEach(function(file) {
if (file.match(new RegExp(regexp))) {
- pushHash(path.normalize(dirname+'/'+file), basename);
-
- // Recursive
- var pp = dirname + '/' + file;
- if (fs.statSync(pp).isDirectory() && options.recursive)
- hash = extend(hash, _ls('-R', pp+'/*'));
- }
+ if (!pushFile(path.normalize(dirname+'/'+file), basename))
+ return;
+
+ // Recursive?
+ if (options.recursive) {
+ var pp = dirname + '/' + file;
+ if (fs.statSync(pp).isDirectory())
+ list = list.concat(_ls('-R'+(options.all?'a':''), pp+'/*'));
+ } // recursive
+ } // if file matches
}); // forEach
return;
}
@@ -155,7 +165,7 @@ function _ls(options, paths) {
error('no such file or directory: ' + p, true);
});
- return hash;
+ return list;
};
exports.ls = wrap('ls', _ls);
@@ -168,16 +178,10 @@ exports.ls = wrap('ls', _ls);
//@ ```javascript
//@ find('src', 'lib');
//@ find(['src', 'lib']); // same as above
-//@ for (file in find('.')) {
-//@ if (!file.match(/\.js$/))
-//@ continue;
-//@ // all files at this point end in '.js'
-//@ }
+//@ find('.').filter(function(file) { return file.match(/\.js$/); });
//@ ```
//@
-//@ Returns list of all files (however deep) in the given paths. For convenient iteration
-//@ via `for (file in find(...))`, the format returned is a hash object:
-//@ `{ 'file1':null, 'dir1/file2':null, ...}`.
+//@ Returns array of all files (however deep) in the given paths.
//@
//@ The main difference from `ls('-R', path)` is that the resulting file names
//@ include the base directories, e.g. `lib/resources/file1` instead of just `file1`.
@@ -189,21 +193,28 @@ function _find(options, paths) {
else if (typeof paths === 'string')
paths = [].slice.call(arguments, 1);
- var hash = {};
+ var list = [];
+
+ function pushFile(file) {
+ if (platform === 'win')
+ file = file.replace(/\\/g, '/');
+ list.push(file);
+ }
// why not simply do ls('-R', paths)? because the output wouldn't give the base dirs
// to get the base dir in the output, we need instead ls('-R', 'dir/*') for every directory
- paths.forEach(function(file){
- hash[file] = null;
+ paths.forEach(function(file) {
+ pushFile(file);
if (fs.statSync(file).isDirectory()) {
- for (subfile in _ls('-Ra', file+'/*'))
- hash[subfile] = null;
+ _ls('-Ra', file+'/*').forEach(function(subfile) {
+ pushFile(subfile);
+ });
}
});
- return hash;
+ return list;
}
exports.find = wrap('find', _find);
@@ -347,9 +358,20 @@ function _rm(options, files) {
// Remove simple file
if (fs.statSync(file).isFile()) {
- fs.unlinkSync(file);
+
+ // Do not check for file writing permissions
+ if (options.force) {
+ _unlinkSync(file);
+ return;
+ }
+
+ if (isWriteable(file))
+ _unlinkSync(file);
+ else
+ error('permission denied: '+file, true);
+
return;
- }
+ } // simple file
// Path is an existing directory, but no -r flag given
if (fs.statSync(file).isDirectory() && !options.recursive) {
@@ -359,7 +381,7 @@ function _rm(options, files) {
// Recursively remove existing directory
if (fs.statSync(file).isDirectory() && options.recursive) {
- rmdirSyncRecursive(file);
+ rmdirSyncRecursive(file, options.force);
}
}); // forEach(file)
}; // rm
@@ -582,7 +604,11 @@ function _to(options, file) {
if (!fs.existsSync( path.dirname(file) ))
error('no such file or directory: ' + path.dirname(file));
- fs.writeFileSync(file, this.toString(), 'utf8');
+ try {
+ fs.writeFileSync(file, this.toString(), 'utf8');
+ } catch(e) {
+ error('could not write to file (code '+e.code+'): '+file, true);
+ }
};
// In the future, when Proxies are default, we can add methods like `.to()` to primitive strings.
// For now, this is a dummy function to bookmark places we need such strings
@@ -751,7 +777,7 @@ exports.which = wrap('which', _which);
//@ like `.to()`.
function _echo(options) {
var messages = [].slice.call(arguments, 1);
- log.apply(this, messages);
+ console.log.apply(this, messages);
return ShellString(messages.join(' '));
};
exports.echo = wrap('echo', _echo);
@@ -783,6 +809,10 @@ exports.env = process.env;
//@ When in synchronous mode returns the object `{ code:..., output:... }`, containing the program's
//@ `output` (stdout + stderr) and its exit `code`. Otherwise the `callback` gets the
//@ arguments `(code, output)`.
+//@
+//@ **Note:** For long-lived processes, it's best to run `exec()` asynchronously as
+//@ the current synchronous implementation uses a lot of CPU. This should be getting
+//@ fixed soon.
function _exec(command, options, callback) {
if (!command)
error('must specify command');
@@ -793,7 +823,7 @@ function _exec(command, options, callback) {
}
options = extend({
- silent: false,
+ silent: state.silent,
async: false
}, options);
@@ -822,11 +852,53 @@ exports.exec = wrap('exec', _exec, {notUnix:true});
//@ Follows Python's [tempfile algorithm](http://docs.python.org/library/tempfile.html#tempfile.tempdir).
exports.tempdir = wrap('tempdir', tempDir);
+
+//@
+//@ #### error()
+//@ Tests if error occurred in the last command. Returns `null` if no error occurred,
+//@ otherwise returns string explaining the error
+exports.error = function() {
+ return state.error;
+}
+
+//@
+//@ #### silent([state])
+//@ Example:
+//@
+//@ ```javascript
+//@ var silentState = silent();
+//@ silent(true);
+//@ /* ... */
+//@ silent(silentState); // restore old silent state
+//@ ```
+//@
+//@ Suppresses all command output if `state = true`, except for `echo()` calls.
+//@ Returns state if no arguments given.
+exports.silent = function(_state) {
+ if (typeof _state !== 'boolean')
+ return state.silent;
+
+ state.silent = _state;
+}
+
+
+//@
+//@ ## Deprecated
+//@
+
+
+
+
//@
//@ #### exists(path [, path ...])
//@ #### exists(path_array)
+//@
+//@ _This function is being deprecated. Use `test()` instead._
+//@
//@ Returns true if all the given paths exist.
function _exists(options, paths) {
+ deprecate('exists', 'Use test() instead.');
+
if (!paths)
error('no paths given');
@@ -844,26 +916,17 @@ function _exists(options, paths) {
};
exports.exists = wrap('exists', _exists);
-//@
-//@ #### error()
-//@ Tests if error occurred in the last command. Returns `null` if no error occurred,
-//@ otherwise returns string explaining the error
-exports.error = function() {
- return state.error;
-}
//@
//@ #### verbose()
+//@
+//@ _This function is being deprecated. Use `silent(false) instead.`_
+//@
//@ Enables all output (default)
exports.verbose = function() {
- state.silent = false;
-}
+ deprecate('verbose', 'Use silent(false) instead.');
-//@
-//@ #### silent()
-//@ Suppresses all output, except for explict `echo()` calls
-exports.silent = function() {
- state.silent = true;
+ state.silent = false;
}
@@ -875,10 +938,6 @@ exports.silent = function() {
-
-
-
-
////////////////////////////////////////////////////////////////////////////////////////////////
//
// Auxiliary functions (internal use only)
@@ -889,6 +948,10 @@ function log() {
console.log.apply(this, arguments);
}
+function deprecate(what, msg) {
+ console.log('*** ShellJS.'+what+': This function is deprecated.', msg);
+}
+
function write(msg) {
if (!state.silent)
process.stdout.write(msg);
@@ -962,7 +1025,7 @@ function wrap(cmd, fn, options) {
} catch (e) {
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
- console.log('maker.js: internal error');
+ console.log('shell.js: internal error');
console.log(e.stack || e);
process.exit(1);
}
@@ -970,7 +1033,7 @@ function wrap(cmd, fn, options) {
throw e;
}
- state.currentCmd = 'maker.js';
+ state.currentCmd = 'shell.js';
return retValue;
}
} // wrap
@@ -984,10 +1047,22 @@ function copyFileSync(srcFile, destFile) {
var BUF_LENGTH = 64*1024,
buf = new Buffer(BUF_LENGTH),
- fdr = fs.openSync(srcFile, 'r'),
- fdw = fs.openSync(destFile, 'w'),
bytesRead = BUF_LENGTH,
- pos = 0;
+ pos = 0,
+ fdr = null,
+ fdw = null;
+
+ try {
+ fdr = fs.openSync(srcFile, 'r');
+ } catch(e) {
+ error('copyFileSync: could not read src file ('+srcFile+')');
+ }
+
+ try {
+ fdw = fs.openSync(destFile, 'w');
+ } catch(e) {
+ error('copyFileSync: could not write to dest file (code='+e.code+'):'+destFile);
+ }
while (bytesRead === BUF_LENGTH) {
bytesRead = fs.readSync(fdr, buf, 0, BUF_LENGTH, pos);
@@ -1050,28 +1125,41 @@ function cpdirSyncRecursive(sourceDir, destDir, opts) {
//
// Licensed under the MIT License
// http://www.opensource.org/licenses/mit-license.php
-function rmdirSyncRecursive(dir) {
+function rmdirSyncRecursive(dir, force) {
var files;
files = fs.readdirSync(dir);
// Loop through and delete everything in the sub-tree after checking it
for(var i = 0; i < files.length; i++) {
- var currFile = fs.lstatSync(dir + "/" + files[i]);
+ var file = dir + "/" + files[i],
+ currFile = fs.lstatSync(file);
- if(currFile.isDirectory()) // Recursive function back to the beginning
- rmdirSyncRecursive(dir + "/" + files[i]);
+ if(currFile.isDirectory()) { // Recursive function back to the beginning
+ rmdirSyncRecursive(file, force);
+ }
- else if(currFile.isSymbolicLink()) // Unlink symlinks
- fs.unlinkSync(dir + "/" + files[i]);
+ else if(currFile.isSymbolicLink()) { // Unlink symlinks
+ if (force || isWriteable(file))
+ _unlinkSync(file);
+ }
else // Assume it's a file - perhaps a try/catch belongs here?
- fs.unlinkSync(dir + "/" + files[i]);
+ if (force || isWriteable(file))
+ _unlinkSync(file);
}
// Now that we know everything in the sub-tree has been deleted, we can delete the main directory.
// Huzzah for the shopkeep.
- return fs.rmdirSync(dir);
+
+ var result;
+ try {
+ result = fs.rmdirSync(dir);
+ } catch(e) {
+ error('could not remove directory (code '+e.code+'): ' + dir, true);
+ }
+
+ return result;
}; // rmdirSyncRecursive
// Recursively creates 'dir'
@@ -1118,7 +1206,7 @@ function writeableDir(dir) {
var testFile = dir+'/'+randomFileName();
try {
fs.writeFileSync(testFile, ' ');
- fs.unlinkSync(testFile);
+ _unlinkSync(testFile);
return dir;
} catch (e) {
return false;
@@ -1151,6 +1239,10 @@ function tempDir() {
// Wrapper around exec() to enable echoing output to console in real time
function execAsync(cmd, opts, callback) {
var output = '';
+
+ var options = extend({
+ silent: state.silent
+ }, opts);
var c = child.exec(cmd, {env: process.env}, function(err) {
if (callback)
@@ -1159,14 +1251,14 @@ function execAsync(cmd, opts, callback) {
c.stdout.on('data', function(data) {
output += data;
- if (!opts.silent)
- write(data);
+ if (!options.silent)
+ process.stdout.write(data);
});
c.stderr.on('data', function(data) {
output += data;
- if (!opts.silent)
- write(data);
+ if (!options.silent)
+ process.stdout.write(data);
});
}
@@ -1178,16 +1270,17 @@ function execAsync(cmd, opts, callback) {
function execSync(cmd, opts) {
var stdoutFile = path.resolve(tempDir()+'/'+randomFileName()),
codeFile = path.resolve(tempDir()+'/'+randomFileName()),
- scriptFile = path.resolve(tempDir()+'/'+randomFileName());
+ scriptFile = path.resolve(tempDir()+'/'+randomFileName()),
+ sleepFile = path.resolve(tempDir()+'/'+randomFileName());
var options = extend({
- silent: false
+ silent: state.silent
}, opts);
var previousStdoutContent = '';
// Echoes stdout changes from running process, if not silent
function updateStdout() {
- if (state.silent || options.silent || !fs.existsSync(stdoutFile))
+ if (options.silent || !fs.existsSync(stdoutFile))
return;
var stdoutContent = fs.readFileSync(stdoutFile, 'utf8');
@@ -1214,9 +1307,9 @@ function execSync(cmd, opts) {
fs.writeFileSync('"+escape(codeFile)+"', err ? err.code.toString() : '0'); \
});";
- if (fs.existsSync(scriptFile)) fs.unlinkSync(scriptFile);
- if (fs.existsSync(stdoutFile)) fs.unlinkSync(stdoutFile);
- if (fs.existsSync(codeFile)) fs.unlinkSync(codeFile);
+ if (fs.existsSync(scriptFile)) _unlinkSync(scriptFile);
+ if (fs.existsSync(stdoutFile)) _unlinkSync(stdoutFile);
+ if (fs.existsSync(codeFile)) _unlinkSync(codeFile);
fs.writeFileSync(scriptFile, script);
child.exec('node '+scriptFile, {
@@ -1225,8 +1318,11 @@ function execSync(cmd, opts) {
});
// The wait loop
- while (!fs.existsSync(codeFile)) { updateStdout(); };
- while (!fs.existsSync(stdoutFile)) { updateStdout(); };
+ // sleepFile is used as a dummy I/O op to mitigate unnecessary CPU usage
+ // (tried many I/O sync ops, writeFileSync() seems to be only one that is effective in reducing
+ // CPU usage, though apparently not so much on Windows)
+ while (!fs.existsSync(codeFile)) { updateStdout(); fs.writeFileSync(sleepFile, 'a'); };
+ while (!fs.existsSync(stdoutFile)) { updateStdout(); fs.writeFileSync(sleepFile, 'a'); };
// At this point codeFile exists, but it's not necessarily flushed yet.
// Keep reading it until it is.
@@ -1236,10 +1332,12 @@ function execSync(cmd, opts) {
var stdout = fs.readFileSync(stdoutFile, 'utf8');
- fs.unlinkSync(scriptFile);
- fs.unlinkSync(stdoutFile);
- fs.unlinkSync(codeFile);
-
+ // No biggie if we can't erase the files now -- they're in a temp dir anyway
+ try { _unlinkSync(scriptFile); } catch(e) {};
+ try { _unlinkSync(stdoutFile); } catch(e) {};
+ try { _unlinkSync(codeFile); } catch(e) {};
+ try { _unlinkSync(sleepFile); } catch(e) {};
+
// True if successful, false if not
var obj = {
code: code,
@@ -1257,8 +1355,9 @@ function expand(list) {
list.forEach(function(listEl) {
// Wildcard present?
if (listEl.search(/\*/) > -1) {
- for (file in _ls('', listEl))
+ _ls('', listEl).forEach(function(file) {
expanded.push(file);
+ });
} else {
expanded.push(listEl);
}
@@ -1290,3 +1389,33 @@ function extend(target) {
return target;
}
+
+// Normalizes _unlinkSync() across platforms to match Unix behavior, i.e.
+// file can be unlinked even if it's read-only, see joyent/node#3006
+function _unlinkSync(file) {
+ try {
+ fs.unlinkSync(file);
+ } catch(e) {
+ // Try to override file permission
+ if (e.code === 'EPERM') {
+ fs.chmodSync(file, '0666');
+ fs.unlinkSync(file);
+ } else {
+ throw e;
+ }
+ }
+}
+
+// Hack to determine if file has write permissions for current user
+// Avoids having to check user, group, etc, but it's probably slow
+function isWriteable(file) {
+ var writePermission = true;
+ try {
+ var __fd = fs.openSync(file, 'a');
+ fs.closeSync(__fd);
+ } catch(e) {
+ writePermission = false;
+ }
+
+ return writePermission;
+}
diff --git a/make.js b/make.js
index 33771aeb7..e0975fec8 100755
--- a/make.js
+++ b/make.js
@@ -97,9 +97,10 @@ target.bundle = function() {
'worker.js',
'../external/jpgjs/jpg.js',
'jpx.js',
- 'bidi.js'];
+ 'bidi.js',
+ 'metadata.js'];
- if (!exists(BUILD_DIR))
+ if (!test('-d', BUILD_DIR))
mkdir(BUILD_DIR);
cd('src');
@@ -142,10 +143,10 @@ target.pagesrepo = function() {
echo();
echo('### Creating fresh clone of gh-pages');
- if (!exists(BUILD_DIR))
+ if (!test('-d', BUILD_DIR))
mkdir(BUILD_DIR);
- if (!exists(GH_PAGES_DIR)) {
+ if (!test('-d', GH_PAGES_DIR)) {
echo();
echo('Cloning project repo...');
echo('(This operation can take a while, depending on network conditions)');
@@ -277,10 +278,10 @@ target.firefox = function() {
// We don't need pdf.js anymore since its inlined
rm('-Rf', FIREFOX_BUILD_CONTENT_DIR + BUILD_DIR);
// Remove '.DS_Store' and other hidden files
- for (file in find(FIREFOX_BUILD_DIR)) {
+ find(FIREFOX_BUILD_DIR).forEach(function(file) {
if (file.match(/^\./))
rm('-f', file);
- }
+ });
// Update the build version number
sed('-i', /PDFJSSCRIPT_VERSION/, EXTENSION_VERSION, FIREFOX_BUILD_DIR + '/install.rdf');
@@ -304,10 +305,10 @@ target.firefox = function() {
// List all files for mozilla-central
cd(FIREFOX_BUILD_DIR);
var extensionFiles = '';
- for (file in find(FIREFOX_MC_EXTENSION_FILES)) {
+ find(FIREFOX_MC_EXTENSION_FILES).forEach(function(file){
if (test('-f', file))
extensionFiles += file+'\n';
- }
+ });
extensionFiles.to('extension-files');
};
@@ -360,10 +361,19 @@ target.test = function() {
target.unittest();
};
+//
+// make bottest
+// (Special tests for the Github bot)
+//
+target.bottest = function() {
+ target.browsertest({noreftest: true});
+ // target.unittest();
+};
+
//
// make browsertest
//
-target.browsertest = function() {
+target.browsertest = function(options) {
cd(ROOT_DIR);
echo();
echo('### Running browser tests');
@@ -371,14 +381,16 @@ target.browsertest = function() {
var PDF_TEST = env['PDF_TEST'] || 'test_manifest.json',
PDF_BROWSERS = env['PDF_BROWSERS'] || 'resources/browser_manifests/browser_manifest.json';
- if (!exists('test/' + PDF_BROWSERS)) {
+ if (!test('-f', 'test/' + PDF_BROWSERS)) {
echo('Browser manifest file test/' + PDF_BROWSERS + ' does not exist.');
echo('Try copying one of the examples in test/resources/browser_manifests/');
exit(1);
}
+ var reftest = (options && options.noreftest) ? '' : '--reftest';
+
cd('test');
- exec(PYTHON_BIN + ' test.py --reftest --browserManifestFile=' + PDF_BROWSERS +
+ exec(PYTHON_BIN + ' -u test.py '+reftest+' --browserManifestFile=' + PDF_BROWSERS +
' --manifestFile=' + PDF_TEST, {async: true});
};
@@ -390,10 +402,37 @@ target.unittest = function() {
echo();
echo('### Running unit tests');
+ if (!which('make')) {
+ echo('make not found. Skipping unit tests...');
+ return;
+ }
+
cd('test/unit');
exec('make', {async: true});
};
+//
+// make botmakeref
+//
+target.botmakeref = function() {
+ cd(ROOT_DIR);
+ echo();
+ echo('### Creating reference images');
+
+ var PDF_TEST = env['PDF_TEST'] || 'test_manifest.json',
+ PDF_BROWSERS = env['PDF_BROWSERS'] || 'resources/browser_manifests/browser_manifest.json';
+
+ if (!test('-f', 'test/' + PDF_BROWSERS)) {
+ echo('Browser manifest file test/' + PDF_BROWSERS + ' does not exist.');
+ echo('Try copying one of the examples in test/resources/browser_manifests/');
+ exit(1);
+ }
+
+ cd('test');
+ exec(PYTHON_BIN + ' -u test.py --masterMode --noPrompts --browserManifestFile=' + PDF_BROWSERS,
+ {async: true});
+};
+
///////////////////////////////////////////////////////////////////////////////////////////
//
diff --git a/src/canvas.js b/src/canvas.js
index 979bd1888..8f29051fd 100644
--- a/src/canvas.js
+++ b/src/canvas.js
@@ -20,56 +20,6 @@ var TextRenderingMode = {
// Minimal font size that would be used during canvas fillText operations.
var MIN_FONT_SIZE = 1;
-var CanvasExtraState = (function CanvasExtraStateClosure() {
- function CanvasExtraState(old) {
- // Are soft masks and alpha values shapes or opacities?
- this.alphaIsShape = false;
- this.fontSize = 0;
- this.fontSizeScale = 1;
- this.textMatrix = IDENTITY_MATRIX;
- this.fontMatrix = IDENTITY_MATRIX;
- this.leading = 0;
- // Current point (in user coordinates)
- this.x = 0;
- this.y = 0;
- // Start of text line (in text coordinates)
- this.lineX = 0;
- this.lineY = 0;
- // Character and word spacing
- this.charSpacing = 0;
- this.wordSpacing = 0;
- this.textHScale = 1;
- this.textRenderingMode = TextRenderingMode.FILL;
- // Color spaces
- this.fillColorSpace = new DeviceGrayCS();
- this.fillColorSpaceObj = null;
- this.strokeColorSpace = new DeviceGrayCS();
- this.strokeColorSpaceObj = null;
- this.fillColorObj = null;
- this.strokeColorObj = null;
- // Default fore and background colors
- this.fillColor = '#000000';
- this.strokeColor = '#000000';
- // Note: fill alpha applies to all non-stroking operations
- this.fillAlpha = 1;
- this.strokeAlpha = 1;
- this.lineWidth = 1;
-
- this.old = old;
- }
-
- CanvasExtraState.prototype = {
- clone: function canvasextra_clone() {
- return Object.create(this);
- },
- setCurrentPoint: function canvasextra_setCurrentPoint(x, y) {
- this.x = x;
- this.y = y;
- }
- };
- return CanvasExtraState;
-})();
-
function createScratchCanvas(width, height) {
var canvas = document.createElement('canvas');
canvas.width = width;
@@ -187,6 +137,56 @@ function addContextCurrentTransform(ctx) {
}
}
+var CanvasExtraState = (function CanvasExtraStateClosure() {
+ function CanvasExtraState(old) {
+ // Are soft masks and alpha values shapes or opacities?
+ this.alphaIsShape = false;
+ this.fontSize = 0;
+ this.fontSizeScale = 1;
+ this.textMatrix = IDENTITY_MATRIX;
+ this.fontMatrix = IDENTITY_MATRIX;
+ this.leading = 0;
+ // Current point (in user coordinates)
+ this.x = 0;
+ this.y = 0;
+ // Start of text line (in text coordinates)
+ this.lineX = 0;
+ this.lineY = 0;
+ // Character and word spacing
+ this.charSpacing = 0;
+ this.wordSpacing = 0;
+ this.textHScale = 1;
+ this.textRenderingMode = TextRenderingMode.FILL;
+ // Color spaces
+ this.fillColorSpace = new DeviceGrayCS();
+ this.fillColorSpaceObj = null;
+ this.strokeColorSpace = new DeviceGrayCS();
+ this.strokeColorSpaceObj = null;
+ this.fillColorObj = null;
+ this.strokeColorObj = null;
+ // Default fore and background colors
+ this.fillColor = '#000000';
+ this.strokeColor = '#000000';
+ // Note: fill alpha applies to all non-stroking operations
+ this.fillAlpha = 1;
+ this.strokeAlpha = 1;
+ this.lineWidth = 1;
+
+ this.old = old;
+ }
+
+ CanvasExtraState.prototype = {
+ clone: function CanvasExtraState_clone() {
+ return Object.create(this);
+ },
+ setCurrentPoint: function CanvasExtraState_setCurrentPoint(x, y) {
+ this.x = x;
+ this.y = y;
+ }
+ };
+ return CanvasExtraState;
+})();
+
var CanvasGraphics = (function CanvasGraphicsClosure() {
// Defines the time the executeOperatorList is going to be executing
// before it stops and shedules a continue of execution.
@@ -241,7 +241,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
'shadingFill': true
},
- beginDrawing: function canvasGraphicsBeginDrawing(mediaBox) {
+ beginDrawing: function CanvasGraphics_beginDrawing(mediaBox) {
var cw = this.ctx.canvas.width, ch = this.ctx.canvas.height;
this.ctx.save();
switch (mediaBox.rotate) {
@@ -267,7 +267,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
this.textLayer.beginLayout();
},
- executeOperatorList: function canvasGraphicsExecuteOperatorList(
+ executeOperatorList: function CanvasGraphics_executeOperatorList(
operatorList,
executionStartIdx, continueCallback,
stepper) {
@@ -332,7 +332,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
}
},
- endDrawing: function canvasGraphicsEndDrawing() {
+ endDrawing: function CanvasGraphics_endDrawing() {
this.ctx.restore();
if (this.textLayer)
@@ -340,32 +340,32 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
},
// Graphics state
- setLineWidth: function canvasGraphicsSetLineWidth(width) {
+ setLineWidth: function CanvasGraphics_setLineWidth(width) {
this.current.lineWidth = width;
this.ctx.lineWidth = width;
},
- setLineCap: function canvasGraphicsSetLineCap(style) {
+ setLineCap: function CanvasGraphics_setLineCap(style) {
this.ctx.lineCap = LINE_CAP_STYLES[style];
},
- setLineJoin: function canvasGraphicsSetLineJoin(style) {
+ setLineJoin: function CanvasGraphics_setLineJoin(style) {
this.ctx.lineJoin = LINE_JOIN_STYLES[style];
},
- setMiterLimit: function canvasGraphicsSetMiterLimit(limit) {
+ setMiterLimit: function CanvasGraphics_setMiterLimit(limit) {
this.ctx.miterLimit = limit;
},
- setDash: function canvasGraphicsSetDash(dashArray, dashPhase) {
+ setDash: function CanvasGraphics_setDash(dashArray, dashPhase) {
this.ctx.mozDash = dashArray;
this.ctx.mozDashOffset = dashPhase;
this.ctx.webkitLineDash = dashArray;
this.ctx.webkitLineDashOffset = dashPhase;
},
- setRenderingIntent: function canvasGraphicsSetRenderingIntent(intent) {
+ setRenderingIntent: function CanvasGraphics_setRenderingIntent(intent) {
TODO('set rendering intent: ' + intent);
},
- setFlatness: function canvasGraphicsSetFlatness(flatness) {
+ setFlatness: function CanvasGraphics_setFlatness(flatness) {
TODO('set flatness: ' + flatness);
},
- setGState: function canvasGraphicsSetGState(states) {
+ setGState: function CanvasGraphics_setGState(states) {
for (var i = 0, ii = states.length; i < ii; i++) {
var state = states[i];
var key = state[0];
@@ -406,52 +406,52 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
}
}
},
- save: function canvasGraphicsSave() {
+ save: function CanvasGraphics_save() {
this.ctx.save();
var old = this.current;
this.stateStack.push(old);
this.current = old.clone();
},
- restore: function canvasGraphicsRestore() {
+ restore: function CanvasGraphics_restore() {
var prev = this.stateStack.pop();
if (prev) {
this.current = prev;
this.ctx.restore();
}
},
- transform: function canvasGraphicsTransform(a, b, c, d, e, f) {
+ transform: function CanvasGraphics_transform(a, b, c, d, e, f) {
this.ctx.transform(a, b, c, d, e, f);
},
// Path
- moveTo: function canvasGraphicsMoveTo(x, y) {
+ moveTo: function CanvasGraphics_moveTo(x, y) {
this.ctx.moveTo(x, y);
this.current.setCurrentPoint(x, y);
},
- lineTo: function canvasGraphicsLineTo(x, y) {
+ lineTo: function CanvasGraphics_lineTo(x, y) {
this.ctx.lineTo(x, y);
this.current.setCurrentPoint(x, y);
},
- curveTo: function canvasGraphicsCurveTo(x1, y1, x2, y2, x3, y3) {
+ 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 canvasGraphicsCurveTo2(x2, y2, x3, y3) {
+ curveTo2: function CanvasGraphics_curveTo2(x2, y2, x3, y3) {
var current = this.current;
this.ctx.bezierCurveTo(current.x, current.y, x2, y2, x3, y3);
current.setCurrentPoint(x3, y3);
},
- curveTo3: function canvasGraphicsCurveTo3(x1, y1, x3, y3) {
+ curveTo3: function CanvasGraphics_curveTo3(x1, y1, x3, y3) {
this.curveTo(x1, y1, x3, y3, x3, y3);
this.current.setCurrentPoint(x3, y3);
},
- closePath: function canvasGraphicsClosePath() {
+ closePath: function CanvasGraphics_closePath() {
this.ctx.closePath();
},
- rectangle: function canvasGraphicsRectangle(x, y, width, height) {
+ rectangle: function CanvasGraphics_rectangle(x, y, width, height) {
this.ctx.rect(x, y, width, height);
},
- stroke: function canvasGraphicsStroke(consumePath) {
+ stroke: function CanvasGraphics_stroke(consumePath) {
consumePath = typeof consumePath !== 'undefined' ? consumePath : true;
var ctx = this.ctx;
var strokeColor = this.current.strokeColor;
@@ -476,11 +476,11 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
// Restore the global alpha to the fill alpha
ctx.globalAlpha = this.current.fillAlpha;
},
- closeStroke: function canvasGraphicsCloseStroke() {
+ closeStroke: function CanvasGraphics_closeStroke() {
this.closePath();
this.stroke();
},
- fill: function canvasGraphicsFill(consumePath) {
+ fill: function CanvasGraphics_fill(consumePath) {
consumePath = typeof consumePath !== 'undefined' ? consumePath : true;
var ctx = this.ctx;
var fillColor = this.current.fillColor;
@@ -497,65 +497,65 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
if (consumePath)
this.consumePath();
},
- eoFill: function canvasGraphicsEoFill() {
+ eoFill: function CanvasGraphics_eoFill() {
var savedFillRule = this.setEOFillRule();
this.fill();
this.restoreFillRule(savedFillRule);
},
- fillStroke: function canvasGraphicsFillStroke() {
+ fillStroke: function CanvasGraphics_fillStroke() {
this.fill(false);
this.stroke(false);
this.consumePath();
},
- eoFillStroke: function canvasGraphicsEoFillStroke() {
+ eoFillStroke: function CanvasGraphics_eoFillStroke() {
var savedFillRule = this.setEOFillRule();
this.fillStroke();
this.restoreFillRule(savedFillRule);
},
- closeFillStroke: function canvasGraphicsCloseFillStroke() {
+ closeFillStroke: function CanvasGraphics_closeFillStroke() {
this.closePath();
this.fillStroke();
},
- closeEOFillStroke: function canvasGraphicsCloseEOFillStroke() {
+ closeEOFillStroke: function CanvasGraphics_closeEOFillStroke() {
var savedFillRule = this.setEOFillRule();
this.closePath();
this.fillStroke();
this.restoreFillRule(savedFillRule);
},
- endPath: function canvasGraphicsEndPath() {
+ endPath: function CanvasGraphics_endPath() {
this.consumePath();
},
// Clipping
- clip: function canvasGraphicsClip() {
+ clip: function CanvasGraphics_clip() {
this.pendingClip = NORMAL_CLIP;
},
- eoClip: function canvasGraphicsEoClip() {
+ eoClip: function CanvasGraphics_eoClip() {
this.pendingClip = EO_CLIP;
},
// Text
- beginText: function canvasGraphicsBeginText() {
+ beginText: function CanvasGraphics_beginText() {
this.current.textMatrix = IDENTITY_MATRIX;
this.current.x = this.current.lineX = 0;
this.current.y = this.current.lineY = 0;
},
- endText: function canvasGraphicsEndText() {
+ endText: function CanvasGraphics_endText() {
},
- setCharSpacing: function canvasGraphicsSetCharSpacing(spacing) {
+ setCharSpacing: function CanvasGraphics_setCharSpacing(spacing) {
this.current.charSpacing = spacing;
},
- setWordSpacing: function canvasGraphicsSetWordSpacing(spacing) {
+ setWordSpacing: function CanvasGraphics_setWordSpacing(spacing) {
this.current.wordSpacing = spacing;
},
- setHScale: function canvasGraphicsSetHScale(scale) {
+ setHScale: function CanvasGraphics_setHScale(scale) {
this.current.textHScale = scale / 100;
},
- setLeading: function canvasGraphicsSetLeading(leading) {
+ setLeading: function CanvasGraphics_setLeading(leading) {
this.current.leading = -leading;
},
- setFont: function canvasGraphicsSetFont(fontRefName, size) {
+ setFont: function CanvasGraphics_setFont(fontRefName, size) {
var fontObj = this.objs.get(fontRefName);
var current = this.current;
@@ -609,32 +609,32 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
var rule = italic + ' ' + bold + ' ' + browserFontSize + 'px ' + typeface;
this.ctx.font = rule;
},
- setTextRenderingMode: function canvasGraphicsSetTextRenderingMode(mode) {
+ setTextRenderingMode: function CanvasGraphics_setTextRenderingMode(mode) {
if (mode >= TextRenderingMode.FILL_ADD_TO_PATH)
TODO('unsupported text rendering mode: ' + mode);
this.current.textRenderingMode = mode;
},
- setTextRise: function canvasGraphicsSetTextRise(rise) {
+ setTextRise: function CanvasGraphics_setTextRise(rise) {
TODO('text rise: ' + rise);
},
- moveText: function canvasGraphicsMoveText(x, y) {
+ moveText: function CanvasGraphics_moveText(x, y) {
this.current.x = this.current.lineX += x;
this.current.y = this.current.lineY += y;
},
- setLeadingMoveText: function canvasGraphicsSetLeadingMoveText(x, y) {
+ setLeadingMoveText: function CanvasGraphics_setLeadingMoveText(x, y) {
this.setLeading(-y);
this.moveText(x, y);
},
- setTextMatrix: function canvasGraphicsSetTextMatrix(a, b, c, d, e, f) {
+ setTextMatrix: function CanvasGraphics_setTextMatrix(a, b, c, d, e, f) {
this.current.textMatrix = [a, b, c, d, e, f];
this.current.x = this.current.lineX = 0;
this.current.y = this.current.lineY = 0;
},
- nextLine: function canvasGraphicsNextLine() {
+ nextLine: function CanvasGraphics_nextLine() {
this.moveText(0, this.current.leading);
},
- applyTextTransforms: function canvasApplyTransforms() {
+ applyTextTransforms: function CanvasGraphics_applyTextTransforms() {
var ctx = this.ctx;
var current = this.current;
var textHScale = current.textHScale;
@@ -646,7 +646,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
ctx.transform.apply(ctx, fontMatrix);
ctx.scale(textHScale, 1);
},
- getTextGeometry: function canvasGetTextGeometry() {
+ getTextGeometry: function CanvasGraphics_getTextGeometry() {
var geometry = {};
var ctx = this.ctx;
var font = this.current.font;
@@ -663,7 +663,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
return geometry;
},
- showText: function canvasGraphicsShowText(str, skipTextSelection) {
+ showText: function CanvasGraphics_showText(str, skipTextSelection) {
var ctx = this.ctx;
var current = this.current;
var font = current.font;
@@ -752,28 +752,30 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
continue;
}
- var char = glyph.fontChar;
+ var character = glyph.fontChar;
var charWidth = glyph.width * fontSize * 0.001 +
Util.sign(current.fontMatrix[0]) * charSpacing;
- var scaledX = x / fontSizeScale;
- switch (textRenderingMode) {
- default: // other unsupported rendering modes
- case TextRenderingMode.FILL:
- case TextRenderingMode.FILL_ADD_TO_PATH:
- ctx.fillText(char, scaledX, 0);
- break;
- case TextRenderingMode.STROKE:
- case TextRenderingMode.STROKE_ADD_TO_PATH:
- ctx.strokeText(char, scaledX, 0);
- break;
- case TextRenderingMode.FILL_STROKE:
- case TextRenderingMode.FILL_STROKE_ADD_TO_PATH:
- ctx.fillText(char, scaledX, 0);
- ctx.strokeText(char, scaledX, 0);
- break;
- case TextRenderingMode.INVISIBLE:
- break;
+ if (!glyph.disabled) {
+ var scaledX = x / fontSizeScale;
+ switch (textRenderingMode) {
+ default: // other unsupported rendering modes
+ case TextRenderingMode.FILL:
+ case TextRenderingMode.FILL_ADD_TO_PATH:
+ ctx.fillText(character, scaledX, 0);
+ break;
+ case TextRenderingMode.STROKE:
+ case TextRenderingMode.STROKE_ADD_TO_PATH:
+ ctx.strokeText(character, scaledX, 0);
+ break;
+ case TextRenderingMode.FILL_STROKE:
+ case TextRenderingMode.FILL_STROKE_ADD_TO_PATH:
+ ctx.fillText(character, scaledX, 0);
+ ctx.strokeText(character, scaledX, 0);
+ break;
+ case TextRenderingMode.INVISIBLE:
+ break;
+ }
}
x += charWidth;
@@ -799,7 +801,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
return text;
},
- showSpacedText: function canvasGraphicsShowSpacedText(arr) {
+ showSpacedText: function CanvasGraphics_showSpacedText(arr) {
var ctx = this.ctx;
var current = this.current;
var font = current.font;
@@ -863,25 +865,25 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
if (textSelection)
this.textLayer.appendText(text, font.loadedName, fontSize);
},
- nextLineShowText: function canvasGraphicsNextLineShowText(text) {
+ nextLineShowText: function CanvasGraphics_nextLineShowText(text) {
this.nextLine();
this.showText(text);
},
nextLineSetSpacingShowText:
- function canvasGraphicsNextLineSetSpacingShowText(wordSpacing,
- charSpacing,
- text) {
+ function CanvasGraphics_nextLineSetSpacingShowText(wordSpacing,
+ charSpacing,
+ text) {
this.setWordSpacing(wordSpacing);
this.setCharSpacing(charSpacing);
this.nextLineShowText(text);
},
// Type3 fonts
- setCharWidth: function canvasGraphicsSetCharWidth(xWidth, yWidth) {
+ setCharWidth: function CanvasGraphics_setCharWidth(xWidth, yWidth) {
// We can safely ignore this since the width should be the same
// as the width in the Widths array.
},
- setCharWidthAndBounds: function canvasGraphicsSetCharWidthAndBounds(xWidth,
+ setCharWidthAndBounds: function CanvasGraphics_setCharWidthAndBounds(xWidth,
yWidth,
llx,
lly,
@@ -895,20 +897,20 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
},
// Color
- setStrokeColorSpace: function canvasGraphicsSetStrokeColorSpace(raw) {
+ setStrokeColorSpace: function CanvasGraphics_setStrokeColorSpace(raw) {
this.current.strokeColorSpace = ColorSpace.fromIR(raw);
},
- setFillColorSpace: function canvasGraphicsSetFillColorSpace(raw) {
+ setFillColorSpace: function CanvasGraphics_setFillColorSpace(raw) {
this.current.fillColorSpace = ColorSpace.fromIR(raw);
},
- setStrokeColor: function canvasGraphicsSetStrokeColor(/*...*/) {
+ setStrokeColor: function CanvasGraphics_setStrokeColor(/*...*/) {
var cs = this.current.strokeColorSpace;
var rgbColor = cs.getRgb(arguments);
var color = Util.makeCssRgb(rgbColor[0], rgbColor[1], rgbColor[2]);
this.ctx.strokeStyle = color;
this.current.strokeColor = color;
},
- getColorN_Pattern: function canvasGraphicsGetColorN_Pattern(IR, cs) {
+ getColorN_Pattern: function CanvasGraphics_getColorN_Pattern(IR, cs) {
if (IR[0] == 'TilingPattern') {
var args = IR[1];
var base = cs.base;
@@ -930,7 +932,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
}
return pattern;
},
- setStrokeColorN: function canvasGraphicsSetStrokeColorN(/*...*/) {
+ setStrokeColorN: function CanvasGraphics_setStrokeColorN(/*...*/) {
var cs = this.current.strokeColorSpace;
if (cs.name == 'Pattern') {
@@ -939,14 +941,14 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
this.setStrokeColor.apply(this, arguments);
}
},
- setFillColor: function canvasGraphicsSetFillColor(/*...*/) {
+ setFillColor: function CanvasGraphics_setFillColor(/*...*/) {
var cs = this.current.fillColorSpace;
var rgbColor = cs.getRgb(arguments);
var color = Util.makeCssRgb(rgbColor[0], rgbColor[1], rgbColor[2]);
this.ctx.fillStyle = color;
this.current.fillColor = color;
},
- setFillColorN: function canvasGraphicsSetFillColorN(/*...*/) {
+ setFillColorN: function CanvasGraphics_setFillColorN(/*...*/) {
var cs = this.current.fillColorSpace;
if (cs.name == 'Pattern') {
@@ -955,7 +957,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
this.setFillColor.apply(this, arguments);
}
},
- setStrokeGray: function canvasGraphicsSetStrokeGray(gray) {
+ setStrokeGray: function CanvasGraphics_setStrokeGray(gray) {
if (!(this.current.strokeColorSpace instanceof DeviceGrayCS))
this.current.strokeColorSpace = new DeviceGrayCS();
@@ -963,7 +965,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
this.ctx.strokeStyle = color;
this.current.strokeColor = color;
},
- setFillGray: function canvasGraphicsSetFillGray(gray) {
+ setFillGray: function CanvasGraphics_setFillGray(gray) {
if (!(this.current.fillColorSpace instanceof DeviceGrayCS))
this.current.fillColorSpace = new DeviceGrayCS();
@@ -971,7 +973,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
this.ctx.fillStyle = color;
this.current.fillColor = color;
},
- setStrokeRGBColor: function canvasGraphicsSetStrokeRGBColor(r, g, b) {
+ setStrokeRGBColor: function CanvasGraphics_setStrokeRGBColor(r, g, b) {
if (!(this.current.strokeColorSpace instanceof DeviceRgbCS))
this.current.strokeColorSpace = new DeviceRgbCS();
@@ -979,7 +981,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
this.ctx.strokeStyle = color;
this.current.strokeColor = color;
},
- setFillRGBColor: function canvasGraphicsSetFillRGBColor(r, g, b) {
+ setFillRGBColor: function CanvasGraphics_setFillRGBColor(r, g, b) {
if (!(this.current.fillColorSpace instanceof DeviceRgbCS))
this.current.fillColorSpace = new DeviceRgbCS();
@@ -987,7 +989,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
this.ctx.fillStyle = color;
this.current.fillColor = color;
},
- setStrokeCMYKColor: function canvasGraphicsSetStrokeCMYKColor(c, m, y, k) {
+ setStrokeCMYKColor: function CanvasGraphics_setStrokeCMYKColor(c, m, y, k) {
if (!(this.current.strokeColorSpace instanceof DeviceCmykCS))
this.current.strokeColorSpace = new DeviceCmykCS();
@@ -995,7 +997,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
this.ctx.strokeStyle = color;
this.current.strokeColor = color;
},
- setFillCMYKColor: function canvasGraphicsSetFillCMYKColor(c, m, y, k) {
+ setFillCMYKColor: function CanvasGraphics_setFillCMYKColor(c, m, y, k) {
if (!(this.current.fillColorSpace instanceof DeviceCmykCS))
this.current.fillColorSpace = new DeviceCmykCS();
@@ -1004,7 +1006,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
this.current.fillColor = color;
},
- shadingFill: function canvasGraphicsShadingFill(patternIR) {
+ shadingFill: function CanvasGraphics_shadingFill(patternIR) {
var ctx = this.ctx;
this.save();
@@ -1042,14 +1044,14 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
},
// Images
- beginInlineImage: function canvasGraphicsBeginInlineImage() {
+ beginInlineImage: function CanvasGraphics_beginInlineImage() {
error('Should not call beginInlineImage');
},
- beginImageData: function canvasGraphicsBeginImageData() {
+ beginImageData: function CanvasGraphics_beginImageData() {
error('Should not call beginImageData');
},
- paintFormXObjectBegin: function canvasGraphicsPaintFormXObjectBegin(matrix,
+ paintFormXObjectBegin: function CanvasGraphics_paintFormXObjectBegin(matrix,
bbox) {
this.save();
@@ -1065,11 +1067,11 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
}
},
- paintFormXObjectEnd: function canvasGraphicsPaintFormXObjectEnd() {
+ paintFormXObjectEnd: function CanvasGraphics_paintFormXObjectEnd() {
this.restore();
},
- paintJpegXObject: function canvasGraphicsPaintJpegXObject(objId, w, h) {
+ paintJpegXObject: function CanvasGraphics_paintJpegXObject(objId, w, h) {
var domImage = this.objs.get(objId);
if (!domImage) {
error('Dependent image isn\'t ready yet');
@@ -1087,7 +1089,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
this.restore();
},
- paintImageMaskXObject: function canvasGraphicsPaintImageMaskXObject(
+ paintImageMaskXObject: function CanvasGraphics_paintImageMaskXObject(
imgArray, inverseDecode, width, height) {
function applyStencilMask(buffer, inverseDecode) {
var imgArrayPos = 0;
@@ -1136,7 +1138,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
this.restore();
},
- paintImageXObject: function canvasGraphicsPaintImageXObject(objId) {
+ paintImageXObject: function CanvasGraphics_paintImageXObject(objId) {
var imgData = this.objs.get(objId);
if (!imgData)
error('Dependent image isn\'t ready yet');
@@ -1156,41 +1158,41 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
this.restore();
},
- putBinaryImageData: function canvasPutBinaryImageData() {
+ putBinaryImageData: function CanvasGraphics_putBinaryImageData() {
//
},
// Marked content
- markPoint: function canvasGraphicsMarkPoint(tag) {
+ markPoint: function CanvasGraphics_markPoint(tag) {
TODO('Marked content');
},
- markPointProps: function canvasGraphicsMarkPointProps(tag, properties) {
+ markPointProps: function CanvasGraphics_markPointProps(tag, properties) {
TODO('Marked content');
},
- beginMarkedContent: function canvasGraphicsBeginMarkedContent(tag) {
+ beginMarkedContent: function CanvasGraphics_beginMarkedContent(tag) {
TODO('Marked content');
},
- beginMarkedContentProps:
- function canvasGraphicsBeginMarkedContentProps(tag, properties) {
+ beginMarkedContentProps: function CanvasGraphics_beginMarkedContentProps(
+ tag, properties) {
TODO('Marked content');
},
- endMarkedContent: function canvasGraphicsEndMarkedContent() {
+ endMarkedContent: function CanvasGraphics_endMarkedContent() {
TODO('Marked content');
},
// Compatibility
- beginCompat: function canvasGraphicsBeginCompat() {
+ beginCompat: function CanvasGraphics_beginCompat() {
TODO('ignore undefined operators (should we do that anyway?)');
},
- endCompat: function canvasGraphicsEndCompat() {
+ endCompat: function CanvasGraphics_endCompat() {
TODO('stop ignoring undefined operators');
},
// Helper functions
- consumePath: function canvasGraphicsConsumePath() {
+ consumePath: function CanvasGraphics_consumePath() {
if (this.pendingClip) {
var savedFillRule = null;
if (this.pendingClip == EO_CLIP)
@@ -1207,15 +1209,15 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
// We generally keep the canvas context set for
// nonzero-winding, and just set evenodd for the operations
// that need them.
- setEOFillRule: function canvasGraphicsSetEOFillRule() {
+ setEOFillRule: function CanvasGraphics_setEOFillRule() {
var savedFillRule = this.ctx.mozFillRule;
this.ctx.mozFillRule = 'evenodd';
return savedFillRule;
},
- restoreFillRule: function canvasGraphicsRestoreFillRule(rule) {
+ restoreFillRule: function CanvasGraphics_restoreFillRule(rule) {
this.ctx.mozFillRule = rule;
},
- getSinglePixelWidth: function getSinglePixelWidth(scale) {
+ getSinglePixelWidth: function CanvasGraphics_getSinglePixelWidth(scale) {
var inverse = this.ctx.mozCurrentTransformInverse;
return Math.abs(inverse[0] + inverse[2]);
}
diff --git a/src/colorspace.js b/src/colorspace.js
index e1df7c725..8d8290109 100644
--- a/src/colorspace.js
+++ b/src/colorspace.js
@@ -12,17 +12,17 @@ var ColorSpace = (function ColorSpaceClosure() {
ColorSpace.prototype = {
// Input: array of size numComps representing color component values
// Output: array of rgb values, each value ranging from [0.1]
- getRgb: function colorSpaceGetRgb(color) {
+ getRgb: function ColorSpace_getRgb(color) {
error('Should not call ColorSpace.getRgb: ' + color);
},
// Input: Uint8Array of component values, each value scaled to [0,255]
// Output: Uint8Array of rgb values, each value scaled to [0,255]
- getRgbBuffer: function colorSpaceGetRgbBuffer(input) {
+ getRgbBuffer: function ColorSpace_getRgbBuffer(input) {
error('Should not call ColorSpace.getRgbBuffer: ' + input);
}
};
- ColorSpace.parse = function colorSpaceParse(cs, xref, res) {
+ ColorSpace.parse = function ColorSpace_parse(cs, xref, res) {
var IR = ColorSpace.parseToIR(cs, xref, res);
if (IR instanceof AlternateCS)
return IR;
@@ -30,7 +30,7 @@ var ColorSpace = (function ColorSpaceClosure() {
return ColorSpace.fromIR(IR);
};
- ColorSpace.fromIR = function colorSpaceFromIR(IR) {
+ ColorSpace.fromIR = function ColorSpace_fromIR(IR) {
var name = isArray(IR) ? IR[0] : IR;
switch (name) {
@@ -68,9 +68,9 @@ var ColorSpace = (function ColorSpaceClosure() {
return null;
};
- ColorSpace.parseToIR = function colorSpaceParseToIR(cs, xref, res) {
+ ColorSpace.parseToIR = function ColorSpace_parseToIR(cs, xref, res) {
if (isName(cs)) {
- var colorSpaces = xref.fetchIfRef(res.get('ColorSpace'));
+ var colorSpaces = res.get('ColorSpace');
if (isDict(colorSpaces)) {
var refcs = colorSpaces.get(cs.name);
if (refcs)
@@ -152,7 +152,7 @@ var ColorSpace = (function ColorSpaceClosure() {
var tintFnIR = PDFFunction.getIR(xref, xref.fetchIfRef(cs[3]));
return ['AlternateCS', numComps, alt, tintFnIR];
case 'Lab':
- var params = cs[1].map;
+ var params = cs[1].getAll();
return ['LabCS', params];
default:
error('unimplemented color space object "' + mode + '"');
@@ -171,7 +171,7 @@ var ColorSpace = (function ColorSpaceClosure() {
* @param {Array} decode Decode map (usually from an image).
* @param {Number} n Number of components the color space has.
*/
- ColorSpace.isDefaultDecode = function colorSpaceIsDefaultDecode(decode, n) {
+ ColorSpace.isDefaultDecode = function ColorSpace_isDefaultDecode(decode, n) {
if (!decode)
return true;
@@ -207,11 +207,11 @@ var AlternateCS = (function AlternateCSClosure() {
}
AlternateCS.prototype = {
- getRgb: function altcs_getRgb(color) {
+ getRgb: function AlternateCS_getRgb(color) {
var tinted = this.tintFn(color);
return this.base.getRgb(tinted);
},
- getRgbBuffer: function altcs_getRgbBuffer(input, bits) {
+ getRgbBuffer: function AlternateCS_getRgbBuffer(input, bits) {
var tintFn = this.tintFn;
var base = this.base;
var scale = 1 / ((1 << bits) - 1);
@@ -232,7 +232,7 @@ var AlternateCS = (function AlternateCSClosure() {
}
return base.getRgbBuffer(baseBuf, 8);
},
- isDefaultDecode: function altcs_isDefaultDecode(decodeMap) {
+ isDefaultDecode: function AlternateCS_isDefaultDecode(decodeMap) {
return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
}
};
@@ -275,7 +275,7 @@ var IndexedCS = (function IndexedCSClosure() {
}
IndexedCS.prototype = {
- getRgb: function indexcs_getRgb(color) {
+ getRgb: function IndexedCS_getRgb(color) {
var numComps = this.base.numComps;
var start = color[0] * numComps;
var c = [];
@@ -285,7 +285,7 @@ var IndexedCS = (function IndexedCSClosure() {
return this.base.getRgb(c);
},
- getRgbBuffer: function indexcs_getRgbBuffer(input) {
+ getRgbBuffer: function IndexedCS_getRgbBuffer(input) {
var base = this.base;
var numComps = base.numComps;
var lookup = this.lookup;
@@ -302,7 +302,7 @@ var IndexedCS = (function IndexedCSClosure() {
return base.getRgbBuffer(baseBuf, 8);
},
- isDefaultDecode: function indexcs_isDefaultDecode(decodeMap) {
+ isDefaultDecode: function IndexedCS_isDefaultDecode(decodeMap) {
// indexed color maps shouldn't be changed
return true;
}
@@ -318,11 +318,11 @@ var DeviceGrayCS = (function DeviceGrayCSClosure() {
}
DeviceGrayCS.prototype = {
- getRgb: function graycs_getRgb(color) {
+ getRgb: function DeviceGrayCS_getRgb(color) {
var c = color[0];
return [c, c, c];
},
- getRgbBuffer: function graycs_getRgbBuffer(input, bits) {
+ getRgbBuffer: function DeviceGrayCS_getRgbBuffer(input, bits) {
var scale = 255 / ((1 << bits) - 1);
var length = input.length;
var rgbBuf = new Uint8Array(length * 3);
@@ -334,7 +334,7 @@ var DeviceGrayCS = (function DeviceGrayCSClosure() {
}
return rgbBuf;
},
- isDefaultDecode: function graycs_isDefaultDecode(decodeMap) {
+ isDefaultDecode: function DeviceGrayCS_isDefaultDecode(decodeMap) {
return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
}
};
@@ -348,10 +348,10 @@ var DeviceRgbCS = (function DeviceRgbCSClosure() {
this.defaultColor = [0, 0, 0];
}
DeviceRgbCS.prototype = {
- getRgb: function rgbcs_getRgb(color) {
+ getRgb: function DeviceRgbCS_getRgb(color) {
return color;
},
- getRgbBuffer: function rgbcs_getRgbBuffer(input, bits) {
+ getRgbBuffer: function DeviceRgbCS_getRgbBuffer(input, bits) {
if (bits == 8)
return input;
var scale = 255 / ((1 << bits) - 1);
@@ -361,7 +361,7 @@ var DeviceRgbCS = (function DeviceRgbCSClosure() {
rgbBuf[i] = (scale * input[i]) | 0;
return rgbBuf;
},
- isDefaultDecode: function rgbcs_isDefaultDecode(decodeMap) {
+ isDefaultDecode: function DeviceRgbCS_isDefaultDecode(decodeMap) {
return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
}
};
@@ -375,7 +375,7 @@ var DeviceCmykCS = (function DeviceCmykCSClosure() {
this.defaultColor = [0, 0, 0, 1];
}
DeviceCmykCS.prototype = {
- getRgb: function cmykcs_getRgb(color) {
+ getRgb: function DeviceCmykCS_getRgb(color) {
var c = color[0], m = color[1], y = color[2], k = color[3];
// CMYK -> CMY: http://www.easyrgb.com/index.php?X=MATH&H=14#text14
@@ -390,7 +390,7 @@ var DeviceCmykCS = (function DeviceCmykCSClosure() {
return [r, g, b];
},
- getRgbBuffer: function cmykcs_getRgbBuffer(colorBuf, bits) {
+ getRgbBuffer: function DeviceCmykCS_getRgbBuffer(colorBuf, bits) {
var scale = 1 / ((1 << bits) - 1);
var length = colorBuf.length / 4;
var rgbBuf = new Uint8Array(length * 3);
@@ -409,7 +409,7 @@ var DeviceCmykCS = (function DeviceCmykCSClosure() {
return rgbBuf;
},
- isDefaultDecode: function cmykcs_isDefaultDecode(decodeMap) {
+ isDefaultDecode: function DeviceCmykCS_isDefaultDecode(decodeMap) {
return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
}
};
@@ -473,7 +473,7 @@ var LabCS = (function LabCSClosure() {
}
LabCS.prototype = {
- getRgb: function labcs_getRgb(color) {
+ getRgb: function LabCS_getRgb(color) {
// Ls,as,bs <---> L*,a*,b* in the spec
var Ls = color[0], as = color[1], bs = color[2];
@@ -499,7 +499,7 @@ var LabCS = (function LabCSClosure() {
return Util.apply3dTransform(XYZtoRGB, [X, Y, Z]);
},
- getRgbBuffer: function labcs_getRgbBuffer(input, bits) {
+ getRgbBuffer: function LabCS_getRgbBuffer(input, bits) {
if (bits == 8)
return input;
var scale = 255 / ((1 << bits) - 1);
@@ -517,7 +517,7 @@ var LabCS = (function LabCSClosure() {
return rgbBuf;
},
- isDefaultDecode: function labcs_isDefaultDecode(decodeMap) {
+ isDefaultDecode: function LabCS_isDefaultDecode(decodeMap) {
// From Table 90 in Adobe's:
// "Document management - Portable document format", 1st ed, 2008
if (decodeMap[0] === 0 && decodeMap[1] === 100 &&
diff --git a/src/core.js b/src/core.js
index 9c671960e..10ae7d085 100644
--- a/src/core.js
+++ b/src/core.js
@@ -72,14 +72,14 @@ var Page = (function PageClosure() {
}
Page.prototype = {
- getPageProp: function pageGetPageProp(key) {
- return this.xref.fetchIfRef(this.pageDict.get(key));
+ getPageProp: function Page_getPageProp(key) {
+ return this.pageDict.get(key);
},
- inheritPageProp: function pageInheritPageProp(key) {
+ inheritPageProp: function Page_inheritPageProp(key) {
var dict = this.pageDict;
var obj = dict.get(key);
while (obj === undefined) {
- dict = this.xref.fetchIfRef(dict.get('Parent'));
+ dict = dict.get('Parent');
if (!dict)
break;
obj = dict.get(key);
@@ -170,8 +170,8 @@ var Page = (function PageClosure() {
return shadow(this, 'rotate', rotate);
},
- startRenderingFromOperatorList: function pageStartRenderingFromOperatorList(
- operatorList, fonts) {
+ startRenderingFromOperatorList:
+ function Page_startRenderingFromOperatorList(operatorList, fonts) {
var self = this;
this.operatorList = operatorList;
@@ -190,7 +190,7 @@ var Page = (function PageClosure() {
);
},
- getOperatorList: function pageGetOperatorList(handler, dependency) {
+ getOperatorList: function Page_getOperatorList(handler, dependency) {
if (this.operatorList) {
// content was compiled
return this.operatorList;
@@ -199,8 +199,8 @@ var Page = (function PageClosure() {
this.stats.time('Build IR Queue');
var xref = this.xref;
- var content = xref.fetchIfRef(this.content);
- var resources = xref.fetchIfRef(this.resources);
+ var content = this.content;
+ var resources = this.resources;
if (isArray(content)) {
// fetching items
var i, n = content.length;
@@ -220,7 +220,7 @@ var Page = (function PageClosure() {
return this.operatorList;
},
- ensureFonts: function pageEnsureFonts(fonts, callback) {
+ ensureFonts: function Page_ensureFonts(fonts, callback) {
this.stats.time('Font Loading');
// Convert the font names to the corresponding font obj.
for (var i = 0, ii = fonts.length; i < ii; i++) {
@@ -238,12 +238,12 @@ var Page = (function PageClosure() {
);
},
- display: function pageDisplay(gfx, callback) {
+ display: function Page_display(gfx, callback) {
var stats = this.stats;
stats.time('Rendering');
var xref = this.xref;
- var resources = xref.fetchIfRef(this.resources);
- var mediaBox = xref.fetchIfRef(this.mediaBox);
+ var resources = this.resources;
+ var mediaBox = this.mediaBox;
assertWellFormed(isDict(resources), 'invalid page resources');
gfx.xref = xref;
@@ -276,7 +276,7 @@ var Page = (function PageClosure() {
}
next();
},
- rotatePoint: function pageRotatePoint(x, y, reverse) {
+ rotatePoint: function Page_rotatePoint(x, y, reverse) {
var rotate = reverse ? (360 - this.rotate) : this.rotate;
switch (rotate) {
case 180:
@@ -291,7 +291,7 @@ var Page = (function PageClosure() {
return {x: x, y: this.height - y};
}
},
- getLinks: function pageGetLinks() {
+ getLinks: function Page_getLinks() {
var links = [];
var annotations = pageGetAnnotations();
var i, n = annotations.length;
@@ -302,12 +302,12 @@ var Page = (function PageClosure() {
}
return links;
},
- getAnnotations: function pageGetAnnotations() {
+ getAnnotations: function Page_getAnnotations() {
var xref = this.xref;
function getInheritableProperty(annotation, name) {
var item = annotation;
while (item && !item.has(name)) {
- item = xref.fetchIfRef(item.get('Parent'));
+ item = item.get('Parent');
}
if (!item)
return null;
@@ -330,7 +330,7 @@ var Page = (function PageClosure() {
}
}
- var annotations = xref.fetchIfRef(this.annotations) || [];
+ var annotations = this.annotations || [];
var i, n = annotations.length;
var items = [];
for (i = 0; i < n; ++i) {
@@ -353,7 +353,7 @@ var Page = (function PageClosure() {
item.height = Math.abs(topLeftCorner.y - bottomRightCorner.y);
switch (subtype.name) {
case 'Link':
- var a = this.xref.fetchIfRef(annotation.get('A'));
+ var a = annotation.get('A');
if (a) {
switch (a.get('S').name) {
case 'URI':
@@ -386,21 +386,22 @@ var Page = (function PageClosure() {
var fieldName = [];
var namedItem = annotation, ref = annotationRef;
while (namedItem) {
- var parentRef = namedItem.get('Parent');
- var parent = xref.fetchIfRef(parentRef);
+ var parent = namedItem.get('Parent');
+ var parentRef = namedItem.getRaw('Parent');
var name = namedItem.get('T');
- if (name)
+ if (name) {
fieldName.unshift(stringToPDFString(name));
- else {
+ } else {
// The field name is absent, that means more than one field
// with the same name may exist. Replacing the empty name
// with the '`' plus index in the parent's 'Kids' array.
// This is not in the PDF spec but necessary to id the
// the input controls.
- var kids = xref.fetchIfRef(parent.get('Kids'));
+ var kids = parent.get('Kids');
var j, jj;
for (j = 0, jj = kids.length; j < jj; j++) {
- if (kids[j].num == ref.num && kids[j].gen == ref.gen)
+ var kidRef = kids[j];
+ if (kidRef.num == ref.num && kidRef.gen == ref.gen)
break;
}
fieldName.unshift('`' + j);
@@ -433,7 +434,7 @@ var Page = (function PageClosure() {
}
return items;
},
- startRendering: function pageStartRendering(ctx, callback, textLayer) {
+ startRendering: function Page_startRendering(ctx, callback, textLayer) {
var stats = this.stats;
stats.time('Overall');
// If there is no displayReadyPromise yet, then the operatorList was never
@@ -490,7 +491,7 @@ var PDFDocModel = (function PDFDocModelClosure() {
assertWellFormed(stream.length > 0, 'stream must have data');
this.stream = stream;
this.setup();
- this.acroForm = this.xref.fetchIfRef(this.catalog.catDict.get('AcroForm'));
+ this.acroForm = this.catalog.catDict.get('AcroForm');
}
function find(stream, needle, limit, backwards) {
@@ -570,7 +571,7 @@ var PDFDocModel = (function PDFDocModelClosure() {
},
// Find the header, remove leading garbage and setup the stream
// starting from the header.
- checkHeader: function pdfDocCheckHeader() {
+ checkHeader: function PDFDocModel_checkHeader() {
var stream = this.stream;
stream.reset();
if (find(stream, '%PDF-', 1024)) {
@@ -580,21 +581,13 @@ var PDFDocModel = (function PDFDocModelClosure() {
}
// May not be a PDF file, continue anyway.
},
- setup: function pdfDocSetup(ownerPassword, userPassword) {
+ setup: function PDFDocModel_setup(ownerPassword, userPassword) {
this.checkHeader();
var xref = new XRef(this.stream,
this.startXRef,
this.mainXRefEntriesOffset);
this.xref = xref;
this.catalog = new Catalog(xref);
- if (xref.trailer && xref.trailer.has('ID')) {
- var fileID = '';
- var id = xref.fetchIfRef(xref.trailer.get('ID'))[0];
- id.split('').forEach(function(el) {
- fileID += Number(el.charCodeAt(0)).toString(16);
- });
- this.fileID = fileID;
- }
},
get numPages() {
var linearization = this.linearization;
@@ -602,23 +595,35 @@ var PDFDocModel = (function PDFDocModelClosure() {
// shadow the prototype getter
return shadow(this, 'numPages', num);
},
- getFingerprint: function pdfDocGetFingerprint() {
- if (this.fileID) {
- return this.fileID;
+ getDocumentInfo: function PDFDocModel_getDocumentInfo() {
+ var info;
+ if (this.xref.trailer.has('Info'))
+ info = this.xref.trailer.get('Info');
+
+ return shadow(this, 'getDocumentInfo', info);
+ },
+ getFingerprint: function PDFDocModel_getFingerprint() {
+ var xref = this.xref, fileID;
+ if (xref.trailer.has('ID')) {
+ fileID = '';
+ var id = xref.trailer.get('ID')[0];
+ id.split('').forEach(function(el) {
+ fileID += Number(el.charCodeAt(0)).toString(16);
+ });
} else {
// If we got no fileID, then we generate one,
// from the first 100 bytes of PDF
var data = this.stream.bytes.subarray(0, 100);
var hash = calculateMD5(data, 0, data.length);
- var strHash = '';
+ fileID = '';
for (var i = 0, length = hash.length; i < length; i++) {
- strHash += Number(hash[i]).toString(16);
+ fileID += Number(hash[i]).toString(16);
}
-
- return strHash;
}
+
+ return shadow(this, 'getFingerprint', fileID);
},
- getPage: function pdfDocGetPage(n) {
+ getPage: function PDFDocModel_getPage(n) {
return this.catalog.getPage(n);
}
};
@@ -645,6 +650,7 @@ var PDFDoc = (function PDFDocClosure() {
this.stream = stream;
this.pdfModel = new PDFDocModel(stream);
this.fingerprint = this.pdfModel.getFingerprint();
+ this.info = this.pdfModel.getDocumentInfo();
this.catalog = this.pdfModel.catalog;
this.objs = new PDFObjects();
@@ -706,13 +712,13 @@ var PDFDoc = (function PDFDocClosure() {
}
PDFDoc.prototype = {
- setupFakeWorker: function() {
+ setupFakeWorker: function PDFDoc_setupFakeWorker() {
// If we don't use a worker, just post/sendMessage to the main thread.
var fakeWorker = {
- postMessage: function pdfDocPostMessage(obj) {
+ postMessage: function PDFDoc_postMessage(obj) {
fakeWorker.onmessage({data: obj});
},
- terminate: function pdfDocTerminate() {}
+ terminate: function PDFDoc_terminate() {}
};
var messageHandler = new MessageHandler('main', fakeWorker);
@@ -724,7 +730,7 @@ var PDFDoc = (function PDFDocClosure() {
},
- setupMessageHandler: function(messageHandler) {
+ setupMessageHandler: function PDFDoc_setupMessageHandler(messageHandler) {
this.messageHandler = messageHandler;
messageHandler.on('page', function pdfDocPage(data) {
@@ -823,7 +829,7 @@ var PDFDoc = (function PDFDocClosure() {
return this.pdfModel.numPages;
},
- startRendering: function pdfDocStartRendering(page) {
+ startRendering: function PDFDoc_startRendering(page) {
// The worker might not be ready to receive the page request yet.
this.workerReadyPromise.then(function pdfDocStartRenderingThen() {
page.stats.time('Page Request');
@@ -831,7 +837,7 @@ var PDFDoc = (function PDFDocClosure() {
}.bind(this));
},
- getPage: function pdfDocGetPage(n) {
+ getPage: function PDFDoc_getPage(n) {
if (this.pageCache[n])
return this.pageCache[n];
@@ -843,7 +849,7 @@ var PDFDoc = (function PDFDocClosure() {
return (this.pageCache[n] = page);
},
- destroy: function pdfDocDestroy() {
+ destroy: function PDFDoc_destroy() {
if (this.worker)
this.worker.terminate();
diff --git a/src/crypto.js b/src/crypto.js
index b1a298223..038c0e332 100644
--- a/src/crypto.js
+++ b/src/crypto.js
@@ -21,7 +21,7 @@ var ARCFourCipher = (function ARCFourCipherClosure() {
}
ARCFourCipher.prototype = {
- encryptBlock: function arcFourCipherEncryptBlock(data) {
+ encryptBlock: function ARCFourCipher_encryptBlock(data) {
var i, n = data.length, tmp, tmp2;
var a = this.a, b = this.b, s = this.s;
var output = new Uint8Array(n);
@@ -133,7 +133,7 @@ var NullCipher = (function NullCipherClosure() {
}
NullCipher.prototype = {
- decryptBlock: function nullCipherDecryptBlock(data) {
+ decryptBlock: function NullCipher_decryptBlock(data) {
return data;
}
};
@@ -371,7 +371,7 @@ var AES128Cipher = (function AES128CipherClosure() {
}
AES128Cipher.prototype = {
- decryptBlock: function aes128CipherDecryptBlock(data) {
+ decryptBlock: function AES128Cipher_decryptBlock(data) {
var i, sourceLength = data.length;
var buffer = this.buffer, bufferLength = this.bufferPosition;
// waiting for IV values -- they are at the start of the stream
@@ -400,7 +400,7 @@ var CipherTransform = (function CipherTransformClosure() {
this.streamCipherConstructor = streamCipherConstructor;
}
CipherTransform.prototype = {
- createStream: function cipherTransformCreateStream(stream) {
+ createStream: function CipherTransform_createStream(stream) {
var cipher = new this.streamCipherConstructor();
return new DecryptStream(stream,
function cipherTransformDecryptStream(data) {
@@ -408,7 +408,7 @@ var CipherTransform = (function CipherTransformClosure() {
}
);
},
- decryptString: function cipherTransformDecryptString(s) {
+ decryptString: function CipherTransform_decryptString(s) {
var cipher = new this.stringCipherConstructor();
var data = stringToBytes(s);
data = cipher.decryptBlock(data);
@@ -573,8 +573,8 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
}
CipherTransformFactory.prototype = {
- createCipherTransform: function buildCipherCreateCipherTransform(num,
- gen) {
+ createCipherTransform:
+ function CipherTransformFactory_createCipherTransform(num, gen) {
if (this.algorithm == 4) {
return new CipherTransform(
buildCipherConstructor(this.cf, this.stmf,
diff --git a/src/evaluator.js b/src/evaluator.js
index 68ca9f640..7f8ffc5d3 100644
--- a/src/evaluator.js
+++ b/src/evaluator.js
@@ -112,8 +112,10 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
};
PartialEvaluator.prototype = {
- getOperatorList: function partialEvaluatorGetOperatorList(stream, resources,
- dependency, queue) {
+ getOperatorList: function PartialEvaluator_getOperatorList(stream,
+ resources,
+ dependency,
+ queue) {
var self = this;
var xref = this.xref;
@@ -131,16 +133,14 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
}
}
- function handleSetFont(fontName, fontRef) {
+ function handleSetFont(fontName, font) {
var loadedName = null;
var fontRes = resources.get('Font');
assert(fontRes, 'fontRes not available');
- fontRes = xref.fetchIfRef(fontRes);
- fontRef = fontRef || fontRes.get(fontName);
- var font = xref.fetchIfRef(fontRef);
+ font = xref.fetchIfRef(font) || fontRes.get(fontName);
assertWellFormed(isDict(font));
if (!font.translated) {
font.translated = self.translateFont(font, xref, resources,
@@ -250,10 +250,10 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
var fnArray = queue.fnArray, argsArray = queue.argsArray;
var dependencyArray = dependency || [];
- resources = xref.fetchIfRef(resources) || new Dict();
- var xobjs = xref.fetchIfRef(resources.get('XObject')) || new Dict();
- var patterns = xref.fetchIfRef(resources.get('Pattern')) || new Dict();
- var parser = new Parser(new Lexer(stream), false);
+ resources = resources || new Dict();
+ var xobjs = resources.get('XObject') || new Dict();
+ var patterns = resources.get('Pattern') || new Dict();
+ var parser = new Parser(new Lexer(stream), false, xref);
var res = resources;
var args = [], obj;
var getObjBt = function getObjBt() {
@@ -285,7 +285,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
var patternName = args[args.length - 1];
// SCN/scn applies patterns along with normal colors
if (isName(patternName)) {
- var pattern = xref.fetchIfRef(patterns.get(patternName.name));
+ var pattern = patterns.get(patternName.name);
if (pattern) {
var dict = isStream(pattern) ? pattern.dict : pattern;
var typeNum = dict.get('PatternType');
@@ -303,7 +303,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
args = TilingPattern.getIR(operatorList, dict, args);
}
else if (typeNum == SHADING_PATTERN) {
- var shading = xref.fetchIfRef(dict.get('Shading'));
+ var shading = dict.get('Shading');
var matrix = dict.get('Matrix');
var pattern = Pattern.parseShading(shading, matrix, xref,
res);
@@ -318,7 +318,6 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
var name = args[0].name;
var xobj = xobjs.get(name);
if (xobj) {
- xobj = xref.fetchIfRef(xobj);
assertWellFormed(isStream(xobj), 'XObject should be a stream');
var type = xobj.dict.get('Subtype');
@@ -369,11 +368,11 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
args = [ColorSpace.parseToIR(args[0], xref, resources)];
break;
case 'shadingFill':
- var shadingRes = xref.fetchIfRef(res.get('Shading'));
+ var shadingRes = res.get('Shading');
if (!shadingRes)
error('No shading resource found');
- var shading = xref.fetchIfRef(shadingRes.get(args[0].name));
+ var shading = shadingRes.get(args[0].name);
if (!shading)
error('No shading object found');
@@ -384,12 +383,12 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
break;
case 'setGState':
var dictName = args[0];
- var extGState = xref.fetchIfRef(resources.get('ExtGState'));
+ var extGState = resources.get('ExtGState');
if (!isDict(extGState) || !extGState.has(dictName.name))
break;
- var gsState = xref.fetchIfRef(extGState.get(dictName.name));
+ var gsState = extGState.get(dictName.name);
// This array holds the converted/processed state data.
var gsStateObj = [];
@@ -468,7 +467,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
if (properties.composite) {
// CIDSystemInfo helps to match CID to glyphs
- var cidSystemInfo = xref.fetchIfRef(dict.get('CIDSystemInfo'));
+ var cidSystemInfo = dict.get('CIDSystemInfo');
if (isDict(cidSystemInfo)) {
properties.cidSystemInfo = {
registry: cidSystemInfo.get('Registry'),
@@ -477,7 +476,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
};
}
- var cidToGidMap = xref.fetchIfRef(dict.get('CIDToGIDMap'));
+ var cidToGidMap = dict.get('CIDToGIDMap');
if (isStream(cidToGidMap))
properties.cidToGidMap = this.readCidToGidMap(cidToGidMap);
}
@@ -488,7 +487,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
Encodings.symbolsEncoding : Encodings.StandardEncoding;
var hasEncoding = dict.has('Encoding');
if (hasEncoding) {
- var encoding = xref.fetchIfRef(dict.get('Encoding'));
+ var encoding = dict.get('Encoding');
if (isDict(encoding)) {
var baseName = encoding.get('BaseEncoding');
if (baseName)
@@ -520,9 +519,8 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
properties.hasEncoding = hasEncoding;
},
- readToUnicode:
- function partialEvaluatorReadToUnicode(toUnicode, xref) {
- var cmapObj = xref.fetchIfRef(toUnicode);
+ readToUnicode: function PartialEvaluator_readToUnicode(toUnicode, xref) {
+ var cmapObj = toUnicode;
var charToUnicode = [];
if (isName(cmapObj)) {
var isIdentityMap = cmapObj.name.substr(0, 9) == 'Identity-';
@@ -535,9 +533,9 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
var cmap = cmapObj.getBytes(cmapObj.length);
for (var i = 0, ii = cmap.length; i < ii; i++) {
- var byte = cmap[i];
- if (byte == 0x20 || byte == 0x0D || byte == 0x0A ||
- byte == 0x3C || byte == 0x5B || byte == 0x5D) {
+ var octet = cmap[i];
+ if (octet == 0x20 || octet == 0x0D || octet == 0x0A ||
+ octet == 0x3C || octet == 0x5B || octet == 0x5D) {
switch (token) {
case 'usecmap':
error('usecmap is not implemented');
@@ -594,7 +592,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
tokens.push(token);
token = '';
}
- switch (byte) {
+ switch (octet) {
case 0x5B:
// begin list parsing
tokens.push(beginArrayToken);
@@ -608,7 +606,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
tokens.push(items);
break;
}
- } else if (byte == 0x3E) {
+ } else if (octet == 0x3E) {
if (token.length) {
if (token.length <= 4) {
// parsing hex number
@@ -634,14 +632,13 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
}
}
} else {
- token += String.fromCharCode(byte);
+ token += String.fromCharCode(octet);
}
}
}
return charToUnicode;
},
- readCidToGidMap:
- function partialEvaluatorReadCidToGidMap(cidToGidStream) {
+ readCidToGidMap: function PartialEvaluator_readCidToGidMap(cidToGidStream) {
// Extract the encoding from the CIDToGIDMap
var glyphsData = cidToGidStream.getBytes();
@@ -658,16 +655,16 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
return result;
},
- extractWidths: function partialEvaluatorWidths(dict,
+ extractWidths: function PartialEvaluator_extractWidths(dict,
xref,
descriptor,
properties) {
var glyphsWidths = [];
var defaultWidth = 0;
if (properties.composite) {
- defaultWidth = xref.fetchIfRef(dict.get('DW')) || 1000;
+ defaultWidth = dict.get('DW') || 1000;
- var widths = xref.fetchIfRef(dict.get('W'));
+ var widths = dict.get('W');
if (widths) {
var start = 0, end = 0;
for (var i = 0, ii = widths.length; i < ii; i++) {
@@ -688,7 +685,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
}
} else {
var firstChar = properties.firstChar;
- var widths = xref.fetchIfRef(dict.get('Widths'));
+ var widths = dict.get('Widths');
if (widths) {
var j = firstChar;
for (var i = 0, ii = widths.length; i < ii; i++)
@@ -710,7 +707,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
properties.widths = glyphsWidths;
},
- getBaseFontMetrics: function getBaseFontMetrics(name) {
+ getBaseFontMetrics: function PartialEvaluator_getBaseFontMetrics(name) {
var defaultWidth = 0, widths = [];
var glyphWidths = Metrics[stdFontMap[name] || name];
if (isNum(glyphWidths)) {
@@ -725,8 +722,10 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
};
},
- translateFont: function partialEvaluatorTranslateFont(dict, xref, resources,
- dependency) {
+ translateFont: function PartialEvaluator_translateFont(dict,
+ xref,
+ resources,
+ dependency) {
var baseDict = dict;
var type = dict.get('Subtype');
assertWellFormed(isName(type), 'invalid font Subtype');
@@ -741,10 +740,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
if (!df)
return null;
- if (isRef(df))
- df = xref.fetch(df);
-
- dict = xref.fetchIfRef(isRef(df) ? df : df[0]);
+ dict = isArray(df) ? xref.fetchIfRef(df[0]) : df;
type = dict.get('Subtype');
assertWellFormed(isName(type), 'invalid font Subtype');
@@ -752,7 +748,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
}
var maxCharIndex = composite ? 0xFFFF : 0xFF;
- var descriptor = xref.fetchIfRef(dict.get('FontDescriptor'));
+ var descriptor = dict.get('FontDescriptor');
if (!descriptor) {
if (type.name == 'Type3') {
// FontDescriptor is only required for Type3 fonts when the document
@@ -801,9 +797,9 @@ 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 = xref.fetchIfRef(dict.get('FirstChar')) || 0;
- var lastChar = xref.fetchIfRef(dict.get('LastChar')) || maxCharIndex;
- var fontName = xref.fetchIfRef(descriptor.get('FontName'));
+ var firstChar = dict.get('FirstChar') || 0;
+ var lastChar = dict.get('LastChar') || maxCharIndex;
+ var fontName = descriptor.get('FontName');
// Some bad pdf's have a string as the font name.
if (isString(fontName))
fontName = new Name(fontName);
@@ -811,19 +807,14 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
var fontFile = descriptor.get('FontFile', 'FontFile2', 'FontFile3');
if (fontFile) {
- fontFile = xref.fetchIfRef(fontFile);
if (fontFile.dict) {
var subtype = fontFile.dict.get('Subtype');
if (subtype)
subtype = subtype.name;
var length1 = fontFile.dict.get('Length1');
- if (!isInt(length1))
- length1 = xref.fetchIfRef(length1);
var length2 = fontFile.dict.get('Length2');
- if (!isInt(length2))
- length2 = xref.fetchIfRef(length2);
}
}
@@ -852,12 +843,12 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
if (type.name === 'Type3') {
properties.coded = true;
- var charProcs = xref.fetchIfRef(dict.get('CharProcs'));
- var fontResources = xref.fetchIfRef(dict.get('Resources')) || resources;
+ var charProcs = dict.get('CharProcs').getAll();
+ var fontResources = dict.get('Resources') || resources;
properties.resources = fontResources;
properties.charProcOperatorList = {};
- for (var key in charProcs.map) {
- var glyphStream = xref.fetchIfRef(charProcs.map[key]);
+ for (var key in charProcs) {
+ var glyphStream = charProcs[key];
properties.charProcOperatorList[key] =
this.getOperatorList(glyphStream, fontResources, dependency);
}
diff --git a/src/fonts.js b/src/fonts.js
index b756ff2ee..a5664cb71 100644
--- a/src/fonts.js
+++ b/src/fonts.js
@@ -1267,7 +1267,7 @@ var Font = (function FontClosure() {
mimetype: null,
encoding: null,
- checkAndRepair: function font_checkAndRepair(name, font, properties) {
+ checkAndRepair: function Font_checkAndRepair(name, font, properties) {
function readTableEntry(file) {
var tag = file.getBytes(4);
tag = String.fromCharCode(tag[0]) +
@@ -1828,8 +1828,9 @@ var Font = (function FontClosure() {
readGlyphNameMap(post, properties);
}
- // Replace the old CMAP table with a shiny new one
+ var glyphs, ids;
if (properties.type == 'CIDFontType2') {
+ // Replace the old CMAP table with a shiny new one
// Type2 composite fonts map characters directly to glyphs so the cmap
// table must be replaced.
// canvas fillText will reencode some characters even if the font has a
@@ -1861,7 +1862,9 @@ var Font = (function FontClosure() {
}
}
- var glyphs = [], ids = [];
+ glyphs = [];
+ ids = [];
+
var usedUnicodes = [];
var unassignedUnicodeItems = [];
for (var i = 1; i < numGlyphs; i++) {
@@ -1892,11 +1895,12 @@ var Font = (function FontClosure() {
glyphs.push({ unicode: unicode, code: cid });
ids.push(i);
}
- cmap.data = createCMapTable(glyphs, ids);
} else {
var cmapTable = readCMapTable(cmap, font);
- var glyphs = cmapTable.glyphs;
- var ids = cmapTable.ids;
+
+ glyphs = cmapTable.glyphs;
+ ids = cmapTable.ids;
+
var hasShortCmap = !!cmapTable.hasShortCmap;
var toFontChar = this.toFontChar;
@@ -2062,9 +2066,15 @@ var Font = (function FontClosure() {
createGlyphNameMap(glyphs, ids, properties);
this.glyphNameMap = properties.glyphNameMap;
+ }
- cmap.data = createCMapTable(glyphs, ids);
+ // Converting glyphs and ids into font's cmap table
+ cmap.data = createCMapTable(glyphs, ids);
+ var unicodeIsEnabled = [];
+ for (var i = 0, ii = glyphs.length; i < ii; i++) {
+ unicodeIsEnabled[glyphs[i].unicode] = true;
}
+ this.unicodeIsEnabled = unicodeIsEnabled;
// Rewrite the 'post' table if needed
if (requiredTables.indexOf('post') != -1) {
@@ -2112,7 +2122,7 @@ var Font = (function FontClosure() {
return stringToArray(ttf.file);
},
- convert: function font_convert(fontName, font, properties) {
+ convert: function Font_convert(fontName, font, properties) {
function isFixedPitch(glyphs) {
for (var i = 0, ii = glyphs.length - 1; i < ii; i++) {
if (glyphs[i] != glyphs[i + 1])
@@ -2254,7 +2264,7 @@ var Font = (function FontClosure() {
return stringToArray(otf.file);
},
- buildToFontChar: function font_buildToFontChar(toUnicode) {
+ buildToFontChar: function Font_buildToFontChar(toUnicode) {
var result = [];
var unusedUnicode = kCmapGlyphOffset;
for (var i = 0, ii = toUnicode.length; i < ii; i++) {
@@ -2267,7 +2277,7 @@ var Font = (function FontClosure() {
return result;
},
- rebuildToUnicode: function font_rebuildToUnicode(properties) {
+ rebuildToUnicode: function Font_rebuildToUnicode(properties) {
var firstChar = properties.firstChar, lastChar = properties.lastChar;
var map = [];
if (properties.composite) {
@@ -2289,7 +2299,7 @@ var Font = (function FontClosure() {
this.toUnicode = map;
},
- loadCidToUnicode: function font_loadCidToUnicode(properties) {
+ loadCidToUnicode: function Font_loadCidToUnicode(properties) {
if (!properties.cidSystemInfo)
return;
@@ -2338,7 +2348,7 @@ var Font = (function FontClosure() {
}
},
- bindDOM: function font_bindDom(data) {
+ bindDOM: function Font_bindDOM(data) {
var fontName = this.loadedName;
// Add the font-face rule to the document
@@ -2390,8 +2400,8 @@ var Font = (function FontClosure() {
return shadow(this, 'spaceWidth', width);
},
- charToGlyph: function fonts_charToGlyph(charcode) {
- var fontCharCode, width, operatorList;
+ charToGlyph: function Font_charToGlyph(charcode) {
+ var fontCharCode, width, operatorList, disabled;
var width = this.widths[charcode];
@@ -2464,16 +2474,19 @@ var Font = (function FontClosure() {
unicodeChars = String.fromCharCode(unicodeChars);
width = (isNum(width) ? width : this.defaultWidth) * this.widthMultiplier;
+ disabled = this.unicodeIsEnabled ?
+ !this.unicodeIsEnabled[fontCharCode] : false;
return {
fontChar: String.fromCharCode(fontCharCode),
unicode: unicodeChars,
width: width,
+ disabled: disabled,
operatorList: operatorList
};
},
- charsToGlyphs: function fonts_charsToGlyphs(chars) {
+ charsToGlyphs: function Font_charsToGlyphs(chars) {
var charsCache = this.charsCache;
var glyphs;
@@ -2837,7 +2850,7 @@ var Type1Parser = function type1Parser() {
return c == ' ' || c == '\n' || c == '\x0d';
}
- this.extractFontProgram = function t1_extractFontProgram(stream) {
+ this.extractFontProgram = function Type1Parser_extractFontProgram(stream) {
var eexec = decrypt(stream, kEexecEncryptionKey, 4);
var eexecStr = '';
for (var i = 0, ii = eexec.length; i < ii; i++)
@@ -2848,7 +2861,7 @@ var Type1Parser = function type1Parser() {
subrs: [],
charstrings: [],
properties: {
- 'private': {
+ 'privateData': {
'lenIV': 4
}
}
@@ -2877,7 +2890,7 @@ var Type1Parser = function type1Parser() {
(token == 'RD' || token == '-|')) {
i++;
var data = eexec.slice(i, i + length);
- var lenIV = program.properties.private['lenIV'];
+ var lenIV = program.properties.privateData['lenIV'];
var encoded = decrypt(data, kCharStringsEncryptionKey, lenIV);
var str = decodeCharString(encoded);
@@ -2917,7 +2930,7 @@ var Type1Parser = function type1Parser() {
var length = parseInt(getToken(), 10);
getToken(); // read in 'RD'
var data = eexec.slice(i + 1, i + 1 + length);
- var lenIV = program.properties.private['lenIV'];
+ var lenIV = program.properties.privateData['lenIV'];
var encoded = decrypt(data, kCharStringsEncryptionKey, lenIV);
var str = decodeCharString(encoded);
i = i + 1 + length;
@@ -2933,12 +2946,12 @@ var Type1Parser = function type1Parser() {
case '/FamilyOtherBlues':
case '/StemSnapH':
case '/StemSnapV':
- program.properties.private[token.substring(1)] =
+ program.properties.privateData[token.substring(1)] =
readNumberArray(eexecStr, i + 1);
break;
case '/StdHW':
case '/StdVW':
- program.properties.private[token.substring(1)] =
+ program.properties.privateData[token.substring(1)] =
readNumberArray(eexecStr, i + 2)[0];
break;
case '/BlueShift':
@@ -2947,7 +2960,7 @@ var Type1Parser = function type1Parser() {
case '/BlueScale':
case '/LanguageGroup':
case '/ExpansionFactor':
- program.properties.private[token.substring(1)] =
+ program.properties.privateData[token.substring(1)] =
readNumber(eexecStr, i + 1);
break;
}
@@ -2962,7 +2975,8 @@ var Type1Parser = function type1Parser() {
return program;
};
- this.extractFontHeader = function t1_extractFontHeader(stream, properties) {
+ this.extractFontHeader = function Type1Parser_extractFontHeader(stream,
+ properties) {
var headerString = '';
for (var i = 0, ii = stream.length; i < ii; i++)
headerString += String.fromCharCode(stream[i]);
@@ -2971,14 +2985,14 @@ var Type1Parser = function type1Parser() {
var count = headerString.length;
for (var i = 0; i < count; i++) {
var getToken = function getToken() {
- var char = headerString[i];
- while (i < count && (isSeparator(char) || char == '/'))
- char = headerString[++i];
+ var character = headerString[i];
+ while (i < count && (isSeparator(character) || character == '/'))
+ character = headerString[++i];
var token = '';
- while (i < count && !(isSeparator(char) || char == '/')) {
- token += char;
- char = headerString[++i];
+ while (i < count && !(isSeparator(character) || character == '/')) {
+ token += character;
+ character = headerString[++i];
}
return token;
@@ -3130,7 +3144,8 @@ var Type1Font = function Type1Font(name, file, properties) {
};
Type1Font.prototype = {
- createCFFIndexHeader: function createCFFIndexHeader(objects, isByte) {
+ createCFFIndexHeader: function Type1Font_createCFFIndexHeader(objects,
+ isByte) {
// First 2 bytes contains the number of objects contained into this index
var count = objects.length;
@@ -3166,7 +3181,7 @@ Type1Font.prototype = {
return data;
},
- encodeNumber: function encodeNumber(value) {
+ encodeNumber: function Type1Font_encodeNumber(value) {
// some of the fonts has ouf-of-range values
// they are just arithmetic overflows
// make sanitizer happy
@@ -3184,7 +3199,7 @@ Type1Font.prototype = {
}
},
- getOrderedCharStrings: function type1Font_getOrderedCharStrings(glyphs,
+ getOrderedCharStrings: function Type1Font_getOrderedCharStrings(glyphs,
properties) {
var charstrings = [];
var i, length, glyphName;
@@ -3210,7 +3225,8 @@ Type1Font.prototype = {
return charstrings;
},
- getType2Charstrings: function getType2Charstrings(type1Charstrings) {
+ getType2Charstrings: function Type1Font_getType2Charstrings(
+ type1Charstrings) {
var type2Charstrings = [];
var count = type1Charstrings.length;
for (var i = 0; i < count; i++) {
@@ -3221,7 +3237,7 @@ Type1Font.prototype = {
return type2Charstrings;
},
- getType2Subrs: function getType2Subrs(type1Subrs) {
+ getType2Subrs: function Type1Font_getType2Subrs(type1Subrs) {
var bias = 0;
var count = type1Subrs.length;
if (count < 1240)
@@ -3273,7 +3289,7 @@ Type1Font.prototype = {
'hvcurveto': 31
},
- flattenCharstring: function flattenCharstring(charstring, map) {
+ flattenCharstring: function Type1Font_flattenCharstring(charstring, map) {
// charstring changes size - can't cache .length in loop
for (var i = 0; i < charstring.length; i++) {
var command = charstring[i];
@@ -3300,7 +3316,7 @@ Type1Font.prototype = {
return charstring;
},
- wrap: function wrap(name, glyphs, charstrings, subrs, properties) {
+ wrap: function Type1Font_wrap(name, glyphs, charstrings, subrs, properties) {
var fields = {
// major version, minor version, header size, offset size
'header': '\x01\x00\x04\x04',
@@ -3344,7 +3360,7 @@ Type1Font.prototype = {
dict += self.encodeNumber(offset) + '\x11'; // Charstrings
offset = offset + fields.charstrings.length;
- dict += self.encodeNumber(fields.private.length);
+ dict += self.encodeNumber(fields.privateData.length);
dict += self.encodeNumber(offset) + '\x12'; // Private
return header + String.fromCharCode(dict.length + 1) + dict;
@@ -3385,7 +3401,7 @@ Type1Font.prototype = {
'charstrings': this.createCFFIndexHeader([[0x8B, 0x0E]].concat(glyphs),
true),
- 'private': (function cffWrapPrivate(self) {
+ 'privateData': (function cffWrapPrivate(self) {
var data =
'\x8b\x14' + // defaultWidth
'\x8b\x15'; // nominalWidth
@@ -3403,9 +3419,9 @@ Type1Font.prototype = {
ExpansionFactor: '\x0c\x18'
};
for (var field in fieldMap) {
- if (!properties.private.hasOwnProperty(field))
+ if (!properties.privateData.hasOwnProperty(field))
continue;
- var value = properties.private[field];
+ var value = properties.privateData[field];
if (isArray(value)) {
data += self.encodeNumber(value[0]);
@@ -3457,7 +3473,7 @@ var CFFFont = (function CFFFontClosure() {
}
CFFFont.prototype = {
- readExtra: function readExtra(cff) {
+ readExtra: function CFFFont_readExtra(cff) {
// charstrings contains info about glyphs (one element per glyph
// containing mappings for {unicode, width})
var charset = cff.charset.charset;
@@ -3472,7 +3488,7 @@ var CFFFont = (function CFFFontClosure() {
this.charstrings = charstrings;
this.glyphIds = glyphIds;
},
- getCharStrings: function getCharStrings(charsets, encoding) {
+ getCharStrings: function CFFFont_getCharStrings(charsets, encoding) {
var charstrings = [];
var unicodeUsed = [];
var unassignedUnicodeItems = [];
@@ -3534,7 +3550,7 @@ var CFFParser = (function CFFParserClosure() {
this.properties = properties;
}
CFFParser.prototype = {
- parse: function parse() {
+ parse: function CFFParser_parse() {
var properties = this.properties;
var cff = new CFF();
this.cff = cff;
@@ -3591,7 +3607,7 @@ var CFFParser = (function CFFParserClosure() {
return cff;
},
- parseHeader: function parseHeader() {
+ parseHeader: function CFFParser_parseHeader() {
var bytes = this.bytes;
var offset = 0;
@@ -3610,7 +3626,7 @@ var CFFParser = (function CFFParserClosure() {
var header = new CFFHeader(major, minor, hdrSize, offSize);
return {obj: header, endPos: hdrSize};
},
- parseDict: function parseDict(dict) {
+ parseDict: function CFFParser_parseDict(dict) {
var pos = 0;
function parseOperand() {
@@ -3680,7 +3696,7 @@ var CFFParser = (function CFFParserClosure() {
}
return entries;
},
- parseIndex: function parseIndex(pos) {
+ parseIndex: function CFFParser_parseIndex(pos) {
var cffIndex = new CFFIndex();
var bytes = this.bytes;
var count = (bytes[pos++] << 8) | bytes[pos++];
@@ -3710,7 +3726,7 @@ var CFFParser = (function CFFParserClosure() {
}
return {obj: cffIndex, endPos: end};
},
- parseNameIndex: function parseNameIndex(index) {
+ parseNameIndex: function CFFParser_parseNameIndex(index) {
var names = [];
for (var i = 0, ii = index.count; i < ii; ++i) {
var name = index.get(i);
@@ -3737,7 +3753,7 @@ var CFFParser = (function CFFParserClosure() {
}
return names;
},
- parseStringIndex: function parseStringIndex(index) {
+ parseStringIndex: function CFFParser_parseStringIndex(index) {
var strings = new CFFStrings();
for (var i = 0, ii = index.count; i < ii; ++i) {
var data = index.get(i);
@@ -3745,7 +3761,7 @@ var CFFParser = (function CFFParserClosure() {
}
return strings;
},
- createDict: function createDict(type, dict, strings) {
+ createDict: function CFFParser_createDict(type, dict, strings) {
var cffDict = new type(strings);
var types = cffDict.types;
@@ -3757,7 +3773,7 @@ var CFFParser = (function CFFParserClosure() {
}
return cffDict;
},
- parseCharStrings: function parseCharStrings(charStringOffset) {
+ parseCharStrings: function CFFParser_parseCharStrings(charStringOffset) {
var charStrings = this.parseIndex(charStringOffset).obj;
// The CFF specification state that the 'dotsection' command
// (12, 0) is deprecated and treated as a no-op, but all Type2
@@ -3786,7 +3802,7 @@ var CFFParser = (function CFFParserClosure() {
}
return charStrings;
},
- parsePrivateDict: function parsePrivateDict(parentDict) {
+ parsePrivateDict: function CFFParser_parsePrivateDict(parentDict) {
// no private dict, do nothing
if (!parentDict.hasName('Private'))
return;
@@ -3824,7 +3840,7 @@ var CFFParser = (function CFFParserClosure() {
var subrsIndex = this.parseIndex(relativeOffset);
privateDict.subrsIndex = subrsIndex.obj;
},
- parseCharsets: function parsecharsets(pos, length, strings, cid) {
+ parseCharsets: function CFFParser_parseCharsets(pos, length, strings, cid) {
if (pos == 0) {
return new CFFCharset(true, CFFCharsetPredefinedTypes.ISO_ADOBE,
ISOAdobeCharset);
@@ -3876,7 +3892,10 @@ var CFFParser = (function CFFParserClosure() {
return new CFFCharset(false, format, charset, raw);
},
- parseEncoding: function parseEncoding(pos, properties, strings, charset) {
+ parseEncoding: function CFFParser_parseEncoding(pos,
+ properties,
+ strings,
+ charset) {
var encoding = {};
var bytes = this.bytes;
var predefined = false;
@@ -3945,7 +3964,7 @@ var CFFParser = (function CFFParserClosure() {
format = format & 0x7f;
return new CFFEncoding(predefined, format, encoding, raw);
},
- parseFDSelect: function parseFDSelect(pos, length) {
+ parseFDSelect: function CFFParser_parseFDSelect(pos, length) {
var start = pos;
var bytes = this.bytes;
var format = bytes[pos++];
@@ -4017,14 +4036,14 @@ var CFFStrings = (function CFFStringsClosure() {
this.strings = [];
}
CFFStrings.prototype = {
- get: function get(index) {
+ get: function CFFStrings_get(index) {
if (index >= 0 && index <= 390)
return CFFStandardStrings[index];
if (index - 391 <= this.strings.length)
return this.strings[index - 391];
return CFFStandardStrings[0];
},
- add: function add(value) {
+ add: function CFFStrings_add(value) {
this.strings.push(value);
},
get count() {
@@ -4040,11 +4059,11 @@ var CFFIndex = (function CFFIndexClosure() {
this.length = 0;
}
CFFIndex.prototype = {
- add: function add(data) {
+ add: function CFFIndex_add(data) {
this.length += data.length;
this.objects.push(data);
},
- get: function get(index) {
+ get: function CFFIndex_get(index) {
return this.objects[index];
},
get count() {
@@ -4067,7 +4086,7 @@ var CFFDict = (function CFFDictClosure() {
}
CFFDict.prototype = {
// value should always be an array
- setByKey: function setByKey(key, value) {
+ setByKey: function CFFDict_setByKey(key, value) {
if (!(key in this.keyToNameMap))
return false;
// ignore empty values
@@ -4080,10 +4099,10 @@ var CFFDict = (function CFFDictClosure() {
this.values[key] = value;
return true;
},
- hasName: function hasName(name) {
+ hasName: function CFFDict_hasName(name) {
return this.nameToKeyMap[name] in this.values;
},
- getByName: function getByName(name) {
+ getByName: function CFFDict_getByName(name) {
if (!(name in this.nameToKeyMap))
error('Invalid dictionary name "' + name + '"');
var key = this.nameToKeyMap[name];
@@ -4091,11 +4110,11 @@ var CFFDict = (function CFFDictClosure() {
return this.defaults[key];
return this.values[key];
},
- removeByName: function removeByName(name) {
+ removeByName: function CFFDict_removeByName(name) {
delete this.values[this.nameToKeyMap[name]];
}
};
- CFFDict.createTables = function createTables(layout) {
+ CFFDict.createTables = function CFFDict_createTables(layout) {
var tables = {
keyToNameMap: {},
nameToKeyMap: {},
@@ -4252,20 +4271,22 @@ var CFFOffsetTracker = (function CFFOffsetTrackerClosure() {
this.offsets = {};
}
CFFOffsetTracker.prototype = {
- isTracking: function isTracking(key) {
+ isTracking: function CFFOffsetTracker_isTracking(key) {
return key in this.offsets;
},
- track: function track(key, location) {
+ track: function CFFOffsetTracker_track(key, location) {
if (key in this.offsets)
error('Already tracking location of ' + key);
this.offsets[key] = location;
},
- offset: function offset(value) {
+ offset: function CFFOffsetTracker_offset(value) {
for (var key in this.offsets) {
this.offsets[key] += value;
}
},
- setEntryLocation: function setEntryLocation(key, values, output) {
+ setEntryLocation: function CFFOffsetTracker_setEntryLocation(key,
+ values,
+ output) {
if (!(key in this.offsets))
error('Not tracking location of ' + key);
var data = output.data;
@@ -4306,12 +4327,12 @@ var CFFCompiler = (function CFFCompilerClosure() {
this.cff = cff;
}
CFFCompiler.prototype = {
- compile: function compile() {
+ compile: function CFFCompiler_compile() {
var cff = this.cff;
var output = {
data: [],
length: 0,
- add: function add(data) {
+ add: function CFFCompiler_add(data) {
this.data = this.data.concat(data);
this.length = this.data.length;
}
@@ -4362,29 +4383,31 @@ var CFFCompiler = (function CFFCompilerClosure() {
output.add(charStrings);
if (cff.isCIDFont) {
+ // For some reason FDSelect must be in front of FDArray on windows. OSX
+ // and linux don't seem to care.
+ topDictTracker.setEntryLocation('FDSelect', [output.length], output);
+ var fdSelect = this.compileFDSelect(cff.fdSelect.raw);
+ output.add(fdSelect);
+
var compiled = this.compileTopDicts(cff.fdArray, output.length);
topDictTracker.setEntryLocation('FDArray', [output.length], output);
output.add(compiled.output);
var fontDictTrackers = compiled.trackers;
this.compilePrivateDicts(cff.fdArray, fontDictTrackers, output);
-
- topDictTracker.setEntryLocation('FDSelect', [output.length], output);
- var fdSelect = this.compileFDSelect(cff.fdSelect.raw);
- output.add(fdSelect);
}
this.compilePrivateDicts([cff.topDict], [topDictTracker], output);
return output.data;
},
- encodeNumber: function encodeNumber(value) {
+ encodeNumber: function CFFCompiler_encodeNumber(value) {
if (parseFloat(value) == parseInt(value) && !isNaN(value)) // isInt
return this.encodeInteger(value);
else
return this.encodeFloat(value);
},
- encodeFloat: function encodeFloat(value) {
+ encodeFloat: function CFFCompiler_encodeFloat(value) {
value = value.toString();
// Strip off the any leading zeros.
if (value.substr(0, 2) === '0.')
@@ -4417,7 +4440,7 @@ var CFFCompiler = (function CFFCompilerClosure() {
out.push(nibbles[i] << 4 | nibbles[i + 1]);
return out;
},
- encodeInteger: function encodeInteger(value) {
+ encodeInteger: function CFFCompiler_encodeInteger(value) {
var code;
if (value >= -107 && value <= 107) {
code = [value + 139];
@@ -4438,7 +4461,7 @@ var CFFCompiler = (function CFFCompilerClosure() {
}
return code;
},
- compileHeader: function compileHeader(header) {
+ compileHeader: function CFFCompiler_compileHeader(header) {
return [
header.major,
header.minor,
@@ -4446,13 +4469,13 @@ var CFFCompiler = (function CFFCompilerClosure() {
header.offSize
];
},
- compileNameIndex: function compileNameIndex(names) {
+ compileNameIndex: function CFFCompiler_compileNameIndex(names) {
var nameIndex = new CFFIndex();
for (var i = 0, ii = names.length; i < ii; ++i)
nameIndex.add(stringToArray(names[i]));
return this.compileIndex(nameIndex);
},
- compileTopDicts: function compileTopDicts(dicts, length) {
+ compileTopDicts: function CFFCompiler_compileTopDicts(dicts, length) {
var fontDictTrackers = [];
var fdArrayIndex = new CFFIndex();
for (var i = 0, ii = dicts.length; i < ii; ++i) {
@@ -4469,7 +4492,9 @@ var CFFCompiler = (function CFFCompilerClosure() {
output: fdArrayIndex
};
},
- compilePrivateDicts: function compilePrivateDicts(dicts, trackers, output) {
+ compilePrivateDicts: function CFFCompiler_compilePrivateDicts(dicts,
+ trackers,
+ output) {
for (var i = 0, ii = dicts.length; i < ii; ++i) {
var fontDict = dicts[i];
if (!fontDict.privateDict || !fontDict.hasName('Private'))
@@ -4492,7 +4517,7 @@ var CFFCompiler = (function CFFCompilerClosure() {
}
}
},
- compileDict: function compileDict(dict, offsetTracker) {
+ compileDict: function CFFCompiler_compileDict(dict, offsetTracker) {
var out = [];
// The dictionary keys must be in a certain order.
var order = dict.order;
@@ -4543,35 +4568,35 @@ var CFFCompiler = (function CFFCompilerClosure() {
}
return out;
},
- compileStringIndex: function compileStringIndex(strings) {
+ compileStringIndex: function CFFCompiler_compileStringIndex(strings) {
var stringIndex = new CFFIndex();
for (var i = 0, ii = strings.length; i < ii; ++i)
stringIndex.add(stringToArray(strings[i]));
return this.compileIndex(stringIndex);
},
- compileGlobalSubrIndex: function compileGlobalSubrIndex() {
+ compileGlobalSubrIndex: function CFFCompiler_compileGlobalSubrIndex() {
var globalSubrIndex = this.cff.globalSubrIndex;
this.out.writeByteArray(this.compileIndex(globalSubrIndex));
},
- compileCharStrings: function compileCharStrings(charStrings) {
+ compileCharStrings: function CFFCompiler_compileCharStrings(charStrings) {
return this.compileIndex(charStrings);
},
- compileCharset: function compileCharset(charset) {
+ compileCharset: function CFFCompiler_compileCharset(charset) {
return this.compileTypedArray(charset.raw);
},
- compileEncoding: function compileEncoding(encoding) {
+ compileEncoding: function CFFCompiler_compileEncoding(encoding) {
return this.compileTypedArray(encoding.raw);
},
- compileFDSelect: function compileFDSelect(fdSelect) {
+ compileFDSelect: function CFFCompiler_compileFDSelect(fdSelect) {
return this.compileTypedArray(fdSelect);
},
- compileTypedArray: function compileTypedArray(data) {
+ compileTypedArray: function CFFCompiler_compileTypedArray(data) {
var out = [];
for (var i = 0, ii = data.length; i < ii; ++i)
out[i] = data[i];
return out;
},
- compileIndex: function compileIndex(index, trackers) {
+ compileIndex: function CFFCompiler_compileIndex(index, trackers) {
trackers = trackers || [];
var objects = index.objects;
// First 2 bytes contains the number of objects contained into this index
diff --git a/src/function.js b/src/function.js
index 5ff5840c5..2e7ad45e6 100644
--- a/src/function.js
+++ b/src/function.js
@@ -10,7 +10,7 @@ var PDFFunction = (function PDFFunctionClosure() {
var CONSTRUCT_POSTSCRIPT = 4;
return {
- getSampleArray: function pdfFunctionGetSampleArray(size, outputSize, bps,
+ getSampleArray: function PDFFunction_getSampleArray(size, outputSize, bps,
str) {
var length = 1;
for (var i = 0, ii = size.length; i < ii; i++)
@@ -38,7 +38,7 @@ var PDFFunction = (function PDFFunctionClosure() {
return array;
},
- getIR: function pdfFunctionGetIR(xref, fn) {
+ getIR: function PDFFunction_getIR(xref, fn) {
var dict = fn.dict;
if (!dict)
dict = fn;
@@ -57,7 +57,7 @@ var PDFFunction = (function PDFFunctionClosure() {
return typeFn.call(this, fn, dict, xref);
},
- fromIR: function pdfFunctionFromIR(IR) {
+ fromIR: function PDFFunction_fromIR(IR) {
var type = IR[0];
switch (type) {
case CONSTRUCT_SAMPLED:
@@ -72,12 +72,12 @@ var PDFFunction = (function PDFFunctionClosure() {
}
},
- parse: function pdfFunctionParse(xref, fn) {
+ parse: function PDFFunction_parse(xref, fn) {
var IR = this.getIR(xref, fn);
return this.fromIR(IR);
},
- constructSampled: function pdfFunctionConstructSampled(str, dict) {
+ constructSampled: function PDFFunction_constructSampled(str, dict) {
function toMultiArray(arr) {
var inputLength = arr.length;
var outputLength = arr.length / 2;
@@ -133,7 +133,7 @@ var PDFFunction = (function PDFFunctionClosure() {
];
},
- constructSampledFromIR: function pdfFunctionConstructSampledFromIR(IR) {
+ 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)));
@@ -221,8 +221,8 @@ var PDFFunction = (function PDFFunctionClosure() {
}
},
- constructInterpolated:
- function pdfFunctionConstructInterpolated(str, dict) {
+ constructInterpolated: function PDFFunction_constructInterpolated(str,
+ dict) {
var c0 = dict.get('C0') || [0];
var c1 = dict.get('C1') || [1];
var n = dict.get('N');
@@ -239,7 +239,7 @@ var PDFFunction = (function PDFFunctionClosure() {
},
constructInterpolatedFromIR:
- function pdfFunctionconstructInterpolatedFromIR(IR) {
+ function PDFFunction_constructInterpolatedFromIR(IR) {
var c0 = IR[1];
var diff = IR[2];
var n = IR[3];
@@ -258,7 +258,7 @@ var PDFFunction = (function PDFFunctionClosure() {
}
},
- constructStiched: function pdfFunctionConstructStiched(fn, dict, xref) {
+ constructStiched: function PDFFunction_constructStiched(fn, dict, xref) {
var domain = dict.get('Domain');
if (!domain)
@@ -268,18 +268,18 @@ var PDFFunction = (function PDFFunctionClosure() {
if (inputSize != 1)
error('Bad domain for stiched function');
- var fnRefs = xref.fetchIfRef(dict.get('Functions'));
+ 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 = xref.fetchIfRef(dict.get('Bounds'));
- var encode = xref.fetchIfRef(dict.get('Encode'));
+ var bounds = dict.get('Bounds');
+ var encode = dict.get('Encode');
return [CONSTRUCT_STICHED, domain, bounds, encode, fns];
},
- constructStichedFromIR: function pdfFunctionConstructStichedFromIR(IR) {
+ constructStichedFromIR: function PDFFunction_constructStichedFromIR(IR) {
var domain = IR[1];
var bounds = IR[2];
var encode = IR[3];
@@ -325,7 +325,7 @@ var PDFFunction = (function PDFFunctionClosure() {
};
},
- constructPostScript: function pdfFunctionConstructPostScript(fn, dict,
+ constructPostScript: function PDFFunction_constructPostScript(fn, dict,
xref) {
var domain = dict.get('Domain');
var range = dict.get('Range');
@@ -343,8 +343,8 @@ var PDFFunction = (function PDFFunctionClosure() {
return [CONSTRUCT_POSTSCRIPT, domain, range, code];
},
- constructPostScriptFromIR:
- function pdfFunctionConstructPostScriptFromIR(IR) {
+ constructPostScriptFromIR: function PDFFunction_constructPostScriptFromIR(
+ IR) {
var domain = IR[1];
var range = IR[2];
var code = IR[3];
@@ -390,13 +390,13 @@ var FunctionCache = (function FunctionCacheClosure() {
this.total = 0;
}
FunctionCache.prototype = {
- has: function has(key) {
+ has: function FunctionCache_has(key) {
return key in this.cache;
},
- get: function get(key) {
+ get: function FunctionCache_get(key) {
return this.cache[key];
},
- set: function set(key, value) {
+ set: function FunctionCache_set(key, value) {
if (this.total < MAX_CACHE_SIZE) {
this.cache[key] = value;
this.total++;
@@ -413,28 +413,28 @@ var PostScriptStack = (function PostScriptStackClosure() {
}
PostScriptStack.prototype = {
- push: function push(value) {
+ push: function PostScriptStack_push(value) {
if (this.stack.length >= MAX_STACK_SIZE)
error('PostScript function stack overflow.');
this.stack.push(value);
},
- pop: function pop() {
+ pop: function PostScriptStack_pop() {
if (this.stack.length <= 0)
error('PostScript function stack underflow.');
return this.stack.pop();
},
- copy: function copy(n) {
+ 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 index(n) {
+ index: function PostScriptStack_index(n) {
this.push(this.stack[this.stack.length - n - 1]);
},
// rotate the last n stack elements p times
- roll: function roll(n, p) {
+ 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;
@@ -457,7 +457,7 @@ var PostScriptEvaluator = (function PostScriptEvaluatorClosure() {
this.operands = operands;
}
PostScriptEvaluator.prototype = {
- execute: function execute(initialStack) {
+ execute: function PostScriptEvaluator_execute(initialStack) {
var stack = new PostScriptStack(initialStack);
var counter = 0;
var operators = this.operators;
@@ -691,31 +691,31 @@ var PostScriptParser = (function PostScriptParserClosure() {
this.prev;
}
PostScriptParser.prototype = {
- nextToken: function nextToken() {
+ nextToken: function PostScriptParser_nextToken() {
this.prev = this.token;
this.token = this.lexer.getToken();
},
- accept: function accept(type) {
+ accept: function PostScriptParser_accept(type) {
if (this.token.type == type) {
this.nextToken();
return true;
}
return false;
},
- expect: function expect(type) {
+ expect: function PostScriptParser_expect(type) {
if (this.accept(type))
return true;
error('Unexpected symbol: found ' + this.token.type + ' expected ' +
type + '.');
},
- parse: function parse() {
+ parse: function PostScriptParser_parse() {
this.nextToken();
this.expect(PostScriptTokenTypes.LBRACE);
this.parseBlock();
this.expect(PostScriptTokenTypes.RBRACE);
return this.operators;
},
- parseBlock: function parseBlock() {
+ parseBlock: function PostScriptParser_parseBlock() {
while (true) {
if (this.accept(PostScriptTokenTypes.NUMBER)) {
this.operators.push(this.prev.value);
@@ -728,7 +728,7 @@ var PostScriptParser = (function PostScriptParserClosure() {
}
}
},
- parseCondition: function parseCondition() {
+ parseCondition: function PostScriptParser_parseCondition() {
// Add two place holders that will be updated later
var conditionLocation = this.operators.length;
this.operators.push(null, null);
@@ -779,7 +779,7 @@ var PostScriptToken = (function PostScriptTokenClosure() {
var opCache = {};
- PostScriptToken.getOperator = function getOperator(op) {
+ PostScriptToken.getOperator = function PostScriptToken_getOperator(op) {
var opValue = opCache[op];
if (opValue)
return opValue;
@@ -802,7 +802,7 @@ var PostScriptLexer = (function PostScriptLexerClosure() {
this.stream = stream;
}
PostScriptLexer.prototype = {
- getToken: function getToken() {
+ getToken: function PostScriptLexer_getToken() {
var s = '';
var ch;
var comment = false;
@@ -852,7 +852,7 @@ var PostScriptLexer = (function PostScriptLexerClosure() {
return PostScriptToken.getOperator(str);
}
},
- getNumber: function getNumber(ch) {
+ getNumber: function PostScriptLexer_getNumber(ch) {
var str = ch;
var stream = this.stream;
while (true) {
diff --git a/src/image.js b/src/image.js
index 7c23a3426..035e2f754 100644
--- a/src/image.js
+++ b/src/image.js
@@ -94,7 +94,7 @@ var PDFImage = (function PDFImageClosure() {
}
}
- var mask = xref.fetchIfRef(dict.get('Mask'));
+ var mask = dict.get('Mask');
if (mask) {
TODO('masked images');
@@ -106,8 +106,8 @@ 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.
*/
- PDFImage.buildImage = function buildImage(callback, handler, xref, res,
- image, inline) {
+ PDFImage.buildImage = function PDFImage_buildImage(callback, handler, xref,
+ res, image, inline) {
var imageDataPromise = new Promise();
var smaskPromise = new Promise();
// The image data and smask data may not be ready yet, wait till both are
@@ -120,7 +120,7 @@ var PDFImage = (function PDFImageClosure() {
handleImageData(handler, xref, res, image, imageDataPromise);
- var smask = xref.fetchIfRef(image.dict.get('SMask'));
+ var smask = image.dict.get('SMask');
if (smask)
handleImageData(handler, xref, res, smask, smaskPromise);
else
@@ -139,7 +139,8 @@ var PDFImage = (function PDFImageClosure() {
* @param {Number} h2 New height.
* @return {TypedArray} Resized image data.
*/
- PDFImage.resize = function resize(pixels, bpc, components, w1, h1, w2, h2) {
+ PDFImage.resize = function PDFImage_resize(pixels, bpc, components,
+ w1, h1, w2, h2) {
var length = w2 * h2 * components;
var temp = bpc <= 8 ? new Uint8Array(length) :
bpc <= 16 ? new Uint16Array(length) : new Uint32Array(length);
@@ -177,7 +178,7 @@ var PDFImage = (function PDFImageClosure() {
return this.height;
return Math.max(this.height, this.smask.height);
},
- getComponents: function getComponents(buffer) {
+ getComponents: function PDFImage_getComponents(buffer) {
var bpc = this.bpc;
var needsDecode = this.needsDecode;
var decodeMap = this.decode;
@@ -265,7 +266,7 @@ var PDFImage = (function PDFImageClosure() {
}
return output;
},
- getOpacity: function getOpacity(width, height) {
+ getOpacity: function PDFImage_getOpacity(width, height) {
var smask = this.smask;
var originalWidth = this.width;
var originalHeight = this.height;
@@ -285,7 +286,8 @@ var PDFImage = (function PDFImageClosure() {
}
return buf;
},
- applyStencilMask: function applyStencilMask(buffer, inverseDecode) {
+ applyStencilMask: function PDFImage_applyStencilMask(buffer,
+ inverseDecode) {
var width = this.width, height = this.height;
var bitStrideLength = (width + 7) >> 3;
var imgArray = this.getImageBytes(bitStrideLength * height);
@@ -308,7 +310,7 @@ var PDFImage = (function PDFImageClosure() {
}
}
},
- fillRgbaBuffer: function fillRgbaBuffer(buffer, width, height) {
+ fillRgbaBuffer: function PDFImage_fillRgbaBuffer(buffer, width, height) {
var numComps = this.numComps;
var originalWidth = this.width;
var originalHeight = this.height;
@@ -335,7 +337,7 @@ var PDFImage = (function PDFImageClosure() {
buffer[i + 3] = opacity[opacityPos++];
}
},
- fillGrayBuffer: function fillGrayBuffer(buffer) {
+ fillGrayBuffer: function PDFImage_fillGrayBuffer(buffer) {
var numComps = this.numComps;
if (numComps != 1)
error('Reading gray scale from a color image: ' + numComps);
@@ -355,7 +357,7 @@ var PDFImage = (function PDFImageClosure() {
for (var i = 0; i < length; ++i)
buffer[i] = (scale * comps[i]) | 0;
},
- getImageBytes: function getImageBytes(length) {
+ getImageBytes: function PDFImage_getImageBytes(length) {
this.image.reset();
return this.image.getBytes(length);
}
diff --git a/src/jpx.js b/src/jpx.js
index 7a13da0b5..63193753d 100644
--- a/src/jpx.js
+++ b/src/jpx.js
@@ -4,1859 +4,1859 @@
'use strict';
var JpxImage = (function JpxImageClosure() {
- 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;
+ // Table E.1
+ var SubbandsGainLog2 = {
+ 'LL': 0,
+ 'LH': 1,
+ 'HL': 1,
+ 'HH': 2
+ };
+ function JpxImage() {
+ this.failOnCorruptedImage = false;
}
-
- // Section B.10.2 Tag trees
- var TagTree = (function TagTreeClosure() {
- function TagTree(width, height) {
- var levelsLength = log2(Math.max(width, height)) + 1;
- this.levels = [];
- for (var i = 0; i < levelsLength; i++) {
- var level = {
- width: width,
- height: height,
- items: []
- };
- this.levels.push(level);
- width = Math.ceil(width / 2);
- height = Math.ceil(height / 2);
+ JpxImage.prototype = {
+ load: function JpxImage_load(url) {
+ var xhr = new XMLHttpRequest();
+ xhr.open('GET', url, 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);
+ },
+ 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;
}
- }
- TagTree.prototype = {
- reset: function tagTreeReset(i, j) {
- var currentLevel = 0, value = 0;
- while (currentLevel < this.levels.length) {
- var level = this.levels[currentLevel];
- var index = i + j * level.width;
- if (index in level.items) {
- value = level.items[index];
- break;
- }
- level.index = index;
- i >>= 1;
- j >>= 1;
- currentLevel++;
- }
- currentLevel--;
- var level = this.levels[currentLevel];
- level.items[level.index] = value;
- this.currentLevel = currentLevel;
- delete this.value;
- },
- incrementValue: function tagTreeIncrementValue() {
- var level = this.levels[this.currentLevel];
- level.items[level.index]++;
- },
- nextLevel: function tagTreeNextLevel() {
- var currentLevel = this.currentLevel;
- var level = this.levels[currentLevel];
- var value = level.items[level.index];
- currentLevel--;
- if (currentLevel < 0) {
- this.value = value;
- return false;
+ 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);
+ position += headerSize;
+ if (lbox == 1) {
+ lbox = ReadUint(data, position, 8);
+ position += 8;
+ headerSize += 8;
}
-
- this.currentLevel = currentLevel;
- var level = this.levels[currentLevel];
- level.items[level.index] = value;
- return true;
- }
- };
- return TagTree;
- })();
-
- var InclusionTree = (function InclusionTreeClosure() {
- function InclusionTree(width, height, defaultValue) {
- var levelsLength = log2(Math.max(width, height)) + 1;
- this.levels = [];
- for (var i = 0; i < levelsLength; i++) {
- var items = new Uint8Array(width * height);
- for (var j = 0, jj = items.length; j < jj; j++)
- items[j] = defaultValue;
-
- var level = {
- width: width,
- height: height,
- items: items
- };
- this.levels.push(level);
-
- width = Math.ceil(width / 2);
- height = Math.ceil(height / 2);
- }
- }
- InclusionTree.prototype = {
- reset: function inclusionTreeReset(i, j, stopValue) {
- var currentLevel = 0;
- while (currentLevel < this.levels.length) {
- var level = this.levels[currentLevel];
- var index = i + j * level.width;
- level.index = index;
- var value = level.items[index];
-
- if (value == 0xFF)
+ if (lbox == 0)
+ lbox = length - position + headerSize;
+ if (lbox < headerSize)
+ error('JPX error: Invalid box field size');
+ var dataLength = lbox - headerSize;
+ var jumpDataLength = true;
+ switch (tbox) {
+ case 0x6A501A1A: // 'jP\032\032'
+ // TODO
+ break;
+ case 0x6A703268: // 'jp2h'
+ jumpDataLength = false; // parsing child boxes
+ break;
+ case 0x636F6C72: // 'colr'
+ // TODO
+ break;
+ case 0x6A703263: // 'jp2c'
+ this.parseCodestream(data, position, position + dataLength);
break;
-
- if (value > stopValue) {
- this.currentLevel = currentLevel;
- // already know about this one, propagating the value to top levels
- this.propagateValues();
- return false;
- }
-
- i >>= 1;
- j >>= 1;
- currentLevel++;
- }
- this.currentLevel = currentLevel - 1;
- return true;
- },
- incrementValue: function inclusionTreeIncrementValue(stopValue) {
- var level = this.levels[this.currentLevel];
- level.items[level.index] = stopValue + 1;
- this.propagateValues();
- },
- propagateValues: function inclusionTreePropagateValues() {
- var levelIndex = this.currentLevel;
- var level = this.levels[levelIndex];
- var currentValue = level.items[level.index];
- while (--levelIndex >= 0) {
- var level = this.levels[levelIndex];
- level.items[level.index] = currentValue;
}
- },
- nextLevel: function inclusionTreeNextLevel() {
- var currentLevel = this.currentLevel;
- var level = this.levels[currentLevel];
- var value = level.items[level.index];
- level.items[level.index] = 0xFF;
- currentLevel--;
- if (currentLevel < 0)
- return false;
-
- this.currentLevel = currentLevel;
- var level = this.levels[currentLevel];
- level.items[level.index] = value;
- return true;
+ if (jumpDataLength)
+ position += dataLength;
}
- };
- return InclusionTree;
- })();
-
- // Implements C.3. Arithmetic decoding procedures
- var ArithmeticDecoder = (function ArithmeticDecoderClosure() {
- var QeTable = [
- {qe: 0x5601, nmps: 1, nlps: 1, switchFlag: 1},
- {qe: 0x3401, nmps: 2, nlps: 6, switchFlag: 0},
- {qe: 0x1801, nmps: 3, nlps: 9, switchFlag: 0},
- {qe: 0x0AC1, nmps: 4, nlps: 12, switchFlag: 0},
- {qe: 0x0521, nmps: 5, nlps: 29, switchFlag: 0},
- {qe: 0x0221, nmps: 38, nlps: 33, switchFlag: 0},
- {qe: 0x5601, nmps: 7, nlps: 6, switchFlag: 1},
- {qe: 0x5401, nmps: 8, nlps: 14, switchFlag: 0},
- {qe: 0x4801, nmps: 9, nlps: 14, switchFlag: 0},
- {qe: 0x3801, nmps: 10, nlps: 14, switchFlag: 0},
- {qe: 0x3001, nmps: 11, nlps: 17, switchFlag: 0},
- {qe: 0x2401, nmps: 12, nlps: 18, switchFlag: 0},
- {qe: 0x1C01, nmps: 13, nlps: 20, switchFlag: 0},
- {qe: 0x1601, nmps: 29, nlps: 21, switchFlag: 0},
- {qe: 0x5601, nmps: 15, nlps: 14, switchFlag: 1},
- {qe: 0x5401, nmps: 16, nlps: 14, switchFlag: 0},
- {qe: 0x5101, nmps: 17, nlps: 15, switchFlag: 0},
- {qe: 0x4801, nmps: 18, nlps: 16, switchFlag: 0},
- {qe: 0x3801, nmps: 19, nlps: 17, switchFlag: 0},
- {qe: 0x3401, nmps: 20, nlps: 18, switchFlag: 0},
- {qe: 0x3001, nmps: 21, nlps: 19, switchFlag: 0},
- {qe: 0x2801, nmps: 22, nlps: 19, switchFlag: 0},
- {qe: 0x2401, nmps: 23, nlps: 20, switchFlag: 0},
- {qe: 0x2201, nmps: 24, nlps: 21, switchFlag: 0},
- {qe: 0x1C01, nmps: 25, nlps: 22, switchFlag: 0},
- {qe: 0x1801, nmps: 26, nlps: 23, switchFlag: 0},
- {qe: 0x1601, nmps: 27, nlps: 24, switchFlag: 0},
- {qe: 0x1401, nmps: 28, nlps: 25, switchFlag: 0},
- {qe: 0x1201, nmps: 29, nlps: 26, switchFlag: 0},
- {qe: 0x1101, nmps: 30, nlps: 27, switchFlag: 0},
- {qe: 0x0AC1, nmps: 31, nlps: 28, switchFlag: 0},
- {qe: 0x09C1, nmps: 32, nlps: 29, switchFlag: 0},
- {qe: 0x08A1, nmps: 33, nlps: 30, switchFlag: 0},
- {qe: 0x0521, nmps: 34, nlps: 31, switchFlag: 0},
- {qe: 0x0441, nmps: 35, nlps: 32, switchFlag: 0},
- {qe: 0x02A1, nmps: 36, nlps: 33, switchFlag: 0},
- {qe: 0x0221, nmps: 37, nlps: 34, switchFlag: 0},
- {qe: 0x0141, nmps: 38, nlps: 35, switchFlag: 0},
- {qe: 0x0111, nmps: 39, nlps: 36, switchFlag: 0},
- {qe: 0x0085, nmps: 40, nlps: 37, switchFlag: 0},
- {qe: 0x0049, nmps: 41, nlps: 38, switchFlag: 0},
- {qe: 0x0025, nmps: 42, nlps: 39, switchFlag: 0},
- {qe: 0x0015, nmps: 43, nlps: 40, switchFlag: 0},
- {qe: 0x0009, nmps: 44, nlps: 41, switchFlag: 0},
- {qe: 0x0005, nmps: 45, nlps: 42, switchFlag: 0},
- {qe: 0x0001, nmps: 45, nlps: 43, switchFlag: 0},
- {qe: 0x5601, nmps: 46, nlps: 46, switchFlag: 0}
- ];
+ },
+ parseCodestream: function JpxImage_parseCodestream(data, start, end) {
+ var context = {};
+ try {
+ var position = start;
+ while (position < end) {
+ var code = readUint16(data, position);
+ position += 2;
- function ArithmeticDecoder(data, start, end) {
- this.data = data;
- this.bp = start;
- this.dataEnd = end;
-
- this.chigh = data[start];
- this.clow = 0;
-
- this.byteIn();
-
- this.chigh = ((this.chigh << 7) & 0xFFFF) | ((this.clow >> 9) & 0x7F);
- this.clow = (this.clow << 7) & 0xFFFF;
- this.ct -= 7;
- this.a = 0x8000;
- }
-
- ArithmeticDecoder.prototype = {
- byteIn: function arithmeticDecoderByteIn() {
- var data = this.data;
- var bp = this.bp;
- if (data[bp] == 0xFF) {
- var b1 = data[bp + 1];
- if (b1 > 0x8F) {
- this.clow += 0xFF00;
- this.ct = 8;
- } else {
- bp++;
- this.clow += (data[bp] << 9);
- this.ct = 7;
- this.bp = bp;
- }
- } else {
- bp++;
- this.clow += bp < this.dataEnd ? (data[bp] << 8) : 0xFF00;
- this.ct = 8;
- this.bp = bp;
- }
- if (this.clow > 0xFFFF) {
- this.chigh += (this.clow >> 16);
- this.clow &= 0xFFFF;
- }
- },
- readBit: function arithmeticDecoderReadBit(cx) {
- var qeIcx = QeTable[cx.index].qe;
- this.a -= qeIcx;
-
- if (this.chigh < qeIcx) {
- var d = this.exchangeLps(cx);
- this.renormD();
- return d;
- } else {
- this.chigh -= qeIcx;
- if ((this.a & 0x8000) == 0) {
- var d = this.exchangeMps(cx);
- this.renormD();
- return d;
- } else {
- return cx.mps;
- }
- }
- },
- renormD: function arithmeticDecoderRenormD() {
- do {
- if (this.ct == 0)
- this.byteIn();
-
- this.a <<= 1;
- this.chigh = ((this.chigh << 1) & 0xFFFF) | ((this.clow >> 15) & 1);
- this.clow = (this.clow << 1) & 0xFFFF;
- this.ct--;
- } while ((this.a & 0x8000) == 0);
- },
- exchangeMps: function arithmeticDecoderExchangeMps(cx) {
- var d;
- var qeTableIcx = QeTable[cx.index];
- if (this.a < qeTableIcx.qe) {
- d = 1 - cx.mps;
-
- if (qeTableIcx.switchFlag == 1) {
- cx.mps = 1 - cx.mps;
- }
- cx.index = qeTableIcx.nlps;
- } else {
- d = cx.mps;
- cx.index = qeTableIcx.nmps;
- }
- return d;
- },
- exchangeLps: function arithmeticDecoderExchangeMps(cx) {
- var d;
- var qeTableIcx = QeTable[cx.index];
- if (this.a < qeTableIcx.qe) {
- this.a = qeTableIcx.qe;
- d = cx.mps;
- cx.index = qeTableIcx.nmps;
- } else {
- this.a = qeTableIcx.qe;
- d = 1 - cx.mps;
-
- if (qeTableIcx.switchFlag == 1) {
- cx.mps = 1 - cx.mps;
- }
- cx.index = qeTableIcx.nlps;
- }
- return d;
- }
- };
-
- return ArithmeticDecoder;
- })();
-
- // Section D. Coefficient bit modeling
- var BitModel = (function BitModelClosure() {
- // Table D-1
- // The index is binary presentation: 0dddvvhh, ddd - sum of Di (0..4),
- // vv - sum of Vi (0..2), and hh - sum of Hi (0..2)
- var LLAndLHContextsLabel = new Uint8Array([
- 0, 5, 8, 0, 3, 7, 8, 0, 4, 7, 8, 0, 0, 0, 0, 0, 1, 6, 8, 0, 3, 7, 8, 0, 4,
- 7, 8, 0, 0, 0, 0, 0, 2, 6, 8, 0, 3, 7, 8, 0, 4, 7, 8, 0, 0, 0, 0, 0, 2, 6,
- 8, 0, 3, 7, 8, 0, 4, 7, 8, 0, 0, 0, 0, 0, 2, 6, 8, 0, 3, 7, 8, 0, 4, 7, 8
- ]);
- var HLContextLabel = new Uint8Array([
- 0, 3, 4, 0, 5, 7, 7, 0, 8, 8, 8, 0, 0, 0, 0, 0, 1, 3, 4, 0, 6, 7, 7, 0, 8,
- 8, 8, 0, 0, 0, 0, 0, 2, 3, 4, 0, 6, 7, 7, 0, 8, 8, 8, 0, 0, 0, 0, 0, 2, 3,
- 4, 0, 6, 7, 7, 0, 8, 8, 8, 0, 0, 0, 0, 0, 2, 3, 4, 0, 6, 7, 7, 0, 8, 8, 8
- ]);
- var HHContextLabel = new Uint8Array([
- 0, 1, 2, 0, 1, 2, 2, 0, 2, 2, 2, 0, 0, 0, 0, 0, 3, 4, 5, 0, 4, 5, 5, 0, 5,
- 5, 5, 0, 0, 0, 0, 0, 6, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 0, 0, 0, 0, 8, 8,
- 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) {
- this.width = width;
- this.height = height;
+ var length = 0, j;
+ switch (code) {
+ case 0xFF4F: // Start of codestream (SOC)
+ context.mainHeader = true;
+ break;
+ case 0xFFD9: // End of codestream (EOC)
+ break;
+ case 0xFF51: // Image and tile size (SIZ)
+ length = readUint16(data, position);
+ var siz = {};
+ siz.Xsiz = readUint32(data, position + 4);
+ siz.Ysiz = readUint32(data, position + 8);
+ siz.XOsiz = readUint32(data, position + 12);
+ siz.YOsiz = readUint32(data, position + 16);
+ siz.XTsiz = readUint32(data, position + 20);
+ siz.YTsiz = readUint32(data, position + 24);
+ siz.XTOsiz = readUint32(data, position + 28);
+ siz.YTOsiz = readUint32(data, position + 32);
+ var componentsCount = readUint16(data, position + 36);
+ siz.Csiz = componentsCount;
+ var components = [];
+ j = position + 38;
+ for (var i = 0; i < componentsCount; i++) {
+ var component = {
+ precision: (data[j] & 0x7F) + 1,
+ isSigned: !!(data[j] & 0x80),
+ XRsiz: data[j + 1],
+ YRsiz: data[j + 1]
+ };
+ calculateComponentDimensions(component, siz);
+ components.push(component);
+ }
+ context.SIZ = siz;
+ context.components = components;
+ calculateTileGrids(context, components);
+ context.QCC = [];
+ context.COC = [];
+ break;
+ case 0xFF5C: // Quantization default (QCD)
+ length = readUint16(data, position);
+ var qcd = {};
+ j = position + 2;
+ var sqcd = data[j++];
+ var spqcdSize, scalarExpounded;
+ switch (sqcd & 0x1F) {
+ case 0:
+ spqcdSize = 8;
+ scalarExpounded = true;
+ break;
+ case 1:
+ spqcdSize = 16;
+ scalarExpounded = false;
+ break;
+ case 2:
+ spqcdSize = 16;
+ scalarExpounded = true;
+ break;
+ default:
+ throw 'Invalid SQcd value ' + sqcd;
+ }
+ qcd.noQuantization = spqcdSize == 8;
+ qcd.scalarExpounded = scalarExpounded;
+ qcd.guardBits = sqcd >> 5;
+ var spqcds = [];
+ while (j < length + position) {
+ var spqcd = {};
+ if (spqcdSize == 8) {
+ spqcd.epsilon = data[j++] >> 3;
+ spqcd.mu = 0;
+ } else {
+ spqcd.epsilon = data[j] >> 3;
+ spqcd.mu = ((data[j] & 0x7) << 8) | data[j + 1];
+ j += 2;
+ }
+ spqcds.push(spqcd);
+ }
+ qcd.SPqcds = spqcds;
+ if (context.mainHeader)
+ context.QCD = qcd;
+ else {
+ context.currentTile.QCD = qcd;
+ context.currentTile.QCC = [];
+ }
+ break;
+ case 0xFF5D: // Quantization component (QCC)
+ length = readUint16(data, position);
+ var qcc = {};
+ j = position + 2;
+ var cqcc;
+ if (context.SIZ.Csiz < 257)
+ cqcc = data[j++];
+ else {
+ cqcc = readUint16(data, j);
+ j += 2;
+ }
+ var sqcd = data[j++];
+ var spqcdSize, scalarExpounded;
+ switch (sqcd & 0x1F) {
+ case 0:
+ spqcdSize = 8;
+ scalarExpounded = true;
+ break;
+ case 1:
+ spqcdSize = 16;
+ scalarExpounded = false;
+ break;
+ case 2:
+ spqcdSize = 16;
+ scalarExpounded = true;
+ break;
+ default:
+ throw 'Invalid SQcd value ' + sqcd;
+ }
+ qcc.noQuantization = spqcdSize == 8;
+ qcc.scalarExpounded = scalarExpounded;
+ qcc.guardBits = sqcd >> 5;
+ var spqcds = [];
+ while (j < length + position) {
+ var spqcd = {};
+ if (spqcdSize == 8) {
+ spqcd.epsilon = data[j++] >> 3;
+ spqcd.mu = 0;
+ } else {
+ spqcd.epsilon = data[j] >> 3;
+ spqcd.mu = ((data[j] & 0x7) << 8) | data[j + 1];
+ j += 2;
+ }
+ spqcds.push(spqcd);
+ }
+ qcc.SPqcds = spqcds;
+ if (context.mainHeader)
+ context.QCC[cqcc] = qcc;
+ else
+ context.currentTile.QCC[cqcc] = qcc;
+ break;
+ case 0xFF52: // Coding style default (COD)
+ length = readUint16(data, position);
+ var cod = {};
+ j = position + 2;
+ var scod = data[j++];
+ 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;
+ cod.multipleComponentTransform = data[j++];
- this.contextLabelTable = subband == 'HH' ? HHContextLabel :
- subband == 'HL' ? HLContextLabel : LLAndLHContextsLabel;
+ cod.decompositionLevelsCount = data[j++];
+ cod.xcb = (data[j++] & 0xF) + 2;
+ cod.ycb = (data[j++] & 0xF) + 2;
+ var blockStyle = data[j++];
+ cod.selectiveArithmeticCodingBypass = !!(blockStyle & 1);
+ cod.resetContextProbabilities = !!(blockStyle & 2);
+ cod.terminationOnEachCodingPass = !!(blockStyle & 4);
+ cod.verticalyStripe = !!(blockStyle & 8);
+ cod.predictableTermination = !!(blockStyle & 16);
+ cod.segmentationSymbolUsed = !!(blockStyle & 32);
+ cod.transformation = data[j++];
+ if (cod.entropyCoderWithCustomPrecincts) {
+ var precinctsSizes = {};
+ while (j < length + position) {
+ var precinctsSize = data[j];
+ precinctsSizes.push({
+ PPx: precinctsSize & 0xF,
+ PPy: precinctsSize >> 4
+ });
+ }
+ cod.precinctsSizes = precinctsSizes;
+ }
- var coefficientCount = width * height;
+ if (cod.sopMarkerUsed || cod.ephMarkerUsed ||
+ cod.selectiveArithmeticCodingBypass ||
+ cod.resetContextProbabilities ||
+ cod.terminationOnEachCodingPass ||
+ cod.verticalyStripe || cod.predictableTermination ||
+ cod.segmentationSymbolUsed)
+ throw 'Unsupported COD options: ' + uneval(cod);
- // coefficients outside the encoding region treated as insignificant
- // add border state cells for significanceState
- this.neighborsSignificance = new Uint8Array(coefficientCount);
- this.coefficentsSign = new Uint8Array(coefficientCount);
- this.coefficentsMagnitude = new Uint32Array(coefficientCount);
- this.processingFlags = new Uint8Array(coefficientCount);
+ if (context.mainHeader)
+ context.COD = cod;
+ else {
+ context.currentTile.COD = cod;
+ context.currentTile.COC = [];
+ }
+ break;
+ case 0xFF90: // Start of tile-part (SOT)
+ length = readUint16(data, position);
+ var tile = {};
+ tile.index = readUint16(data, position + 2);
+ tile.length = readUint32(data, position + 4);
+ tile.dataEnd = tile.length + position - 2;
+ tile.partIndex = data[position + 8];
+ tile.partsCount = data[position + 9];
- var bitsDecoded = new Uint8Array(this.width * this.height);
- for (var i = 0, ii = bitsDecoded.length; i < ii; i++)
- bitsDecoded[i] = zeroBitPlanes;
- this.bitsDecoded = bitsDecoded;
+ context.mainHeader = false;
+ if (tile.partIndex == 0) {
+ // reset component specific settings
+ tile.COD = context.COD;
+ tile.COC = context.COC.slice(0); // clone of the global COC
+ tile.QCD = context.QCD;
+ tile.QCC = context.QCC.slice(0); // clone of the global COC
+ }
+ context.currentTile = tile;
+ break;
+ case 0xFF93: // Start of data (SOD)
+ var tile = context.currentTile;
+ if (tile.partIndex == 0) {
+ initializeTile(context, tile.index);
+ buildPackets(context);
+ }
- this.reset();
- }
+ // moving to the end of the data
+ length = tile.dataEnd - position;
- BitModel.prototype = {
- setDecoder: function bitModelSetDecoder(decoder) {
- this.decoder = decoder;
- },
- reset: function bitModelReset() {
- this.uniformContext = {index: 46, mps: 0};
- this.runLengthContext = {index: 3, mps: 0};
- this.contexts = [];
- this.contexts.push({index: 4, mps: 0});
- for (var i = 1; i <= 16; i++)
- this.contexts.push({index: 0, mps: 0});
- },
- setNeighborsSignificance:
- function bitModelSetNeighborsSignificance(row, column) {
- var neighborsSignificance = this.neighborsSignificance;
- var width = this.width, height = this.height;
- var index = row * width + column;
- if (row > 0) {
- if (column > 0)
- neighborsSignificance[index - width - 1] += 0x10;
- if (column + 1 < width)
- neighborsSignificance[index - width + 1] += 0x10;
- neighborsSignificance[index - width] += 0x04;
- }
- if (row + 1 < height) {
- if (column > 0)
- neighborsSignificance[index + width - 1] += 0x10;
- if (column + 1 < width)
- neighborsSignificance[index + width + 1] += 0x10;
- neighborsSignificance[index + width] += 0x04;
+ parseTilePackets(context, data, position, length);
+ break;
+ case 0xFF64: // Comment (COM)
+ length = readUint16(data, position);
+ // skipping content
+ break;
+ default:
+ throw 'Unknown codestream code: ' + code.toString(16);
+ }
+ position += length;
}
- if (column > 0)
- neighborsSignificance[index - 1] += 0x01;
- if (column + 1 < width)
- neighborsSignificance[index + 1] += 0x01;
- neighborsSignificance[index] |= 0x80;
- },
- runSignificancePropogationPass:
- function bitModelRunSignificancePropogationPass() {
- var decoder = this.decoder;
- 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++) {
- var index = i0 * width + j;
- for (var i1 = 0; i1 < 4; i1++, index += width) {
- var i = i0 + i1;
- if (i >= height)
- break;
-
- if (coefficentsMagnitude[index] || !neighborsSignificance[index])
- continue;
+ } catch (e) {
+ if (this.failOnCorruptedImage)
+ error('JPX error: ' + e);
+ else
+ warn('JPX error: ' + e + '. Trying to recover');
+ }
+ this.tiles = transformComponents(context);
+ this.width = context.SIZ.Xsiz - context.SIZ.XOsiz;
+ this.height = context.SIZ.Ysiz - context.SIZ.YOsiz;
+ 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);
+ component.x1 = Math.ceil(siz.Xsiz / component.XRsiz);
+ component.y0 = Math.ceil(siz.YOsiz / component.YRsiz);
+ component.y1 = Math.ceil(siz.Ysiz / component.YRsiz);
+ component.width = component.x1 - component.x0;
+ component.height = component.y1 - component.y0;
+ }
+ function calculateTileGrids(context, components) {
+ var siz = context.SIZ;
+ // Section B.3 Division into tile and tile-components
+ var 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.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);
+ tile.ty1 = Math.min(siz.YTOsiz + (q + 1) * siz.YTsiz, siz.Ysiz);
+ tile.width = tile.tx1 - tile.tx0;
+ tile.height = tile.ty1 - tile.ty0;
+ tile.components = [];
+ tiles.push(tile);
+ }
+ }
+ context.tiles = tiles;
- var contextLabel = labels[neighborsSignificance[index]];
- var cx = contexts[contextLabel];
- var decision = decoder.readBit(cx);
- if (decision) {
- var sign = this.decodeSignBit(i, j);
- coefficentsSign[index] = sign;
- coefficentsMagnitude[index] = 1;
- this.setNeighborsSignificance(i, j);
- processingFlags[index] |= firstMagnitudeBitMask;
- }
- bitsDecoded[index]++;
- processingFlags[index] |= processedMask;
- }
- }
+ 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];
+ tileComponent.tcx0 = Math.ceil(tile.tx0 / component.XRsiz);
+ tileComponent.tcy0 = Math.ceil(tile.ty0 / component.YRsiz);
+ tileComponent.tcx1 = Math.ceil(tile.tx1 / component.XRsiz);
+ tileComponent.tcy1 = Math.ceil(tile.ty1 / component.YRsiz);
+ tileComponent.width = tileComponent.tcx1 - tileComponent.tcx0;
+ tileComponent.height = tileComponent.tcy1 - tileComponent.tcy0;
+ tile.components[i] = tileComponent;
+ }
+ }
+ }
+ function getBlocksDimensions(context, component, r) {
+ var codOrCoc = component.codingStyleParameters;
+ var result = {};
+ if (!codOrCoc.entropyCoderWithCustomPrecincts) {
+ result.PPx = 15;
+ result.PPy = 15;
+ } else {
+ result.PPx = codOrCoc.precinctsSizes[r].PPx;
+ result.PPy = codOrCoc.precinctsSizes[r].PPy;
+ }
+ // calculate codeblock size as described in section B.7
+ result.xcb_ = r > 0 ? Math.min(codOrCoc.xcb, result.PPx - 1) :
+ Math.min(codOrCoc.xcb, result.PPx);
+ result.ycb_ = r > 0 ? Math.min(codOrCoc.ycb, result.PPy - 1) :
+ Math.min(codOrCoc.ycb, result.PPy);
+ return result;
+ }
+ function buildPrecincts(context, resolution, dimensions) {
+ // Section B.6 Division resolution to precincts
+ var precinctWidth = 1 << dimensions.PPx;
+ var precinctHeight = 1 << dimensions.PPy;
+ var numprecinctswide = resolution.trx1 > resolution.trx0 ?
+ Math.ceil(resolution.trx1 / precinctWidth) -
+ Math.floor(resolution.trx0 / precinctWidth) : 0;
+ var numprecinctshigh = resolution.try1 > resolution.try0 ?
+ Math.ceil(resolution.try1 / precinctHeight) -
+ Math.floor(resolution.try0 / precinctHeight) : 0;
+ var numprecincts = numprecinctswide * numprecinctshigh;
+ var precinctXOffset = Math.floor(resolution.trx0 / precinctWidth) *
+ precinctWidth;
+ var precinctYOffset = Math.floor(resolution.try0 / precinctHeight) *
+ precinctHeight;
+ resolution.precinctParameters = {
+ precinctXOffset: precinctXOffset,
+ precinctYOffset: precinctYOffset,
+ precinctWidth: precinctWidth,
+ precinctHeight: precinctHeight,
+ numprecinctswide: numprecinctswide,
+ numprecinctshigh: numprecinctshigh,
+ numprecincts: numprecincts
+ };
+ }
+ function buildCodeblocks(context, subband, dimensions) {
+ // Section B.7 Division sub-band into code-blocks
+ var xcb_ = dimensions.xcb_;
+ 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 precinctParameters = subband.resolution.precinctParameters;
+ var codeblocks = [];
+ var precincts = [];
+ for (var j = cby0; j < cby1; j++) {
+ for (var i = cbx0; i < cbx1; i++) {
+ var codeblock = {
+ cbx: i,
+ cby: j,
+ tbx0: codeblockWidth * i,
+ tby0: codeblockHeight * j,
+ tbx1: codeblockWidth * (i + 1),
+ tby1: codeblockHeight * (j + 1)
+ };
+ // calculate precinct number
+ var pi = Math.floor((codeblock.tbx0 -
+ precinctParameters.precinctXOffset) /
+ precinctParameters.precinctWidth);
+ var pj = Math.floor((codeblock.tby0 -
+ precinctParameters.precinctYOffset) /
+ precinctParameters.precinctHeight);
+ var 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);
+ } else {
+ precincts[precinctNumber] = precinct = {
+ cbxMin: i,
+ cbyMin: j,
+ cbxMax: i,
+ cbyMax: j
+ };
}
- },
- decodeSignBit: function bitModelDecodeSignBit(row, column) {
- 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 contextLabelAndXor = SignContextLabels[
- 3 * (1 - horizontalContribution) + (1 - verticalContribution)];
- var contextLabel = contextLabelAndXor.contextLabel;
- var cx = this.contexts[contextLabel];
- var decoded = this.decoder.readBit(cx);
- return decoded ^ contextLabelAndXor.xorBit;
- },
- runMagnitudeRefinementPass:
- function bitModelRunMagnitudeRefinementPass() {
- var decoder = this.decoder;
- var width = this.width, height = this.height;
- var coefficentsMagnitude = this.coefficentsMagnitude;
- var neighborsSignificance = this.neighborsSignificance;
- var contexts = this.contexts;
- var bitsDecoded = this.bitsDecoded;
- var processingFlags = this.processingFlags;
- var processedMask = 1;
- var firstMagnitudeBitMask = 2;
- for (var i0 = 0; i0 < height; i0 += 4) {
- 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;
+ codeblock.precinct = precinct;
+ }
+ }
+ subband.codeblockParameters = {
+ codeblockWidth: xcb_,
+ codeblockHeight: ycb_,
+ numcodeblockwide: cbx1 - cbx0 + 1,
+ 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) {
+ var precinctCodeblocks = [];
+ // Section B.10.8 Order of info in packet
+ var subbands = resolution.subbands;
+ // sub-bands already ordered in 'LL', 'HL', 'LH', and 'HH' sequence
+ for (var i = 0, ii = subbands.length; i < ii; i++) {
+ var subband = subbands[i];
+ var codeblocks = subband.codeblocks;
+ for (var j = 0, jj = codeblocks.length; j < jj; j++) {
+ var codeblock = codeblocks[j];
+ if (codeblock.precinctNumber != precinctNumber)
+ continue;
+ precinctCodeblocks.push(codeblock);
+ }
+ }
+ return {
+ layerNumber: layerNumber,
+ codeblocks: precinctCodeblocks
+ };
+ }
+ function LayerResolutionComponentPositionIterator(context) {
+ var siz = context.SIZ;
+ var tileIndex = context.currentTile.index;
+ var tile = context.tiles[tileIndex];
+ var layersCount = tile.codingStyleDefaultParameters.layersCount;
+ var componentsCount = siz.Csiz;
+ var maxDecompositionLevelsCount = 0;
+ for (var q = 0; q < componentsCount; q++) {
+ maxDecompositionLevelsCount = Math.max(maxDecompositionLevelsCount,
+ tile.components[q].codingStyleParameters.decompositionLevelsCount);
+ }
- // significant but not those that have just become
- if (!coefficentsMagnitude[index] ||
- (processingFlags[index] & processedMask) != 0)
- continue;
+ var l = 0, r = 0, i = 0, k = 0;
- var contextLabel = 16;
- if ((processingFlags[index] &
- firstMagnitudeBitMask) != 0) {
- processingFlags[i * width + j] ^= firstMagnitudeBitMask;
- // first refinement
- var significance = neighborsSignificance[index];
- var sumOfSignificance = (significance & 3) +
- ((significance >> 2) & 3) + ((significance >> 4) & 7);
- contextLabel = sumOfSignificance >= 1 ? 15 : 14;
- }
+ this.nextPacket = function JpxImage_nextPacket() {
+ // Section B.12.1.1 Layer-resolution-component-position
+ for (; l < layersCount; l++) {
+ for (; r <= maxDecompositionLevelsCount; r++) {
+ for (; i < componentsCount; i++) {
+ var component = tile.components[i];
+ if (r > component.codingStyleParameters.decompositionLevelsCount)
+ continue;
- var cx = contexts[contextLabel];
- var bit = decoder.readBit(cx);
- coefficentsMagnitude[index] =
- (coefficentsMagnitude[index] << 1) | bit;
- bitsDecoded[index]++;
- processingFlags[index] |= processedMask;
+ var resolution = component.resolutions[r];
+ var numprecincts = resolution.precinctParameters.numprecincts;
+ for (; k < numprecincts;) {
+ var packet = createPacket(resolution, k, l);
+ k++;
+ return packet;
}
+ k = 0;
}
+ i = 0;
}
- },
- runCleanupPass: function bitModelRunCleanupPass() {
- 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;
- var labels = this.contextLabelTable;
- var bitsDecoded = this.bitsDecoded;
- var processingFlags = this.processingFlags;
- var processedMask = 1;
- var firstMagnitudeBitMask = 2;
- var oneRowDown = width;
- var twoRowsDown = width * 2;
- var threeRowsDown = width * 3;
- for (var i0 = 0; i0 < height; i0 += 4) {
- for (var j = 0; j < width; j++) {
- var index0 = i0 * width + j;
- // using the property: labels[neighborsSignificance[index]] == 0
- // when neighborsSignificance[index] == 0
- var allEmpty = i0 + 3 < height &&
- processingFlags[index0] == 0 &&
- processingFlags[index0 + oneRowDown] == 0 &&
- processingFlags[index0 + twoRowsDown] == 0 &&
- processingFlags[index0 + threeRowsDown] == 0 &&
- neighborsSignificance[index0] == 0 &&
- neighborsSignificance[index0 + oneRowDown] == 0 &&
- neighborsSignificance[index0 + twoRowsDown] == 0 &&
- neighborsSignificance[index0 + threeRowsDown] == 0;
- var i1 = 0, index = index0;
- var cx, i;
- if (allEmpty) {
- cx = this.runLengthContext;
- var hasSignificantCoefficent = decoder.readBit(cx);
- if (!hasSignificantCoefficent) {
- bitsDecoded[index0]++;
- bitsDecoded[index0 + oneRowDown]++;
- bitsDecoded[index0 + twoRowsDown]++;
- bitsDecoded[index0 + threeRowsDown]++;
- continue; // next column
- }
- cx = this.uniformContext;
- i1 = (decoder.readBit(cx) << 1) | decoder.readBit(cx);
- i = i0 + i1;
- index += i1 * width;
-
- var sign = this.decodeSignBit(i, j);
- coefficentsSign[index] = sign;
- coefficentsMagnitude[index] = 1;
- this.setNeighborsSignificance(i, j);
- processingFlags[index] |= firstMagnitudeBitMask;
-
- index = index0;
- for (var i2 = i0; i2 <= i; i2++, index += width)
- bitsDecoded[index]++;
+ r = 0;
+ }
+ throw 'Out of packets';
+ };
+ }
+ function ResolutionLayerComponentPositionIterator(context) {
+ var siz = context.SIZ;
+ var tileIndex = context.currentTile.index;
+ var tile = context.tiles[tileIndex];
+ var layersCount = tile.codingStyleDefaultParameters.layersCount;
+ var componentsCount = siz.Csiz;
+ var maxDecompositionLevelsCount = 0;
+ for (var q = 0; q < componentsCount; q++) {
+ maxDecompositionLevelsCount = Math.max(maxDecompositionLevelsCount,
+ tile.components[q].codingStyleParameters.decompositionLevelsCount);
+ }
- i1++;
- }
- for (; i1 < 4; i1++, index += width) {
- i = i0 + i1;
- if (i >= height)
- break;
+ var r = 0, l = 0, i = 0, k = 0;
- if (coefficentsMagnitude[index] ||
- (processingFlags[index] & processedMask) != 0)
- continue;
+ this.nextPacket = function JpxImage_nextPacket() {
+ // Section B.12.1.2 Resolution-layer-component-position
+ for (; r <= maxDecompositionLevelsCount; r++) {
+ for (; l < layersCount; l++) {
+ for (; i < componentsCount; i++) {
+ var component = tile.components[i];
+ if (r > component.codingStyleParameters.decompositionLevelsCount)
+ continue;
- var contextLabel = labels[neighborsSignificance[index]];
- cx = contexts[contextLabel];
- var decision = decoder.readBit(cx);
- if (decision == 1) {
- var sign = this.decodeSignBit(i, j);
- coefficentsSign[index] = sign;
- coefficentsMagnitude[index] = 1;
- this.setNeighborsSignificance(i, j);
- processingFlags[index] |= firstMagnitudeBitMask;
- }
- bitsDecoded[index]++;
+ var resolution = component.resolutions[r];
+ var numprecincts = resolution.precinctParameters.numprecincts;
+ for (; k < numprecincts;) {
+ var packet = createPacket(resolution, k, l);
+ k++;
+ return packet;
}
+ k = 0;
}
+ i = 0;
}
+ l = 0;
}
+ throw 'Out of packets';
};
+ }
+ function buildPackets(context) {
+ var siz = context.SIZ;
+ var tileIndex = context.currentTile.index;
+ var tile = context.tiles[tileIndex];
+ var componentsCount = siz.Csiz;
+ // Creating resolutions and sub-bands for each component
+ for (var c = 0; c < componentsCount; c++) {
+ var component = tile.components[c];
+ var decompositionLevelsCount =
+ component.codingStyleParameters.decompositionLevelsCount;
+ // Section B.5 Resolution levels and sub-bands
+ var resolutions = [];
+ var subbands = [];
+ for (var r = 0; r <= decompositionLevelsCount; r++) {
+ var blocksDimensions = getBlocksDimensions(context, component, r);
+ var resolution = {};
+ var scale = 1 << (decompositionLevelsCount - r);
+ resolution.trx0 = Math.ceil(component.tcx0 / scale);
+ resolution.try0 = Math.ceil(component.tcy0 / scale);
+ resolution.trx1 = Math.ceil(component.tcx1 / scale);
+ resolution.try1 = Math.ceil(component.tcy1 / scale);
+ buildPrecincts(context, resolution, blocksDimensions);
+ resolutions.push(resolution);
- return BitModel;
- })();
+ var subband;
+ if (r == 0) {
+ // one sub-band (LL) with last decomposition
+ subband = {};
+ subband.type = 'LL';
+ subband.tbx0 = Math.ceil(component.tcx0 / scale);
+ subband.tby0 = Math.ceil(component.tcy0 / scale);
+ subband.tbx1 = Math.ceil(component.tcx1 / scale);
+ subband.tby1 = Math.ceil(component.tcy1 / scale);
+ subband.resolution = resolution;
+ buildCodeblocks(context, subband, blocksDimensions);
+ subbands.push(subband);
+ resolution.subbands = [subband];
+ } else {
+ var bscale = 1 << (decompositionLevelsCount - r + 1);
+ var resolutionSubbands = [];
+ // three sub-bands (HL, LH and HH) with rest of decompositions
+ subband = {};
+ subband.type = 'HL';
+ subband.tbx0 = Math.ceil(component.tcx0 / bscale - 0.5);
+ subband.tby0 = Math.ceil(component.tcy0 / bscale);
+ subband.tbx1 = Math.ceil(component.tcx1 / bscale - 0.5);
+ subband.tby1 = Math.ceil(component.tcy1 / bscale);
+ subband.resolution = resolution;
+ buildCodeblocks(context, subband, blocksDimensions);
+ subbands.push(subband);
+ resolutionSubbands.push(subband);
- // Section F, Discrete wavelet transofrmation
- var Transform = (function TransformClosure() {
- function Transform() {
- }
- 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);
- }
- return ll;
- };
- Transform.prototype.iterate = function transformIterate(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;
+ subband = {};
+ subband.type = 'LH';
+ subband.tbx0 = Math.ceil(component.tcx0 / bscale);
+ subband.tby0 = Math.ceil(component.tcy0 / bscale - 0.5);
+ subband.tbx1 = Math.ceil(component.tcx1 / bscale);
+ subband.tby1 = Math.ceil(component.tcy1 / bscale - 0.5);
+ subband.resolution = resolution;
+ buildCodeblocks(context, subband, blocksDimensions);
+ subbands.push(subband);
+ resolutionSubbands.push(subband);
- // Section F.3.3 interleave
- var width = llWidth + hlWidth;
- var height = llHeight + lhHeight;
- var items = new Float32Array(width * height);
- for (var i = 0, ii = llHeight; i < ii; i++) {
- var k = i * llWidth, l = i * 2 * width;
- for (var j = 0, jj = llWidth; j < jj; j++, k++, l += 2)
- items[l] = llItems[k];
- }
- for (var i = 0, ii = hlHeight; i < ii; i++) {
- var k = i * hlWidth, l = i * 2 * width + 1;
- for (var j = 0, jj = hlWidth; j < jj; j++, k++, l += 2)
- items[l] = hlItems[k];
+ subband = {};
+ subband.type = 'HH';
+ subband.tbx0 = Math.ceil(component.tcx0 / bscale - 0.5);
+ subband.tby0 = Math.ceil(component.tcy0 / bscale - 0.5);
+ subband.tbx1 = Math.ceil(component.tcx1 / bscale - 0.5);
+ subband.tby1 = Math.ceil(component.tcy1 / bscale - 0.5);
+ subband.resolution = resolution;
+ buildCodeblocks(context, subband, blocksDimensions);
+ subbands.push(subband);
+ resolutionSubbands.push(subband);
+
+ resolution.subbands = resolutionSubbands;
+ }
}
- for (var i = 0, ii = lhHeight; i < ii; i++) {
- var k = i * lhWidth, l = (i * 2 + 1) * width;
- for (var j = 0, jj = lhWidth; j < jj; j++, k++, l += 2)
- items[l] = lhItems[k];
+ component.resolutions = resolutions;
+ component.subbands = subbands;
+ }
+ // Generate the packets sequence
+ var progressionOrder = tile.codingStyleDefaultParameters.progressionOrder;
+ var packetsIterator;
+ switch (progressionOrder) {
+ case 0:
+ tile.packetsIterator =
+ new LayerResolutionComponentPositionIterator(context);
+ break;
+ case 1:
+ tile.packetsIterator =
+ new ResolutionLayerComponentPositionIterator(context);
+ break;
+ default:
+ throw 'Unsupported progression order ' + progressionOrder;
+ }
+ }
+ function parseTilePackets(context, data, offset, dataLength) {
+ var position = 0;
+ var buffer, bufferSize = 0, skipNextBit = false;
+ function readBits(count) {
+ while (bufferSize < count) {
+ var b = data[offset + position];
+ position++;
+ if (skipNextBit) {
+ buffer = (buffer << 7) | b;
+ bufferSize += 7;
+ skipNextBit = false;
+ } else {
+ buffer = (buffer << 8) | b;
+ bufferSize += 8;
+ }
+ if (b == 0xFF) {
+ skipNextBit = true;
+ }
}
- for (var i = 0, ii = hhHeight; i < ii; i++) {
- var k = i * hhWidth, l = (i * 2 + 1) * width + 1;
- for (var j = 0, jj = hhWidth; j < jj; j++, k++, l += 2)
- items[l] = hhItems[k];
+ bufferSize -= count;
+ return (buffer >>> bufferSize) & ((1 << count) - 1);
+ }
+ function alignToByte() {
+ bufferSize = 0;
+ if (skipNextBit) {
+ position++;
+ skipNextBit = false;
}
-
- var bufferPadding = 4;
- var bufferLength = new Float32Array(Math.max(width, height) +
- 2 * bufferPadding);
- var buffer = new Float32Array(bufferLength);
- var bufferOut = new Float32Array(bufferLength);
-
- // 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;
- }
- continue;
- }
-
- var k = v * width;
- var l = bufferPadding;
- for (var u = 0; u < width; u++, k++, l++)
- buffer[l] = items[k];
-
- // Section F.3.7 extending... using max extension of 4
- var i1 = bufferPadding - 1, j1 = bufferPadding + 1;
- var i2 = bufferPadding + width - 2, j2 = bufferPadding + width;
- buffer[i1--] = buffer[j1++];
- buffer[j2++] = buffer[i2--];
- buffer[i1--] = buffer[j1++];
- buffer[j2++] = buffer[i2--];
- buffer[i1--] = buffer[j1++];
- buffer[j2++] = buffer[i2--];
- buffer[i1--] = buffer[j1++];
- buffer[j2++] = buffer[i2--];
-
- this.filter(buffer, bufferPadding, width, u0, bufferOut);
-
- k = v * width;
- l = bufferPadding;
- for (var u = 0; u < width; u++, k++, l++)
- items[k] = bufferOut[l];
+ }
+ function readCodingpasses() {
+ var value = readBits(1);
+ if (value == 0)
+ return 1;
+ value = (value << 1) | readBits(1);
+ if (value == 0x02)
+ return 2;
+ value = (value << 2) | readBits(2);
+ if (value <= 0x0E)
+ return (value & 0x03) + 3;
+ value = (value << 5) | readBits(5);
+ if (value <= 0x1FE)
+ return (value & 0x1F) + 6;
+ value = (value << 7) | readBits(7);
+ return (value & 0x7F) + 37;
+ }
+ var tileIndex = context.currentTile.index;
+ var tile = context.tiles[tileIndex];
+ var packetsIterator = tile.packetsIterator;
+ while (position < dataLength) {
+ var packet = packetsIterator.nextPacket();
+ if (!readBits(1)) {
+ alignToByte();
+ continue;
}
+ var layerNumber = packet.layerNumber;
+ var queue = [];
+ for (var i = 0, ii = packet.codeblocks.length; i < ii; i++) {
+ var 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;
+ if ('included' in codeblock) {
+ codeblockIncluded = !!readBits(1);
+ } else {
+ // reading inclusion tree
+ var precinct = codeblock.precinct;
+ var inclusionTree, zeroBitPlanesTree;
+ if ('inclusionTree' in precinct) {
+ inclusionTree = precinct.inclusionTree;
+ } else {
+ // building inclusion and zero bit-planes trees
+ var width = precinct.cbxMax - precinct.cbxMin + 1;
+ var height = precinct.cbyMax - precinct.cbyMin + 1;
+ inclusionTree = new InclusionTree(width, height, layerNumber);
+ zeroBitPlanesTree = new TagTree(width, height);
+ precinct.inclusionTree = inclusionTree;
+ precinct.zeroBitPlanesTree = zeroBitPlanesTree;
+ }
- // Section F.3.5 VER_SR
- for (var u = 0; u < width; u++) {
- 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 (inclusionTree.reset(codeblockColumn, codeblockRow, layerNumber)) {
+ while (true) {
+ if (readBits(1)) {
+ var valueReady = !inclusionTree.nextLevel();
+ if (valueReady) {
+ codeblock.included = true;
+ codeblockIncluded = firstTimeInclusion = true;
+ break;
+ }
+ } else {
+ inclusionTree.incrementValue(layerNumber);
+ break;
+ }
+ }
}
+ }
+ if (!codeblockIncluded)
continue;
+ if (firstTimeInclusion) {
+ zeroBitPlanesTree = precinct.zeroBitPlanesTree;
+ zeroBitPlanesTree.reset(codeblockColumn, codeblockRow);
+ while (true) {
+ if (readBits(1)) {
+ var valueReady = !zeroBitPlanesTree.nextLevel();
+ if (valueReady)
+ break;
+ } else
+ zeroBitPlanesTree.incrementValue();
+ }
+ codeblock.zeroBitPlanes = zeroBitPlanesTree.value;
}
-
- var k = u;
- var l = bufferPadding;
- for (var v = 0; v < height; v++, k += width, l++)
- buffer[l] = items[k];
-
- // Section F.3.7 extending... using max extension of 4
- var i1 = bufferPadding - 1, j1 = bufferPadding + 1;
- var i2 = bufferPadding + height - 2, j2 = bufferPadding + height;
- buffer[i1--] = buffer[j1++];
- buffer[j2++] = buffer[i2--];
- buffer[i1--] = buffer[j1++];
- buffer[j2++] = buffer[i2--];
- buffer[i1--] = buffer[j1++];
- buffer[j2++] = buffer[i2--];
- buffer[i1--] = buffer[j1++];
- buffer[j2++] = buffer[i2--];
-
- this.filter(buffer, bufferPadding, height, v0, bufferOut);
-
- k = u;
- l = bufferPadding;
- for (var v = 0; v < height; v++, k += width, l++)
- items[k] = bufferOut[l];
+ var codingpasses = readCodingpasses();
+ while (readBits(1))
+ codeblock.Lblock++;
+ var codingpassesLog2 = log2(codingpasses);
+ // rounding down log2
+ var bits = ((codingpasses < (1 << codingpassesLog2)) ?
+ codingpassesLog2 - 1 : codingpassesLog2) + codeblock.Lblock;
+ var codedDataLength = readBits(bits);
+ queue.push({
+ codeblock: codeblock,
+ codingpasses: codingpasses,
+ dataLength: codedDataLength
+ });
+ }
+ alignToByte();
+ while (queue.length > 0) {
+ var packetItem = queue.shift();
+ var codeblock = packetItem.codeblock;
+ if (!('data' in codeblock))
+ codeblock.data = [];
+ codeblock.data.push({
+ data: data,
+ start: offset + position,
+ end: offset + position + packetItem.dataLength,
+ codingpasses: packetItem.codingpasses
+ });
+ position += packetItem.dataLength;
}
- return {
- width: width,
- height: height,
- items: items
- };
- };
- return Transform;
- })();
-
- // Section 3.8.2 Irreversible 9-7 filter
- var IrreversibleTransform = (function IrreversibleTransformClosure() {
- function IrreversibleTransform() {
- Transform.call(this);
}
+ return position;
+ }
+ function copyCoefficients(coefficients, x0, y0, width, height,
+ delta, mb, codeblocks, transformation) {
+ var r = 0.5; // formula (E-6)
+ for (var i = 0, ii = codeblocks.length; i < ii; ++i) {
+ var codeblock = codeblocks[i];
+ var blockWidth = codeblock.tbx1_ - codeblock.tbx0_;
+ var blockHeight = codeblock.tby1_ - codeblock.tby0_;
+ if (blockWidth == 0 || blockHeight == 0)
+ continue;
+ if (!('data' in codeblock))
+ continue;
- 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);
-
- var alpha = -1.586134342059924;
- var beta = -0.052980118572961;
- var gamma = 0.882911075530934;
- var delta = 0.443506852043971;
- 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 2
- var j = offset_ - 3;
- for (var n = i0_ - 2, nn = i1_ + 2; n < nn; n++, j += 2)
- x[j] = K_ * y[j];
-
- // 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]);
+ var bitModel, currentCodingpassType;
+ bitModel = new BitModel(blockWidth, blockHeight, codeblock.subbandType,
+ codeblock.zeroBitPlanes);
+ currentCodingpassType = 2; // first bit plane starts from cleanup
- // 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]);
+ // collect data
+ var data = codeblock.data, totalLength = 0, codingpasses = 0;
+ for (var q = 0, qq = data.length; q < qq; q++) {
+ var dataItem = data[q];
+ 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 chunk = dataItem.data.subarray(dataItem.start, dataItem.end);
+ encodedData.set(chunk, k);
+ k += chunk.length;
+ }
+ // decoding the item
+ var decoder = new ArithmeticDecoder(encodedData, 0, totalLength);
+ bitModel.setDecoder(decoder);
- // 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]);
+ for (var q = 0; q < codingpasses; q++) {
+ switch (currentCodingpassType) {
+ case 0:
+ bitModel.runSignificancePropogationPass();
+ break;
+ case 1:
+ bitModel.runMagnitudeRefinementPass();
+ break;
+ case 2:
+ bitModel.runCleanupPass();
+ break;
+ }
+ currentCodingpassType = (currentCodingpassType + 1) % 3;
+ }
- // 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]);
- };
+ var offset = (codeblock.tbx0_ - x0) + (codeblock.tby0_ - y0) * width;
+ var position = 0;
+ for (var j = 0; j < blockHeight; j++) {
+ for (var k = 0; k < blockWidth; k++) {
+ var n = (bitModel.coefficentsSign[position] ? -1 : 1) *
+ bitModel.coefficentsMagnitude[position];
+ var nb = bitModel.bitsDecoded[position], correction;
+ if (transformation == 0 || mb > nb) {
+ // use r only if transformation is irreversible or
+ // not all bitplanes were decoded for reversible transformation
+ n += n < 0 ? n - r : n > 0 ? n + r : 0;
+ correction = 1 << (mb - nb);
+ } else
+ correction = 1;
+ coefficients[offset++] = n * correction * delta;
+ position++;
+ }
+ offset += width - blockWidth;
+ }
+ }
+ }
+ function transformTile(context, tile, c) {
+ var component = tile.components[c];
+ var codingStyleParameters = component.codingStyleParameters;
+ var quantizationParameters = component.quantizationParameters;
+ var decompositionLevelsCount =
+ codingStyleParameters.decompositionLevelsCount;
+ var spqcds = quantizationParameters.SPqcds;
+ var scalarExpounded = quantizationParameters.scalarExpounded;
+ var guardBits = quantizationParameters.guardBits;
+ var transformation = codingStyleParameters.transformation;
+ var precision = context.components[c].precision;
- return IrreversibleTransform;
- })();
+ var subbandCoefficients = [];
+ var k = 0, b = 0;
+ for (var i = 0; i <= decompositionLevelsCount; i++) {
+ var resolution = component.resolutions[i];
- // Section 3.8.1 Reversible 5-3 filter
- var ReversibleTransform = (function ReversibleTransformClosure() {
- function ReversibleTransform() {
- Transform.call(this);
- }
+ for (var j = 0, jj = resolution.subbands.length; j < jj; j++) {
+ var mu, epsilon;
+ if (!scalarExpounded) {
+ // formula E-5
+ mu = spqcds[0].mu;
+ epsilon = spqcds[0].epsilon + (i > 0 ? 1 - i : 0);
+ } else {
+ mu = spqcds[b].mu;
+ epsilon = spqcds[b].epsilon;
+ }
- 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);
+ var subband = resolution.subbands[j];
+ var width = subband.tbx1 - subband.tbx0;
+ var height = subband.tby1 - subband.tby0;
+ var gainLog2 = SubbandsGainLog2[subband.type];
- 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);
+ // calulate quantization coefficient (Section E.1.1.1)
+ var delta = Math.pow(2, (precision + gainLog2) - epsilon) *
+ (1 + mu / 2048);
+ var mb = (guardBits + epsilon - 1);
- 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);
- };
+ var coefficients = new Float32Array(width * height);
+ copyCoefficients(coefficients, subband.tbx0, subband.tby0,
+ width, height, delta, mb, subband.codeblocks, transformation);
- return ReversibleTransform;
- })();
+ subbandCoefficients.push({
+ width: width,
+ height: height,
+ items: coefficients
+ });
- function calculateComponentDimensions(component, siz) {
- // Section B.2 Component mapping
- component.x0 = Math.ceil(siz.XOsiz / component.XRsiz);
- component.x1 = Math.ceil(siz.Xsiz / component.XRsiz);
- component.y0 = Math.ceil(siz.YOsiz / component.YRsiz);
- component.y1 = Math.ceil(siz.Ysiz / component.YRsiz);
- component.width = component.x1 - component.x0;
- component.height = component.y1 - component.y0;
- }
- function calculateTileGrids(context, components) {
- var siz = context.SIZ;
- // Section B.3 Division into tile and tile-components
- var 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.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);
- tile.ty1 = Math.min(siz.YTOsiz + (q + 1) * siz.YTsiz, siz.Ysiz);
- tile.width = tile.tx1 - tile.tx0;
- tile.height = tile.ty1 - tile.ty0;
- tile.components = [];
- tiles.push(tile);
+ b++;
}
}
- context.tiles = tiles;
- 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];
- tileComponent.tcx0 = Math.ceil(tile.tx0 / component.XRsiz);
- tileComponent.tcy0 = Math.ceil(tile.ty0 / component.YRsiz);
- tileComponent.tcx1 = Math.ceil(tile.tx1 / component.XRsiz);
- tileComponent.tcy1 = Math.ceil(tile.ty1 / component.YRsiz);
- tileComponent.width = tileComponent.tcx1 - tileComponent.tcx0;
- tileComponent.height = tileComponent.tcy1 - tileComponent.tcy0;
- tile.components[i] = tileComponent;
- }
- }
- }
- function getBlocksDimensions(context, component, r) {
- var codOrCoc = component.codingStyleParameters;
- var result = {};
- if (!codOrCoc.entropyCoderWithCustomPrecincts) {
- result.PPx = 15;
- result.PPy = 15;
- } else {
- result.PPx = codOrCoc.precinctsSizes[r].PPx;
- result.PPy = codOrCoc.precinctsSizes[r].PPy;
- }
- // calculate codeblock size as described in section B.7
- result.xcb_ = r > 0 ? Math.min(codOrCoc.xcb, result.PPx - 1) :
- Math.min(codOrCoc.xcb, result.PPx);
- result.ycb_ = r > 0 ? Math.min(codOrCoc.ycb, result.PPy - 1) :
- Math.min(codOrCoc.ycb, result.PPy);
- return result;
- }
- function buildPrecincts(context, resolution, dimensions) {
- // Section B.6 Division resolution to precincts
- var precinctWidth = 1 << dimensions.PPx;
- var precinctHeight = 1 << dimensions.PPy;
- var numprecinctswide = resolution.trx1 > resolution.trx0 ?
- Math.ceil(resolution.trx1 / precinctWidth) -
- Math.floor(resolution.trx0 / precinctWidth) : 0;
- var numprecinctshigh = resolution.try1 > resolution.try0 ?
- Math.ceil(resolution.try1 / precinctHeight) -
- Math.floor(resolution.try0 / precinctHeight) : 0;
- var numprecincts = numprecinctswide * numprecinctshigh;
- var precinctXOffset = Math.floor(resolution.trx0 / precinctWidth) *
- precinctWidth;
- var precinctYOffset = Math.floor(resolution.try0 / precinctHeight) *
- precinctHeight;
- resolution.precinctParameters = {
- precinctXOffset: precinctXOffset,
- precinctYOffset: precinctYOffset,
- precinctWidth: precinctWidth,
- precinctHeight: precinctHeight,
- numprecinctswide: numprecinctswide,
- numprecinctshigh: numprecinctshigh,
- numprecincts: numprecincts
+ var transformation = codingStyleParameters.transformation;
+ var transform = transformation == 0 ? new IrreversibleTransform() :
+ new ReversibleTransform();
+ var result = transform.calculate(subbandCoefficients,
+ component.tcx0, component.tcy0);
+ return {
+ left: component.tcx0,
+ top: component.tcy0,
+ width: result.width,
+ height: result.height,
+ items: result.items
};
}
- function buildCodeblocks(context, subband, dimensions) {
- // Section B.7 Division sub-band into code-blocks
- var xcb_ = dimensions.xcb_;
- 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 precinctParameters = subband.resolution.precinctParameters;
- var codeblocks = [];
- var precincts = [];
- for (var j = cby0; j < cby1; j++) {
- for (var i = cbx0; i < cbx1; i++) {
- var codeblock = {
- cbx: i,
- cby: j,
- tbx0: codeblockWidth * i,
- tby0: codeblockHeight * j,
- tbx1: codeblockWidth * (i + 1),
- tby1: codeblockHeight * (j + 1)
- };
- // calculate precinct number
- var pi = Math.floor((codeblock.tbx0 -
- precinctParameters.precinctXOffset) /
- precinctParameters.precinctWidth);
- var pj = Math.floor((codeblock.tby0 -
- precinctParameters.precinctYOffset) /
- precinctParameters.precinctHeight);
- var 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);
- } else {
- precincts[precinctNumber] = precinct = {
- cbxMin: i,
- cbyMin: j,
- cbxMax: i,
- cbyMax: j
- };
+ function transformComponents(context) {
+ var siz = context.SIZ;
+ var components = context.components;
+ var componentsCount = siz.Csiz;
+ 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);
+ }
+
+ // Section G.2.2 Inverse multi component transform
+ if (tile.codingStyleDefaultParameters.multipleComponentTransform) {
+ 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;
}
- codeblock.precinct = precinct;
}
- }
- subband.codeblockParameters = {
- codeblockWidth: xcb_,
- codeblockHeight: ycb_,
- numcodeblockwide: cbx1 - cbx0 + 1,
- 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) {
- var precinctCodeblocks = [];
- // Section B.10.8 Order of info in packet
- var subbands = resolution.subbands;
- // sub-bands already ordered in 'LL', 'HL', 'LH', and 'HH' sequence
- for (var i = 0, ii = subbands.length; i < ii; i++) {
- var subband = subbands[i];
- var codeblocks = subband.codeblocks;
- for (var j = 0, jj = codeblocks.length; j < jj; j++) {
- var codeblock = codeblocks[j];
- if (codeblock.precinctNumber != precinctNumber)
+
+ // 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;
- precinctCodeblocks.push(codeblock);
+
+ 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;
+ }
+
+ // 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;
+ }
+ result[c].items = data;
}
+
+ resultImages.push(result);
}
- return {
- layerNumber: layerNumber,
- codeblocks: precinctCodeblocks
- };
+ return resultImages;
}
- function LayerResolutionComponentPositionIterator(context) {
+ function initializeTile(context, tileIndex) {
var siz = context.SIZ;
- var tileIndex = context.currentTile.index;
- var tile = context.tiles[tileIndex];
- var layersCount = tile.codingStyleDefaultParameters.layersCount;
var componentsCount = siz.Csiz;
- var maxDecompositionLevelsCount = 0;
- for (var q = 0; q < componentsCount; q++) {
- maxDecompositionLevelsCount = Math.max(maxDecompositionLevelsCount,
- tile.components[q].codingStyleParameters.decompositionLevelsCount);
+ 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 ?
+ context.currentTile.QCC[c] : context.currentTile.QCD;
+ component.quantizationParameters = qcdOrQcc;
+ var codOrCoc = c in context.currentTile.COC ?
+ context.currentTile.COC[c] : context.currentTile.COD;
+ component.codingStyleParameters = codOrCoc;
}
+ tile.codingStyleDefaultParameters = context.currentTile.COD;
+ }
- var l = 0, r = 0, i = 0, k = 0;
-
- this.nextPacket = function progressionOrder0NextPacket() {
- // Section B.12.1.1 Layer-resolution-component-position
- for (; l < layersCount; l++) {
- for (; r <= maxDecompositionLevelsCount; r++) {
- for (; i < componentsCount; i++) {
- var component = tile.components[i];
- if (r > component.codingStyleParameters.decompositionLevelsCount)
- continue;
-
- var resolution = component.resolutions[r];
- var numprecincts = resolution.precinctParameters.numprecincts;
- for (; k < numprecincts;) {
- var packet = createPacket(resolution, k, l);
- k++;
- return packet;
- }
- k = 0;
+ // Section B.10.2 Tag trees
+ var TagTree = (function TagTreeClosure() {
+ function TagTree(width, height) {
+ var levelsLength = log2(Math.max(width, height)) + 1;
+ this.levels = [];
+ for (var i = 0; i < levelsLength; i++) {
+ var level = {
+ width: width,
+ height: height,
+ items: []
+ };
+ this.levels.push(level);
+ width = Math.ceil(width / 2);
+ height = Math.ceil(height / 2);
+ }
+ }
+ TagTree.prototype = {
+ reset: function TagTree_reset(i, j) {
+ var currentLevel = 0, value = 0;
+ while (currentLevel < this.levels.length) {
+ var level = this.levels[currentLevel];
+ var index = i + j * level.width;
+ if (index in level.items) {
+ value = level.items[index];
+ break;
}
- i = 0;
+ level.index = index;
+ i >>= 1;
+ j >>= 1;
+ currentLevel++;
}
- r = 0;
+ currentLevel--;
+ var level = this.levels[currentLevel];
+ level.items[level.index] = value;
+ this.currentLevel = currentLevel;
+ delete this.value;
+ },
+ incrementValue: function TagTree_incrementValue() {
+ var level = this.levels[this.currentLevel];
+ level.items[level.index]++;
+ },
+ nextLevel: function TagTree_nextLevel() {
+ var currentLevel = this.currentLevel;
+ var level = this.levels[currentLevel];
+ var value = level.items[level.index];
+ currentLevel--;
+ if (currentLevel < 0) {
+ this.value = value;
+ return false;
+ }
+
+ this.currentLevel = currentLevel;
+ var level = this.levels[currentLevel];
+ level.items[level.index] = value;
+ return true;
}
- throw 'Out of packets';
};
- }
- function ResolutionLayerComponentPositionIterator(context) {
- var siz = context.SIZ;
- var tileIndex = context.currentTile.index;
- var tile = context.tiles[tileIndex];
- var layersCount = tile.codingStyleDefaultParameters.layersCount;
- var componentsCount = siz.Csiz;
- var maxDecompositionLevelsCount = 0;
- for (var q = 0; q < componentsCount; q++) {
- maxDecompositionLevelsCount = Math.max(maxDecompositionLevelsCount,
- tile.components[q].codingStyleParameters.decompositionLevelsCount);
- }
+ return TagTree;
+ })();
- var r = 0, l = 0, i = 0, k = 0;
+ var InclusionTree = (function InclusionTreeClosure() {
+ function InclusionTree(width, height, defaultValue) {
+ var levelsLength = log2(Math.max(width, height)) + 1;
+ this.levels = [];
+ for (var i = 0; i < levelsLength; i++) {
+ var items = new Uint8Array(width * height);
+ for (var j = 0, jj = items.length; j < jj; j++)
+ items[j] = defaultValue;
- this.nextPacket = function progressionOrder1NextPacket() {
- // Section B.12.1.2 Resolution-layer-component-position
- for (; r <= maxDecompositionLevelsCount; r++) {
- for (; l < layersCount; l++) {
- for (; i < componentsCount; i++) {
- var component = tile.components[i];
- if (r > component.codingStyleParameters.decompositionLevelsCount)
- continue;
+ var level = {
+ width: width,
+ height: height,
+ items: items
+ };
+ this.levels.push(level);
- var resolution = component.resolutions[r];
- var numprecincts = resolution.precinctParameters.numprecincts;
- for (; k < numprecincts;) {
- var packet = createPacket(resolution, k, l);
- k++;
- return packet;
- }
- k = 0;
+ width = Math.ceil(width / 2);
+ height = Math.ceil(height / 2);
+ }
+ }
+ InclusionTree.prototype = {
+ reset: function InclusionTree_reset(i, j, stopValue) {
+ var currentLevel = 0;
+ while (currentLevel < this.levels.length) {
+ var level = this.levels[currentLevel];
+ var index = i + j * level.width;
+ level.index = index;
+ var value = level.items[index];
+
+ if (value == 0xFF)
+ break;
+
+ if (value > stopValue) {
+ this.currentLevel = currentLevel;
+ // already know about this one, propagating the value to top levels
+ this.propagateValues();
+ return false;
}
- i = 0;
+
+ i >>= 1;
+ j >>= 1;
+ currentLevel++;
}
- l = 0;
+ this.currentLevel = currentLevel - 1;
+ return true;
+ },
+ incrementValue: function InclusionTree_incrementValue(stopValue) {
+ var level = this.levels[this.currentLevel];
+ level.items[level.index] = stopValue + 1;
+ this.propagateValues();
+ },
+ propagateValues: function InclusionTree_propagateValues() {
+ var levelIndex = this.currentLevel;
+ var level = this.levels[levelIndex];
+ var currentValue = level.items[level.index];
+ while (--levelIndex >= 0) {
+ var level = this.levels[levelIndex];
+ level.items[level.index] = currentValue;
+ }
+ },
+ nextLevel: function InclusionTree_nextLevel() {
+ var currentLevel = this.currentLevel;
+ var level = this.levels[currentLevel];
+ var value = level.items[level.index];
+ level.items[level.index] = 0xFF;
+ currentLevel--;
+ if (currentLevel < 0)
+ return false;
+
+ this.currentLevel = currentLevel;
+ var level = this.levels[currentLevel];
+ level.items[level.index] = value;
+ return true;
}
- throw 'Out of packets';
};
- }
- function buildPackets(context) {
- var siz = context.SIZ;
- var tileIndex = context.currentTile.index;
- var tile = context.tiles[tileIndex];
- var componentsCount = siz.Csiz;
- // Creating resolutions and sub-bands for each component
- for (var c = 0; c < componentsCount; c++) {
- var component = tile.components[c];
- var decompositionLevelsCount =
- component.codingStyleParameters.decompositionLevelsCount;
- // Section B.5 Resolution levels and sub-bands
- var resolutions = [];
- var subbands = [];
- for (var r = 0; r <= decompositionLevelsCount; r++) {
- var blocksDimensions = getBlocksDimensions(context, component, r);
- var resolution = {};
- var scale = 1 << (decompositionLevelsCount - r);
- resolution.trx0 = Math.ceil(component.tcx0 / scale);
- resolution.try0 = Math.ceil(component.tcy0 / scale);
- resolution.trx1 = Math.ceil(component.tcx1 / scale);
- resolution.try1 = Math.ceil(component.tcy1 / scale);
- buildPrecincts(context, resolution, blocksDimensions);
- resolutions.push(resolution);
+ return InclusionTree;
+ })();
+
+ // Implements C.3. Arithmetic decoding procedures
+ var ArithmeticDecoder = (function ArithmeticDecoderClosure() {
+ var QeTable = [
+ {qe: 0x5601, nmps: 1, nlps: 1, switchFlag: 1},
+ {qe: 0x3401, nmps: 2, nlps: 6, switchFlag: 0},
+ {qe: 0x1801, nmps: 3, nlps: 9, switchFlag: 0},
+ {qe: 0x0AC1, nmps: 4, nlps: 12, switchFlag: 0},
+ {qe: 0x0521, nmps: 5, nlps: 29, switchFlag: 0},
+ {qe: 0x0221, nmps: 38, nlps: 33, switchFlag: 0},
+ {qe: 0x5601, nmps: 7, nlps: 6, switchFlag: 1},
+ {qe: 0x5401, nmps: 8, nlps: 14, switchFlag: 0},
+ {qe: 0x4801, nmps: 9, nlps: 14, switchFlag: 0},
+ {qe: 0x3801, nmps: 10, nlps: 14, switchFlag: 0},
+ {qe: 0x3001, nmps: 11, nlps: 17, switchFlag: 0},
+ {qe: 0x2401, nmps: 12, nlps: 18, switchFlag: 0},
+ {qe: 0x1C01, nmps: 13, nlps: 20, switchFlag: 0},
+ {qe: 0x1601, nmps: 29, nlps: 21, switchFlag: 0},
+ {qe: 0x5601, nmps: 15, nlps: 14, switchFlag: 1},
+ {qe: 0x5401, nmps: 16, nlps: 14, switchFlag: 0},
+ {qe: 0x5101, nmps: 17, nlps: 15, switchFlag: 0},
+ {qe: 0x4801, nmps: 18, nlps: 16, switchFlag: 0},
+ {qe: 0x3801, nmps: 19, nlps: 17, switchFlag: 0},
+ {qe: 0x3401, nmps: 20, nlps: 18, switchFlag: 0},
+ {qe: 0x3001, nmps: 21, nlps: 19, switchFlag: 0},
+ {qe: 0x2801, nmps: 22, nlps: 19, switchFlag: 0},
+ {qe: 0x2401, nmps: 23, nlps: 20, switchFlag: 0},
+ {qe: 0x2201, nmps: 24, nlps: 21, switchFlag: 0},
+ {qe: 0x1C01, nmps: 25, nlps: 22, switchFlag: 0},
+ {qe: 0x1801, nmps: 26, nlps: 23, switchFlag: 0},
+ {qe: 0x1601, nmps: 27, nlps: 24, switchFlag: 0},
+ {qe: 0x1401, nmps: 28, nlps: 25, switchFlag: 0},
+ {qe: 0x1201, nmps: 29, nlps: 26, switchFlag: 0},
+ {qe: 0x1101, nmps: 30, nlps: 27, switchFlag: 0},
+ {qe: 0x0AC1, nmps: 31, nlps: 28, switchFlag: 0},
+ {qe: 0x09C1, nmps: 32, nlps: 29, switchFlag: 0},
+ {qe: 0x08A1, nmps: 33, nlps: 30, switchFlag: 0},
+ {qe: 0x0521, nmps: 34, nlps: 31, switchFlag: 0},
+ {qe: 0x0441, nmps: 35, nlps: 32, switchFlag: 0},
+ {qe: 0x02A1, nmps: 36, nlps: 33, switchFlag: 0},
+ {qe: 0x0221, nmps: 37, nlps: 34, switchFlag: 0},
+ {qe: 0x0141, nmps: 38, nlps: 35, switchFlag: 0},
+ {qe: 0x0111, nmps: 39, nlps: 36, switchFlag: 0},
+ {qe: 0x0085, nmps: 40, nlps: 37, switchFlag: 0},
+ {qe: 0x0049, nmps: 41, nlps: 38, switchFlag: 0},
+ {qe: 0x0025, nmps: 42, nlps: 39, switchFlag: 0},
+ {qe: 0x0015, nmps: 43, nlps: 40, switchFlag: 0},
+ {qe: 0x0009, nmps: 44, nlps: 41, switchFlag: 0},
+ {qe: 0x0005, nmps: 45, nlps: 42, switchFlag: 0},
+ {qe: 0x0001, nmps: 45, nlps: 43, switchFlag: 0},
+ {qe: 0x5601, nmps: 46, nlps: 46, switchFlag: 0}
+ ];
- var subband;
- if (r == 0) {
- // one sub-band (LL) with last decomposition
- subband = {};
- subband.type = 'LL';
- subband.tbx0 = Math.ceil(component.tcx0 / scale);
- subband.tby0 = Math.ceil(component.tcy0 / scale);
- subband.tbx1 = Math.ceil(component.tcx1 / scale);
- subband.tby1 = Math.ceil(component.tcy1 / scale);
- subband.resolution = resolution;
- buildCodeblocks(context, subband, blocksDimensions);
- subbands.push(subband);
- resolution.subbands = [subband];
- } else {
- var bscale = 1 << (decompositionLevelsCount - r + 1);
- var resolutionSubbands = [];
- // three sub-bands (HL, LH and HH) with rest of decompositions
- subband = {};
- subband.type = 'HL';
- subband.tbx0 = Math.ceil(component.tcx0 / bscale - 0.5);
- subband.tby0 = Math.ceil(component.tcy0 / bscale);
- subband.tbx1 = Math.ceil(component.tcx1 / bscale - 0.5);
- subband.tby1 = Math.ceil(component.tcy1 / bscale);
- subband.resolution = resolution;
- buildCodeblocks(context, subband, blocksDimensions);
- subbands.push(subband);
- resolutionSubbands.push(subband);
+ function ArithmeticDecoder(data, start, end) {
+ this.data = data;
+ this.bp = start;
+ this.dataEnd = end;
- subband = {};
- subband.type = 'LH';
- subband.tbx0 = Math.ceil(component.tcx0 / bscale);
- subband.tby0 = Math.ceil(component.tcy0 / bscale - 0.5);
- subband.tbx1 = Math.ceil(component.tcx1 / bscale);
- subband.tby1 = Math.ceil(component.tcy1 / bscale - 0.5);
- subband.resolution = resolution;
- buildCodeblocks(context, subband, blocksDimensions);
- subbands.push(subband);
- resolutionSubbands.push(subband);
+ this.chigh = data[start];
+ this.clow = 0;
- subband = {};
- subband.type = 'HH';
- subband.tbx0 = Math.ceil(component.tcx0 / bscale - 0.5);
- subband.tby0 = Math.ceil(component.tcy0 / bscale - 0.5);
- subband.tbx1 = Math.ceil(component.tcx1 / bscale - 0.5);
- subband.tby1 = Math.ceil(component.tcy1 / bscale - 0.5);
- subband.resolution = resolution;
- buildCodeblocks(context, subband, blocksDimensions);
- subbands.push(subband);
- resolutionSubbands.push(subband);
+ this.byteIn();
- resolution.subbands = resolutionSubbands;
- }
- }
- component.resolutions = resolutions;
- component.subbands = subbands;
- }
- // Generate the packets sequence
- var progressionOrder = tile.codingStyleDefaultParameters.progressionOrder;
- var packetsIterator;
- switch (progressionOrder) {
- case 0:
- tile.packetsIterator =
- new LayerResolutionComponentPositionIterator(context);
- break;
- case 1:
- tile.packetsIterator =
- new ResolutionLayerComponentPositionIterator(context);
- break;
- default:
- throw 'Unsupported progression order ' + progressionOrder;
+ this.chigh = ((this.chigh << 7) & 0xFFFF) | ((this.clow >> 9) & 0x7F);
+ this.clow = (this.clow << 7) & 0xFFFF;
+ this.ct -= 7;
+ this.a = 0x8000;
}
- }
- function parseTilePackets(context, data, offset, dataLength) {
- var position = 0;
- var buffer, bufferSize = 0, skipNextBit = false;
- function readBits(count) {
- while (bufferSize < count) {
- var b = data[offset + position];
- position++;
- if (skipNextBit) {
- buffer = (buffer << 7) | b;
- bufferSize += 7;
- skipNextBit = false;
+
+ ArithmeticDecoder.prototype = {
+ byteIn: function ArithmeticDecoder_byteIn() {
+ var data = this.data;
+ var bp = this.bp;
+ if (data[bp] == 0xFF) {
+ var b1 = data[bp + 1];
+ if (b1 > 0x8F) {
+ this.clow += 0xFF00;
+ this.ct = 8;
+ } else {
+ bp++;
+ this.clow += (data[bp] << 9);
+ this.ct = 7;
+ this.bp = bp;
+ }
} else {
- buffer = (buffer << 8) | b;
- bufferSize += 8;
+ bp++;
+ this.clow += bp < this.dataEnd ? (data[bp] << 8) : 0xFF00;
+ this.ct = 8;
+ this.bp = bp;
}
- if (b == 0xFF) {
- skipNextBit = true;
+ if (this.clow > 0xFFFF) {
+ this.chigh += (this.clow >> 16);
+ this.clow &= 0xFFFF;
}
- }
- bufferSize -= count;
- return (buffer >>> bufferSize) & ((1 << count) - 1);
- }
- function alignToByte() {
- bufferSize = 0;
- if (skipNextBit) {
- position++;
- skipNextBit = false;
- }
- }
- function readCodingpasses() {
- var value = readBits(1);
- if (value == 0)
- return 1;
- value = (value << 1) | readBits(1);
- if (value == 0x02)
- return 2;
- value = (value << 2) | readBits(2);
- if (value <= 0x0E)
- return (value & 0x03) + 3;
- value = (value << 5) | readBits(5);
- if (value <= 0x1FE)
- return (value & 0x1F) + 6;
- value = (value << 7) | readBits(7);
- return (value & 0x7F) + 37;
- }
- var tileIndex = context.currentTile.index;
- var tile = context.tiles[tileIndex];
- var packetsIterator = tile.packetsIterator;
- while (position < dataLength) {
- var packet = packetsIterator.nextPacket();
- if (!readBits(1)) {
- alignToByte();
- continue;
- }
- var layerNumber = packet.layerNumber;
- var queue = [];
- for (var i = 0, ii = packet.codeblocks.length; i < ii; i++) {
- var 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;
- if ('included' in codeblock) {
- codeblockIncluded = !!readBits(1);
+ },
+ readBit: function ArithmeticDecoder_readBit(cx) {
+ var qeIcx = QeTable[cx.index].qe;
+ this.a -= qeIcx;
+
+ if (this.chigh < qeIcx) {
+ var d = this.exchangeLps(cx);
+ this.renormD();
+ return d;
} else {
- // reading inclusion tree
- var precinct = codeblock.precinct;
- var inclusionTree, zeroBitPlanesTree;
- if ('inclusionTree' in precinct) {
- inclusionTree = precinct.inclusionTree;
+ this.chigh -= qeIcx;
+ if ((this.a & 0x8000) == 0) {
+ var d = this.exchangeMps(cx);
+ this.renormD();
+ return d;
} else {
- // building inclusion and zero bit-planes trees
- var width = precinct.cbxMax - precinct.cbxMin + 1;
- var height = precinct.cbyMax - precinct.cbyMin + 1;
- inclusionTree = new InclusionTree(width, height, layerNumber);
- zeroBitPlanesTree = new TagTree(width, height);
- precinct.inclusionTree = inclusionTree;
- precinct.zeroBitPlanesTree = zeroBitPlanesTree;
+ return cx.mps;
}
+ }
+ },
+ renormD: function ArithmeticDecoder_renormD() {
+ do {
+ if (this.ct == 0)
+ this.byteIn();
- if (inclusionTree.reset(codeblockColumn, codeblockRow, layerNumber)) {
- while (true) {
- if (readBits(1)) {
- var valueReady = !inclusionTree.nextLevel();
- if (valueReady) {
- codeblock.included = true;
- codeblockIncluded = firstTimeInclusion = true;
- break;
- }
- } else {
- inclusionTree.incrementValue(layerNumber);
- break;
- }
- }
+ this.a <<= 1;
+ this.chigh = ((this.chigh << 1) & 0xFFFF) | ((this.clow >> 15) & 1);
+ this.clow = (this.clow << 1) & 0xFFFF;
+ this.ct--;
+ } while ((this.a & 0x8000) == 0);
+ },
+ exchangeMps: function ArithmeticDecoder_exchangeMps(cx) {
+ var d;
+ var qeTableIcx = QeTable[cx.index];
+ if (this.a < qeTableIcx.qe) {
+ d = 1 - cx.mps;
+
+ if (qeTableIcx.switchFlag == 1) {
+ cx.mps = 1 - cx.mps;
}
+ cx.index = qeTableIcx.nlps;
+ } else {
+ d = cx.mps;
+ cx.index = qeTableIcx.nmps;
}
- if (!codeblockIncluded)
- continue;
- if (firstTimeInclusion) {
- zeroBitPlanesTree = precinct.zeroBitPlanesTree;
- zeroBitPlanesTree.reset(codeblockColumn, codeblockRow);
- while (true) {
- if (readBits(1)) {
- var valueReady = !zeroBitPlanesTree.nextLevel();
- if (valueReady)
- break;
- } else
- zeroBitPlanesTree.incrementValue();
+ return d;
+ },
+ exchangeLps: function ArithmeticDecoder_exchangeLps(cx) {
+ var d;
+ var qeTableIcx = QeTable[cx.index];
+ if (this.a < qeTableIcx.qe) {
+ this.a = qeTableIcx.qe;
+ d = cx.mps;
+ cx.index = qeTableIcx.nmps;
+ } else {
+ this.a = qeTableIcx.qe;
+ d = 1 - cx.mps;
+
+ if (qeTableIcx.switchFlag == 1) {
+ cx.mps = 1 - cx.mps;
}
- codeblock.zeroBitPlanes = zeroBitPlanesTree.value;
+ cx.index = qeTableIcx.nlps;
}
- var codingpasses = readCodingpasses();
- while (readBits(1))
- codeblock.Lblock++;
- var codingpassesLog2 = log2(codingpasses);
- // rounding down log2
- var bits = ((codingpasses < (1 << codingpassesLog2)) ?
- codingpassesLog2 - 1 : codingpassesLog2) + codeblock.Lblock;
- var codedDataLength = readBits(bits);
- queue.push({
- codeblock: codeblock,
- codingpasses: codingpasses,
- dataLength: codedDataLength
- });
- }
- alignToByte();
- while (queue.length > 0) {
- var packetItem = queue.shift();
- var codeblock = packetItem.codeblock;
- if (!('data' in codeblock))
- codeblock.data = [];
- codeblock.data.push({
- data: data,
- start: offset + position,
- end: offset + position + packetItem.dataLength,
- codingpasses: packetItem.codingpasses
- });
- position += packetItem.dataLength;
+ return d;
}
+ };
+
+ return ArithmeticDecoder;
+ })();
+
+ // Section D. Coefficient bit modeling
+ var BitModel = (function BitModelClosure() {
+ // Table D-1
+ // The index is binary presentation: 0dddvvhh, ddd - sum of Di (0..4),
+ // vv - sum of Vi (0..2), and hh - sum of Hi (0..2)
+ var LLAndLHContextsLabel = new Uint8Array([
+ 0, 5, 8, 0, 3, 7, 8, 0, 4, 7, 8, 0, 0, 0, 0, 0, 1, 6, 8, 0, 3, 7, 8, 0, 4,
+ 7, 8, 0, 0, 0, 0, 0, 2, 6, 8, 0, 3, 7, 8, 0, 4, 7, 8, 0, 0, 0, 0, 0, 2, 6,
+ 8, 0, 3, 7, 8, 0, 4, 7, 8, 0, 0, 0, 0, 0, 2, 6, 8, 0, 3, 7, 8, 0, 4, 7, 8
+ ]);
+ var HLContextLabel = new Uint8Array([
+ 0, 3, 4, 0, 5, 7, 7, 0, 8, 8, 8, 0, 0, 0, 0, 0, 1, 3, 4, 0, 6, 7, 7, 0, 8,
+ 8, 8, 0, 0, 0, 0, 0, 2, 3, 4, 0, 6, 7, 7, 0, 8, 8, 8, 0, 0, 0, 0, 0, 2, 3,
+ 4, 0, 6, 7, 7, 0, 8, 8, 8, 0, 0, 0, 0, 0, 2, 3, 4, 0, 6, 7, 7, 0, 8, 8, 8
+ ]);
+ var HHContextLabel = new Uint8Array([
+ 0, 1, 2, 0, 1, 2, 2, 0, 2, 2, 2, 0, 0, 0, 0, 0, 3, 4, 5, 0, 4, 5, 5, 0, 5,
+ 5, 5, 0, 0, 0, 0, 0, 6, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 0, 0, 0, 0, 8, 8,
+ 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;
}
- return position;
- }
- function copyCoefficients(coefficients, x0, y0, width, height,
- delta, mb, codeblocks, transformation) {
- var r = 0.5; // formula (E-6)
- for (var i = 0, ii = codeblocks.length; i < ii; ++i) {
- var codeblock = codeblocks[i];
- var blockWidth = codeblock.tbx1_ - codeblock.tbx0_;
- var blockHeight = codeblock.tby1_ - codeblock.tby0_;
- if (blockWidth == 0 || blockHeight == 0)
- continue;
- if (!('data' in codeblock))
- continue;
+ // 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}
+ ];
- var bitModel, currentCodingpassType;
- bitModel = new BitModel(blockWidth, blockHeight, codeblock.subbandType,
- codeblock.zeroBitPlanes);
- currentCodingpassType = 2; // first bit plane starts from cleanup
+ function BitModel(width, height, subband, zeroBitPlanes) {
+ this.width = width;
+ this.height = height;
- // collect data
- var data = codeblock.data, totalLength = 0, codingpasses = 0;
- for (var q = 0, qq = data.length; q < qq; q++) {
- var dataItem = data[q];
- 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 chunk = dataItem.data.subarray(dataItem.start, dataItem.end);
- encodedData.set(chunk, k);
- k += chunk.length;
- }
- // decoding the item
- var decoder = new ArithmeticDecoder(encodedData, 0, totalLength);
- bitModel.setDecoder(decoder);
+ this.contextLabelTable = subband == 'HH' ? HHContextLabel :
+ subband == 'HL' ? HLContextLabel : LLAndLHContextsLabel;
- for (var q = 0; q < codingpasses; q++) {
- switch (currentCodingpassType) {
- case 0:
- bitModel.runSignificancePropogationPass();
- break;
- case 1:
- bitModel.runMagnitudeRefinementPass();
- break;
- case 2:
- bitModel.runCleanupPass();
- break;
- }
- currentCodingpassType = (currentCodingpassType + 1) % 3;
- }
+ var coefficientCount = width * height;
- var offset = (codeblock.tbx0_ - x0) + (codeblock.tby0_ - y0) * width;
- var position = 0;
- for (var j = 0; j < blockHeight; j++) {
- for (var k = 0; k < blockWidth; k++) {
- var n = (bitModel.coefficentsSign[position] ? -1 : 1) *
- bitModel.coefficentsMagnitude[position];
- var nb = bitModel.bitsDecoded[position], correction;
- if (transformation == 0 || mb > nb) {
- // use r only if transformation is irreversible or
- // not all bitplanes were decoded for reversible transformation
- n += n < 0 ? n - r : n > 0 ? n + r : 0;
- correction = 1 << (mb - nb);
- } else
- correction = 1;
- coefficients[offset++] = n * correction * delta;
- position++;
- }
- offset += width - blockWidth;
- }
+ // coefficients outside the encoding region treated as insignificant
+ // add border state cells for significanceState
+ this.neighborsSignificance = new Uint8Array(coefficientCount);
+ this.coefficentsSign = new Uint8Array(coefficientCount);
+ this.coefficentsMagnitude = new Uint32Array(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;
+ this.bitsDecoded = bitsDecoded;
+
+ this.reset();
}
- }
- // Table E.1
- var SubbandsGainLog2 = {
- 'LL': 0,
- 'LH': 1,
- 'HL': 1,
- 'HH': 2
- };
- function transformTile(context, tile, c) {
- var component = tile.components[c];
- var codingStyleParameters = component.codingStyleParameters;
- var quantizationParameters = component.quantizationParameters;
- var decompositionLevelsCount =
- codingStyleParameters.decompositionLevelsCount;
- var spqcds = quantizationParameters.SPqcds;
- var scalarExpounded = quantizationParameters.scalarExpounded;
- var guardBits = quantizationParameters.guardBits;
- var transformation = codingStyleParameters.transformation;
- var precision = context.components[c].precision;
- var subbandCoefficients = [];
- var k = 0, b = 0;
- for (var i = 0; i <= decompositionLevelsCount; i++) {
- var resolution = component.resolutions[i];
+ BitModel.prototype = {
+ setDecoder: function BitModel_setDecoder(decoder) {
+ this.decoder = decoder;
+ },
+ reset: function BitModel_reset() {
+ this.uniformContext = {index: 46, mps: 0};
+ this.runLengthContext = {index: 3, mps: 0};
+ this.contexts = [];
+ this.contexts.push({index: 4, mps: 0});
+ for (var i = 1; i <= 16; i++)
+ this.contexts.push({index: 0, mps: 0});
+ },
+ setNeighborsSignificance:
+ function BitModel_setNeighborsSignificance(row, column) {
+ var neighborsSignificance = this.neighborsSignificance;
+ var width = this.width, height = this.height;
+ var index = row * width + column;
+ if (row > 0) {
+ if (column > 0)
+ neighborsSignificance[index - width - 1] += 0x10;
+ if (column + 1 < width)
+ neighborsSignificance[index - width + 1] += 0x10;
+ neighborsSignificance[index - width] += 0x04;
+ }
+ if (row + 1 < height) {
+ if (column > 0)
+ neighborsSignificance[index + width - 1] += 0x10;
+ if (column + 1 < width)
+ neighborsSignificance[index + width + 1] += 0x10;
+ neighborsSignificance[index + width] += 0x04;
+ }
+ if (column > 0)
+ neighborsSignificance[index - 1] += 0x01;
+ if (column + 1 < width)
+ neighborsSignificance[index + 1] += 0x01;
+ neighborsSignificance[index] |= 0x80;
+ },
+ runSignificancePropogationPass:
+ function BitModel_runSignificancePropogationPass() {
+ var decoder = this.decoder;
+ 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++) {
+ var index = i0 * width + j;
+ for (var i1 = 0; i1 < 4; i1++, index += width) {
+ var i = i0 + i1;
+ if (i >= height)
+ break;
- for (var j = 0, jj = resolution.subbands.length; j < jj; j++) {
- var mu, epsilon;
- if (!scalarExpounded) {
- // formula E-5
- mu = spqcds[0].mu;
- epsilon = spqcds[0].epsilon + (i > 0 ? 1 - i : 0);
- } else {
- mu = spqcds[b].mu;
- epsilon = spqcds[b].epsilon;
- }
+ if (coefficentsMagnitude[index] || !neighborsSignificance[index])
+ continue;
- var subband = resolution.subbands[j];
- var width = subband.tbx1 - subband.tbx0;
- var height = subband.tby1 - subband.tby0;
- var gainLog2 = SubbandsGainLog2[subband.type];
+ var contextLabel = labels[neighborsSignificance[index]];
+ var cx = contexts[contextLabel];
+ var decision = decoder.readBit(cx);
+ if (decision) {
+ var sign = this.decodeSignBit(i, j);
+ coefficentsSign[index] = sign;
+ coefficentsMagnitude[index] = 1;
+ this.setNeighborsSignificance(i, j);
+ processingFlags[index] |= firstMagnitudeBitMask;
+ }
+ bitsDecoded[index]++;
+ processingFlags[index] |= processedMask;
+ }
+ }
+ }
+ },
+ decodeSignBit: function BitModel_decodeSignBit(row, column) {
+ 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]);
- // calulate quantization coefficient (Section E.1.1.1)
- var delta = Math.pow(2, (precision + gainLog2) - epsilon) *
- (1 + mu / 2048);
- var mb = (guardBits + epsilon - 1);
+ var contextLabelAndXor = SignContextLabels[
+ 3 * (1 - horizontalContribution) + (1 - verticalContribution)];
+ var contextLabel = contextLabelAndXor.contextLabel;
+ var cx = this.contexts[contextLabel];
+ var decoded = this.decoder.readBit(cx);
+ return decoded ^ contextLabelAndXor.xorBit;
+ },
+ runMagnitudeRefinementPass:
+ function BitModel_runMagnitudeRefinementPass() {
+ var decoder = this.decoder;
+ var width = this.width, height = this.height;
+ var coefficentsMagnitude = this.coefficentsMagnitude;
+ var neighborsSignificance = this.neighborsSignificance;
+ var contexts = this.contexts;
+ var bitsDecoded = this.bitsDecoded;
+ var processingFlags = this.processingFlags;
+ var processedMask = 1;
+ var firstMagnitudeBitMask = 2;
+ for (var i0 = 0; i0 < height; i0 += 4) {
+ 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;
- var coefficients = new Float32Array(width * height);
- copyCoefficients(coefficients, subband.tbx0, subband.tby0,
- width, height, delta, mb, subband.codeblocks, transformation);
+ // significant but not those that have just become
+ if (!coefficentsMagnitude[index] ||
+ (processingFlags[index] & processedMask) != 0)
+ continue;
- subbandCoefficients.push({
- width: width,
- height: height,
- items: coefficients
- });
+ var contextLabel = 16;
+ if ((processingFlags[index] &
+ firstMagnitudeBitMask) != 0) {
+ processingFlags[i * width + j] ^= firstMagnitudeBitMask;
+ // first refinement
+ var significance = neighborsSignificance[index];
+ var sumOfSignificance = (significance & 3) +
+ ((significance >> 2) & 3) + ((significance >> 4) & 7);
+ contextLabel = sumOfSignificance >= 1 ? 15 : 14;
+ }
- b++;
- }
- }
+ var cx = contexts[contextLabel];
+ var bit = decoder.readBit(cx);
+ coefficentsMagnitude[index] =
+ (coefficentsMagnitude[index] << 1) | bit;
+ bitsDecoded[index]++;
+ processingFlags[index] |= processedMask;
+ }
+ }
+ }
+ },
+ runCleanupPass: function BitModel_runCleanupPass() {
+ 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;
+ var labels = this.contextLabelTable;
+ var bitsDecoded = this.bitsDecoded;
+ var processingFlags = this.processingFlags;
+ var processedMask = 1;
+ var firstMagnitudeBitMask = 2;
+ var oneRowDown = width;
+ var twoRowsDown = width * 2;
+ var threeRowsDown = width * 3;
+ for (var i0 = 0; i0 < height; i0 += 4) {
+ for (var j = 0; j < width; j++) {
+ var index0 = i0 * width + j;
+ // using the property: labels[neighborsSignificance[index]] == 0
+ // when neighborsSignificance[index] == 0
+ var allEmpty = i0 + 3 < height &&
+ processingFlags[index0] == 0 &&
+ processingFlags[index0 + oneRowDown] == 0 &&
+ processingFlags[index0 + twoRowsDown] == 0 &&
+ processingFlags[index0 + threeRowsDown] == 0 &&
+ neighborsSignificance[index0] == 0 &&
+ neighborsSignificance[index0 + oneRowDown] == 0 &&
+ neighborsSignificance[index0 + twoRowsDown] == 0 &&
+ neighborsSignificance[index0 + threeRowsDown] == 0;
+ var i1 = 0, index = index0;
+ var cx, i;
+ if (allEmpty) {
+ cx = this.runLengthContext;
+ var hasSignificantCoefficent = decoder.readBit(cx);
+ if (!hasSignificantCoefficent) {
+ bitsDecoded[index0]++;
+ bitsDecoded[index0 + oneRowDown]++;
+ bitsDecoded[index0 + twoRowsDown]++;
+ bitsDecoded[index0 + threeRowsDown]++;
+ continue; // next column
+ }
+ cx = this.uniformContext;
+ i1 = (decoder.readBit(cx) << 1) | decoder.readBit(cx);
+ i = i0 + i1;
+ index += i1 * width;
- var transformation = codingStyleParameters.transformation;
- var transform = transformation == 0 ? new IrreversibleTransform() :
- new ReversibleTransform();
- var result = transform.calculate(subbandCoefficients,
- component.tcx0, component.tcy0);
- return {
- left: component.tcx0,
- top: component.tcy0,
- width: result.width,
- height: result.height,
- items: result.items
- };
- }
- function transformComponents(context) {
- var siz = context.SIZ;
- var components = context.components;
- var componentsCount = siz.Csiz;
- 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 sign = this.decodeSignBit(i, j);
+ coefficentsSign[index] = sign;
+ coefficentsMagnitude[index] = 1;
+ this.setNeighborsSignificance(i, j);
+ processingFlags[index] |= firstMagnitudeBitMask;
- // Section G.2.2 Inverse multi component transform
- if (tile.codingStyleDefaultParameters.multipleComponentTransform) {
- 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;
- }
- }
+ index = index0;
+ for (var i2 = i0; i2 <= i; i2++, index += width)
+ bitsDecoded[index]++;
- // 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;
+ i1++;
+ }
+ for (; i1 < 4; i1++, index += width) {
+ i = i0 + i1;
+ if (i >= height)
+ break;
- 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 (coefficentsMagnitude[index] ||
+ (processingFlags[index] & processedMask) != 0)
+ continue;
- // 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;
+ var contextLabel = labels[neighborsSignificance[index]];
+ cx = contexts[contextLabel];
+ var decision = decoder.readBit(cx);
+ if (decision == 1) {
+ var sign = this.decodeSignBit(i, j);
+ coefficentsSign[index] = sign;
+ coefficentsMagnitude[index] = 1;
+ this.setNeighborsSignificance(i, j);
+ processingFlags[index] |= firstMagnitudeBitMask;
+ }
+ bitsDecoded[index]++;
+ }
+ }
}
- result[c].items = data;
}
+ };
- resultImages.push(result);
- }
- return resultImages;
- }
- function initializeTile(context, tileIndex) {
- 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 ?
- context.currentTile.QCC[c] : context.currentTile.QCD;
- component.quantizationParameters = qcdOrQcc;
- var codOrCoc = c in context.currentTile.COC ?
- context.currentTile.COC[c] : context.currentTile.COD;
- component.codingStyleParameters = codOrCoc;
- }
- tile.codingStyleDefaultParameters = context.currentTile.COD;
- }
+ return BitModel;
+ })();
- function JpxImage() {
- this.failOnCorruptedImage = false;
- }
- JpxImage.prototype = {
- load: function jpxImageLoad(url) {
- var xhr = new XMLHttpRequest();
- xhr.open('GET', url, 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);
- },
- parse: function jpxImageParse(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 position = 0, length = data.length;
- while (position < length) {
- var headerSize = 8;
- var lbox = ReadUint(data, position, 4);
- var tbox = ReadUint(data, position + 4, 4);
- position += headerSize;
- if (lbox == 1) {
- lbox = ReadUint(data, position, 8);
- position += 8;
- headerSize += 8;
- }
- if (lbox == 0)
- lbox = length - position + headerSize;
- if (lbox < headerSize)
- error('JPX error: Invalid box field size');
- var dataLength = lbox - headerSize;
- var jumpDataLength = true;
- switch (tbox) {
- case 0x6A501A1A: // 'jP\032\032'
- // TODO
- break;
- case 0x6A703268: // 'jp2h'
- jumpDataLength = false; // parsing child boxes
- break;
- case 0x636F6C72: // 'colr'
- // TODO
- break;
- case 0x6A703263: // 'jp2c'
- this.parseCodestream(data, position, position + dataLength);
- break;
- }
- if (jumpDataLength)
- position += dataLength;
+ // Section F, Discrete wavelet transofrmation
+ var Transform = (function TransformClosure() {
+ function Transform() {
+ }
+ 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);
}
- },
- parseCodestream: function jpxImageParseCodestream(data, start, end) {
- var context = {};
- try {
- var position = start;
- while (position < end) {
- var code = readUint16(data, position);
- position += 2;
+ return ll;
+ };
+ 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 length = 0, j;
- switch (code) {
- case 0xFF4F: // Start of codestream (SOC)
- context.mainHeader = true;
- break;
- case 0xFFD9: // End of codestream (EOC)
- break;
- case 0xFF51: // Image and tile size (SIZ)
- length = readUint16(data, position);
- var siz = {};
- siz.Xsiz = readUint32(data, position + 4);
- siz.Ysiz = readUint32(data, position + 8);
- siz.XOsiz = readUint32(data, position + 12);
- siz.YOsiz = readUint32(data, position + 16);
- siz.XTsiz = readUint32(data, position + 20);
- siz.YTsiz = readUint32(data, position + 24);
- siz.XTOsiz = readUint32(data, position + 28);
- siz.YTOsiz = readUint32(data, position + 32);
- var componentsCount = readUint16(data, position + 36);
- siz.Csiz = componentsCount;
- var components = [];
- j = position + 38;
- for (var i = 0; i < componentsCount; i++) {
- var component = {
- precision: (data[j] & 0x7F) + 1,
- isSigned: !!(data[j] & 0x80),
- XRsiz: data[j + 1],
- YRsiz: data[j + 1]
- };
- calculateComponentDimensions(component, siz);
- components.push(component);
- }
- context.SIZ = siz;
- context.components = components;
- calculateTileGrids(context, components);
- context.QCC = [];
- context.COC = [];
- break;
- case 0xFF5C: // Quantization default (QCD)
- length = readUint16(data, position);
- var qcd = {};
- j = position + 2;
- var sqcd = data[j++];
- var spqcdSize, scalarExpounded;
- switch (sqcd & 0x1F) {
- case 0:
- spqcdSize = 8;
- scalarExpounded = true;
- break;
- case 1:
- spqcdSize = 16;
- scalarExpounded = false;
- break;
- case 2:
- spqcdSize = 16;
- scalarExpounded = true;
- break;
- default:
- throw 'Invalid SQcd value ' + sqcd;
- }
- qcd.noQuantization = spqcdSize == 8;
- qcd.scalarExpounded = scalarExpounded;
- qcd.guardBits = sqcd >> 5;
- var spqcds = [];
- while (j < length + position) {
- var spqcd = {};
- if (spqcdSize == 8) {
- spqcd.epsilon = data[j++] >> 3;
- spqcd.mu = 0;
- } else {
- spqcd.epsilon = data[j] >> 3;
- spqcd.mu = ((data[j] & 0x7) << 8) | data[j + 1];
- j += 2;
- }
- spqcds.push(spqcd);
- }
- qcd.SPqcds = spqcds;
- if (context.mainHeader)
- context.QCD = qcd;
- else {
- context.currentTile.QCD = qcd;
- context.currentTile.QCC = [];
- }
- break;
- case 0xFF5D: // Quantization component (QCC)
- length = readUint16(data, position);
- var qcc = {};
- j = position + 2;
- var cqcc;
- if (context.SIZ.Csiz < 257)
- cqcc = data[j++];
- else {
- cqcc = readUint16(data, j);
- j += 2;
- }
- var sqcd = data[j++];
- var spqcdSize, scalarExpounded;
- switch (sqcd & 0x1F) {
- case 0:
- spqcdSize = 8;
- scalarExpounded = true;
- break;
- case 1:
- spqcdSize = 16;
- scalarExpounded = false;
- break;
- case 2:
- spqcdSize = 16;
- scalarExpounded = true;
- break;
- default:
- throw 'Invalid SQcd value ' + sqcd;
- }
- qcc.noQuantization = spqcdSize == 8;
- qcc.scalarExpounded = scalarExpounded;
- qcc.guardBits = sqcd >> 5;
- var spqcds = [];
- while (j < length + position) {
- var spqcd = {};
- if (spqcdSize == 8) {
- spqcd.epsilon = data[j++] >> 3;
- spqcd.mu = 0;
- } else {
- spqcd.epsilon = data[j] >> 3;
- spqcd.mu = ((data[j] & 0x7) << 8) | data[j + 1];
- j += 2;
- }
- spqcds.push(spqcd);
- }
- qcc.SPqcds = spqcds;
- if (context.mainHeader)
- context.QCC[cqcc] = qcc;
- else
- context.currentTile.QCC[cqcc] = qcc;
- break;
- case 0xFF52: // Coding style default (COD)
- length = readUint16(data, position);
- var cod = {};
- j = position + 2;
- var scod = data[j++];
- 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;
- cod.multipleComponentTransform = data[j++];
+ // Section F.3.3 interleave
+ var width = llWidth + hlWidth;
+ var height = llHeight + lhHeight;
+ var items = new Float32Array(width * height);
+ for (var i = 0, ii = llHeight; i < ii; i++) {
+ var k = i * llWidth, l = i * 2 * width;
+ for (var j = 0, jj = llWidth; j < jj; j++, k++, l += 2)
+ items[l] = llItems[k];
+ }
+ for (var i = 0, ii = hlHeight; i < ii; i++) {
+ var k = i * hlWidth, l = i * 2 * width + 1;
+ for (var j = 0, jj = hlWidth; j < jj; j++, k++, l += 2)
+ items[l] = hlItems[k];
+ }
+ for (var i = 0, ii = lhHeight; i < ii; i++) {
+ var k = i * lhWidth, l = (i * 2 + 1) * width;
+ for (var j = 0, jj = lhWidth; j < jj; j++, k++, l += 2)
+ items[l] = lhItems[k];
+ }
+ for (var i = 0, ii = hhHeight; i < ii; i++) {
+ var k = i * hhWidth, l = (i * 2 + 1) * width + 1;
+ for (var j = 0, jj = hhWidth; j < jj; j++, k++, l += 2)
+ items[l] = hhItems[k];
+ }
- cod.decompositionLevelsCount = data[j++];
- cod.xcb = (data[j++] & 0xF) + 2;
- cod.ycb = (data[j++] & 0xF) + 2;
- var blockStyle = data[j++];
- cod.selectiveArithmeticCodingBypass = !!(blockStyle & 1);
- cod.resetContextProbabilities = !!(blockStyle & 2);
- cod.terminationOnEachCodingPass = !!(blockStyle & 4);
- cod.verticalyStripe = !!(blockStyle & 8);
- cod.predictableTermination = !!(blockStyle & 16);
- cod.segmentationSymbolUsed = !!(blockStyle & 32);
- cod.transformation = data[j++];
- if (cod.entropyCoderWithCustomPrecincts) {
- var precinctsSizes = {};
- while (j < length + position) {
- var precinctsSize = data[j];
- precinctsSizes.push({
- PPx: precinctsSize & 0xF,
- PPy: precinctsSize >> 4
- });
- }
- cod.precinctsSizes = precinctsSizes;
- }
+ var bufferPadding = 4;
+ var bufferLength = new Float32Array(Math.max(width, height) +
+ 2 * bufferPadding);
+ var buffer = new Float32Array(bufferLength);
+ var bufferOut = new Float32Array(bufferLength);
- if (cod.sopMarkerUsed || cod.ephMarkerUsed ||
- cod.selectiveArithmeticCodingBypass ||
- cod.resetContextProbabilities ||
- cod.terminationOnEachCodingPass ||
- cod.verticalyStripe || cod.predictableTermination ||
- cod.segmentationSymbolUsed)
- throw 'Unsupported COD options: ' + uneval(cod);
+ // 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;
+ }
+ continue;
+ }
- if (context.mainHeader)
- context.COD = cod;
- else {
- context.currentTile.COD = cod;
- context.currentTile.COC = [];
- }
- break;
- case 0xFF90: // Start of tile-part (SOT)
- length = readUint16(data, position);
- var tile = {};
- tile.index = readUint16(data, position + 2);
- tile.length = readUint32(data, position + 4);
- tile.dataEnd = tile.length + position - 2;
- tile.partIndex = data[position + 8];
- tile.partsCount = data[position + 9];
+ var k = v * width;
+ var l = bufferPadding;
+ for (var u = 0; u < width; u++, k++, l++)
+ buffer[l] = items[k];
- context.mainHeader = false;
- if (tile.partIndex == 0) {
- // reset component specific settings
- tile.COD = context.COD;
- tile.COC = context.COC.slice(0); // clone of the global COC
- tile.QCD = context.QCD;
- tile.QCC = context.QCC.slice(0); // clone of the global COC
- }
- context.currentTile = tile;
- break;
- case 0xFF93: // Start of data (SOD)
- var tile = context.currentTile;
- if (tile.partIndex == 0) {
- initializeTile(context, tile.index);
- buildPackets(context);
- }
+ // Section F.3.7 extending... using max extension of 4
+ var i1 = bufferPadding - 1, j1 = bufferPadding + 1;
+ var i2 = bufferPadding + width - 2, j2 = bufferPadding + width;
+ buffer[i1--] = buffer[j1++];
+ buffer[j2++] = buffer[i2--];
+ buffer[i1--] = buffer[j1++];
+ buffer[j2++] = buffer[i2--];
+ buffer[i1--] = buffer[j1++];
+ buffer[j2++] = buffer[i2--];
+ buffer[i1--] = buffer[j1++];
+ buffer[j2++] = buffer[i2--];
- // moving to the end of the data
- length = tile.dataEnd - position;
+ this.filter(buffer, bufferPadding, width, u0, bufferOut);
- parseTilePackets(context, data, position, length);
- break;
- case 0xFF64: // Comment (COM)
- length = readUint16(data, position);
- // skipping content
- break;
- default:
- throw 'Unknown codestream code: ' + code.toString(16);
+ k = v * width;
+ l = bufferPadding;
+ for (var u = 0; u < width; u++, k++, l++)
+ items[k] = bufferOut[l];
+ }
+
+ // Section F.3.5 VER_SR
+ for (var u = 0; u < width; u++) {
+ 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;
}
- position += length;
+ continue;
}
- } catch (e) {
- if (this.failOnCorruptedImage)
- error('JPX error: ' + e);
- else
- warn('JPX error: ' + e + '. Trying to recover');
+
+ var k = u;
+ var l = bufferPadding;
+ for (var v = 0; v < height; v++, k += width, l++)
+ buffer[l] = items[k];
+
+ // Section F.3.7 extending... using max extension of 4
+ var i1 = bufferPadding - 1, j1 = bufferPadding + 1;
+ var i2 = bufferPadding + height - 2, j2 = bufferPadding + height;
+ buffer[i1--] = buffer[j1++];
+ buffer[j2++] = buffer[i2--];
+ buffer[i1--] = buffer[j1++];
+ buffer[j2++] = buffer[i2--];
+ buffer[i1--] = buffer[j1++];
+ buffer[j2++] = buffer[i2--];
+ buffer[i1--] = buffer[j1++];
+ buffer[j2++] = buffer[i2--];
+
+ this.filter(buffer, bufferPadding, height, v0, bufferOut);
+
+ k = u;
+ l = bufferPadding;
+ for (var v = 0; v < height; v++, k += width, l++)
+ items[k] = bufferOut[l];
}
- this.tiles = transformComponents(context);
- this.width = context.SIZ.Xsiz - context.SIZ.XOsiz;
- this.height = context.SIZ.Ysiz - context.SIZ.YOsiz;
- this.componentsCount = context.SIZ.Csiz;
+ return {
+ width: width,
+ height: height,
+ items: items
+ };
+ };
+ return Transform;
+ })();
+
+ // Section 3.8.2 Irreversible 9-7 filter
+ var IrreversibleTransform = (function IrreversibleTransformClosure() {
+ function IrreversibleTransform() {
+ Transform.call(this);
}
- };
+
+ 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);
+
+ var alpha = -1.586134342059924;
+ var beta = -0.052980118572961;
+ var gamma = 0.882911075530934;
+ var delta = 0.443506852043971;
+ 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 2
+ var j = offset_ - 3;
+ for (var n = i0_ - 2, nn = i1_ + 2; n < nn; n++, j += 2)
+ x[j] = K_ * y[j];
+
+ // 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 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]);
+
+ // 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]);
+
+ // 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]);
+ };
+
+ return IrreversibleTransform;
+ })();
+
+ // Section 3.8.1 Reversible 5-3 filter
+ var ReversibleTransform = (function ReversibleTransformClosure() {
+ function ReversibleTransform() {
+ Transform.call(this);
+ }
+
+ 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);
+
+ 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 (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);
+ };
+
+ return ReversibleTransform;
+ })();
+
return JpxImage;
})();
+
diff --git a/src/metadata.js b/src/metadata.js
new file mode 100644
index 000000000..f38056168
--- /dev/null
+++ b/src/metadata.js
@@ -0,0 +1,66 @@
+/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
+
+'use strict';
+
+var Metadata = PDFJS.Metadata = (function MetadataClosure() {
+ function Metadata(meta) {
+ if (typeof meta === 'string') {
+ var parser = new DOMParser();
+ meta = parser.parseFromString(meta, 'application/xml');
+ } else if (!(meta instanceof Document)) {
+ error('Metadata: Invalid metadata object');
+ }
+
+ this.metaDocument = meta;
+ this.metadata = {};
+ this.parse();
+ }
+
+ Metadata.prototype = {
+ parse: function Metadata_parse() {
+ var doc = this.metaDocument;
+ var rdf = doc.documentElement;
+
+ if (rdf.nodeName.toLowerCase() !== 'rdf:rdf') { // Wrapped in
+ rdf = rdf.firstChild;
+ while (rdf && rdf.nodeName.toLowerCase() !== 'rdf:rdf')
+ rdf = rdf.nextSibling;
+ }
+
+ var nodeName = (rdf) ? rdf.nodeName.toLowerCase() : null;
+ if (!rdf || nodeName !== 'rdf:rdf' || !rdf.hasChildNodes())
+ return;
+
+ var childNodes = rdf.childNodes, desc, namespace, entries, entry;
+
+ for (var i = 0, length = childNodes.length; i < length; i++) {
+ desc = childNodes[i];
+ if (desc.nodeName.toLowerCase() !== 'rdf:description')
+ continue;
+
+ entries = [];
+ for (var ii = 0, iLength = desc.childNodes.length; ii < iLength; ii++) {
+ if (desc.childNodes[ii].nodeName.toLowerCase() !== '#text')
+ entries.push(desc.childNodes[ii]);
+ }
+
+ for (ii = 0, iLength = entries.length; ii < iLength; ii++) {
+ var entry = entries[ii];
+ var name = entry.nodeName.toLowerCase();
+ this.metadata[name] = entry.textContent.trim();
+ }
+ }
+ },
+
+ get: function Metadata_get(name) {
+ return this.metadata[name] || null;
+ },
+
+ has: function Metadata_has(name) {
+ return typeof this.metadata[name] !== 'undefined';
+ }
+ };
+
+ return Metadata;
+})();
diff --git a/src/obj.js b/src/obj.js
index 3c649fb06..200b40a7f 100644
--- a/src/obj.js
+++ b/src/obj.js
@@ -22,7 +22,7 @@ var Cmd = (function CmdClosure() {
var cmdCache = {};
- Cmd.get = function cmdGet(cmd) {
+ Cmd.get = function Cmd_get(cmd) {
var cmdValue = cmdCache[cmd];
if (cmdValue)
return cmdValue;
@@ -34,36 +34,52 @@ var Cmd = (function CmdClosure() {
})();
var Dict = (function DictClosure() {
- function Dict() {
+ // 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;
}
Dict.prototype = {
- get: function dictGet(key1, key2, key3) {
+ // automatically dereferences Ref objects
+ get: function Dict_get(key1, key2, key3) {
var value;
+ var xref = this.xref;
if (typeof (value = this.map[key1]) != 'undefined' || key1 in this.map ||
typeof key2 == 'undefined') {
- return value;
+ return xref ? this.xref.fetchIfRef(value) : value;
}
if (typeof (value = this.map[key2]) != 'undefined' || key2 in this.map ||
typeof key3 == 'undefined') {
- return value;
+ return xref ? this.xref.fetchIfRef(value) : value;
}
-
- return this.map[key3] || null;
+ value = this.map[key3] || null;
+ return xref ? this.xref.fetchIfRef(value) : value;
+ },
+ // no dereferencing
+ getRaw: function Dict_getRaw(key) {
+ return this.map[key];
+ },
+ // creates new map and dereferences all Refs
+ getAll: function Dict_getAll() {
+ var all = {};
+ for (var key in this.map)
+ all[key] = this.get(key);
+ return all;
},
- set: function dictSet(key, value) {
+ set: function Dict_set(key, value) {
this.map[key] = value;
},
- has: function dictHas(key) {
+ has: function Dict_has(key) {
return key in this.map;
},
- forEach: function dictForEach(callback) {
+ forEach: function Dict_forEach(callback) {
for (var key in this.map) {
- callback(key, this.map[key]);
+ callback(key, this.get(key));
}
}
};
@@ -90,11 +106,11 @@ var RefSet = (function RefSetClosure() {
}
RefSet.prototype = {
- has: function refSetHas(ref) {
+ has: function RefSet_has(ref) {
return !!this.dict['R' + ref.num + '.' + ref.gen];
},
- put: function refSetPut(ref) {
+ put: function RefSet_put(ref) {
this.dict['R' + ref.num + '.' + ref.gen] = ref;
}
};
@@ -111,20 +127,33 @@ var Catalog = (function CatalogClosure() {
}
Catalog.prototype = {
+ get metadata() {
+ var stream = this.catDict.get('Metadata');
+ var metadata;
+ if (stream && isDict(stream.dict)) {
+ var type = stream.dict.get('Type');
+ var subtype = stream.dict.get('Subtype');
+
+ if (isName(type) && isName(subtype) &&
+ type.name === 'Metadata' && subtype.name === 'XML') {
+ metadata = stringToPDFString(bytesToString(stream.getBytes()));
+ }
+ }
+
+ return shadow(this, 'metadata', metadata);
+ },
get toplevelPagesDict() {
var pagesObj = this.catDict.get('Pages');
- assertWellFormed(isRef(pagesObj), 'invalid top-level pages reference');
- var xrefObj = this.xref.fetch(pagesObj);
- assertWellFormed(isDict(xrefObj), 'invalid top-level pages dictionary');
+ assertWellFormed(isDict(pagesObj), 'invalid top-level pages dictionary');
// shadow the prototype getter
- return shadow(this, 'toplevelPagesDict', xrefObj);
+ return shadow(this, 'toplevelPagesDict', pagesObj);
},
get documentOutline() {
var xref = this.xref;
- var obj = xref.fetchIfRef(this.catDict.get('Outlines'));
+ var obj = this.catDict.get('Outlines');
var root = { items: [] };
if (isDict(obj)) {
- obj = obj.get('First');
+ obj = obj.getRaw('First');
var processed = new RefSet();
if (isRef(obj)) {
var queue = [{obj: obj, parent: root}];
@@ -133,20 +162,20 @@ var Catalog = (function CatalogClosure() {
processed.put(obj);
while (queue.length > 0) {
var i = queue.shift();
- var outlineDict = xref.fetch(i.obj);
+ var outlineDict = xref.fetchIfRef(i.obj);
if (outlineDict === null)
continue;
if (!outlineDict.has('Title'))
error('Invalid outline item');
var dest = outlineDict.get('A');
if (dest)
- dest = xref.fetchIfRef(dest).get('D');
+ dest = dest.get('D');
else if (outlineDict.has('Dest')) {
- dest = outlineDict.get('Dest');
+ dest = outlineDict.getRaw('Dest');
if (isName(dest))
dest = dest.name;
}
- var title = xref.fetchIfRef(outlineDict.get('Title'));
+ var title = outlineDict.get('Title');
var outlineItem = {
dest: dest,
title: stringToPDFString(title),
@@ -157,12 +186,12 @@ var Catalog = (function CatalogClosure() {
items: []
};
i.parent.items.push(outlineItem);
- obj = outlineDict.get('First');
+ obj = outlineDict.getRaw('First');
if (isRef(obj) && !processed.has(obj)) {
queue.push({obj: obj, parent: outlineItem});
processed.put(obj);
}
- obj = outlineDict.get('Next');
+ obj = outlineDict.getRaw('Next');
if (isRef(obj) && !processed.has(obj)) {
queue.push({obj: obj, parent: i.parent});
processed.put(obj);
@@ -182,7 +211,7 @@ var Catalog = (function CatalogClosure() {
// shadow the prototype getter
return shadow(this, 'num', obj);
},
- traverseKids: function catalogTraverseKids(pagesDict) {
+ traverseKids: function Catalog_traverseKids(pagesDict) {
var pageCache = this.pageCache;
var kids = pagesDict.get('Kids');
assertWellFormed(isArray(kids),
@@ -190,7 +219,7 @@ var Catalog = (function CatalogClosure() {
for (var i = 0, ii = kids.length; i < ii; ++i) {
var kid = kids[i];
assertWellFormed(isRef(kid),
- 'page dictionary kid is not a reference');
+ 'page dictionary kid is not a reference');
var obj = this.xref.fetch(kid);
if (isDict(obj, 'Page') || (isDict(obj) && !obj.has('Kids'))) {
pageCache.push(new Page(this.xref, pageCache.length, obj, kid));
@@ -204,8 +233,7 @@ var Catalog = (function CatalogClosure() {
}
},
get destinations() {
- function fetchDestination(xref, ref) {
- var dest = xref.fetchIfRef(ref);
+ function fetchDestination(dest) {
return isDict(dest) ? dest.get('D') : dest;
}
@@ -213,16 +241,16 @@ var Catalog = (function CatalogClosure() {
var dests = {}, nameTreeRef, nameDictionaryRef;
var obj = this.catDict.get('Names');
if (obj)
- nameTreeRef = xref.fetchIfRef(obj).get('Dests');
+ nameTreeRef = obj.getRaw('Dests');
else if (this.catDict.has('Dests'))
nameDictionaryRef = this.catDict.get('Dests');
if (nameDictionaryRef) {
// reading simple destination dictionary
- obj = xref.fetchIfRef(nameDictionaryRef);
+ obj = nameDictionaryRef;
obj.forEach(function catalogForEach(key, value) {
if (!value) return;
- dests[key] = fetchDestination(xref, value);
+ dests[key] = fetchDestination(value);
});
}
if (nameTreeRef) {
@@ -246,13 +274,13 @@ var Catalog = (function CatalogClosure() {
}
var names = obj.get('Names');
for (i = 0, n = names.length; i < n; i += 2) {
- dests[names[i]] = fetchDestination(xref, names[i + 1]);
+ dests[names[i]] = fetchDestination(xref.fetchIfRef(names[i + 1]));
}
}
}
return shadow(this, 'destinations', dests);
},
- getPage: function catalogGetPage(n) {
+ getPage: function Catalog_getPage(n) {
var pageCache = this.pageCache;
if (!pageCache) {
pageCache = this.pageCache = [];
@@ -271,6 +299,7 @@ var XRef = (function XRefClosure() {
this.entries = [];
this.xrefstms = {};
var trailerDict = this.readXRef(startXRef);
+ trailerDict.xref = this;
this.trailer = trailerDict;
// prepare the XRef cache
this.cache = [];
@@ -278,17 +307,17 @@ var XRef = (function XRefClosure() {
var encrypt = trailerDict.get('Encrypt');
if (encrypt) {
var fileId = trailerDict.get('ID');
- this.encrypt = new CipherTransformFactory(this.fetch(encrypt),
+ this.encrypt = new CipherTransformFactory(encrypt,
fileId[0] /*, password */);
}
// get the root dictionary (catalog) object
- if (!isRef(this.root = trailerDict.get('Root')))
+ if (!(this.root = trailerDict.get('Root')))
error('Invalid root reference');
}
XRef.prototype = {
- readXRefTable: function readXRefTable(parser) {
+ readXRefTable: function XRef_readXRefTable(parser) {
// Example of cross-reference table:
// xref
// 0 1 <-- subsection header (first obj #, obj count)
@@ -355,7 +384,7 @@ var XRef = (function XRefClosure() {
return dict;
},
- readXRefStream: function readXRefStream(stream) {
+ readXRefStream: function XRef_readXRefStream(stream) {
var streamParameters = stream.parameters;
var byteWidths = streamParameters.get('W');
var range = streamParameters.get('Index');
@@ -406,7 +435,7 @@ var XRef = (function XRefClosure() {
}
return streamParameters;
},
- indexObjects: function indexObjects() {
+ indexObjects: function XRef_indexObjects() {
// Simple scan through the PDF content to find objects,
// trailers and XRef streams.
function readToken(data, offset) {
@@ -498,7 +527,7 @@ var XRef = (function XRefClosure() {
var dict;
for (var i = 0, ii = trailers.length; i < ii; ++i) {
stream.pos = trailers[i];
- var parser = new Parser(new Lexer(stream), true);
+ var parser = new Parser(new Lexer(stream), true, null);
var obj = parser.getObj();
if (!isCmd(obj, 'trailer'))
continue;
@@ -515,12 +544,12 @@ var XRef = (function XRefClosure() {
// nothing helps
error('Invalid PDF structure');
},
- readXRef: function readXref(startXRef) {
+ readXRef: function XRef_readXRef(startXRef) {
var stream = this.stream;
stream.pos = startXRef;
try {
- var parser = new Parser(new Lexer(stream), true);
+ var parser = new Parser(new Lexer(stream), true, null);
var obj = parser.getObj();
var dict;
@@ -568,18 +597,19 @@ var XRef = (function XRefClosure() {
warn('Indexing all PDF objects');
return this.indexObjects();
},
- getEntry: function xRefGetEntry(i) {
+ getEntry: function XRef_getEntry(i) {
var e = this.entries[i];
if (e === null)
return null;
return e.free ? null : e; // returns null is the entry is free
},
- fetchIfRef: function xRefFetchIfRef(obj) {
+ fetchIfRef: function XRef_fetchIfRef(obj) {
if (!isRef(obj))
return obj;
return this.fetch(obj);
},
- fetch: function xRefFetch(ref, suppressEncryption) {
+ fetch: function XRef_fetch(ref, suppressEncryption) {
+ assertWellFormed(isRef(ref), 'ref object is not a reference');
var num = ref.num;
if (num in this.cache)
return this.cache[num];
@@ -641,7 +671,7 @@ var XRef = (function XRefClosure() {
if (!isInt(first) || !isInt(n)) {
error('invalid first and n parameters for ObjStm stream');
}
- parser = new Parser(new Lexer(stream), false);
+ parser = new Parser(new Lexer(stream), false, this);
var i, entries = [], nums = [];
// read the object numbers to populate cache
for (i = 0; i < n; ++i) {
@@ -666,8 +696,8 @@ var XRef = (function XRefClosure() {
}
return e;
},
- getCatalogObj: function xRefGetCatalogObj() {
- return this.fetch(this.root);
+ getCatalogObj: function XRef_getCatalogObj() {
+ return this.root;
}
};
@@ -693,7 +723,7 @@ var PDFObjects = (function PDFObjectsClosure() {
* Ensures there is an object defined for `objId`. Stores `data` on the
* object *if* it is created.
*/
- ensureObj: function pdfObjectsEnsureObj(objId, data) {
+ ensureObj: function PDFObjects_ensureObj(objId, data) {
if (this.objs[objId])
return this.objs[objId];
return this.objs[objId] = new Promise(objId, data);
@@ -708,7 +738,7 @@ var PDFObjects = (function PDFObjectsClosure() {
* function and the object is already resolved, the callback gets called
* right away.
*/
- get: function pdfObjectsGet(objId, callback) {
+ get: function PDFObjects_get(objId, callback) {
// If there is a callback, then the get can be async and the object is
// not required to be resolved right now
if (callback) {
@@ -731,7 +761,7 @@ var PDFObjects = (function PDFObjectsClosure() {
/**
* Resolves the object `objId` with optional `data`.
*/
- resolve: function pdfObjectsResolve(objId, data) {
+ resolve: function PDFObjects_resolve(objId, data) {
var objs = this.objs;
// In case there is a promise already on this object, just resolve it.
@@ -742,11 +772,11 @@ var PDFObjects = (function PDFObjectsClosure() {
}
},
- onData: function pdfObjectsOnData(objId, callback) {
+ onData: function PDFObjects_onData(objId, callback) {
this.ensureObj(objId).onData(callback);
},
- isResolved: function pdfObjectsIsResolved(objId) {
+ isResolved: function PDFObjects_isResolved(objId) {
var objs = this.objs;
if (!objs[objId]) {
return false;
@@ -755,7 +785,7 @@ var PDFObjects = (function PDFObjectsClosure() {
}
},
- hasData: function pdfObjectsHasData(objId) {
+ hasData: function PDFObjects_hasData(objId) {
var objs = this.objs;
if (!objs[objId]) {
return false;
@@ -767,7 +797,7 @@ var PDFObjects = (function PDFObjectsClosure() {
/**
* Sets the data of an object but *doesn't* resolve it.
*/
- setData: function pdfObjectsSetData(objId, data) {
+ setData: function PDFObjects_setData(objId, data) {
// Watchout! If you call `this.ensureObj(objId, data)` you're going to
// create a *resolved* promise which shouldn't be the case!
this.ensureObj(objId).data = data;
diff --git a/src/parser.js b/src/parser.js
index fad8b2c03..1c50d0f5f 100644
--- a/src/parser.js
+++ b/src/parser.js
@@ -19,11 +19,11 @@ var Parser = (function ParserClosure() {
}
Parser.prototype = {
- refill: function parserRefill() {
+ refill: function Parser_refill() {
this.buf1 = this.lexer.getObj();
this.buf2 = this.lexer.getObj();
},
- shift: function parserShift() {
+ shift: function Parser_shift() {
if (isCmd(this.buf2, 'ID')) {
this.buf1 = this.buf2;
this.buf2 = null;
@@ -34,7 +34,7 @@ var Parser = (function ParserClosure() {
this.buf2 = this.lexer.getObj();
}
},
- getObj: function parserGetObj(cipherTransform) {
+ getObj: function Parser_getObj(cipherTransform) {
if (isCmd(this.buf1, 'BI')) { // inline image
this.shift();
return this.makeInlineImage(cipherTransform);
@@ -51,7 +51,7 @@ var Parser = (function ParserClosure() {
}
if (isCmd(this.buf1, '<<')) { // dictionary or stream
this.shift();
- var dict = new Dict();
+ var dict = new Dict(this.xref);
while (!isCmd(this.buf1, '>>') && !isEOF(this.buf1)) {
if (!isName(this.buf1))
error('Dictionary key must be a name object');
@@ -98,7 +98,7 @@ var Parser = (function ParserClosure() {
this.shift();
return obj;
},
- makeInlineImage: function parserMakeInlineImage(cipherTransform) {
+ makeInlineImage: function Parser_makeInlineImage(cipherTransform) {
var lexer = this.lexer;
var stream = lexer.stream;
@@ -160,11 +160,11 @@ var Parser = (function ParserClosure() {
return imageStream;
},
- fetchIfRef: function parserFetchIfRef(obj) {
+ fetchIfRef: function Parser_fetchIfRef(obj) {
// not relying on the xref.fetchIfRef -- xref might not be set
return isRef(obj) ? this.xref.fetch(obj) : obj;
},
- makeStream: function parserMakeStream(dict, cipherTransform) {
+ makeStream: function Parser_makeStream(dict, cipherTransform) {
var lexer = this.lexer;
var stream = lexer.stream;
@@ -192,7 +192,7 @@ var Parser = (function ParserClosure() {
stream.parameters = dict;
return stream;
},
- filter: function parserFilter(stream, dict, length) {
+ 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))
@@ -215,7 +215,7 @@ var Parser = (function ParserClosure() {
}
return stream;
},
- makeFilter: function parserMakeFilter(stream, name, length, params) {
+ makeFilter: function Parser_makeFilter(stream, name, length, params) {
if (name == 'FlateDecode' || name == 'Fl') {
if (params) {
return new PredictorStream(new FlateStream(stream), params);
@@ -265,7 +265,7 @@ var Lexer = (function LexerClosure() {
this.stream = stream;
}
- Lexer.isSpace = function lexerIsSpace(ch) {
+ Lexer.isSpace = function Lexer_isSpace(ch) {
return ch == ' ' || ch == '\t' || ch == '\x0d' || ch == '\x0a';
};
@@ -300,7 +300,7 @@ var Lexer = (function LexerClosure() {
}
Lexer.prototype = {
- getNumber: function lexerGetNumber(ch) {
+ getNumber: function Lexer_getNumber(ch) {
var floating = false;
var str = ch;
var stream = this.stream;
@@ -328,7 +328,7 @@ var Lexer = (function LexerClosure() {
error('Invalid floating point number: ' + value);
return value;
},
- getString: function lexerGetString() {
+ getString: function Lexer_getString() {
var numParen = 1;
var done = false;
var str = '';
@@ -412,7 +412,7 @@ var Lexer = (function LexerClosure() {
} while (!done);
return str;
},
- getName: function lexerGetName(ch) {
+ getName: function Lexer_getName(ch) {
var str = '';
var stream = this.stream;
while (!!(ch = stream.lookChar()) && !specialChars[ch.charCodeAt(0)]) {
@@ -439,7 +439,7 @@ var Lexer = (function LexerClosure() {
str.length);
return new Name(str);
},
- getHexString: function lexerGetHexString(ch) {
+ getHexString: function Lexer_getHexString(ch) {
var str = '';
var stream = this.stream;
for (;;) {
@@ -468,7 +468,7 @@ var Lexer = (function LexerClosure() {
}
return str;
},
- getObj: function lexerGetObj() {
+ getObj: function Lexer_getObj() {
// skip whitespace and comments
var comment = false;
var stream = this.stream;
@@ -541,7 +541,7 @@ var Lexer = (function LexerClosure() {
return null;
return Cmd.get(str);
},
- skipToNextLine: function lexerSkipToNextLine() {
+ skipToNextLine: function Lexer_skipToNextLine() {
var stream = this.stream;
while (true) {
var ch = stream.getChar();
@@ -554,7 +554,7 @@ var Lexer = (function LexerClosure() {
}
}
},
- skip: function lexerSkip() {
+ skip: function Lexer_skip() {
this.stream.skip();
}
};
@@ -564,7 +564,7 @@ var Lexer = (function LexerClosure() {
var Linearization = (function LinearizationClosure() {
function Linearization(stream) {
- this.parser = new Parser(new Lexer(stream), false);
+ this.parser = new Parser(new Lexer(stream), false, null);
var obj1 = this.parser.getObj();
var obj2 = this.parser.getObj();
var obj3 = this.parser.getObj();
@@ -578,7 +578,7 @@ var Linearization = (function LinearizationClosure() {
}
Linearization.prototype = {
- getInt: function linearizationGetInt(name) {
+ getInt: function Linearization_getInt(name) {
var linDict = this.linDict;
var obj;
if (isDict(linDict) &&
@@ -588,7 +588,7 @@ var Linearization = (function LinearizationClosure() {
}
error('"' + name + '" field in linearization table is invalid');
},
- getHint: function linearizationGetHint(index) {
+ getHint: function Linearization_getHint(index) {
var linDict = this.linDict;
var obj1, obj2;
if (isDict(linDict) &&
diff --git a/src/pattern.js b/src/pattern.js
index e31fdbe3f..9ff4a77bf 100644
--- a/src/pattern.js
+++ b/src/pattern.js
@@ -17,16 +17,16 @@ var Pattern = (function PatternClosure() {
Pattern.prototype = {
// Input: current Canvas context
// Output: the appropriate fillStyle or strokeStyle
- getPattern: function pattern_getStyle(ctx) {
+ getPattern: function Pattern_getPattern(ctx) {
error('Should not call Pattern.getStyle: ' + ctx);
}
};
- Pattern.shadingFromIR = function pattern_shadingFromIR(raw) {
+ Pattern.shadingFromIR = function Pattern_shadingFromIR(raw) {
return Shadings[raw[0]].fromIR(raw);
};
- Pattern.parseShading = function pattern_shading(shading, matrix, xref, res) {
+ Pattern.parseShading = function Pattern_parseShading(shading, matrix, xref, res) {
var dict = isStream(shading) ? shading.dict : shading;
var type = dict.get('ShadingType');
@@ -78,7 +78,6 @@ Shadings.RadialAxial = (function RadialAxialClosure() {
this.extendEnd = extendEnd;
var fnObj = dict.get('Function');
- fnObj = xref.fetchIfRef(fnObj);
if (isArray(fnObj))
error('No support for array of functions');
if (!isPDFFunction(fnObj))
@@ -101,7 +100,7 @@ Shadings.RadialAxial = (function RadialAxialClosure() {
this.colorStops = colorStops;
}
- RadialAxial.fromIR = function radialAxialShadingGetIR(raw) {
+ RadialAxial.fromIR = function RadialAxial_fromIR(raw) {
var type = raw[1];
var colorStops = raw[2];
var p0 = raw[3];
@@ -138,7 +137,7 @@ Shadings.RadialAxial = (function RadialAxialClosure() {
};
RadialAxial.prototype = {
- getIR: function radialAxialShadingGetIR() {
+ getIR: function RadialAxial_getIR() {
var coordsArr = this.coordsArr;
var type = this.shadingType;
if (type == PatternType.AXIAL) {
@@ -173,12 +172,12 @@ Shadings.Dummy = (function DummyClosure() {
this.type = 'Pattern';
}
- Dummy.fromIR = function dummyShadingFromIR() {
+ Dummy.fromIR = function Dummy_fromIR() {
return 'hotpink';
};
Dummy.prototype = {
- getIR: function dummyShadingGetIR() {
+ getIR: function Dummy_getIR() {
return ['Dummy'];
}
};
@@ -267,7 +266,7 @@ var TilingPattern = (function TilingPatternClosure() {
this.canvas = tmpCanvas;
}
- TilingPattern.getIR = function tiling_getIR(operatorList, dict, args) {
+ TilingPattern.getIR = function TilingPattern_getIR(operatorList, dict, args) {
var matrix = dict.get('Matrix');
var bbox = dict.get('BBox');
var xstep = dict.get('XStep');
@@ -280,7 +279,7 @@ var TilingPattern = (function TilingPatternClosure() {
};
TilingPattern.prototype = {
- getPattern: function tiling_getPattern() {
+ getPattern: function TilingPattern_getPattern() {
var matrix = this.matrix;
var curMatrix = this.curMatrix;
var ctx = this.ctx;
diff --git a/src/stream.js b/src/stream.js
index d31f3d50b..48c462fb2 100644
--- a/src/stream.js
+++ b/src/stream.js
@@ -18,14 +18,14 @@ var Stream = (function StreamClosure() {
get length() {
return this.end - this.start;
},
- getByte: function stream_getByte() {
+ getByte: function Stream_getByte() {
if (this.pos >= this.end)
return null;
return this.bytes[this.pos++];
},
// returns subarray of original buffer
// should only be read
- getBytes: function stream_getBytes(length) {
+ getBytes: function Stream_getBytes(length) {
var bytes = this.bytes;
var pos = this.pos;
var strEnd = this.end;
@@ -40,28 +40,28 @@ var Stream = (function StreamClosure() {
this.pos = end;
return bytes.subarray(pos, end);
},
- lookChar: function stream_lookChar() {
+ lookChar: function Stream_lookChar() {
if (this.pos >= this.end)
return null;
return String.fromCharCode(this.bytes[this.pos]);
},
- getChar: function stream_getChar() {
+ getChar: function Stream_getChar() {
if (this.pos >= this.end)
return null;
return String.fromCharCode(this.bytes[this.pos++]);
},
- skip: function stream_skip(n) {
+ skip: function Stream_skip(n) {
if (!n)
n = 1;
this.pos += n;
},
- reset: function stream_reset() {
+ reset: function Stream_reset() {
this.pos = this.start;
},
- moveStart: function stream_moveStart() {
+ moveStart: function Stream_moveStart() {
this.start = this.pos;
},
- makeSubStream: function stream_makeSubstream(start, length, dict) {
+ makeSubStream: function Stream_makeSubStream(start, length, dict) {
return new Stream(this.bytes.buffer, start, length, dict);
},
isStream: true
@@ -94,7 +94,7 @@ var DecodeStream = (function DecodeStreamClosure() {
}
DecodeStream.prototype = {
- ensureBuffer: function decodestream_ensureBuffer(requested) {
+ ensureBuffer: function DecodeStream_ensureBuffer(requested) {
var buffer = this.buffer;
var current = buffer ? buffer.byteLength : 0;
if (requested < current)
@@ -107,7 +107,7 @@ var DecodeStream = (function DecodeStreamClosure() {
buffer2[i] = buffer[i];
return (this.buffer = buffer2);
},
- getByte: function decodestream_getByte() {
+ getByte: function DecodeStream_getByte() {
var pos = this.pos;
while (this.bufferLength <= pos) {
if (this.eof)
@@ -116,7 +116,7 @@ var DecodeStream = (function DecodeStreamClosure() {
}
return this.buffer[this.pos++];
},
- getBytes: function decodestream_getBytes(length) {
+ getBytes: function DecodeStream_getBytes(length) {
var end, pos = this.pos;
if (length) {
@@ -144,7 +144,7 @@ var DecodeStream = (function DecodeStreamClosure() {
this.pos = end;
return this.buffer.subarray(pos, end);
},
- lookChar: function decodestream_lookChar() {
+ lookChar: function DecodeStream_lookChar() {
var pos = this.pos;
while (this.bufferLength <= pos) {
if (this.eof)
@@ -153,7 +153,7 @@ var DecodeStream = (function DecodeStreamClosure() {
}
return String.fromCharCode(this.buffer[this.pos]);
},
- getChar: function decodestream_getChar() {
+ getChar: function DecodeStream_getChar() {
var pos = this.pos;
while (this.bufferLength <= pos) {
if (this.eof)
@@ -162,18 +162,18 @@ var DecodeStream = (function DecodeStreamClosure() {
}
return String.fromCharCode(this.buffer[this.pos++]);
},
- makeSubStream: function decodestream_makeSubstream(start, length, dict) {
+ makeSubStream: function DecodeStream_makeSubStream(start, length, dict) {
var end = start + length;
while (this.bufferLength <= end && !this.eof)
this.readBlock();
return new Stream(this.buffer, start, length, dict);
},
- skip: function decodestream_skip(n) {
+ skip: function DecodeStream_skip(n) {
if (!n)
n = 1;
this.pos += n;
},
- reset: function decodestream_reset() {
+ reset: function DecodeStream_reset() {
this.pos = 0;
}
};
@@ -188,14 +188,14 @@ var FakeStream = (function FakeStreamClosure() {
}
FakeStream.prototype = Object.create(DecodeStream.prototype);
- FakeStream.prototype.readBlock = function fakeStreamReadBlock() {
+ FakeStream.prototype.readBlock = function FakeStream_readBlock() {
var bufferLength = this.bufferLength;
bufferLength += 1024;
var buffer = this.ensureBuffer(bufferLength);
this.bufferLength = bufferLength;
};
- FakeStream.prototype.getBytes = function fakeStreamGetBytes(length) {
+ FakeStream.prototype.getBytes = function FakeStream_getBytes(length) {
var end, pos = this.pos;
if (length) {
@@ -368,7 +368,7 @@ var FlateStream = (function FlateStreamClosure() {
FlateStream.prototype = Object.create(DecodeStream.prototype);
- FlateStream.prototype.getBits = function flateStreamGetBits(bits) {
+ FlateStream.prototype.getBits = function FlateStream_getBits(bits) {
var codeSize = this.codeSize;
var codeBuf = this.codeBuf;
var bytes = this.bytes;
@@ -388,7 +388,7 @@ var FlateStream = (function FlateStreamClosure() {
return b;
};
- FlateStream.prototype.getCode = function flateStreamGetCode(table) {
+ FlateStream.prototype.getCode = function FlateStream_getCode(table) {
var codes = table[0];
var maxLen = table[1];
var codeSize = this.codeSize;
@@ -453,7 +453,7 @@ var FlateStream = (function FlateStreamClosure() {
return [codes, maxLen];
};
- FlateStream.prototype.readBlock = function flateStreamReadBlock() {
+ FlateStream.prototype.readBlock = function FlateStream_readBlock() {
// read block header
var hdr = this.getBits(3);
if (hdr & 1)
@@ -823,7 +823,7 @@ var JpegStream = (function JpegStreamClosure() {
JpegStream.prototype = Object.create(DecodeStream.prototype);
- JpegStream.prototype.ensureBuffer = function jpegStreamEnsureBuffer(req) {
+ JpegStream.prototype.ensureBuffer = function JpegStream_ensureBuffer(req) {
if (this.bufferLength)
return;
try {
@@ -840,18 +840,18 @@ var JpegStream = (function JpegStreamClosure() {
error('JPEG error: ' + e);
}
};
- JpegStream.prototype.getIR = function jpegStreamGetIR() {
+ JpegStream.prototype.getIR = function JpegStream_getIR() {
return bytesToString(this.bytes);
};
- JpegStream.prototype.getChar = function jpegStreamGetChar() {
+ JpegStream.prototype.getChar = function JpegStream_getChar() {
error('internal error: getChar is not valid on JpegStream');
};
/**
* Checks if the image can be decoded and displayed by the browser without any
* further processing such as color space conversions.
*/
- JpegStream.prototype.isNativelySupported = function isNativelySupported(xref,
- res) {
+ JpegStream.prototype.isNativelySupported =
+ function JpegStream_isNativelySupported(xref, res) {
var cs = ColorSpace.parse(this.dict.get('ColorSpace'), xref, res);
// when bug 674619 lands, let's check if browser can do
// normal cmyk and then we won't need to decode in JS
@@ -865,8 +865,8 @@ var JpegStream = (function JpegStreamClosure() {
/**
* Checks if the image can be decoded by the browser.
*/
- JpegStream.prototype.isNativelyDecodable = function isNativelyDecodable(xref,
- res) {
+ JpegStream.prototype.isNativelyDecodable =
+ function JpegStream_isNativelyDecodable(xref, res) {
var cs = ColorSpace.parse(this.dict.get('ColorSpace'), xref, res);
var numComps = cs.numComps;
if (numComps == 1 || numComps == 3)
@@ -892,7 +892,7 @@ var JpxStream = (function JpxStreamClosure() {
JpxStream.prototype = Object.create(DecodeStream.prototype);
- JpxStream.prototype.ensureBuffer = function jpxStreamEnsureBuffer(req) {
+ JpxStream.prototype.ensureBuffer = function JpxStream_ensureBuffer(req) {
if (this.bufferLength)
return;
@@ -972,7 +972,7 @@ var JpxStream = (function JpxStreamClosure() {
this.buffer = data;
this.bufferLength = data.length;
};
- JpxStream.prototype.getChar = function jpxStreamGetChar() {
+ JpxStream.prototype.getChar = function JpxStream_getChar() {
error('internal error: getChar is not valid on JpxStream');
};
@@ -992,7 +992,7 @@ var DecryptStream = (function DecryptStreamClosure() {
DecryptStream.prototype = Object.create(DecodeStream.prototype);
- DecryptStream.prototype.readBlock = function decryptStreamReadBlock() {
+ DecryptStream.prototype.readBlock = function DecryptStream_readBlock() {
var chunk = this.str.getBytes(chunkSize);
if (!chunk || chunk.length == 0) {
this.eof = true;
@@ -1023,7 +1023,7 @@ var Ascii85Stream = (function Ascii85StreamClosure() {
Ascii85Stream.prototype = Object.create(DecodeStream.prototype);
- Ascii85Stream.prototype.readBlock = function ascii85StreamReadBlock() {
+ Ascii85Stream.prototype.readBlock = function Ascii85Stream_readBlock() {
var tildaCode = '~'.charCodeAt(0);
var zCode = 'z'.charCodeAt(0);
var str = this.str;
@@ -1118,7 +1118,7 @@ var AsciiHexStream = (function AsciiHexStreamClosure() {
AsciiHexStream.prototype = Object.create(DecodeStream.prototype);
- AsciiHexStream.prototype.readBlock = function asciiHexStreamReadBlock() {
+ AsciiHexStream.prototype.readBlock = function AsciiHexStream_readBlock() {
var gtCode = '>'.charCodeAt(0), bytes = this.str.getBytes(), c, n,
decodeLength, buffer, bufferLength, i, length;
@@ -1161,7 +1161,7 @@ var RunLengthStream = (function RunLengthStreamClosure() {
RunLengthStream.prototype = Object.create(DecodeStream.prototype);
- RunLengthStream.prototype.readBlock = function runLengthStreamReadBlock() {
+ RunLengthStream.prototype.readBlock = function RunLengthStream_readBlock() {
// The repeatHeader has following format. The first byte defines type of run
// and amount of bytes to repeat/copy: n = 0 through 127 - copy next n bytes
// (in addition to the second byte from the header), n = 129 through 255 -
@@ -1671,7 +1671,7 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
CCITTFaxStream.prototype = Object.create(DecodeStream.prototype);
- CCITTFaxStream.prototype.readBlock = function ccittFaxStreamReadBlock() {
+ CCITTFaxStream.prototype.readBlock = function CCITTFaxStream_readBlock() {
while (!this.eof) {
var c = this.lookChar();
this.buf = EOF;
@@ -1729,7 +1729,7 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
this.codingPos = codingPos;
};
- CCITTFaxStream.prototype.lookChar = function ccittFaxStreamLookChar() {
+ CCITTFaxStream.prototype.lookChar = function CCITTFaxStream_lookChar() {
if (this.buf != EOF)
return this.buf;
@@ -2140,7 +2140,7 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
return 1;
};
- CCITTFaxStream.prototype.lookBits = function ccittFaxStreamLookBits(n) {
+ CCITTFaxStream.prototype.lookBits = function CCITTFaxStream_lookBits(n) {
var c;
while (this.inputBits < n) {
if ((c = this.str.getByte()) == null) {
@@ -2155,7 +2155,7 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
return (this.inputBuf >> (this.inputBits - n)) & (0xFFFF >> (16 - n));
};
- CCITTFaxStream.prototype.eatBits = function ccittFaxStreamEatBits(n) {
+ CCITTFaxStream.prototype.eatBits = function CCITTFaxStream_eatBits(n) {
if ((this.inputBits -= n) < 0)
this.inputBits = 0;
};
@@ -2192,7 +2192,7 @@ var LZWStream = (function LZWStreamClosure() {
LZWStream.prototype = Object.create(DecodeStream.prototype);
- LZWStream.prototype.readBits = function lzwStreamReadBits(n) {
+ LZWStream.prototype.readBits = function LZWStream_readBits(n) {
var bitsCached = this.bitsCached;
var cachedData = this.cachedData;
while (bitsCached < n) {
@@ -2210,7 +2210,7 @@ var LZWStream = (function LZWStreamClosure() {
return (cachedData >>> bitsCached) & ((1 << n) - 1);
};
- LZWStream.prototype.readBlock = function lzwStreamReadBlock() {
+ LZWStream.prototype.readBlock = function LZWStream_readBlock() {
var blockSize = 512;
var estimatedDecodedSize = blockSize * 2, decodedSizeDelta = blockSize;
var i, j, q;
diff --git a/src/util.js b/src/util.js
index 243d66262..de7f3c1d5 100644
--- a/src/util.js
+++ b/src/util.js
@@ -79,19 +79,19 @@ var IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0];
var Util = (function UtilClosure() {
function Util() {}
- Util.makeCssRgb = function makergb(r, g, b) {
+ Util.makeCssRgb = function Util_makeCssRgb(r, g, b) {
var ri = (255 * r) | 0, gi = (255 * g) | 0, bi = (255 * b) | 0;
return 'rgb(' + ri + ',' + gi + ',' + bi + ')';
};
- Util.makeCssCmyk = function makecmyk(c, m, y, k) {
+ Util.makeCssCmyk = function Util_makeCssCmyk(c, m, y, k) {
c = (new DeviceCmykCS()).getRgb([c, m, y, k]);
var ri = (255 * c[0]) | 0, gi = (255 * c[1]) | 0, bi = (255 * c[2]) | 0;
return 'rgb(' + ri + ',' + gi + ',' + bi + ')';
};
// For 2d affine transforms
- Util.applyTransform = function apply(p, m) {
+ Util.applyTransform = function Util_applyTransform(p, m) {
var xt = p[0] * m[0] + p[1] * m[2] + m[4];
var yt = p[0] * m[1] + p[1] * m[3] + m[5];
return [xt, yt];
@@ -103,7 +103,7 @@ var Util = (function UtilClosure() {
// | g h i | | Z |
// M is assumed to be serialized as [a,b,c,d,e,f,g,h,i],
// with v as [X,Y,Z]
- Util.apply3dTransform = function apply3d(m, v) {
+ Util.apply3dTransform = function Util_apply3dTransform(m, v) {
return [
m[0] * v[0] + m[1] * v[1] + m[2] * v[2],
m[3] * v[0] + m[4] * v[1] + m[5] * v[2],
@@ -115,7 +115,7 @@ var Util = (function UtilClosure() {
// For coordinate systems whose origin lies in the bottom-left, this
// means normalization to (BL,TR) ordering. For systems with origin in the
// top-left, this means (TL,BR) ordering.
- Util.normalizeRect = function normalizeRect(rect) {
+ Util.normalizeRect = function Util_normalizeRect(rect) {
var r = rect.slice(0); // clone rect
if (rect[0] > rect[2]) {
r[0] = rect[2];
@@ -131,7 +131,7 @@ var Util = (function UtilClosure() {
// Returns a rectangle [x1, y1, x2, y2] corresponding to the
// intersection of rect1 and rect2. If no intersection, returns 'false'
// The rectangle coordinates of rect1, rect2 should be [x1, y1, x2, y2]
- Util.intersect = function intersect(rect1, rect2) {
+ Util.intersect = function Util_intersect(rect1, rect2) {
function compare(a, b) {
return a - b;
};
@@ -167,7 +167,7 @@ var Util = (function UtilClosure() {
return result;
}
- Util.sign = function sign(num) {
+ Util.sign = function Util_sign(num) {
return num < 0 ? -1 : 1;
};
@@ -304,7 +304,7 @@ var Promise = (function PromiseClosure() {
* @param {Promise[]} promises Array of promises to wait for.
* @return {Promise} New dependant promise.
*/
- Promise.all = function(promises) {
+ Promise.all = function Promise_all(promises) {
var deferred = new Promise();
var unresolved = promises.length;
var results = [];
@@ -351,7 +351,7 @@ var Promise = (function PromiseClosure() {
return this._data;
},
- onData: function promiseOnData(callback) {
+ onData: function Promise_onData(callback) {
if (this._data !== EMPTY_PROMISE) {
callback(this._data);
} else {
@@ -359,7 +359,7 @@ var Promise = (function PromiseClosure() {
}
},
- resolve: function promiseResolve(data) {
+ resolve: function Promise_resolve(data) {
if (this.isResolved) {
error('A Promise can be resolved only once ' + this.name);
}
@@ -376,7 +376,7 @@ var Promise = (function PromiseClosure() {
}
},
- reject: function proimseReject(reason) {
+ reject: function Promise_reject(reason) {
if (this.isRejected) {
error('A Promise can be rejected only once ' + this.name);
}
@@ -393,7 +393,7 @@ var Promise = (function PromiseClosure() {
}
},
- then: function promiseThen(callback, errback) {
+ then: function Promise_then(callback, errback) {
if (!callback) {
error('Requiring callback' + this.name);
}
@@ -428,14 +428,14 @@ var StatTimer = (function StatTimerClosure() {
this.enabled = true;
}
StatTimer.prototype = {
- time: function statTimerTime(name) {
+ time: function StatTimer_time(name) {
if (!this.enabled)
return;
if (name in this.started)
throw 'Timer is already running for ' + name;
this.started[name] = Date.now();
},
- timeEnd: function statTimerTimeEnd(name) {
+ timeEnd: function StatTimer_timeEnd(name) {
if (!this.enabled)
return;
if (!(name in this.started))
@@ -448,7 +448,7 @@ var StatTimer = (function StatTimerClosure() {
// Remove timer from started so it can be called again.
delete this.started[name];
},
- toString: function statTimerToString() {
+ toString: function StatTimer_toString() {
var times = this.times;
var out = '';
// Find the longest name for padding purposes.
diff --git a/src/utils/fonts_utils.js b/src/utils/fonts_utils.js
index 2a1f0ea72..65c02fce2 100644
--- a/src/utils/fonts_utils.js
+++ b/src/utils/fonts_utils.js
@@ -122,9 +122,9 @@ function readFontDictData(aString, aMap) {
token = '';
var parsed = false;
while (!parsed) {
- var byte = aString[i++];
+ var octet = aString[i++];
- var nibbles = [parseInt(byte / 16, 10), parseInt(byte % 16, 10)];
+ var nibbles = [parseInt(octet / 16, 10), parseInt(octet % 16, 10)];
for (var j = 0; j < nibbles.length; j++) {
var nibble = nibbles[j];
switch (nibble) {
@@ -336,7 +336,7 @@ var Type2Parser = function type2Parser(aFilePath) {
var privateDict = [];
for (var i = 0; i < priv.size; i++)
privateDict.push(aStream.getByte());
- dump('private:' + privateDict);
+ dump('privateData:' + privateDict);
parseAsToken(privateDict, CFFDictPrivateDataMap);
for (var p in font.map)
diff --git a/test/driver.js b/test/driver.js
index 5a3263bda..a1dc4b242 100644
--- a/test/driver.js
+++ b/test/driver.js
@@ -248,16 +248,21 @@ function done() {
}
}
-function sendTaskResult(snapshot, task, failure) {
- var result = { browser: browser,
- id: task.id,
- numPages: task.pdfDoc ?
- (task.pageLimit || task.pdfDoc.numPages) : 0,
- failure: failure,
- file: task.file,
- round: task.round,
- page: task.pageNum,
- snapshot: snapshot };
+function sendTaskResult(snapshot, task, failure, result) {
+ // Optional result argument is for retrying XHR requests - see below
+ if (!result) {
+ result = JSON.stringify({
+ browser: browser,
+ id: task.id,
+ numPages: task.pdfDoc ?
+ (task.pageLimit || task.pdfDoc.numPages) : 0,
+ failure: failure,
+ file: task.file,
+ round: task.round,
+ page: task.pageNum,
+ snapshot: snapshot
+ });
+ }
var r = new XMLHttpRequest();
// (The POST URI is ignored atm.)
@@ -266,10 +271,13 @@ function sendTaskResult(snapshot, task, failure) {
r.onreadystatechange = function sendTaskResultOnreadystatechange(e) {
if (r.readyState == 4) {
inFlightRequests--;
+ // Retry until successful
+ if (r.status !== 200)
+ sendTaskResult(null, null, null, result);
}
};
document.getElementById('inFlightCount').innerHTML = inFlightRequests++;
- r.send(JSON.stringify(result));
+ r.send(result);
}
function clear(ctx) {
diff --git a/test/pdfs/wnv_chinese.pdf.link b/test/pdfs/wnv_chinese.pdf.link
index fbbc81760..0bd2af8f6 100644
--- a/test/pdfs/wnv_chinese.pdf.link
+++ b/test/pdfs/wnv_chinese.pdf.link
@@ -1 +1 @@
-http://www.cdc.gov/ncidod/dvbid/westnile/languages/chinese.pdf
+http://web.archive.org/web/20110623114753/http://www.cdc.gov/ncidod/dvbid/westnile/languages/chinese.pdf
diff --git a/web/viewer.css b/web/viewer.css
index fdce0288a..9a0cf388c 100644
--- a/web/viewer.css
+++ b/web/viewer.css
@@ -391,11 +391,43 @@ canvas {
}
}
-#loading {
+#loadingBox {
margin: 100px 0;
text-align: center;
}
+#loadingBar {
+ background-color: #333;
+ display: inline-block;
+ border: 1px solid black;
+ clear: both;
+ margin:0px;
+ line-height: 0;
+ border-radius: 4px;
+ width: 15em;
+ height: 1.5em;
+}
+
+#loadingBar .progress {
+ background-color: green;
+ display: inline-block;
+ float: left;
+
+ background: #b4e391;
+ background: -moz-linear-gradient(top, #b4e391 0%, #61c419 50%, #b4e391 100%);
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#b4e391), color-stop(50%,#61c419), color-stop(100%,#b4e391));
+ background: -webkit-linear-gradient(top, #b4e391 0%,#61c419 50%,#b4e391 100%);
+ background: -o-linear-gradient(top, #b4e391 0%,#61c419 50%,#b4e391 100%);
+ background: -ms-linear-gradient(top, #b4e391 0%,#61c419 50%,#b4e391 100%);
+ background: linear-gradient(top, #b4e391 0%,#61c419 50%,#b4e391 100%);
+
+ border-top-left-radius: 3px;
+ border-bottom-left-radius: 3px;
+
+ width: 0%;
+ height: 100%;
+}
+
#PDFBug {
font-size: 10px;
position: fixed;
diff --git a/web/viewer.html b/web/viewer.html
index 34b2e77cb..d275f77c1 100644
--- a/web/viewer.html
+++ b/web/viewer.html
@@ -11,6 +11,7 @@
+
@@ -142,7 +143,10 @@
- Loading... 0%
+