update
This commit is contained in:
178
.obsidian/pdfjs/pdfextract/pdfjs/LICENSE
vendored
Normal file
178
.obsidian/pdfjs/pdfextract/pdfjs/LICENSE
vendored
Normal file
@@ -0,0 +1,178 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
138
.obsidian/pdfjs/pdfextract/pdfjs/README.md
vendored
Normal file
138
.obsidian/pdfjs/pdfextract/pdfjs/README.md
vendored
Normal file
@@ -0,0 +1,138 @@
|
||||
# PDF.js
|
||||
|
||||
PDF.js is a Portable Document Format (PDF) viewer that is built with HTML5.
|
||||
|
||||
PDF.js is community-driven and supported by Mozilla Labs. Our goal is to
|
||||
create a general-purpose, web standards-based platform for parsing and
|
||||
rendering PDFs.
|
||||
|
||||
## Contributing
|
||||
|
||||
PDF.js is an open source project and always looking for more contributors. To
|
||||
get involved checkout:
|
||||
|
||||
+ [Workflow](https://github.com/mozilla/pdf.js/wiki/Contributing)
|
||||
+ [Style Guide](https://github.com/mozilla/pdf.js/wiki/Style-Guide)
|
||||
+ [FAQ](https://github.com/mozilla/pdf.js/wiki/Frequently-Asked-Questions)
|
||||
+ [Good Beginner Bugs](https://github.com/mozilla/pdf.js/issues?direction=desc&labels=5-good-beginner-bug&page=1&sort=created&state=open)
|
||||
+ [Priorities](https://github.com/mozilla/pdf.js/milestones)
|
||||
+ [Attend a Public Meeting](https://github.com/mozilla/pdf.js/wiki/Weekly-Public-Meetings)
|
||||
|
||||
For further questions or guidance feel free to stop by #pdfjs on
|
||||
irc.mozilla.org.
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Online demo
|
||||
|
||||
+ http://mozilla.github.io/pdf.js/web/viewer.html
|
||||
|
||||
### Browser Extensions
|
||||
|
||||
#### Firefox
|
||||
|
||||
PDF.js is built into version 19+ of Firefox, however two extensions are still
|
||||
available that are updated at a different rate:
|
||||
|
||||
+ [Development Version](http://mozilla.github.io/pdf.js/extensions/firefox/pdf.js.xpi) - This version is updated every time new code is merged into the PDF.js codebase. This should be quite stable but still might break from time to time.
|
||||
+ [Stable Version](https://addons.mozilla.org/firefox/addon/pdfjs) - After version 24 of Firefox is released we no longer plan to support the stable extension. The stable version will then be considered whatever is built into Firefox.
|
||||
|
||||
#### Chrome and Opera
|
||||
|
||||
The Chromium extension is still somewhat experimental but it can be installed two
|
||||
ways:
|
||||
|
||||
+ [Unofficial Version](https://chrome.google.com/webstore/detail/pdf-viewer/oemmndcbldboiebfnladdacbdfmadadm) - *This extension is maintained by a PDF.js contributor.*
|
||||
+ Build Your Own - Get the code as explained below and issue `node make chromium`. Then open
|
||||
Chrome, go to `Tools > Extension` and load the (unpackaged) extension from the
|
||||
directory `build/chromium`.
|
||||
|
||||
The version of the extension for the Opera browser can be found at the [Opera add-ons catalog](https://addons.opera.com/en/extensions/details/pdf-viewer/).
|
||||
|
||||
## Getting the Code
|
||||
|
||||
To get a local copy of the current code, clone it using git:
|
||||
|
||||
$ git clone git://github.com/mozilla/pdf.js.git pdfjs
|
||||
$ cd pdfjs
|
||||
|
||||
Next, you need to start a local web server as some browsers don't allow opening
|
||||
PDF files for a file:// url:
|
||||
|
||||
$ node make server
|
||||
|
||||
You can install Node via [nvm](https://github.com/creationix/nvm) or the
|
||||
[official package](http://nodejs.org). If everything worked out, you can now
|
||||
serve
|
||||
|
||||
+ http://localhost:8888/web/viewer.html
|
||||
|
||||
You can also view all the test pdf files on the right side serving
|
||||
|
||||
+ http://localhost:8888/test/pdfs/?frame
|
||||
|
||||
## Building PDF.js
|
||||
|
||||
In order to bundle all `src/` files into two productions scripts and build the generic
|
||||
viewer, issue:
|
||||
|
||||
$ node make generic
|
||||
|
||||
This will generate `pdf.js` and `pdf.worker.js` in the `build/generic/build/` directory.
|
||||
Both scripts are needed but only `pdf.js` needs to be included since `pdf.worker.js` will
|
||||
be loaded by `pdf.js`. If you want to support more browsers than Firefox you'll also need
|
||||
to include `compatibility.js` from `build/generic/web/`. The PDF.js files are large and
|
||||
should be minified for production.
|
||||
|
||||
## Learning
|
||||
|
||||
You can play with the PDF.js API directly from your browser through the live
|
||||
demos below:
|
||||
|
||||
+ [Hello world](http://mozilla.github.io/pdf.js/examples/learning/helloworld.html)
|
||||
+ [Simple reader with prev/next page controls](http://mozilla.github.io/pdf.js/examples/learning/prevnext.html)
|
||||
|
||||
The repo contains a hello world example that you can run locally:
|
||||
|
||||
+ [examples/helloworld/](https://github.com/mozilla/pdf.js/blob/master/examples/helloworld/)
|
||||
|
||||
For an introduction to the PDF.js code, check out the presentation by our
|
||||
contributor Julian Viereck:
|
||||
|
||||
+ http://www.youtube.com/watch?v=Iv15UY-4Fg8
|
||||
|
||||
You can read more about PDF.js here:
|
||||
|
||||
+ http://andreasgal.com/2011/06/15/pdf-js/
|
||||
+ http://blog.mozilla.com/cjones/2011/06/15/overview-of-pdf-js-guts/
|
||||
|
||||
Even more learning resources can be found at:
|
||||
|
||||
+ https://github.com/mozilla/pdf.js/wiki/Additional-Learning-Resources
|
||||
|
||||
## Questions
|
||||
|
||||
Check out our FAQs and get answers to common questions:
|
||||
|
||||
+ https://github.com/mozilla/pdf.js/wiki/Frequently-Asked-Questions
|
||||
|
||||
Talk to us on IRC:
|
||||
|
||||
+ #pdfjs on irc.mozilla.org
|
||||
|
||||
Join our mailing list:
|
||||
|
||||
+ dev-pdf-js@lists.mozilla.org
|
||||
|
||||
Subscribe either using lists.mozilla.org or Google Groups:
|
||||
|
||||
+ https://lists.mozilla.org/listinfo/dev-pdf-js
|
||||
+ https://groups.google.com/group/mozilla.dev.pdf-js/topics
|
||||
|
||||
Follow us on twitter: @pdfjs
|
||||
|
||||
+ http://twitter.com/#!/pdfjs
|
||||
|
||||
Weekly Public Meetings
|
||||
|
||||
+ https://github.com/mozilla/pdf.js/wiki/Weekly-Public-Meetings
|
562
.obsidian/pdfjs/pdfextract/pdfjs/src/core/annotation.js
vendored
Normal file
562
.obsidian/pdfjs/pdfextract/pdfjs/src/core/annotation.js
vendored
Normal file
@@ -0,0 +1,562 @@
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
/* Copyright 2012 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/* globals PDFJS, Util, isDict, isName, stringToPDFString, warn, Dict, Stream,
|
||||
stringToBytes, assert, Promise, isArray, ObjectLoader, OperatorList,
|
||||
isValidUrl, OPS, createPromiseCapability, AnnotationType */
|
||||
|
||||
'use strict';
|
||||
|
||||
var DEFAULT_ICON_SIZE = 22; // px
|
||||
var SUPPORTED_TYPES = ['Link', 'Text', 'Widget'];
|
||||
|
||||
var Annotation = (function AnnotationClosure() {
|
||||
// 12.5.5: Algorithm: Appearance streams
|
||||
function getTransformMatrix(rect, bbox, matrix) {
|
||||
var bounds = Util.getAxialAlignedBoundingBox(bbox, matrix);
|
||||
var minX = bounds[0];
|
||||
var minY = bounds[1];
|
||||
var maxX = bounds[2];
|
||||
var maxY = bounds[3];
|
||||
|
||||
if (minX === maxX || minY === maxY) {
|
||||
// From real-life file, bbox was [0, 0, 0, 0]. In this case,
|
||||
// just apply the transform for rect
|
||||
return [1, 0, 0, 1, rect[0], rect[1]];
|
||||
}
|
||||
|
||||
var xRatio = (rect[2] - rect[0]) / (maxX - minX);
|
||||
var yRatio = (rect[3] - rect[1]) / (maxY - minY);
|
||||
return [
|
||||
xRatio,
|
||||
0,
|
||||
0,
|
||||
yRatio,
|
||||
rect[0] - minX * xRatio,
|
||||
rect[1] - minY * yRatio
|
||||
];
|
||||
}
|
||||
|
||||
function getDefaultAppearance(dict) {
|
||||
var appearanceState = dict.get('AP');
|
||||
if (!isDict(appearanceState)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var appearance;
|
||||
var appearances = appearanceState.get('N');
|
||||
if (isDict(appearances)) {
|
||||
var as = dict.get('AS');
|
||||
if (as && appearances.has(as.name)) {
|
||||
appearance = appearances.get(as.name);
|
||||
}
|
||||
} else {
|
||||
appearance = appearances;
|
||||
}
|
||||
return appearance;
|
||||
}
|
||||
|
||||
function Annotation(params) {
|
||||
var dict = params.dict;
|
||||
var data = this.data = {};
|
||||
|
||||
data.subtype = dict.get('Subtype').name;
|
||||
var rect = dict.get('Rect') || [0, 0, 0, 0];
|
||||
data.rect = Util.normalizeRect(rect);
|
||||
data.annotationFlags = dict.get('F');
|
||||
|
||||
if (data.subtype=='Highlight') {
|
||||
var content = dict.get('Contents');
|
||||
data.content = stringToPDFString(content || '');
|
||||
var title = dict.get('T');
|
||||
data.title = stringToPDFString(title || '');
|
||||
}
|
||||
|
||||
// annotation name
|
||||
data.name = dict.get('NM');
|
||||
// modification time
|
||||
data.mtime = dict.get('M');
|
||||
|
||||
// get quad points for annotation
|
||||
data.quadPoints = [];
|
||||
var quadpts = dict.get('QuadPoints') || [];
|
||||
for (var j = 0; j < quadpts.length; j += 8) {
|
||||
// NB: we don't transform the quadpoints here, but later once we know
|
||||
// the user space => device space transformation.
|
||||
var topLeft = {x: quadpts[j + 4], y: quadpts[j + 5]};
|
||||
var bottomRight = {x: quadpts[j + 2], y: quadpts[j + 3]};
|
||||
var quad = {};
|
||||
quad.x = Math.min(topLeft.x, bottomRight.x);
|
||||
quad.y = Math.min(topLeft.y, bottomRight.y);
|
||||
quad.width = Math.abs(topLeft.x - bottomRight.x);
|
||||
quad.height = Math.abs(topLeft.y - bottomRight.y);
|
||||
data.quadPoints.push(quad);
|
||||
}
|
||||
|
||||
var color = dict.get('C');
|
||||
if (isArray(color) && color.length === 3) {
|
||||
// TODO(mack): currently only supporting rgb; need support different
|
||||
// colorspaces
|
||||
data.color = color;
|
||||
} else {
|
||||
data.color = [0, 0, 0];
|
||||
}
|
||||
|
||||
// Some types of annotations have border style dict which has more
|
||||
// info than the border array
|
||||
if (dict.has('BS')) {
|
||||
var borderStyle = dict.get('BS');
|
||||
data.borderWidth = borderStyle.has('W') ? borderStyle.get('W') : 1;
|
||||
} else {
|
||||
var borderArray = dict.get('Border') || [0, 0, 1];
|
||||
data.borderWidth = borderArray[2] || 0;
|
||||
|
||||
// TODO: implement proper support for annotations with line dash patterns.
|
||||
var dashArray = borderArray[3];
|
||||
if (data.borderWidth > 0 && dashArray) {
|
||||
if (!isArray(dashArray)) {
|
||||
// Ignore the border if dashArray is not actually an array,
|
||||
// this is consistent with the behaviour in Adobe Reader.
|
||||
data.borderWidth = 0;
|
||||
} else {
|
||||
var dashArrayLength = dashArray.length;
|
||||
if (dashArrayLength > 0) {
|
||||
// According to the PDF specification: the elements in a dashArray
|
||||
// shall be numbers that are nonnegative and not all equal to zero.
|
||||
var isInvalid = false;
|
||||
var numPositive = 0;
|
||||
for (var i = 0; i < dashArrayLength; i++) {
|
||||
var validNumber = (+dashArray[i] >= 0);
|
||||
if (!validNumber) {
|
||||
isInvalid = true;
|
||||
break;
|
||||
} else if (dashArray[i] > 0) {
|
||||
numPositive++;
|
||||
}
|
||||
}
|
||||
if (isInvalid || numPositive === 0) {
|
||||
data.borderWidth = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.appearance = getDefaultAppearance(dict);
|
||||
data.hasAppearance = !!this.appearance;
|
||||
data.id = params.ref.num;
|
||||
}
|
||||
|
||||
Annotation.prototype = {
|
||||
|
||||
getData: function Annotation_getData() {
|
||||
return this.data;
|
||||
},
|
||||
|
||||
isInvisible: function Annotation_isInvisible() {
|
||||
var data = this.data;
|
||||
if (data && SUPPORTED_TYPES.indexOf(data.subtype) !== -1) {
|
||||
return false;
|
||||
} else {
|
||||
return !!(data &&
|
||||
data.annotationFlags && // Default: not invisible
|
||||
data.annotationFlags & 0x1); // Invisible
|
||||
}
|
||||
},
|
||||
|
||||
isViewable: function Annotation_isViewable() {
|
||||
var data = this.data;
|
||||
return !!(!this.isInvisible() &&
|
||||
data &&
|
||||
(!data.annotationFlags ||
|
||||
!(data.annotationFlags & 0x22)) && // Hidden or NoView
|
||||
data.rect); // rectangle is necessary
|
||||
},
|
||||
|
||||
isPrintable: function Annotation_isPrintable() {
|
||||
var data = this.data;
|
||||
return !!(!this.isInvisible() &&
|
||||
data &&
|
||||
data.annotationFlags && // Default: not printable
|
||||
data.annotationFlags & 0x4 && // Print
|
||||
!(data.annotationFlags & 0x2) && // Hidden
|
||||
data.rect); // rectangle is necessary
|
||||
},
|
||||
|
||||
loadResources: function Annotation_loadResources(keys) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
this.appearance.dict.getAsync('Resources').then(function (resources) {
|
||||
if (!resources) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
var objectLoader = new ObjectLoader(resources.map,
|
||||
keys,
|
||||
resources.xref);
|
||||
objectLoader.load().then(function() {
|
||||
resolve(resources);
|
||||
}, reject);
|
||||
}, reject);
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
getOperatorList: function Annotation_getOperatorList(evaluator) {
|
||||
|
||||
if (!this.appearance) {
|
||||
return Promise.resolve(new OperatorList());
|
||||
}
|
||||
|
||||
var data = this.data;
|
||||
|
||||
var appearanceDict = this.appearance.dict;
|
||||
var resourcesPromise = this.loadResources([
|
||||
'ExtGState',
|
||||
'ColorSpace',
|
||||
'Pattern',
|
||||
'Shading',
|
||||
'XObject',
|
||||
'Font'
|
||||
// ProcSet
|
||||
// Properties
|
||||
]);
|
||||
var bbox = appearanceDict.get('BBox') || [0, 0, 1, 1];
|
||||
var matrix = appearanceDict.get('Matrix') || [1, 0, 0, 1, 0 ,0];
|
||||
var transform = getTransformMatrix(data.rect, bbox, matrix);
|
||||
var self = this;
|
||||
|
||||
return resourcesPromise.then(function(resources) {
|
||||
var opList = new OperatorList();
|
||||
opList.addOp(OPS.beginAnnotation, [data.rect, transform, matrix]);
|
||||
return evaluator.getOperatorList(self.appearance, resources, opList).
|
||||
then(function () {
|
||||
opList.addOp(OPS.endAnnotation, []);
|
||||
self.appearance.reset();
|
||||
return opList;
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Annotation.getConstructor =
|
||||
function Annotation_getConstructor(subtype, fieldType) {
|
||||
|
||||
if (!subtype) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO(mack): Implement FreeText annotations
|
||||
if (subtype === 'Link') {
|
||||
return LinkAnnotation;
|
||||
} else if (subtype === 'Text') {
|
||||
return TextAnnotation;
|
||||
} else if (subtype === 'Widget') {
|
||||
if (!fieldType) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (fieldType === 'Tx') {
|
||||
return TextWidgetAnnotation;
|
||||
} else {
|
||||
return WidgetAnnotation;
|
||||
}
|
||||
} else {
|
||||
return Annotation;
|
||||
}
|
||||
};
|
||||
|
||||
Annotation.fromRef = function Annotation_fromRef(xref, ref) {
|
||||
|
||||
var dict = xref.fetchIfRef(ref);
|
||||
if (!isDict(dict)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var subtype = dict.get('Subtype');
|
||||
subtype = isName(subtype) ? subtype.name : '';
|
||||
if (!subtype) {
|
||||
return;
|
||||
}
|
||||
|
||||
var fieldType = Util.getInheritableProperty(dict, 'FT');
|
||||
fieldType = isName(fieldType) ? fieldType.name : '';
|
||||
|
||||
var Constructor = Annotation.getConstructor(subtype, fieldType);
|
||||
if (!Constructor) {
|
||||
return;
|
||||
}
|
||||
|
||||
var params = {
|
||||
dict: dict,
|
||||
ref: ref,
|
||||
};
|
||||
|
||||
var annotation = new Constructor(params);
|
||||
|
||||
if (annotation.isViewable() || annotation.isPrintable()) {
|
||||
return annotation;
|
||||
} else {
|
||||
if (SUPPORTED_TYPES.indexOf(subtype) === -1) {
|
||||
warn('unimplemented annotation type: ' + subtype);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Annotation.appendToOperatorList = function Annotation_appendToOperatorList(
|
||||
annotations, opList, pdfManager, partialEvaluator, intent) {
|
||||
|
||||
function reject(e) {
|
||||
annotationsReadyCapability.reject(e);
|
||||
}
|
||||
|
||||
var annotationsReadyCapability = createPromiseCapability();
|
||||
|
||||
var annotationPromises = [];
|
||||
for (var i = 0, n = annotations.length; i < n; ++i) {
|
||||
if (intent === 'display' && annotations[i].isViewable() ||
|
||||
intent === 'print' && annotations[i].isPrintable()) {
|
||||
annotationPromises.push(
|
||||
annotations[i].getOperatorList(partialEvaluator));
|
||||
}
|
||||
}
|
||||
Promise.all(annotationPromises).then(function(datas) {
|
||||
opList.addOp(OPS.beginAnnotations, []);
|
||||
for (var i = 0, n = datas.length; i < n; ++i) {
|
||||
var annotOpList = datas[i];
|
||||
opList.addOpList(annotOpList);
|
||||
}
|
||||
opList.addOp(OPS.endAnnotations, []);
|
||||
annotationsReadyCapability.resolve();
|
||||
}, reject);
|
||||
|
||||
return annotationsReadyCapability.promise;
|
||||
};
|
||||
|
||||
return Annotation;
|
||||
})();
|
||||
|
||||
var WidgetAnnotation = (function WidgetAnnotationClosure() {
|
||||
|
||||
function WidgetAnnotation(params) {
|
||||
Annotation.call(this, params);
|
||||
|
||||
var dict = params.dict;
|
||||
var data = this.data;
|
||||
|
||||
data.fieldValue = stringToPDFString(
|
||||
Util.getInheritableProperty(dict, 'V') || '');
|
||||
data.alternativeText = stringToPDFString(dict.get('TU') || '');
|
||||
data.defaultAppearance = Util.getInheritableProperty(dict, 'DA') || '';
|
||||
var fieldType = Util.getInheritableProperty(dict, 'FT');
|
||||
data.fieldType = isName(fieldType) ? fieldType.name : '';
|
||||
data.fieldFlags = Util.getInheritableProperty(dict, 'Ff') || 0;
|
||||
this.fieldResources = Util.getInheritableProperty(dict, 'DR') || Dict.empty;
|
||||
|
||||
// Building the full field name by collecting the field and
|
||||
// its ancestors 'T' data and joining them using '.'.
|
||||
var fieldName = [];
|
||||
var namedItem = dict;
|
||||
var ref = params.ref;
|
||||
while (namedItem) {
|
||||
var parent = namedItem.get('Parent');
|
||||
var parentRef = namedItem.getRaw('Parent');
|
||||
var name = namedItem.get('T');
|
||||
if (name) {
|
||||
fieldName.unshift(stringToPDFString(name));
|
||||
} else if (parent && ref) {
|
||||
// The field name is absent, that means more than one field
|
||||
// with the same name may exist. Replacing the empty name
|
||||
// with the '`' plus index in the parent's 'Kids' array.
|
||||
// This is not in the PDF spec but necessary to id the
|
||||
// the input controls.
|
||||
var kids = parent.get('Kids');
|
||||
var j, jj;
|
||||
for (j = 0, jj = kids.length; j < jj; j++) {
|
||||
var kidRef = kids[j];
|
||||
if (kidRef.num === ref.num && kidRef.gen === ref.gen) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
fieldName.unshift('`' + j);
|
||||
}
|
||||
namedItem = parent;
|
||||
ref = parentRef;
|
||||
}
|
||||
data.fullName = fieldName.join('.');
|
||||
}
|
||||
|
||||
var parent = Annotation.prototype;
|
||||
Util.inherit(WidgetAnnotation, Annotation, {
|
||||
isViewable: function WidgetAnnotation_isViewable() {
|
||||
if (this.data.fieldType === 'Sig') {
|
||||
warn('unimplemented annotation type: Widget signature');
|
||||
return false;
|
||||
}
|
||||
|
||||
return parent.isViewable.call(this);
|
||||
}
|
||||
});
|
||||
|
||||
return WidgetAnnotation;
|
||||
})();
|
||||
|
||||
var TextWidgetAnnotation = (function TextWidgetAnnotationClosure() {
|
||||
function TextWidgetAnnotation(params) {
|
||||
WidgetAnnotation.call(this, params);
|
||||
|
||||
this.data.textAlignment = Util.getInheritableProperty(params.dict, 'Q');
|
||||
this.data.annotationType = AnnotationType.WIDGET;
|
||||
this.data.hasHtml = !this.data.hasAppearance && !!this.data.fieldValue;
|
||||
}
|
||||
|
||||
Util.inherit(TextWidgetAnnotation, WidgetAnnotation, {
|
||||
getOperatorList: function TextWidgetAnnotation_getOperatorList(evaluator) {
|
||||
if (this.appearance) {
|
||||
return Annotation.prototype.getOperatorList.call(this, evaluator);
|
||||
}
|
||||
|
||||
var opList = new OperatorList();
|
||||
var data = this.data;
|
||||
|
||||
// Even if there is an appearance stream, ignore it. This is the
|
||||
// behaviour used by Adobe Reader.
|
||||
if (!data.defaultAppearance) {
|
||||
return Promise.resolve(opList);
|
||||
}
|
||||
|
||||
var stream = new Stream(stringToBytes(data.defaultAppearance));
|
||||
return evaluator.getOperatorList(stream, this.fieldResources, opList).
|
||||
then(function () {
|
||||
return opList;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return TextWidgetAnnotation;
|
||||
})();
|
||||
|
||||
var InteractiveAnnotation = (function InteractiveAnnotationClosure() {
|
||||
function InteractiveAnnotation(params) {
|
||||
Annotation.call(this, params);
|
||||
|
||||
this.data.hasHtml = true;
|
||||
}
|
||||
|
||||
Util.inherit(InteractiveAnnotation, Annotation, { });
|
||||
|
||||
return InteractiveAnnotation;
|
||||
})();
|
||||
|
||||
var TextAnnotation = (function TextAnnotationClosure() {
|
||||
function TextAnnotation(params) {
|
||||
InteractiveAnnotation.call(this, params);
|
||||
|
||||
var dict = params.dict;
|
||||
var data = this.data;
|
||||
|
||||
var content = dict.get('Contents');
|
||||
var title = dict.get('T');
|
||||
data.annotationType = AnnotationType.TEXT;
|
||||
data.content = stringToPDFString(content || '');
|
||||
data.title = stringToPDFString(title || '');
|
||||
|
||||
if (data.hasAppearance) {
|
||||
data.name = 'NoIcon';
|
||||
} else {
|
||||
data.rect[1] = data.rect[3] - DEFAULT_ICON_SIZE;
|
||||
data.rect[2] = data.rect[0] + DEFAULT_ICON_SIZE;
|
||||
data.name = dict.has('Name') ? dict.get('Name').name : 'Note';
|
||||
}
|
||||
|
||||
if (dict.has('C')) {
|
||||
data.hasBgColor = true;
|
||||
}
|
||||
}
|
||||
|
||||
Util.inherit(TextAnnotation, InteractiveAnnotation, { });
|
||||
|
||||
return TextAnnotation;
|
||||
})();
|
||||
|
||||
var LinkAnnotation = (function LinkAnnotationClosure() {
|
||||
function LinkAnnotation(params) {
|
||||
InteractiveAnnotation.call(this, params);
|
||||
|
||||
var dict = params.dict;
|
||||
var data = this.data;
|
||||
data.annotationType = AnnotationType.LINK;
|
||||
|
||||
var action = dict.get('A');
|
||||
if (action) {
|
||||
var linkType = action.get('S').name;
|
||||
if (linkType === 'URI') {
|
||||
var url = action.get('URI');
|
||||
if (isName(url)) {
|
||||
// Some bad PDFs do not put parentheses around relative URLs.
|
||||
url = '/' + url.name;
|
||||
} else if (url) {
|
||||
url = addDefaultProtocolToUrl(url);
|
||||
}
|
||||
// TODO: pdf spec mentions urls can be relative to a Base
|
||||
// entry in the dictionary.
|
||||
if (!isValidUrl(url, false)) {
|
||||
url = '';
|
||||
}
|
||||
data.url = url;
|
||||
} else if (linkType === 'GoTo') {
|
||||
data.dest = action.get('D');
|
||||
} else if (linkType === 'GoToR') {
|
||||
var urlDict = action.get('F');
|
||||
if (isDict(urlDict)) {
|
||||
// We assume that the 'url' is a Filspec dictionary
|
||||
// and fetch the url without checking any further
|
||||
url = urlDict.get('F') || '';
|
||||
}
|
||||
|
||||
// TODO: pdf reference says that GoToR
|
||||
// can also have 'NewWindow' attribute
|
||||
if (!isValidUrl(url, false)) {
|
||||
url = '';
|
||||
}
|
||||
data.url = url;
|
||||
data.dest = action.get('D');
|
||||
} else if (linkType === 'Named') {
|
||||
data.action = action.get('N').name;
|
||||
} else {
|
||||
warn('unrecognized link type: ' + linkType);
|
||||
}
|
||||
} else if (dict.has('Dest')) {
|
||||
// simple destination link
|
||||
var dest = dict.get('Dest');
|
||||
data.dest = isName(dest) ? dest.name : dest;
|
||||
}
|
||||
}
|
||||
|
||||
// Lets URLs beginning with 'www.' default to using the 'http://' protocol.
|
||||
function addDefaultProtocolToUrl(url) {
|
||||
if (url && url.indexOf('www.') === 0) {
|
||||
return ('http://' + url);
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
Util.inherit(LinkAnnotation, InteractiveAnnotation, {
|
||||
hasOperatorList: function LinkAnnotation_hasOperatorList() {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
return LinkAnnotation;
|
||||
})();
|
185
.obsidian/pdfjs/pdfextract/pdfjs/src/core/arithmetic_decoder.js
vendored
Normal file
185
.obsidian/pdfjs/pdfextract/pdfjs/src/core/arithmetic_decoder.js
vendored
Normal file
@@ -0,0 +1,185 @@
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
/* Copyright 2012 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
/* This class implements the QM Coder decoding as defined in
|
||||
* JPEG 2000 Part I Final Committee Draft Version 1.0
|
||||
* Annex C.3 Arithmetic decoding procedure
|
||||
* available at http://www.jpeg.org/public/fcd15444-1.pdf
|
||||
*
|
||||
* The arithmetic decoder is used in conjunction with context models to decode
|
||||
* JPEG2000 and JBIG2 streams.
|
||||
*/
|
||||
var ArithmeticDecoder = (function ArithmeticDecoderClosure() {
|
||||
// Table C-2
|
||||
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}
|
||||
];
|
||||
|
||||
// C.3.5 Initialisation of the decoder (INITDEC)
|
||||
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 = {
|
||||
// C.3.4 Compressed data input (BYTEIN)
|
||||
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 {
|
||||
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;
|
||||
}
|
||||
},
|
||||
// C.3.2 Decoding a decision (DECODE)
|
||||
readBit: function ArithmeticDecoder_readBit(contexts, pos) {
|
||||
// contexts are packed into 1 byte:
|
||||
// highest 7 bits carry cx.index, lowest bit carries cx.mps
|
||||
var cx_index = contexts[pos] >> 1, cx_mps = contexts[pos] & 1;
|
||||
var qeTableIcx = QeTable[cx_index];
|
||||
var qeIcx = qeTableIcx.qe;
|
||||
var d;
|
||||
var a = this.a - qeIcx;
|
||||
|
||||
if (this.chigh < qeIcx) {
|
||||
// exchangeLps
|
||||
if (a < qeIcx) {
|
||||
a = qeIcx;
|
||||
d = cx_mps;
|
||||
cx_index = qeTableIcx.nmps;
|
||||
} else {
|
||||
a = qeIcx;
|
||||
d = 1 ^ cx_mps;
|
||||
if (qeTableIcx.switchFlag === 1) {
|
||||
cx_mps = d;
|
||||
}
|
||||
cx_index = qeTableIcx.nlps;
|
||||
}
|
||||
} else {
|
||||
this.chigh -= qeIcx;
|
||||
if ((a & 0x8000) !== 0) {
|
||||
this.a = a;
|
||||
return cx_mps;
|
||||
}
|
||||
// exchangeMps
|
||||
if (a < qeIcx) {
|
||||
d = 1 ^ cx_mps;
|
||||
if (qeTableIcx.switchFlag === 1) {
|
||||
cx_mps = d;
|
||||
}
|
||||
cx_index = qeTableIcx.nlps;
|
||||
} else {
|
||||
d = cx_mps;
|
||||
cx_index = qeTableIcx.nmps;
|
||||
}
|
||||
}
|
||||
// C.3.3 renormD;
|
||||
do {
|
||||
if (this.ct === 0) {
|
||||
this.byteIn();
|
||||
}
|
||||
|
||||
a <<= 1;
|
||||
this.chigh = ((this.chigh << 1) & 0xFFFF) | ((this.clow >> 15) & 1);
|
||||
this.clow = (this.clow << 1) & 0xFFFF;
|
||||
this.ct--;
|
||||
} while ((a & 0x8000) === 0);
|
||||
this.a = a;
|
||||
|
||||
contexts[pos] = cx_index << 1 | cx_mps;
|
||||
return d;
|
||||
}
|
||||
};
|
||||
|
||||
return ArithmeticDecoder;
|
||||
})();
|
427
.obsidian/pdfjs/pdfextract/pdfjs/src/core/bidi.js
vendored
Normal file
427
.obsidian/pdfjs/pdfextract/pdfjs/src/core/bidi.js
vendored
Normal file
@@ -0,0 +1,427 @@
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
/* globals PDFJS */
|
||||
/* Copyright 2012 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var bidi = PDFJS.bidi = (function bidiClosure() {
|
||||
// Character types for symbols from 0000 to 00FF.
|
||||
var baseTypes = [
|
||||
'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'S', 'B', 'S', 'WS',
|
||||
'B', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN',
|
||||
'BN', 'BN', 'B', 'B', 'B', 'S', 'WS', 'ON', 'ON', 'ET', 'ET', 'ET', 'ON',
|
||||
'ON', 'ON', 'ON', 'ON', 'ON', 'CS', 'ON', 'CS', 'ON', 'EN', 'EN', 'EN',
|
||||
'EN', 'EN', 'EN', 'EN', 'EN', 'EN', 'EN', 'ON', 'ON', 'ON', 'ON', 'ON',
|
||||
'ON', 'ON', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L',
|
||||
'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'ON', 'ON',
|
||||
'ON', 'ON', 'ON', 'ON', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L',
|
||||
'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L',
|
||||
'L', 'ON', 'ON', 'ON', 'ON', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'B', 'BN',
|
||||
'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN',
|
||||
'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN',
|
||||
'BN', 'CS', 'ON', 'ET', 'ET', 'ET', 'ET', 'ON', 'ON', 'ON', 'ON', 'L', 'ON',
|
||||
'ON', 'ON', 'ON', 'ON', 'ET', 'ET', 'EN', 'EN', 'ON', 'L', 'ON', 'ON', 'ON',
|
||||
'EN', 'L', 'ON', 'ON', 'ON', 'ON', 'ON', 'L', 'L', 'L', 'L', 'L', 'L', 'L',
|
||||
'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L',
|
||||
'L', 'ON', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L',
|
||||
'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L',
|
||||
'L', 'L', 'L', 'ON', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L'
|
||||
];
|
||||
|
||||
// Character types for symbols from 0600 to 06FF
|
||||
var arabicTypes = [
|
||||
'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
|
||||
'CS', 'AL', 'ON', 'ON', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'AL',
|
||||
'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
|
||||
'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
|
||||
'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
|
||||
'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
|
||||
'AL', 'AL', 'AL', 'AL', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM',
|
||||
'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'AL', 'AL', 'AL', 'AL',
|
||||
'AL', 'AL', 'AL', 'AN', 'AN', 'AN', 'AN', 'AN', 'AN', 'AN', 'AN', 'AN',
|
||||
'AN', 'ET', 'AN', 'AN', 'AL', 'AL', 'AL', 'NSM', 'AL', 'AL', 'AL', 'AL',
|
||||
'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
|
||||
'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
|
||||
'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
|
||||
'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
|
||||
'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
|
||||
'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
|
||||
'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
|
||||
'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
|
||||
'AL', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM',
|
||||
'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'ON', 'NSM',
|
||||
'NSM', 'NSM', 'NSM', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
|
||||
'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL'
|
||||
];
|
||||
|
||||
function isOdd(i) {
|
||||
return (i & 1) !== 0;
|
||||
}
|
||||
|
||||
function isEven(i) {
|
||||
return (i & 1) === 0;
|
||||
}
|
||||
|
||||
function findUnequal(arr, start, value) {
|
||||
for (var j = start, jj = arr.length; j < jj; ++j) {
|
||||
if (arr[j] !== value) {
|
||||
return j;
|
||||
}
|
||||
}
|
||||
return j;
|
||||
}
|
||||
|
||||
function setValues(arr, start, end, value) {
|
||||
for (var j = start; j < end; ++j) {
|
||||
arr[j] = value;
|
||||
}
|
||||
}
|
||||
|
||||
function reverseValues(arr, start, end) {
|
||||
for (var i = start, j = end - 1; i < j; ++i, --j) {
|
||||
var temp = arr[i];
|
||||
arr[i] = arr[j];
|
||||
arr[j] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
function createBidiText(str, isLTR, vertical) {
|
||||
return {
|
||||
str: str,
|
||||
dir: (vertical ? 'ttb' : (isLTR ? 'ltr' : 'rtl'))
|
||||
};
|
||||
}
|
||||
|
||||
// These are used in bidi(), which is called frequently. We re-use them on
|
||||
// each call to avoid unnecessary allocations.
|
||||
var chars = [];
|
||||
var types = [];
|
||||
|
||||
function bidi(str, startLevel, vertical) {
|
||||
var isLTR = true;
|
||||
var strLength = str.length;
|
||||
if (strLength === 0 || vertical) {
|
||||
return createBidiText(str, isLTR, vertical);
|
||||
}
|
||||
|
||||
// Get types and fill arrays
|
||||
chars.length = strLength;
|
||||
types.length = strLength;
|
||||
var numBidi = 0;
|
||||
|
||||
var i, ii;
|
||||
for (i = 0; i < strLength; ++i) {
|
||||
chars[i] = str.charAt(i);
|
||||
|
||||
var charCode = str.charCodeAt(i);
|
||||
var charType = 'L';
|
||||
if (charCode <= 0x00ff) {
|
||||
charType = baseTypes[charCode];
|
||||
} else if (0x0590 <= charCode && charCode <= 0x05f4) {
|
||||
charType = 'R';
|
||||
} else if (0x0600 <= charCode && charCode <= 0x06ff) {
|
||||
charType = arabicTypes[charCode & 0xff];
|
||||
} else if (0x0700 <= charCode && charCode <= 0x08AC) {
|
||||
charType = 'AL';
|
||||
}
|
||||
if (charType === 'R' || charType === 'AL' || charType === 'AN') {
|
||||
numBidi++;
|
||||
}
|
||||
types[i] = charType;
|
||||
}
|
||||
|
||||
// Detect the bidi method
|
||||
// - If there are no rtl characters then no bidi needed
|
||||
// - If less than 30% chars are rtl then string is primarily ltr
|
||||
// - If more than 30% chars are rtl then string is primarily rtl
|
||||
if (numBidi === 0) {
|
||||
isLTR = true;
|
||||
return createBidiText(str, isLTR);
|
||||
}
|
||||
|
||||
if (startLevel === -1) {
|
||||
if ((strLength / numBidi) < 0.3) {
|
||||
isLTR = true;
|
||||
startLevel = 0;
|
||||
} else {
|
||||
isLTR = false;
|
||||
startLevel = 1;
|
||||
}
|
||||
}
|
||||
|
||||
var levels = [];
|
||||
for (i = 0; i < strLength; ++i) {
|
||||
levels[i] = startLevel;
|
||||
}
|
||||
|
||||
/*
|
||||
X1-X10: skip most of this, since we are NOT doing the embeddings.
|
||||
*/
|
||||
var e = (isOdd(startLevel) ? 'R' : 'L');
|
||||
var sor = e;
|
||||
var eor = sor;
|
||||
|
||||
/*
|
||||
W1. Examine each non-spacing mark (NSM) in the level run, and change the
|
||||
type of the NSM to the type of the previous character. If the NSM is at the
|
||||
start of the level run, it will get the type of sor.
|
||||
*/
|
||||
var lastType = sor;
|
||||
for (i = 0; i < strLength; ++i) {
|
||||
if (types[i] === 'NSM') {
|
||||
types[i] = lastType;
|
||||
} else {
|
||||
lastType = types[i];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
W2. Search backwards from each instance of a European number until the
|
||||
first strong type (R, L, AL, or sor) is found. If an AL is found, change
|
||||
the type of the European number to Arabic number.
|
||||
*/
|
||||
lastType = sor;
|
||||
var t;
|
||||
for (i = 0; i < strLength; ++i) {
|
||||
t = types[i];
|
||||
if (t === 'EN') {
|
||||
types[i] = (lastType === 'AL') ? 'AN' : 'EN';
|
||||
} else if (t === 'R' || t === 'L' || t === 'AL') {
|
||||
lastType = t;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
W3. Change all ALs to R.
|
||||
*/
|
||||
for (i = 0; i < strLength; ++i) {
|
||||
t = types[i];
|
||||
if (t === 'AL') {
|
||||
types[i] = 'R';
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
W4. A single European separator between two European numbers changes to a
|
||||
European number. A single common separator between two numbers of the same
|
||||
type changes to that type:
|
||||
*/
|
||||
for (i = 1; i < strLength - 1; ++i) {
|
||||
if (types[i] === 'ES' && types[i - 1] === 'EN' && types[i + 1] === 'EN') {
|
||||
types[i] = 'EN';
|
||||
}
|
||||
if (types[i] === 'CS' &&
|
||||
(types[i - 1] === 'EN' || types[i - 1] === 'AN') &&
|
||||
types[i + 1] === types[i - 1]) {
|
||||
types[i] = types[i - 1];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
W5. A sequence of European terminators adjacent to European numbers changes
|
||||
to all European numbers:
|
||||
*/
|
||||
for (i = 0; i < strLength; ++i) {
|
||||
if (types[i] === 'EN') {
|
||||
// do before
|
||||
var j;
|
||||
for (j = i - 1; j >= 0; --j) {
|
||||
if (types[j] !== 'ET') {
|
||||
break;
|
||||
}
|
||||
types[j] = 'EN';
|
||||
}
|
||||
// do after
|
||||
for (j = i + 1; j < strLength; --j) {
|
||||
if (types[j] !== 'ET') {
|
||||
break;
|
||||
}
|
||||
types[j] = 'EN';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
W6. Otherwise, separators and terminators change to Other Neutral:
|
||||
*/
|
||||
for (i = 0; i < strLength; ++i) {
|
||||
t = types[i];
|
||||
if (t === 'WS' || t === 'ES' || t === 'ET' || t === 'CS') {
|
||||
types[i] = 'ON';
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
W7. Search backwards from each instance of a European number until the
|
||||
first strong type (R, L, or sor) is found. If an L is found, then change
|
||||
the type of the European number to L.
|
||||
*/
|
||||
lastType = sor;
|
||||
for (i = 0; i < strLength; ++i) {
|
||||
t = types[i];
|
||||
if (t === 'EN') {
|
||||
types[i] = ((lastType === 'L') ? 'L' : 'EN');
|
||||
} else if (t === 'R' || t === 'L') {
|
||||
lastType = t;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
N1. A sequence of neutrals takes the direction of the surrounding strong
|
||||
text if the text on both sides has the same direction. European and Arabic
|
||||
numbers are treated as though they were R. Start-of-level-run (sor) and
|
||||
end-of-level-run (eor) are used at level run boundaries.
|
||||
*/
|
||||
for (i = 0; i < strLength; ++i) {
|
||||
if (types[i] === 'ON') {
|
||||
var end = findUnequal(types, i + 1, 'ON');
|
||||
var before = sor;
|
||||
if (i > 0) {
|
||||
before = types[i - 1];
|
||||
}
|
||||
|
||||
var after = eor;
|
||||
if (end + 1 < strLength) {
|
||||
after = types[end + 1];
|
||||
}
|
||||
if (before !== 'L') {
|
||||
before = 'R';
|
||||
}
|
||||
if (after !== 'L') {
|
||||
after = 'R';
|
||||
}
|
||||
if (before === after) {
|
||||
setValues(types, i, end, before);
|
||||
}
|
||||
i = end - 1; // reset to end (-1 so next iteration is ok)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
N2. Any remaining neutrals take the embedding direction.
|
||||
*/
|
||||
for (i = 0; i < strLength; ++i) {
|
||||
if (types[i] === 'ON') {
|
||||
types[i] = e;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
I1. For all characters with an even (left-to-right) embedding direction,
|
||||
those of type R go up one level and those of type AN or EN go up two
|
||||
levels.
|
||||
I2. For all characters with an odd (right-to-left) embedding direction,
|
||||
those of type L, EN or AN go up one level.
|
||||
*/
|
||||
for (i = 0; i < strLength; ++i) {
|
||||
t = types[i];
|
||||
if (isEven(levels[i])) {
|
||||
if (t === 'R') {
|
||||
levels[i] += 1;
|
||||
} else if (t === 'AN' || t === 'EN') {
|
||||
levels[i] += 2;
|
||||
}
|
||||
} else { // isOdd
|
||||
if (t === 'L' || t === 'AN' || t === 'EN') {
|
||||
levels[i] += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
L1. On each line, reset the embedding level of the following characters to
|
||||
the paragraph embedding level:
|
||||
|
||||
segment separators,
|
||||
paragraph separators,
|
||||
any sequence of whitespace characters preceding a segment separator or
|
||||
paragraph separator, and any sequence of white space characters at the end
|
||||
of the line.
|
||||
*/
|
||||
|
||||
// don't bother as text is only single line
|
||||
|
||||
/*
|
||||
L2. From the highest level found in the text to the lowest odd level on
|
||||
each line, reverse any contiguous sequence of characters that are at that
|
||||
level or higher.
|
||||
*/
|
||||
|
||||
// find highest level & lowest odd level
|
||||
var highestLevel = -1;
|
||||
var lowestOddLevel = 99;
|
||||
var level;
|
||||
for (i = 0, ii = levels.length; i < ii; ++i) {
|
||||
level = levels[i];
|
||||
if (highestLevel < level) {
|
||||
highestLevel = level;
|
||||
}
|
||||
if (lowestOddLevel > level && isOdd(level)) {
|
||||
lowestOddLevel = level;
|
||||
}
|
||||
}
|
||||
|
||||
// now reverse between those limits
|
||||
for (level = highestLevel; level >= lowestOddLevel; --level) {
|
||||
// find segments to reverse
|
||||
var start = -1;
|
||||
for (i = 0, ii = levels.length; i < ii; ++i) {
|
||||
if (levels[i] < level) {
|
||||
if (start >= 0) {
|
||||
reverseValues(chars, start, i);
|
||||
start = -1;
|
||||
}
|
||||
} else if (start < 0) {
|
||||
start = i;
|
||||
}
|
||||
}
|
||||
if (start >= 0) {
|
||||
reverseValues(chars, start, levels.length);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
L3. Combining marks applied to a right-to-left base character will at this
|
||||
point precede their base character. If the rendering engine expects them to
|
||||
follow the base characters in the final display process, then the ordering
|
||||
of the marks and the base character must be reversed.
|
||||
*/
|
||||
|
||||
// don't bother for now
|
||||
|
||||
/*
|
||||
L4. A character that possesses the mirrored property as specified by
|
||||
Section 4.7, Mirrored, must be depicted by a mirrored glyph if the resolved
|
||||
directionality of that character is R.
|
||||
*/
|
||||
|
||||
// don't mirror as characters are already mirrored in the pdf
|
||||
|
||||
// Finally, return string
|
||||
var result = '';
|
||||
for (i = 0, ii = chars.length; i < ii; ++i) {
|
||||
var ch = chars[i];
|
||||
if (ch !== '<' && ch !== '>') {
|
||||
result += ch;
|
||||
}
|
||||
}
|
||||
return createBidiText(result, isLTR);
|
||||
}
|
||||
|
||||
return bidi;
|
||||
})();
|
||||
|
119
.obsidian/pdfjs/pdfextract/pdfjs/src/core/charsets.js
vendored
Normal file
119
.obsidian/pdfjs/pdfextract/pdfjs/src/core/charsets.js
vendored
Normal file
@@ -0,0 +1,119 @@
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
/* Copyright 2012 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var ISOAdobeCharset = [
|
||||
'.notdef', 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar',
|
||||
'percent', 'ampersand', 'quoteright', 'parenleft', 'parenright',
|
||||
'asterisk', 'plus', 'comma', 'hyphen', 'period', 'slash', 'zero',
|
||||
'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight',
|
||||
'nine', 'colon', 'semicolon', 'less', 'equal', 'greater', 'question',
|
||||
'at', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
|
||||
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
|
||||
'bracketleft', 'backslash', 'bracketright', 'asciicircum', 'underscore',
|
||||
'quoteleft', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
|
||||
'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
|
||||
'braceleft', 'bar', 'braceright', 'asciitilde', 'exclamdown', 'cent',
|
||||
'sterling', 'fraction', 'yen', 'florin', 'section', 'currency',
|
||||
'quotesingle', 'quotedblleft', 'guillemotleft', 'guilsinglleft',
|
||||
'guilsinglright', 'fi', 'fl', 'endash', 'dagger', 'daggerdbl',
|
||||
'periodcentered', 'paragraph', 'bullet', 'quotesinglbase',
|
||||
'quotedblbase', 'quotedblright', 'guillemotright', 'ellipsis',
|
||||
'perthousand', 'questiondown', 'grave', 'acute', 'circumflex', 'tilde',
|
||||
'macron', 'breve', 'dotaccent', 'dieresis', 'ring', 'cedilla',
|
||||
'hungarumlaut', 'ogonek', 'caron', 'emdash', 'AE', 'ordfeminine',
|
||||
'Lslash', 'Oslash', 'OE', 'ordmasculine', 'ae', 'dotlessi', 'lslash',
|
||||
'oslash', 'oe', 'germandbls', 'onesuperior', 'logicalnot', 'mu',
|
||||
'trademark', 'Eth', 'onehalf', 'plusminus', 'Thorn', 'onequarter',
|
||||
'divide', 'brokenbar', 'degree', 'thorn', 'threequarters', 'twosuperior',
|
||||
'registered', 'minus', 'eth', 'multiply', 'threesuperior', 'copyright',
|
||||
'Aacute', 'Acircumflex', 'Adieresis', 'Agrave', 'Aring', 'Atilde',
|
||||
'Ccedilla', 'Eacute', 'Ecircumflex', 'Edieresis', 'Egrave', 'Iacute',
|
||||
'Icircumflex', 'Idieresis', 'Igrave', 'Ntilde', 'Oacute', 'Ocircumflex',
|
||||
'Odieresis', 'Ograve', 'Otilde', 'Scaron', 'Uacute', 'Ucircumflex',
|
||||
'Udieresis', 'Ugrave', 'Yacute', 'Ydieresis', 'Zcaron', 'aacute',
|
||||
'acircumflex', 'adieresis', 'agrave', 'aring', 'atilde', 'ccedilla',
|
||||
'eacute', 'ecircumflex', 'edieresis', 'egrave', 'iacute', 'icircumflex',
|
||||
'idieresis', 'igrave', 'ntilde', 'oacute', 'ocircumflex', 'odieresis',
|
||||
'ograve', 'otilde', 'scaron', 'uacute', 'ucircumflex', 'udieresis',
|
||||
'ugrave', 'yacute', 'ydieresis', 'zcaron'
|
||||
];
|
||||
|
||||
var ExpertCharset = [
|
||||
'.notdef', 'space', 'exclamsmall', 'Hungarumlautsmall', 'dollaroldstyle',
|
||||
'dollarsuperior', 'ampersandsmall', 'Acutesmall', 'parenleftsuperior',
|
||||
'parenrightsuperior', 'twodotenleader', 'onedotenleader', 'comma',
|
||||
'hyphen', 'period', 'fraction', 'zerooldstyle', 'oneoldstyle',
|
||||
'twooldstyle', 'threeoldstyle', 'fouroldstyle', 'fiveoldstyle',
|
||||
'sixoldstyle', 'sevenoldstyle', 'eightoldstyle', 'nineoldstyle',
|
||||
'colon', 'semicolon', 'commasuperior', 'threequartersemdash',
|
||||
'periodsuperior', 'questionsmall', 'asuperior', 'bsuperior',
|
||||
'centsuperior', 'dsuperior', 'esuperior', 'isuperior', 'lsuperior',
|
||||
'msuperior', 'nsuperior', 'osuperior', 'rsuperior', 'ssuperior',
|
||||
'tsuperior', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'parenleftinferior',
|
||||
'parenrightinferior', 'Circumflexsmall', 'hyphensuperior', 'Gravesmall',
|
||||
'Asmall', 'Bsmall', 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall',
|
||||
'Hsmall', 'Ismall', 'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall',
|
||||
'Osmall', 'Psmall', 'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall',
|
||||
'Vsmall', 'Wsmall', 'Xsmall', 'Ysmall', 'Zsmall', 'colonmonetary',
|
||||
'onefitted', 'rupiah', 'Tildesmall', 'exclamdownsmall', 'centoldstyle',
|
||||
'Lslashsmall', 'Scaronsmall', 'Zcaronsmall', 'Dieresissmall',
|
||||
'Brevesmall', 'Caronsmall', 'Dotaccentsmall', 'Macronsmall',
|
||||
'figuredash', 'hypheninferior', 'Ogoneksmall', 'Ringsmall',
|
||||
'Cedillasmall', 'onequarter', 'onehalf', 'threequarters',
|
||||
'questiondownsmall', 'oneeighth', 'threeeighths', 'fiveeighths',
|
||||
'seveneighths', 'onethird', 'twothirds', 'zerosuperior', 'onesuperior',
|
||||
'twosuperior', 'threesuperior', 'foursuperior', 'fivesuperior',
|
||||
'sixsuperior', 'sevensuperior', 'eightsuperior', 'ninesuperior',
|
||||
'zeroinferior', 'oneinferior', 'twoinferior', 'threeinferior',
|
||||
'fourinferior', 'fiveinferior', 'sixinferior', 'seveninferior',
|
||||
'eightinferior', 'nineinferior', 'centinferior', 'dollarinferior',
|
||||
'periodinferior', 'commainferior', 'Agravesmall', 'Aacutesmall',
|
||||
'Acircumflexsmall', 'Atildesmall', 'Adieresissmall', 'Aringsmall',
|
||||
'AEsmall', 'Ccedillasmall', 'Egravesmall', 'Eacutesmall',
|
||||
'Ecircumflexsmall', 'Edieresissmall', 'Igravesmall', 'Iacutesmall',
|
||||
'Icircumflexsmall', 'Idieresissmall', 'Ethsmall', 'Ntildesmall',
|
||||
'Ogravesmall', 'Oacutesmall', 'Ocircumflexsmall', 'Otildesmall',
|
||||
'Odieresissmall', 'OEsmall', 'Oslashsmall', 'Ugravesmall', 'Uacutesmall',
|
||||
'Ucircumflexsmall', 'Udieresissmall', 'Yacutesmall', 'Thornsmall',
|
||||
'Ydieresissmall'
|
||||
];
|
||||
|
||||
var ExpertSubsetCharset = [
|
||||
'.notdef', 'space', 'dollaroldstyle', 'dollarsuperior',
|
||||
'parenleftsuperior', 'parenrightsuperior', 'twodotenleader',
|
||||
'onedotenleader', 'comma', 'hyphen', 'period', 'fraction',
|
||||
'zerooldstyle', 'oneoldstyle', 'twooldstyle', 'threeoldstyle',
|
||||
'fouroldstyle', 'fiveoldstyle', 'sixoldstyle', 'sevenoldstyle',
|
||||
'eightoldstyle', 'nineoldstyle', 'colon', 'semicolon', 'commasuperior',
|
||||
'threequartersemdash', 'periodsuperior', 'asuperior', 'bsuperior',
|
||||
'centsuperior', 'dsuperior', 'esuperior', 'isuperior', 'lsuperior',
|
||||
'msuperior', 'nsuperior', 'osuperior', 'rsuperior', 'ssuperior',
|
||||
'tsuperior', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'parenleftinferior',
|
||||
'parenrightinferior', 'hyphensuperior', 'colonmonetary', 'onefitted',
|
||||
'rupiah', 'centoldstyle', 'figuredash', 'hypheninferior', 'onequarter',
|
||||
'onehalf', 'threequarters', 'oneeighth', 'threeeighths', 'fiveeighths',
|
||||
'seveneighths', 'onethird', 'twothirds', 'zerosuperior', 'onesuperior',
|
||||
'twosuperior', 'threesuperior', 'foursuperior', 'fivesuperior',
|
||||
'sixsuperior', 'sevensuperior', 'eightsuperior', 'ninesuperior',
|
||||
'zeroinferior', 'oneinferior', 'twoinferior', 'threeinferior',
|
||||
'fourinferior', 'fiveinferior', 'sixinferior', 'seveninferior',
|
||||
'eightinferior', 'nineinferior', 'centinferior', 'dollarinferior',
|
||||
'periodinferior', 'commainferior'
|
||||
];
|
||||
|
560
.obsidian/pdfjs/pdfextract/pdfjs/src/core/chunked_stream.js
vendored
Normal file
560
.obsidian/pdfjs/pdfextract/pdfjs/src/core/chunked_stream.js
vendored
Normal file
@@ -0,0 +1,560 @@
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
/* Copyright 2012 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/* globals assert, MissingDataException, isInt, NetworkManager, Promise,
|
||||
isEmptyObj, createPromiseCapability */
|
||||
|
||||
'use strict';
|
||||
|
||||
var ChunkedStream = (function ChunkedStreamClosure() {
|
||||
function ChunkedStream(length, chunkSize, manager) {
|
||||
this.bytes = new Uint8Array(length);
|
||||
this.start = 0;
|
||||
this.pos = 0;
|
||||
this.end = length;
|
||||
this.chunkSize = chunkSize;
|
||||
this.loadedChunks = [];
|
||||
this.numChunksLoaded = 0;
|
||||
this.numChunks = Math.ceil(length / chunkSize);
|
||||
this.manager = manager;
|
||||
this.progressiveDataLength = 0;
|
||||
this.lastSuccessfulEnsureByteChunk = -1; // a single-entry cache
|
||||
}
|
||||
|
||||
// required methods for a stream. if a particular stream does not
|
||||
// implement these, an error should be thrown
|
||||
ChunkedStream.prototype = {
|
||||
|
||||
getMissingChunks: function ChunkedStream_getMissingChunks() {
|
||||
var chunks = [];
|
||||
for (var chunk = 0, n = this.numChunks; chunk < n; ++chunk) {
|
||||
if (!this.loadedChunks[chunk]) {
|
||||
chunks.push(chunk);
|
||||
}
|
||||
}
|
||||
return chunks;
|
||||
},
|
||||
|
||||
getBaseStreams: function ChunkedStream_getBaseStreams() {
|
||||
return [this];
|
||||
},
|
||||
|
||||
allChunksLoaded: function ChunkedStream_allChunksLoaded() {
|
||||
return this.numChunksLoaded === this.numChunks;
|
||||
},
|
||||
|
||||
onReceiveData: function ChunkedStream_onReceiveData(begin, chunk) {
|
||||
var end = begin + chunk.byteLength;
|
||||
|
||||
assert(begin % this.chunkSize === 0, 'Bad begin offset: ' + begin);
|
||||
// Using this.length is inaccurate here since this.start can be moved
|
||||
// See ChunkedStream.moveStart()
|
||||
var length = this.bytes.length;
|
||||
assert(end % this.chunkSize === 0 || end === length,
|
||||
'Bad end offset: ' + end);
|
||||
|
||||
this.bytes.set(new Uint8Array(chunk), begin);
|
||||
var chunkSize = this.chunkSize;
|
||||
var beginChunk = Math.floor(begin / chunkSize);
|
||||
var endChunk = Math.floor((end - 1) / chunkSize) + 1;
|
||||
var curChunk;
|
||||
|
||||
for (curChunk = beginChunk; curChunk < endChunk; ++curChunk) {
|
||||
if (!this.loadedChunks[curChunk]) {
|
||||
this.loadedChunks[curChunk] = true;
|
||||
++this.numChunksLoaded;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onReceiveProgressiveData:
|
||||
function ChunkedStream_onReceiveProgressiveData(data) {
|
||||
var position = this.progressiveDataLength;
|
||||
var beginChunk = Math.floor(position / this.chunkSize);
|
||||
|
||||
this.bytes.set(new Uint8Array(data), position);
|
||||
position += data.byteLength;
|
||||
this.progressiveDataLength = position;
|
||||
var endChunk = position >= this.end ? this.numChunks :
|
||||
Math.floor(position / this.chunkSize);
|
||||
var curChunk;
|
||||
for (curChunk = beginChunk; curChunk < endChunk; ++curChunk) {
|
||||
if (!this.loadedChunks[curChunk]) {
|
||||
this.loadedChunks[curChunk] = true;
|
||||
++this.numChunksLoaded;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
ensureByte: function ChunkedStream_ensureByte(pos) {
|
||||
var chunk = Math.floor(pos / this.chunkSize);
|
||||
if (chunk === this.lastSuccessfulEnsureByteChunk) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.loadedChunks[chunk]) {
|
||||
throw new MissingDataException(pos, pos + 1);
|
||||
}
|
||||
this.lastSuccessfulEnsureByteChunk = chunk;
|
||||
},
|
||||
|
||||
ensureRange: function ChunkedStream_ensureRange(begin, end) {
|
||||
if (begin >= end) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (end <= this.progressiveDataLength) {
|
||||
return;
|
||||
}
|
||||
|
||||
var chunkSize = this.chunkSize;
|
||||
var beginChunk = Math.floor(begin / chunkSize);
|
||||
var endChunk = Math.floor((end - 1) / chunkSize) + 1;
|
||||
for (var chunk = beginChunk; chunk < endChunk; ++chunk) {
|
||||
if (!this.loadedChunks[chunk]) {
|
||||
throw new MissingDataException(begin, end);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
nextEmptyChunk: function ChunkedStream_nextEmptyChunk(beginChunk) {
|
||||
var chunk, n;
|
||||
for (chunk = beginChunk, n = this.numChunks; chunk < n; ++chunk) {
|
||||
if (!this.loadedChunks[chunk]) {
|
||||
return chunk;
|
||||
}
|
||||
}
|
||||
// Wrap around to beginning
|
||||
for (chunk = 0; chunk < beginChunk; ++chunk) {
|
||||
if (!this.loadedChunks[chunk]) {
|
||||
return chunk;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
hasChunk: function ChunkedStream_hasChunk(chunk) {
|
||||
return !!this.loadedChunks[chunk];
|
||||
},
|
||||
|
||||
get length() {
|
||||
return this.end - this.start;
|
||||
},
|
||||
|
||||
get isEmpty() {
|
||||
return this.length === 0;
|
||||
},
|
||||
|
||||
getByte: function ChunkedStream_getByte() {
|
||||
var pos = this.pos;
|
||||
if (pos >= this.end) {
|
||||
return -1;
|
||||
}
|
||||
this.ensureByte(pos);
|
||||
return this.bytes[this.pos++];
|
||||
},
|
||||
|
||||
getUint16: function ChunkedStream_getUint16() {
|
||||
var b0 = this.getByte();
|
||||
var b1 = this.getByte();
|
||||
return (b0 << 8) + b1;
|
||||
},
|
||||
|
||||
getInt32: function ChunkedStream_getInt32() {
|
||||
var b0 = this.getByte();
|
||||
var b1 = this.getByte();
|
||||
var b2 = this.getByte();
|
||||
var b3 = this.getByte();
|
||||
return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3;
|
||||
},
|
||||
|
||||
// returns subarray of original buffer
|
||||
// should only be read
|
||||
getBytes: function ChunkedStream_getBytes(length) {
|
||||
var bytes = this.bytes;
|
||||
var pos = this.pos;
|
||||
var strEnd = this.end;
|
||||
|
||||
if (!length) {
|
||||
this.ensureRange(pos, strEnd);
|
||||
return bytes.subarray(pos, strEnd);
|
||||
}
|
||||
|
||||
var end = pos + length;
|
||||
if (end > strEnd) {
|
||||
end = strEnd;
|
||||
}
|
||||
this.ensureRange(pos, end);
|
||||
|
||||
this.pos = end;
|
||||
return bytes.subarray(pos, end);
|
||||
},
|
||||
|
||||
peekByte: function ChunkedStream_peekByte() {
|
||||
var peekedByte = this.getByte();
|
||||
this.pos--;
|
||||
return peekedByte;
|
||||
},
|
||||
|
||||
peekBytes: function ChunkedStream_peekBytes(length) {
|
||||
var bytes = this.getBytes(length);
|
||||
this.pos -= bytes.length;
|
||||
return bytes;
|
||||
},
|
||||
|
||||
getByteRange: function ChunkedStream_getBytes(begin, end) {
|
||||
this.ensureRange(begin, end);
|
||||
return this.bytes.subarray(begin, end);
|
||||
},
|
||||
|
||||
skip: function ChunkedStream_skip(n) {
|
||||
if (!n) {
|
||||
n = 1;
|
||||
}
|
||||
this.pos += n;
|
||||
},
|
||||
|
||||
reset: function ChunkedStream_reset() {
|
||||
this.pos = this.start;
|
||||
},
|
||||
|
||||
moveStart: function ChunkedStream_moveStart() {
|
||||
this.start = this.pos;
|
||||
},
|
||||
|
||||
makeSubStream: function ChunkedStream_makeSubStream(start, length, dict) {
|
||||
this.ensureRange(start, start + length);
|
||||
|
||||
function ChunkedStreamSubstream() {}
|
||||
ChunkedStreamSubstream.prototype = Object.create(this);
|
||||
ChunkedStreamSubstream.prototype.getMissingChunks = function() {
|
||||
var chunkSize = this.chunkSize;
|
||||
var beginChunk = Math.floor(this.start / chunkSize);
|
||||
var endChunk = Math.floor((this.end - 1) / chunkSize) + 1;
|
||||
var missingChunks = [];
|
||||
for (var chunk = beginChunk; chunk < endChunk; ++chunk) {
|
||||
if (!this.loadedChunks[chunk]) {
|
||||
missingChunks.push(chunk);
|
||||
}
|
||||
}
|
||||
return missingChunks;
|
||||
};
|
||||
var subStream = new ChunkedStreamSubstream();
|
||||
subStream.pos = subStream.start = start;
|
||||
subStream.end = start + length || this.end;
|
||||
subStream.dict = dict;
|
||||
return subStream;
|
||||
},
|
||||
|
||||
isStream: true
|
||||
};
|
||||
|
||||
return ChunkedStream;
|
||||
})();
|
||||
|
||||
var ChunkedStreamManager = (function ChunkedStreamManagerClosure() {
|
||||
|
||||
function ChunkedStreamManager(length, chunkSize, url, args) {
|
||||
this.stream = new ChunkedStream(length, chunkSize, this);
|
||||
this.length = length;
|
||||
this.chunkSize = chunkSize;
|
||||
this.url = url;
|
||||
this.disableAutoFetch = args.disableAutoFetch;
|
||||
var msgHandler = this.msgHandler = args.msgHandler;
|
||||
|
||||
if (args.chunkedViewerLoading) {
|
||||
msgHandler.on('OnDataRange', this.onReceiveData.bind(this));
|
||||
msgHandler.on('OnDataProgress', this.onProgress.bind(this));
|
||||
this.sendRequest = function ChunkedStreamManager_sendRequest(begin, end) {
|
||||
msgHandler.send('RequestDataRange', { begin: begin, end: end });
|
||||
};
|
||||
} else {
|
||||
|
||||
var getXhr = function getXhr() {
|
||||
//#if B2G
|
||||
// return new XMLHttpRequest({ mozSystem: true });
|
||||
//#else
|
||||
return new XMLHttpRequest();
|
||||
//#endif
|
||||
};
|
||||
this.networkManager = new NetworkManager(this.url, {
|
||||
getXhr: getXhr,
|
||||
httpHeaders: args.httpHeaders,
|
||||
withCredentials: args.withCredentials
|
||||
});
|
||||
this.sendRequest = function ChunkedStreamManager_sendRequest(begin, end) {
|
||||
this.networkManager.requestRange(begin, end, {
|
||||
onDone: this.onReceiveData.bind(this),
|
||||
onProgress: this.onProgress.bind(this)
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
this.currRequestId = 0;
|
||||
|
||||
this.chunksNeededByRequest = {};
|
||||
this.requestsByChunk = {};
|
||||
this.callbacksByRequest = {};
|
||||
this.progressiveDataLength = 0;
|
||||
|
||||
this._loadedStreamCapability = createPromiseCapability();
|
||||
|
||||
if (args.initialData) {
|
||||
this.onReceiveData({chunk: args.initialData});
|
||||
}
|
||||
}
|
||||
|
||||
ChunkedStreamManager.prototype = {
|
||||
onLoadedStream: function ChunkedStreamManager_getLoadedStream() {
|
||||
return this._loadedStreamCapability.promise;
|
||||
},
|
||||
|
||||
// Get all the chunks that are not yet loaded and groups them into
|
||||
// contiguous ranges to load in as few requests as possible
|
||||
requestAllChunks: function ChunkedStreamManager_requestAllChunks() {
|
||||
var missingChunks = this.stream.getMissingChunks();
|
||||
this.requestChunks(missingChunks);
|
||||
return this._loadedStreamCapability.promise;
|
||||
},
|
||||
|
||||
requestChunks: function ChunkedStreamManager_requestChunks(chunks,
|
||||
callback) {
|
||||
var requestId = this.currRequestId++;
|
||||
|
||||
var chunksNeeded;
|
||||
var i, ii;
|
||||
this.chunksNeededByRequest[requestId] = chunksNeeded = {};
|
||||
for (i = 0, ii = chunks.length; i < ii; i++) {
|
||||
if (!this.stream.hasChunk(chunks[i])) {
|
||||
chunksNeeded[chunks[i]] = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (isEmptyObj(chunksNeeded)) {
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
this.callbacksByRequest[requestId] = callback;
|
||||
|
||||
var chunksToRequest = [];
|
||||
for (var chunk in chunksNeeded) {
|
||||
chunk = chunk | 0;
|
||||
if (!(chunk in this.requestsByChunk)) {
|
||||
this.requestsByChunk[chunk] = [];
|
||||
chunksToRequest.push(chunk);
|
||||
}
|
||||
this.requestsByChunk[chunk].push(requestId);
|
||||
}
|
||||
|
||||
if (!chunksToRequest.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
var groupedChunksToRequest = this.groupChunks(chunksToRequest);
|
||||
|
||||
for (i = 0; i < groupedChunksToRequest.length; ++i) {
|
||||
var groupedChunk = groupedChunksToRequest[i];
|
||||
var begin = groupedChunk.beginChunk * this.chunkSize;
|
||||
var end = Math.min(groupedChunk.endChunk * this.chunkSize, this.length);
|
||||
this.sendRequest(begin, end);
|
||||
}
|
||||
},
|
||||
|
||||
getStream: function ChunkedStreamManager_getStream() {
|
||||
return this.stream;
|
||||
},
|
||||
|
||||
// Loads any chunks in the requested range that are not yet loaded
|
||||
requestRange: function ChunkedStreamManager_requestRange(
|
||||
begin, end, callback) {
|
||||
|
||||
end = Math.min(end, this.length);
|
||||
|
||||
var beginChunk = this.getBeginChunk(begin);
|
||||
var endChunk = this.getEndChunk(end);
|
||||
|
||||
var chunks = [];
|
||||
for (var chunk = beginChunk; chunk < endChunk; ++chunk) {
|
||||
chunks.push(chunk);
|
||||
}
|
||||
|
||||
this.requestChunks(chunks, callback);
|
||||
},
|
||||
|
||||
requestRanges: function ChunkedStreamManager_requestRanges(ranges,
|
||||
callback) {
|
||||
ranges = ranges || [];
|
||||
var chunksToRequest = [];
|
||||
|
||||
for (var i = 0; i < ranges.length; i++) {
|
||||
var beginChunk = this.getBeginChunk(ranges[i].begin);
|
||||
var endChunk = this.getEndChunk(ranges[i].end);
|
||||
for (var chunk = beginChunk; chunk < endChunk; ++chunk) {
|
||||
if (chunksToRequest.indexOf(chunk) < 0) {
|
||||
chunksToRequest.push(chunk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
chunksToRequest.sort(function(a, b) { return a - b; });
|
||||
this.requestChunks(chunksToRequest, callback);
|
||||
},
|
||||
|
||||
// Groups a sorted array of chunks into as few continguous larger
|
||||
// chunks as possible
|
||||
groupChunks: function ChunkedStreamManager_groupChunks(chunks) {
|
||||
var groupedChunks = [];
|
||||
var beginChunk = -1;
|
||||
var prevChunk = -1;
|
||||
for (var i = 0; i < chunks.length; ++i) {
|
||||
var chunk = chunks[i];
|
||||
|
||||
if (beginChunk < 0) {
|
||||
beginChunk = chunk;
|
||||
}
|
||||
|
||||
if (prevChunk >= 0 && prevChunk + 1 !== chunk) {
|
||||
groupedChunks.push({ beginChunk: beginChunk,
|
||||
endChunk: prevChunk + 1 });
|
||||
beginChunk = chunk;
|
||||
}
|
||||
if (i + 1 === chunks.length) {
|
||||
groupedChunks.push({ beginChunk: beginChunk,
|
||||
endChunk: chunk + 1 });
|
||||
}
|
||||
|
||||
prevChunk = chunk;
|
||||
}
|
||||
return groupedChunks;
|
||||
},
|
||||
|
||||
onProgress: function ChunkedStreamManager_onProgress(args) {
|
||||
var bytesLoaded = (this.stream.numChunksLoaded * this.chunkSize +
|
||||
args.loaded);
|
||||
this.msgHandler.send('DocProgress', {
|
||||
loaded: bytesLoaded,
|
||||
total: this.length
|
||||
});
|
||||
},
|
||||
|
||||
onReceiveData: function ChunkedStreamManager_onReceiveData(args) {
|
||||
var chunk = args.chunk;
|
||||
var isProgressive = args.begin === undefined;
|
||||
var begin = isProgressive ? this.progressiveDataLength : args.begin;
|
||||
var end = begin + chunk.byteLength;
|
||||
|
||||
var beginChunk = Math.floor(begin / this.chunkSize);
|
||||
var endChunk = end < this.length ? Math.floor(end / this.chunkSize) :
|
||||
Math.ceil(end / this.chunkSize);
|
||||
|
||||
if (isProgressive) {
|
||||
this.stream.onReceiveProgressiveData(chunk);
|
||||
this.progressiveDataLength = end;
|
||||
} else {
|
||||
this.stream.onReceiveData(begin, chunk);
|
||||
}
|
||||
|
||||
if (this.stream.allChunksLoaded()) {
|
||||
this._loadedStreamCapability.resolve(this.stream);
|
||||
}
|
||||
|
||||
var loadedRequests = [];
|
||||
var i, requestId;
|
||||
for (chunk = beginChunk; chunk < endChunk; ++chunk) {
|
||||
// The server might return more chunks than requested
|
||||
var requestIds = this.requestsByChunk[chunk] || [];
|
||||
delete this.requestsByChunk[chunk];
|
||||
|
||||
for (i = 0; i < requestIds.length; ++i) {
|
||||
requestId = requestIds[i];
|
||||
var chunksNeeded = this.chunksNeededByRequest[requestId];
|
||||
if (chunk in chunksNeeded) {
|
||||
delete chunksNeeded[chunk];
|
||||
}
|
||||
|
||||
if (!isEmptyObj(chunksNeeded)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
loadedRequests.push(requestId);
|
||||
}
|
||||
}
|
||||
|
||||
// If there are no pending requests, automatically fetch the next
|
||||
// unfetched chunk of the PDF
|
||||
if (!this.disableAutoFetch && isEmptyObj(this.requestsByChunk)) {
|
||||
var nextEmptyChunk;
|
||||
if (this.stream.numChunksLoaded === 1) {
|
||||
// This is a special optimization so that after fetching the first
|
||||
// chunk, rather than fetching the second chunk, we fetch the last
|
||||
// chunk.
|
||||
var lastChunk = this.stream.numChunks - 1;
|
||||
if (!this.stream.hasChunk(lastChunk)) {
|
||||
nextEmptyChunk = lastChunk;
|
||||
}
|
||||
} else {
|
||||
nextEmptyChunk = this.stream.nextEmptyChunk(endChunk);
|
||||
}
|
||||
if (isInt(nextEmptyChunk)) {
|
||||
this.requestChunks([nextEmptyChunk]);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < loadedRequests.length; ++i) {
|
||||
requestId = loadedRequests[i];
|
||||
var callback = this.callbacksByRequest[requestId];
|
||||
delete this.callbacksByRequest[requestId];
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
this.msgHandler.send('DocProgress', {
|
||||
loaded: this.stream.numChunksLoaded * this.chunkSize,
|
||||
total: this.length
|
||||
});
|
||||
},
|
||||
|
||||
onError: function ChunkedStreamManager_onError(err) {
|
||||
this._loadedStreamCapability.reject(err);
|
||||
},
|
||||
|
||||
getBeginChunk: function ChunkedStreamManager_getBeginChunk(begin) {
|
||||
var chunk = Math.floor(begin / this.chunkSize);
|
||||
return chunk;
|
||||
},
|
||||
|
||||
getEndChunk: function ChunkedStreamManager_getEndChunk(end) {
|
||||
if (end % this.chunkSize === 0) {
|
||||
return end / this.chunkSize;
|
||||
}
|
||||
|
||||
// 0 -> 0
|
||||
// 1 -> 1
|
||||
// 99 -> 1
|
||||
// 100 -> 1
|
||||
// 101 -> 2
|
||||
var chunk = Math.floor((end - 1) / this.chunkSize) + 1;
|
||||
return chunk;
|
||||
}
|
||||
};
|
||||
|
||||
return ChunkedStreamManager;
|
||||
})();
|
||||
|
956
.obsidian/pdfjs/pdfextract/pdfjs/src/core/cmap.js
vendored
Normal file
956
.obsidian/pdfjs/pdfextract/pdfjs/src/core/cmap.js
vendored
Normal file
@@ -0,0 +1,956 @@
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
/* Copyright 2012 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/* globals Util, isString, isInt, warn, error, isCmd, isEOF, isName, Lexer,
|
||||
isStream, StringStream, PDFJS, assert */
|
||||
|
||||
'use strict';
|
||||
|
||||
var BUILT_IN_CMAPS = [
|
||||
// << Start unicode maps.
|
||||
'Adobe-GB1-UCS2',
|
||||
'Adobe-CNS1-UCS2',
|
||||
'Adobe-Japan1-UCS2',
|
||||
'Adobe-Korea1-UCS2',
|
||||
// >> End unicode maps.
|
||||
'78-EUC-H',
|
||||
'78-EUC-V',
|
||||
'78-H',
|
||||
'78-RKSJ-H',
|
||||
'78-RKSJ-V',
|
||||
'78-V',
|
||||
'78ms-RKSJ-H',
|
||||
'78ms-RKSJ-V',
|
||||
'83pv-RKSJ-H',
|
||||
'90ms-RKSJ-H',
|
||||
'90ms-RKSJ-V',
|
||||
'90msp-RKSJ-H',
|
||||
'90msp-RKSJ-V',
|
||||
'90pv-RKSJ-H',
|
||||
'90pv-RKSJ-V',
|
||||
'Add-H',
|
||||
'Add-RKSJ-H',
|
||||
'Add-RKSJ-V',
|
||||
'Add-V',
|
||||
'Adobe-CNS1-0',
|
||||
'Adobe-CNS1-1',
|
||||
'Adobe-CNS1-2',
|
||||
'Adobe-CNS1-3',
|
||||
'Adobe-CNS1-4',
|
||||
'Adobe-CNS1-5',
|
||||
'Adobe-CNS1-6',
|
||||
'Adobe-GB1-0',
|
||||
'Adobe-GB1-1',
|
||||
'Adobe-GB1-2',
|
||||
'Adobe-GB1-3',
|
||||
'Adobe-GB1-4',
|
||||
'Adobe-GB1-5',
|
||||
'Adobe-Japan1-0',
|
||||
'Adobe-Japan1-1',
|
||||
'Adobe-Japan1-2',
|
||||
'Adobe-Japan1-3',
|
||||
'Adobe-Japan1-4',
|
||||
'Adobe-Japan1-5',
|
||||
'Adobe-Japan1-6',
|
||||
'Adobe-Korea1-0',
|
||||
'Adobe-Korea1-1',
|
||||
'Adobe-Korea1-2',
|
||||
'B5-H',
|
||||
'B5-V',
|
||||
'B5pc-H',
|
||||
'B5pc-V',
|
||||
'CNS-EUC-H',
|
||||
'CNS-EUC-V',
|
||||
'CNS1-H',
|
||||
'CNS1-V',
|
||||
'CNS2-H',
|
||||
'CNS2-V',
|
||||
'ETHK-B5-H',
|
||||
'ETHK-B5-V',
|
||||
'ETen-B5-H',
|
||||
'ETen-B5-V',
|
||||
'ETenms-B5-H',
|
||||
'ETenms-B5-V',
|
||||
'EUC-H',
|
||||
'EUC-V',
|
||||
'Ext-H',
|
||||
'Ext-RKSJ-H',
|
||||
'Ext-RKSJ-V',
|
||||
'Ext-V',
|
||||
'GB-EUC-H',
|
||||
'GB-EUC-V',
|
||||
'GB-H',
|
||||
'GB-V',
|
||||
'GBK-EUC-H',
|
||||
'GBK-EUC-V',
|
||||
'GBK2K-H',
|
||||
'GBK2K-V',
|
||||
'GBKp-EUC-H',
|
||||
'GBKp-EUC-V',
|
||||
'GBT-EUC-H',
|
||||
'GBT-EUC-V',
|
||||
'GBT-H',
|
||||
'GBT-V',
|
||||
'GBTpc-EUC-H',
|
||||
'GBTpc-EUC-V',
|
||||
'GBpc-EUC-H',
|
||||
'GBpc-EUC-V',
|
||||
'H',
|
||||
'HKdla-B5-H',
|
||||
'HKdla-B5-V',
|
||||
'HKdlb-B5-H',
|
||||
'HKdlb-B5-V',
|
||||
'HKgccs-B5-H',
|
||||
'HKgccs-B5-V',
|
||||
'HKm314-B5-H',
|
||||
'HKm314-B5-V',
|
||||
'HKm471-B5-H',
|
||||
'HKm471-B5-V',
|
||||
'HKscs-B5-H',
|
||||
'HKscs-B5-V',
|
||||
'Hankaku',
|
||||
'Hiragana',
|
||||
'KSC-EUC-H',
|
||||
'KSC-EUC-V',
|
||||
'KSC-H',
|
||||
'KSC-Johab-H',
|
||||
'KSC-Johab-V',
|
||||
'KSC-V',
|
||||
'KSCms-UHC-H',
|
||||
'KSCms-UHC-HW-H',
|
||||
'KSCms-UHC-HW-V',
|
||||
'KSCms-UHC-V',
|
||||
'KSCpc-EUC-H',
|
||||
'KSCpc-EUC-V',
|
||||
'Katakana',
|
||||
'NWP-H',
|
||||
'NWP-V',
|
||||
'RKSJ-H',
|
||||
'RKSJ-V',
|
||||
'Roman',
|
||||
'UniCNS-UCS2-H',
|
||||
'UniCNS-UCS2-V',
|
||||
'UniCNS-UTF16-H',
|
||||
'UniCNS-UTF16-V',
|
||||
'UniCNS-UTF32-H',
|
||||
'UniCNS-UTF32-V',
|
||||
'UniCNS-UTF8-H',
|
||||
'UniCNS-UTF8-V',
|
||||
'UniGB-UCS2-H',
|
||||
'UniGB-UCS2-V',
|
||||
'UniGB-UTF16-H',
|
||||
'UniGB-UTF16-V',
|
||||
'UniGB-UTF32-H',
|
||||
'UniGB-UTF32-V',
|
||||
'UniGB-UTF8-H',
|
||||
'UniGB-UTF8-V',
|
||||
'UniJIS-UCS2-H',
|
||||
'UniJIS-UCS2-HW-H',
|
||||
'UniJIS-UCS2-HW-V',
|
||||
'UniJIS-UCS2-V',
|
||||
'UniJIS-UTF16-H',
|
||||
'UniJIS-UTF16-V',
|
||||
'UniJIS-UTF32-H',
|
||||
'UniJIS-UTF32-V',
|
||||
'UniJIS-UTF8-H',
|
||||
'UniJIS-UTF8-V',
|
||||
'UniJIS2004-UTF16-H',
|
||||
'UniJIS2004-UTF16-V',
|
||||
'UniJIS2004-UTF32-H',
|
||||
'UniJIS2004-UTF32-V',
|
||||
'UniJIS2004-UTF8-H',
|
||||
'UniJIS2004-UTF8-V',
|
||||
'UniJISPro-UCS2-HW-V',
|
||||
'UniJISPro-UCS2-V',
|
||||
'UniJISPro-UTF8-V',
|
||||
'UniJISX0213-UTF32-H',
|
||||
'UniJISX0213-UTF32-V',
|
||||
'UniJISX02132004-UTF32-H',
|
||||
'UniJISX02132004-UTF32-V',
|
||||
'UniKS-UCS2-H',
|
||||
'UniKS-UCS2-V',
|
||||
'UniKS-UTF16-H',
|
||||
'UniKS-UTF16-V',
|
||||
'UniKS-UTF32-H',
|
||||
'UniKS-UTF32-V',
|
||||
'UniKS-UTF8-H',
|
||||
'UniKS-UTF8-V',
|
||||
'V',
|
||||
'WP-Symbol'];
|
||||
|
||||
// CMap, not to be confused with TrueType's cmap.
|
||||
var CMap = (function CMapClosure() {
|
||||
function CMap(builtInCMap) {
|
||||
// Codespace ranges are stored as follows:
|
||||
// [[1BytePairs], [2BytePairs], [3BytePairs], [4BytePairs]]
|
||||
// where nBytePairs are ranges e.g. [low1, high1, low2, high2, ...]
|
||||
this.codespaceRanges = [[], [], [], []];
|
||||
this.numCodespaceRanges = 0;
|
||||
// Map entries have one of two forms.
|
||||
// - cid chars are 16-bit unsigned integers, stored as integers.
|
||||
// - bf chars are variable-length byte sequences, stored as strings, with
|
||||
// one byte per character.
|
||||
this._map = [];
|
||||
this.vertical = false;
|
||||
this.useCMap = null;
|
||||
this.builtInCMap = builtInCMap;
|
||||
}
|
||||
CMap.prototype = {
|
||||
addCodespaceRange: function(n, low, high) {
|
||||
this.codespaceRanges[n - 1].push(low, high);
|
||||
this.numCodespaceRanges++;
|
||||
},
|
||||
|
||||
mapCidRange: function(low, high, dstLow) {
|
||||
while (low <= high) {
|
||||
this._map[low++] = dstLow++;
|
||||
}
|
||||
},
|
||||
|
||||
mapBfRange: function(low, high, dstLow) {
|
||||
var lastByte = dstLow.length - 1;
|
||||
while (low <= high) {
|
||||
this._map[low++] = dstLow;
|
||||
// Only the last byte has to be incremented.
|
||||
dstLow = dstLow.substr(0, lastByte) +
|
||||
String.fromCharCode(dstLow.charCodeAt(lastByte) + 1);
|
||||
}
|
||||
},
|
||||
|
||||
mapBfRangeToArray: function(low, high, array) {
|
||||
var i = 0, ii = array.length;
|
||||
while (low <= high && i < ii) {
|
||||
this._map[low] = array[i++];
|
||||
++low;
|
||||
}
|
||||
},
|
||||
|
||||
// This is used for both bf and cid chars.
|
||||
mapOne: function(src, dst) {
|
||||
this._map[src] = dst;
|
||||
},
|
||||
|
||||
lookup: function(code) {
|
||||
return this._map[code];
|
||||
},
|
||||
|
||||
contains: function(code) {
|
||||
return this._map[code] !== undefined;
|
||||
},
|
||||
|
||||
forEach: function(callback) {
|
||||
// Most maps have fewer than 65536 entries, and for those we use normal
|
||||
// array iteration. But really sparse tables are possible -- e.g. with
|
||||
// indices in the *billions*. For such tables we use for..in, which isn't
|
||||
// ideal because it stringifies the indices for all present elements, but
|
||||
// it does avoid iterating over every undefined entry.
|
||||
var map = this._map;
|
||||
var length = map.length;
|
||||
var i;
|
||||
if (length <= 0x10000) {
|
||||
for (i = 0; i < length; i++) {
|
||||
if (map[i] !== undefined) {
|
||||
callback(i, map[i]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (i in this._map) {
|
||||
callback(i, map[i]);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
charCodeOf: function(value) {
|
||||
return this._map.indexOf(value);
|
||||
},
|
||||
|
||||
getMap: function() {
|
||||
return this._map;
|
||||
},
|
||||
|
||||
readCharCode: function(str, offset, out) {
|
||||
var c = 0;
|
||||
var codespaceRanges = this.codespaceRanges;
|
||||
var codespaceRangesLen = this.codespaceRanges.length;
|
||||
// 9.7.6.2 CMap Mapping
|
||||
// The code length is at most 4.
|
||||
for (var n = 0; n < codespaceRangesLen; n++) {
|
||||
c = ((c << 8) | str.charCodeAt(offset + n)) >>> 0;
|
||||
// Check each codespace range to see if it falls within.
|
||||
var codespaceRange = codespaceRanges[n];
|
||||
for (var k = 0, kk = codespaceRange.length; k < kk;) {
|
||||
var low = codespaceRange[k++];
|
||||
var high = codespaceRange[k++];
|
||||
if (c >= low && c <= high) {
|
||||
out.charcode = c;
|
||||
out.length = n + 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
out.charcode = 0;
|
||||
out.length = 1;
|
||||
}
|
||||
};
|
||||
return CMap;
|
||||
})();
|
||||
|
||||
// A special case of CMap, where the _map array implicitly has a length of
|
||||
// 65535 and each element is equal to its index.
|
||||
var IdentityCMap = (function IdentityCMapClosure() {
|
||||
function IdentityCMap(vertical, n) {
|
||||
CMap.call(this);
|
||||
this.vertical = vertical;
|
||||
this.addCodespaceRange(n, 0, 0xffff);
|
||||
}
|
||||
Util.inherit(IdentityCMap, CMap, {});
|
||||
|
||||
IdentityCMap.prototype = {
|
||||
addCodespaceRange: CMap.prototype.addCodespaceRange,
|
||||
|
||||
mapCidRange: function(low, high, dstLow) {
|
||||
error('should not call mapCidRange');
|
||||
},
|
||||
|
||||
mapBfRange: function(low, high, dstLow) {
|
||||
error('should not call mapBfRange');
|
||||
},
|
||||
|
||||
mapBfRangeToArray: function(low, high, array) {
|
||||
error('should not call mapBfRangeToArray');
|
||||
},
|
||||
|
||||
mapOne: function(src, dst) {
|
||||
error('should not call mapCidOne');
|
||||
},
|
||||
|
||||
lookup: function(code) {
|
||||
return (isInt(code) && code <= 0xffff) ? code : undefined;
|
||||
},
|
||||
|
||||
contains: function(code) {
|
||||
return isInt(code) && code <= 0xffff;
|
||||
},
|
||||
|
||||
forEach: function(callback) {
|
||||
for (var i = 0; i <= 0xffff; i++) {
|
||||
callback(i, i);
|
||||
}
|
||||
},
|
||||
|
||||
charCodeOf: function(value) {
|
||||
return (isInt(value) && value <= 0xffff) ? value : -1;
|
||||
},
|
||||
|
||||
getMap: function() {
|
||||
// Sometimes identity maps must be instantiated, but it's rare.
|
||||
var map = new Array(0x10000);
|
||||
for (var i = 0; i <= 0xffff; i++) {
|
||||
map[i] = i;
|
||||
}
|
||||
return map;
|
||||
},
|
||||
|
||||
readCharCode: CMap.prototype.readCharCode
|
||||
};
|
||||
|
||||
return IdentityCMap;
|
||||
})();
|
||||
|
||||
var BinaryCMapReader = (function BinaryCMapReaderClosure() {
|
||||
function fetchBinaryData(url) {
|
||||
var nonBinaryRequest = PDFJS.disableWorker;
|
||||
var request = new XMLHttpRequest();
|
||||
request.open('GET', url, false);
|
||||
if (!nonBinaryRequest) {
|
||||
try {
|
||||
request.responseType = 'arraybuffer';
|
||||
nonBinaryRequest = request.responseType !== 'arraybuffer';
|
||||
} catch (e) {
|
||||
nonBinaryRequest = true;
|
||||
}
|
||||
}
|
||||
if (nonBinaryRequest && request.overrideMimeType) {
|
||||
request.overrideMimeType('text/plain; charset=x-user-defined');
|
||||
}
|
||||
request.send(null);
|
||||
if (nonBinaryRequest ? !request.responseText : !request.response) {
|
||||
error('Unable to get binary cMap at: ' + url);
|
||||
}
|
||||
if (nonBinaryRequest) {
|
||||
var data = Array.prototype.map.call(request.responseText, function (ch) {
|
||||
return ch.charCodeAt(0) & 255;
|
||||
});
|
||||
return new Uint8Array(data);
|
||||
}
|
||||
return new Uint8Array(request.response);
|
||||
}
|
||||
|
||||
function hexToInt(a, size) {
|
||||
var n = 0;
|
||||
for (var i = 0; i <= size; i++) {
|
||||
n = (n << 8) | a[i];
|
||||
}
|
||||
return n >>> 0;
|
||||
}
|
||||
|
||||
function hexToStr(a, size) {
|
||||
// This code is hot. Special-case some common values to avoid creating an
|
||||
// object with subarray().
|
||||
if (size === 1) {
|
||||
return String.fromCharCode(a[0], a[1]);
|
||||
}
|
||||
if (size === 3) {
|
||||
return String.fromCharCode(a[0], a[1], a[2], a[3]);
|
||||
}
|
||||
return String.fromCharCode.apply(null, a.subarray(0, size + 1));
|
||||
}
|
||||
|
||||
function addHex(a, b, size) {
|
||||
var c = 0;
|
||||
for (var i = size; i >= 0; i--) {
|
||||
c += a[i] + b[i];
|
||||
a[i] = c & 255;
|
||||
c >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
function incHex(a, size) {
|
||||
var c = 1;
|
||||
for (var i = size; i >= 0 && c > 0; i--) {
|
||||
c += a[i];
|
||||
a[i] = c & 255;
|
||||
c >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
var MAX_NUM_SIZE = 16;
|
||||
var MAX_ENCODED_NUM_SIZE = 19; // ceil(MAX_NUM_SIZE * 7 / 8)
|
||||
|
||||
function BinaryCMapStream(data) {
|
||||
this.buffer = data;
|
||||
this.pos = 0;
|
||||
this.end = data.length;
|
||||
this.tmpBuf = new Uint8Array(MAX_ENCODED_NUM_SIZE);
|
||||
}
|
||||
|
||||
BinaryCMapStream.prototype = {
|
||||
readByte: function () {
|
||||
if (this.pos >= this.end) {
|
||||
return -1;
|
||||
}
|
||||
return this.buffer[this.pos++];
|
||||
},
|
||||
readNumber: function () {
|
||||
var n = 0;
|
||||
var last;
|
||||
do {
|
||||
var b = this.readByte();
|
||||
if (b < 0) {
|
||||
error('unexpected EOF in bcmap');
|
||||
}
|
||||
last = !(b & 0x80);
|
||||
n = (n << 7) | (b & 0x7F);
|
||||
} while (!last);
|
||||
return n;
|
||||
},
|
||||
readSigned: function () {
|
||||
var n = this.readNumber();
|
||||
return (n & 1) ? ~(n >>> 1) : n >>> 1;
|
||||
},
|
||||
readHex: function (num, size) {
|
||||
num.set(this.buffer.subarray(this.pos,
|
||||
this.pos + size + 1));
|
||||
this.pos += size + 1;
|
||||
},
|
||||
readHexNumber: function (num, size) {
|
||||
var last;
|
||||
var stack = this.tmpBuf, sp = 0;
|
||||
do {
|
||||
var b = this.readByte();
|
||||
if (b < 0) {
|
||||
error('unexpected EOF in bcmap');
|
||||
}
|
||||
last = !(b & 0x80);
|
||||
stack[sp++] = b & 0x7F;
|
||||
} while (!last);
|
||||
var i = size, buffer = 0, bufferSize = 0;
|
||||
while (i >= 0) {
|
||||
while (bufferSize < 8 && stack.length > 0) {
|
||||
buffer = (stack[--sp] << bufferSize) | buffer;
|
||||
bufferSize += 7;
|
||||
}
|
||||
num[i] = buffer & 255;
|
||||
i--;
|
||||
buffer >>= 8;
|
||||
bufferSize -= 8;
|
||||
}
|
||||
},
|
||||
readHexSigned: function (num, size) {
|
||||
this.readHexNumber(num, size);
|
||||
var sign = num[size] & 1 ? 255 : 0;
|
||||
var c = 0;
|
||||
for (var i = 0; i <= size; i++) {
|
||||
c = ((c & 1) << 8) | num[i];
|
||||
num[i] = (c >> 1) ^ sign;
|
||||
}
|
||||
},
|
||||
readString: function () {
|
||||
var len = this.readNumber();
|
||||
var s = '';
|
||||
for (var i = 0; i < len; i++) {
|
||||
s += String.fromCharCode(this.readNumber());
|
||||
}
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
function processBinaryCMap(url, cMap, extend) {
|
||||
var data = fetchBinaryData(url);
|
||||
var stream = new BinaryCMapStream(data);
|
||||
|
||||
var header = stream.readByte();
|
||||
cMap.vertical = !!(header & 1);
|
||||
|
||||
var useCMap = null;
|
||||
var start = new Uint8Array(MAX_NUM_SIZE);
|
||||
var end = new Uint8Array(MAX_NUM_SIZE);
|
||||
var char = new Uint8Array(MAX_NUM_SIZE);
|
||||
var charCode = new Uint8Array(MAX_NUM_SIZE);
|
||||
var tmp = new Uint8Array(MAX_NUM_SIZE);
|
||||
var code;
|
||||
|
||||
var b;
|
||||
while ((b = stream.readByte()) >= 0) {
|
||||
var type = b >> 5;
|
||||
if (type === 7) { // metadata, e.g. comment or usecmap
|
||||
switch (b & 0x1F) {
|
||||
case 0:
|
||||
stream.readString(); // skipping comment
|
||||
break;
|
||||
case 1:
|
||||
useCMap = stream.readString();
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
var sequence = !!(b & 0x10);
|
||||
var dataSize = b & 15;
|
||||
|
||||
assert(dataSize + 1 <= MAX_NUM_SIZE);
|
||||
|
||||
var ucs2DataSize = 1;
|
||||
var subitemsCount = stream.readNumber();
|
||||
var i;
|
||||
switch (type) {
|
||||
case 0: // codespacerange
|
||||
stream.readHex(start, dataSize);
|
||||
stream.readHexNumber(end, dataSize);
|
||||
addHex(end, start, dataSize);
|
||||
cMap.addCodespaceRange(dataSize + 1, hexToInt(start, dataSize),
|
||||
hexToInt(end, dataSize));
|
||||
for (i = 1; i < subitemsCount; i++) {
|
||||
incHex(end, dataSize);
|
||||
stream.readHexNumber(start, dataSize);
|
||||
addHex(start, end, dataSize);
|
||||
stream.readHexNumber(end, dataSize);
|
||||
addHex(end, start, dataSize);
|
||||
cMap.addCodespaceRange(dataSize + 1, hexToInt(start, dataSize),
|
||||
hexToInt(end, dataSize));
|
||||
}
|
||||
break;
|
||||
case 1: // notdefrange
|
||||
stream.readHex(start, dataSize);
|
||||
stream.readHexNumber(end, dataSize);
|
||||
addHex(end, start, dataSize);
|
||||
code = stream.readNumber();
|
||||
// undefined range, skipping
|
||||
for (i = 1; i < subitemsCount; i++) {
|
||||
incHex(end, dataSize);
|
||||
stream.readHexNumber(start, dataSize);
|
||||
addHex(start, end, dataSize);
|
||||
stream.readHexNumber(end, dataSize);
|
||||
addHex(end, start, dataSize);
|
||||
code = stream.readNumber();
|
||||
// nop
|
||||
}
|
||||
break;
|
||||
case 2: // cidchar
|
||||
stream.readHex(char, dataSize);
|
||||
code = stream.readNumber();
|
||||
cMap.mapOne(hexToInt(char, dataSize), code);
|
||||
for (i = 1; i < subitemsCount; i++) {
|
||||
incHex(char, dataSize);
|
||||
if (!sequence) {
|
||||
stream.readHexNumber(tmp, dataSize);
|
||||
addHex(char, tmp, dataSize);
|
||||
}
|
||||
code = stream.readSigned() + (code + 1);
|
||||
cMap.mapOne(hexToInt(char, dataSize), code);
|
||||
}
|
||||
break;
|
||||
case 3: // cidrange
|
||||
stream.readHex(start, dataSize);
|
||||
stream.readHexNumber(end, dataSize);
|
||||
addHex(end, start, dataSize);
|
||||
code = stream.readNumber();
|
||||
cMap.mapCidRange(hexToInt(start, dataSize), hexToInt(end, dataSize),
|
||||
code);
|
||||
for (i = 1; i < subitemsCount; i++) {
|
||||
incHex(end, dataSize);
|
||||
if (!sequence) {
|
||||
stream.readHexNumber(start, dataSize);
|
||||
addHex(start, end, dataSize);
|
||||
} else {
|
||||
start.set(end);
|
||||
}
|
||||
stream.readHexNumber(end, dataSize);
|
||||
addHex(end, start, dataSize);
|
||||
code = stream.readNumber();
|
||||
cMap.mapCidRange(hexToInt(start, dataSize), hexToInt(end, dataSize),
|
||||
code);
|
||||
}
|
||||
break;
|
||||
case 4: // bfchar
|
||||
stream.readHex(char, ucs2DataSize);
|
||||
stream.readHex(charCode, dataSize);
|
||||
cMap.mapOne(hexToInt(char, ucs2DataSize),
|
||||
hexToStr(charCode, dataSize));
|
||||
for (i = 1; i < subitemsCount; i++) {
|
||||
incHex(char, ucs2DataSize);
|
||||
if (!sequence) {
|
||||
stream.readHexNumber(tmp, ucs2DataSize);
|
||||
addHex(char, tmp, ucs2DataSize);
|
||||
}
|
||||
incHex(charCode, dataSize);
|
||||
stream.readHexSigned(tmp, dataSize);
|
||||
addHex(charCode, tmp, dataSize);
|
||||
cMap.mapOne(hexToInt(char, ucs2DataSize),
|
||||
hexToStr(charCode, dataSize));
|
||||
}
|
||||
break;
|
||||
case 5: // bfrange
|
||||
stream.readHex(start, ucs2DataSize);
|
||||
stream.readHexNumber(end, ucs2DataSize);
|
||||
addHex(end, start, ucs2DataSize);
|
||||
stream.readHex(charCode, dataSize);
|
||||
cMap.mapBfRange(hexToInt(start, ucs2DataSize),
|
||||
hexToInt(end, ucs2DataSize),
|
||||
hexToStr(charCode, dataSize));
|
||||
for (i = 1; i < subitemsCount; i++) {
|
||||
incHex(end, ucs2DataSize);
|
||||
if (!sequence) {
|
||||
stream.readHexNumber(start, ucs2DataSize);
|
||||
addHex(start, end, ucs2DataSize);
|
||||
} else {
|
||||
start.set(end);
|
||||
}
|
||||
stream.readHexNumber(end, ucs2DataSize);
|
||||
addHex(end, start, ucs2DataSize);
|
||||
stream.readHex(charCode, dataSize);
|
||||
cMap.mapBfRange(hexToInt(start, ucs2DataSize),
|
||||
hexToInt(end, ucs2DataSize),
|
||||
hexToStr(charCode, dataSize));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
error('Unknown type: ' + type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (useCMap) {
|
||||
extend(useCMap);
|
||||
}
|
||||
return cMap;
|
||||
}
|
||||
|
||||
function BinaryCMapReader() {}
|
||||
|
||||
BinaryCMapReader.prototype = {
|
||||
read: processBinaryCMap
|
||||
};
|
||||
|
||||
return BinaryCMapReader;
|
||||
})();
|
||||
|
||||
var CMapFactory = (function CMapFactoryClosure() {
|
||||
function strToInt(str) {
|
||||
var a = 0;
|
||||
for (var i = 0; i < str.length; i++) {
|
||||
a = (a << 8) | str.charCodeAt(i);
|
||||
}
|
||||
return a >>> 0;
|
||||
}
|
||||
|
||||
function expectString(obj) {
|
||||
if (!isString(obj)) {
|
||||
error('Malformed CMap: expected string.');
|
||||
}
|
||||
}
|
||||
|
||||
function expectInt(obj) {
|
||||
if (!isInt(obj)) {
|
||||
error('Malformed CMap: expected int.');
|
||||
}
|
||||
}
|
||||
|
||||
function parseBfChar(cMap, lexer) {
|
||||
while (true) {
|
||||
var obj = lexer.getObj();
|
||||
if (isEOF(obj)) {
|
||||
break;
|
||||
}
|
||||
if (isCmd(obj, 'endbfchar')) {
|
||||
return;
|
||||
}
|
||||
expectString(obj);
|
||||
var src = strToInt(obj);
|
||||
obj = lexer.getObj();
|
||||
// TODO are /dstName used?
|
||||
expectString(obj);
|
||||
var dst = obj;
|
||||
cMap.mapOne(src, dst);
|
||||
}
|
||||
}
|
||||
|
||||
function parseBfRange(cMap, lexer) {
|
||||
while (true) {
|
||||
var obj = lexer.getObj();
|
||||
if (isEOF(obj)) {
|
||||
break;
|
||||
}
|
||||
if (isCmd(obj, 'endbfrange')) {
|
||||
return;
|
||||
}
|
||||
expectString(obj);
|
||||
var low = strToInt(obj);
|
||||
obj = lexer.getObj();
|
||||
expectString(obj);
|
||||
var high = strToInt(obj);
|
||||
obj = lexer.getObj();
|
||||
if (isInt(obj) || isString(obj)) {
|
||||
var dstLow = isInt(obj) ? String.fromCharCode(obj) : obj;
|
||||
cMap.mapBfRange(low, high, dstLow);
|
||||
} else if (isCmd(obj, '[')) {
|
||||
obj = lexer.getObj();
|
||||
var array = [];
|
||||
while (!isCmd(obj, ']') && !isEOF(obj)) {
|
||||
array.push(obj);
|
||||
obj = lexer.getObj();
|
||||
}
|
||||
cMap.mapBfRangeToArray(low, high, array);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
error('Invalid bf range.');
|
||||
}
|
||||
|
||||
function parseCidChar(cMap, lexer) {
|
||||
while (true) {
|
||||
var obj = lexer.getObj();
|
||||
if (isEOF(obj)) {
|
||||
break;
|
||||
}
|
||||
if (isCmd(obj, 'endcidchar')) {
|
||||
return;
|
||||
}
|
||||
expectString(obj);
|
||||
var src = strToInt(obj);
|
||||
obj = lexer.getObj();
|
||||
expectInt(obj);
|
||||
var dst = obj;
|
||||
cMap.mapOne(src, dst);
|
||||
}
|
||||
}
|
||||
|
||||
function parseCidRange(cMap, lexer) {
|
||||
while (true) {
|
||||
var obj = lexer.getObj();
|
||||
if (isEOF(obj)) {
|
||||
break;
|
||||
}
|
||||
if (isCmd(obj, 'endcidrange')) {
|
||||
return;
|
||||
}
|
||||
expectString(obj);
|
||||
var low = strToInt(obj);
|
||||
obj = lexer.getObj();
|
||||
expectString(obj);
|
||||
var high = strToInt(obj);
|
||||
obj = lexer.getObj();
|
||||
expectInt(obj);
|
||||
var dstLow = obj;
|
||||
cMap.mapCidRange(low, high, dstLow);
|
||||
}
|
||||
}
|
||||
|
||||
function parseCodespaceRange(cMap, lexer) {
|
||||
while (true) {
|
||||
var obj = lexer.getObj();
|
||||
if (isEOF(obj)) {
|
||||
break;
|
||||
}
|
||||
if (isCmd(obj, 'endcodespacerange')) {
|
||||
return;
|
||||
}
|
||||
if (!isString(obj)) {
|
||||
break;
|
||||
}
|
||||
var low = strToInt(obj);
|
||||
obj = lexer.getObj();
|
||||
if (!isString(obj)) {
|
||||
break;
|
||||
}
|
||||
var high = strToInt(obj);
|
||||
cMap.addCodespaceRange(obj.length, low, high);
|
||||
}
|
||||
error('Invalid codespace range.');
|
||||
}
|
||||
|
||||
function parseWMode(cMap, lexer) {
|
||||
var obj = lexer.getObj();
|
||||
if (isInt(obj)) {
|
||||
cMap.vertical = !!obj;
|
||||
}
|
||||
}
|
||||
|
||||
function parseCMap(cMap, lexer, builtInCMapParams, useCMap) {
|
||||
var previous;
|
||||
var embededUseCMap;
|
||||
objLoop: while (true) {
|
||||
var obj = lexer.getObj();
|
||||
if (isEOF(obj)) {
|
||||
break;
|
||||
} else if (isName(obj)) {
|
||||
if (obj.name === 'WMode') {
|
||||
parseWMode(cMap, lexer);
|
||||
}
|
||||
previous = obj;
|
||||
} else if (isCmd(obj)) {
|
||||
switch (obj.cmd) {
|
||||
case 'endcmap':
|
||||
break objLoop;
|
||||
case 'usecmap':
|
||||
if (isName(previous)) {
|
||||
embededUseCMap = previous.name;
|
||||
}
|
||||
break;
|
||||
case 'begincodespacerange':
|
||||
parseCodespaceRange(cMap, lexer);
|
||||
break;
|
||||
case 'beginbfchar':
|
||||
parseBfChar(cMap, lexer);
|
||||
break;
|
||||
case 'begincidchar':
|
||||
parseCidChar(cMap, lexer);
|
||||
break;
|
||||
case 'beginbfrange':
|
||||
parseBfRange(cMap, lexer);
|
||||
break;
|
||||
case 'begincidrange':
|
||||
parseCidRange(cMap, lexer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!useCMap && embededUseCMap) {
|
||||
// Load the usecmap definition from the file only if there wasn't one
|
||||
// specified.
|
||||
useCMap = embededUseCMap;
|
||||
}
|
||||
if (useCMap) {
|
||||
extendCMap(cMap, builtInCMapParams, useCMap);
|
||||
}
|
||||
}
|
||||
|
||||
function extendCMap(cMap, builtInCMapParams, useCMap) {
|
||||
cMap.useCMap = createBuiltInCMap(useCMap, builtInCMapParams);
|
||||
// If there aren't any code space ranges defined clone all the parent ones
|
||||
// into this cMap.
|
||||
if (cMap.numCodespaceRanges === 0) {
|
||||
var useCodespaceRanges = cMap.useCMap.codespaceRanges;
|
||||
for (var i = 0; i < useCodespaceRanges.length; i++) {
|
||||
cMap.codespaceRanges[i] = useCodespaceRanges[i].slice();
|
||||
}
|
||||
cMap.numCodespaceRanges = cMap.useCMap.numCodespaceRanges;
|
||||
}
|
||||
// Merge the map into the current one, making sure not to override
|
||||
// any previously defined entries.
|
||||
cMap.useCMap.forEach(function(key, value) {
|
||||
if (!cMap.contains(key)) {
|
||||
cMap.mapOne(key, cMap.useCMap.lookup(key));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function parseBinaryCMap(name, builtInCMapParams) {
|
||||
var url = builtInCMapParams.url + name + '.bcmap';
|
||||
var cMap = new CMap(true);
|
||||
new BinaryCMapReader().read(url, cMap, function (useCMap) {
|
||||
extendCMap(cMap, builtInCMapParams, useCMap);
|
||||
});
|
||||
return cMap;
|
||||
}
|
||||
|
||||
function createBuiltInCMap(name, builtInCMapParams) {
|
||||
if (name === 'Identity-H') {
|
||||
return new IdentityCMap(false, 2);
|
||||
} else if (name === 'Identity-V') {
|
||||
return new IdentityCMap(true, 2);
|
||||
}
|
||||
if (BUILT_IN_CMAPS.indexOf(name) === -1) {
|
||||
error('Unknown cMap name: ' + name);
|
||||
}
|
||||
assert(builtInCMapParams, 'built-in cMap parameters are not provided');
|
||||
|
||||
if (builtInCMapParams.packed) {
|
||||
return parseBinaryCMap(name, builtInCMapParams);
|
||||
}
|
||||
|
||||
var request = new XMLHttpRequest();
|
||||
var url = builtInCMapParams.url + name;
|
||||
request.open('GET', url, false);
|
||||
request.send(null);
|
||||
if (!request.responseText) {
|
||||
error('Unable to get cMap at: ' + url);
|
||||
}
|
||||
var cMap = new CMap(true);
|
||||
var lexer = new Lexer(new StringStream(request.responseText));
|
||||
parseCMap(cMap, lexer, builtInCMapParams, null);
|
||||
return cMap;
|
||||
}
|
||||
|
||||
return {
|
||||
create: function (encoding, builtInCMapParams, useCMap) {
|
||||
if (isName(encoding)) {
|
||||
return createBuiltInCMap(encoding.name, builtInCMapParams);
|
||||
} else if (isStream(encoding)) {
|
||||
var cMap = new CMap();
|
||||
var lexer = new Lexer(encoding);
|
||||
try {
|
||||
parseCMap(cMap, lexer, builtInCMapParams, useCMap);
|
||||
} catch (e) {
|
||||
warn('Invalid CMap data. ' + e);
|
||||
}
|
||||
return cMap;
|
||||
}
|
||||
error('Encoding required.');
|
||||
}
|
||||
};
|
||||
})();
|
1246
.obsidian/pdfjs/pdfextract/pdfjs/src/core/colorspace.js
vendored
Normal file
1246
.obsidian/pdfjs/pdfextract/pdfjs/src/core/colorspace.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
531
.obsidian/pdfjs/pdfextract/pdfjs/src/core/core.js
vendored
Normal file
531
.obsidian/pdfjs/pdfextract/pdfjs/src/core/core.js
vendored
Normal file
@@ -0,0 +1,531 @@
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
/* Copyright 2012 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/* globals assert, calculateMD5, Catalog, Dict, error, info, isArray,
|
||||
isArrayBuffer, isName, isStream, isString, createPromiseCapability,
|
||||
Linearization, NullStream, PartialEvaluator, shadow, Stream, Lexer,
|
||||
StreamsSequenceStream, stringToPDFString, stringToBytes, Util, XRef,
|
||||
MissingDataException, Promise, Annotation, ObjectLoader, OperatorList
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var Page = (function PageClosure() {
|
||||
|
||||
var LETTER_SIZE_MEDIABOX = [0, 0, 612, 792];
|
||||
|
||||
function Page(pdfManager, xref, pageIndex, pageDict, ref, fontCache) {
|
||||
this.pdfManager = pdfManager;
|
||||
this.pageIndex = pageIndex;
|
||||
this.pageDict = pageDict;
|
||||
this.xref = xref;
|
||||
this.ref = ref;
|
||||
this.fontCache = fontCache;
|
||||
this.idCounters = {
|
||||
obj: 0
|
||||
};
|
||||
this.resourcesPromise = null;
|
||||
}
|
||||
|
||||
Page.prototype = {
|
||||
getPageProp: function Page_getPageProp(key) {
|
||||
return this.pageDict.get(key);
|
||||
},
|
||||
|
||||
getInheritedPageProp: function Page_inheritPageProp(key) {
|
||||
var dict = this.pageDict;
|
||||
var value = dict.get(key);
|
||||
while (value === undefined) {
|
||||
dict = dict.get('Parent');
|
||||
if (!dict) {
|
||||
break;
|
||||
}
|
||||
value = dict.get(key);
|
||||
}
|
||||
return value;
|
||||
},
|
||||
|
||||
get content() {
|
||||
return this.getPageProp('Contents');
|
||||
},
|
||||
|
||||
get resources() {
|
||||
var value = this.getInheritedPageProp('Resources');
|
||||
// For robustness: The spec states that a \Resources entry has to be
|
||||
// present, but can be empty. Some document omit it still. In this case
|
||||
// return an empty dictionary:
|
||||
if (value === undefined) {
|
||||
value = Dict.empty;
|
||||
}
|
||||
return shadow(this, 'resources', value);
|
||||
},
|
||||
|
||||
get mediaBox() {
|
||||
var obj = this.getInheritedPageProp('MediaBox');
|
||||
// Reset invalid media box to letter size.
|
||||
if (!isArray(obj) || obj.length !== 4) {
|
||||
obj = LETTER_SIZE_MEDIABOX;
|
||||
}
|
||||
return shadow(this, 'mediaBox', obj);
|
||||
},
|
||||
|
||||
get view() {
|
||||
var mediaBox = this.mediaBox;
|
||||
var cropBox = this.getInheritedPageProp('CropBox');
|
||||
if (!isArray(cropBox) || cropBox.length !== 4) {
|
||||
return shadow(this, 'view', mediaBox);
|
||||
}
|
||||
|
||||
// From the spec, 6th ed., p.963:
|
||||
// "The crop, bleed, trim, and art boxes should not ordinarily
|
||||
// extend beyond the boundaries of the media box. If they do, they are
|
||||
// effectively reduced to their intersection with the media box."
|
||||
cropBox = Util.intersect(cropBox, mediaBox);
|
||||
if (!cropBox) {
|
||||
return shadow(this, 'view', mediaBox);
|
||||
}
|
||||
return shadow(this, 'view', cropBox);
|
||||
},
|
||||
|
||||
get annotationRefs() {
|
||||
return shadow(this, 'annotationRefs',
|
||||
this.getInheritedPageProp('Annots'));
|
||||
},
|
||||
|
||||
get rotate() {
|
||||
var rotate = this.getInheritedPageProp('Rotate') || 0;
|
||||
// Normalize rotation so it's a multiple of 90 and between 0 and 270
|
||||
if (rotate % 90 !== 0) {
|
||||
rotate = 0;
|
||||
} else if (rotate >= 360) {
|
||||
rotate = rotate % 360;
|
||||
} else if (rotate < 0) {
|
||||
// The spec doesn't cover negatives, assume its counterclockwise
|
||||
// rotation. The following is the other implementation of modulo.
|
||||
rotate = ((rotate % 360) + 360) % 360;
|
||||
}
|
||||
return shadow(this, 'rotate', rotate);
|
||||
},
|
||||
|
||||
getContentStream: function Page_getContentStream() {
|
||||
var content = this.content;
|
||||
var stream;
|
||||
if (isArray(content)) {
|
||||
// fetching items
|
||||
var xref = this.xref;
|
||||
var i, n = content.length;
|
||||
var streams = [];
|
||||
for (i = 0; i < n; ++i) {
|
||||
streams.push(xref.fetchIfRef(content[i]));
|
||||
}
|
||||
stream = new StreamsSequenceStream(streams);
|
||||
} else if (isStream(content)) {
|
||||
stream = content;
|
||||
} else {
|
||||
// replacing non-existent page content with empty one
|
||||
stream = new NullStream();
|
||||
}
|
||||
return stream;
|
||||
},
|
||||
|
||||
loadResources: function Page_loadResources(keys) {
|
||||
if (!this.resourcesPromise) {
|
||||
// TODO: add async getInheritedPageProp and remove this.
|
||||
this.resourcesPromise = this.pdfManager.ensure(this, 'resources');
|
||||
}
|
||||
return this.resourcesPromise.then(function resourceSuccess() {
|
||||
var objectLoader = new ObjectLoader(this.resources.map,
|
||||
keys,
|
||||
this.xref);
|
||||
return objectLoader.load();
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
getOperatorList: function Page_getOperatorList(handler, intent) {
|
||||
var self = this;
|
||||
|
||||
var pdfManager = this.pdfManager;
|
||||
var contentStreamPromise = pdfManager.ensure(this, 'getContentStream',
|
||||
[]);
|
||||
var resourcesPromise = this.loadResources([
|
||||
'ExtGState',
|
||||
'ColorSpace',
|
||||
'Pattern',
|
||||
'Shading',
|
||||
'XObject',
|
||||
'Font'
|
||||
// ProcSet
|
||||
// Properties
|
||||
]);
|
||||
|
||||
var partialEvaluator = new PartialEvaluator(pdfManager, this.xref,
|
||||
handler, this.pageIndex,
|
||||
'p' + this.pageIndex + '_',
|
||||
this.idCounters,
|
||||
this.fontCache);
|
||||
|
||||
var dataPromises = Promise.all([contentStreamPromise, resourcesPromise]);
|
||||
var pageListPromise = dataPromises.then(function(data) {
|
||||
var contentStream = data[0];
|
||||
var opList = new OperatorList(intent, handler, self.pageIndex);
|
||||
|
||||
handler.send('StartRenderPage', {
|
||||
transparency: partialEvaluator.hasBlendModes(self.resources),
|
||||
pageIndex: self.pageIndex,
|
||||
intent: intent
|
||||
});
|
||||
return partialEvaluator.getOperatorList(contentStream, self.resources,
|
||||
opList).then(function () {
|
||||
return opList;
|
||||
});
|
||||
});
|
||||
|
||||
var annotationsPromise = pdfManager.ensure(this, 'annotations');
|
||||
return Promise.all([pageListPromise, annotationsPromise]).then(
|
||||
function(datas) {
|
||||
var pageOpList = datas[0];
|
||||
var annotations = datas[1];
|
||||
|
||||
if (annotations.length === 0) {
|
||||
pageOpList.flush(true);
|
||||
return pageOpList;
|
||||
}
|
||||
|
||||
var annotationsReadyPromise = Annotation.appendToOperatorList(
|
||||
annotations, pageOpList, pdfManager, partialEvaluator, intent);
|
||||
return annotationsReadyPromise.then(function () {
|
||||
pageOpList.flush(true);
|
||||
return pageOpList;
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
extractTextContent: function Page_extractTextContent() {
|
||||
var handler = {
|
||||
on: function nullHandlerOn() {},
|
||||
send: function nullHandlerSend() {}
|
||||
};
|
||||
|
||||
var self = this;
|
||||
|
||||
var pdfManager = this.pdfManager;
|
||||
var contentStreamPromise = pdfManager.ensure(this, 'getContentStream',
|
||||
[]);
|
||||
|
||||
var resourcesPromise = this.loadResources([
|
||||
'ExtGState',
|
||||
'XObject',
|
||||
'Font'
|
||||
]);
|
||||
|
||||
var dataPromises = Promise.all([contentStreamPromise,
|
||||
resourcesPromise]);
|
||||
return dataPromises.then(function(data) {
|
||||
var contentStream = data[0];
|
||||
var partialEvaluator = new PartialEvaluator(pdfManager, self.xref,
|
||||
handler, self.pageIndex,
|
||||
'p' + self.pageIndex + '_',
|
||||
self.idCounters,
|
||||
self.fontCache);
|
||||
|
||||
return partialEvaluator.getTextContent(contentStream,
|
||||
self.resources);
|
||||
});
|
||||
},
|
||||
|
||||
getAnnotationsData: function Page_getAnnotationsData() {
|
||||
var annotations = this.annotations;
|
||||
var annotationsData = [];
|
||||
for (var i = 0, n = annotations.length; i < n; ++i) {
|
||||
annotationsData.push(annotations[i].getData());
|
||||
}
|
||||
// sort items in visual order: top->bottom, left->right
|
||||
function sortAnnotations(a, b) {
|
||||
// rect=[x1, y1, x2, y2]
|
||||
if (a.rect[2] < b.rect[0]) return -1;
|
||||
if (b.rect[2] < a.rect[0]) return 1;
|
||||
if (a.rect[1] < b.rect[1]) return 1;
|
||||
if (a.rect[1] > b.rect[1]) return -1;
|
||||
return 0;
|
||||
}
|
||||
annotationsData.sort(sortAnnotations);
|
||||
// return annotations
|
||||
return annotationsData;
|
||||
},
|
||||
|
||||
get annotations() {
|
||||
var annotations = [];
|
||||
var annotationRefs = (this.annotationRefs || []);
|
||||
for (var i = 0, n = annotationRefs.length; i < n; ++i) {
|
||||
var annotationRef = annotationRefs[i];
|
||||
var annotation = Annotation.fromRef(this.xref, annotationRef);
|
||||
if (annotation) {
|
||||
annotations.push(annotation);
|
||||
}
|
||||
}
|
||||
return shadow(this, 'annotations', annotations);
|
||||
}
|
||||
};
|
||||
|
||||
return Page;
|
||||
})();
|
||||
|
||||
/**
|
||||
* The `PDFDocument` holds all the data of the PDF file. Compared to the
|
||||
* `PDFDoc`, this one doesn't have any job management code.
|
||||
* Right now there exists one PDFDocument on the main thread + one object
|
||||
* for each worker. If there is no worker support enabled, there are two
|
||||
* `PDFDocument` objects on the main thread created.
|
||||
*/
|
||||
var PDFDocument = (function PDFDocumentClosure() {
|
||||
function PDFDocument(pdfManager, arg, password) {
|
||||
if (isStream(arg)) {
|
||||
init.call(this, pdfManager, arg, password);
|
||||
} else if (isArrayBuffer(arg)) {
|
||||
init.call(this, pdfManager, new Stream(arg), password);
|
||||
} else {
|
||||
error('PDFDocument: Unknown argument type');
|
||||
}
|
||||
}
|
||||
|
||||
function init(pdfManager, stream, password) {
|
||||
assert(stream.length > 0, 'stream must have data');
|
||||
this.pdfManager = pdfManager;
|
||||
this.stream = stream;
|
||||
var xref = new XRef(this.stream, password, pdfManager);
|
||||
this.xref = xref;
|
||||
}
|
||||
|
||||
function find(stream, needle, limit, backwards) {
|
||||
var pos = stream.pos;
|
||||
var end = stream.end;
|
||||
var strBuf = [];
|
||||
if (pos + limit > end) {
|
||||
limit = end - pos;
|
||||
}
|
||||
for (var n = 0; n < limit; ++n) {
|
||||
strBuf.push(String.fromCharCode(stream.getByte()));
|
||||
}
|
||||
var str = strBuf.join('');
|
||||
stream.pos = pos;
|
||||
var index = backwards ? str.lastIndexOf(needle) : str.indexOf(needle);
|
||||
if (index === -1) {
|
||||
return false; /* not found */
|
||||
}
|
||||
stream.pos += index;
|
||||
return true; /* found */
|
||||
}
|
||||
|
||||
var DocumentInfoValidators = {
|
||||
get entries() {
|
||||
// Lazily build this since all the validation functions below are not
|
||||
// defined until after this file loads.
|
||||
return shadow(this, 'entries', {
|
||||
Title: isString,
|
||||
Author: isString,
|
||||
Subject: isString,
|
||||
Keywords: isString,
|
||||
Creator: isString,
|
||||
Producer: isString,
|
||||
CreationDate: isString,
|
||||
ModDate: isString,
|
||||
Trapped: isName
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
PDFDocument.prototype = {
|
||||
parse: function PDFDocument_parse(recoveryMode) {
|
||||
this.setup(recoveryMode);
|
||||
try {
|
||||
// checking if AcroForm is present
|
||||
this.acroForm = this.catalog.catDict.get('AcroForm');
|
||||
if (this.acroForm) {
|
||||
this.xfa = this.acroForm.get('XFA');
|
||||
var fields = this.acroForm.get('Fields');
|
||||
if ((!fields || !isArray(fields) || fields.length === 0) &&
|
||||
!this.xfa) {
|
||||
// no fields and no XFA -- not a form (?)
|
||||
this.acroForm = null;
|
||||
}
|
||||
}
|
||||
} catch (ex) {
|
||||
info('Something wrong with AcroForm entry');
|
||||
this.acroForm = null;
|
||||
}
|
||||
},
|
||||
|
||||
get linearization() {
|
||||
var linearization = null;
|
||||
if (this.stream.length) {
|
||||
try {
|
||||
linearization = Linearization.create(this.stream);
|
||||
} catch (err) {
|
||||
if (err instanceof MissingDataException) {
|
||||
throw err;
|
||||
}
|
||||
info(err);
|
||||
}
|
||||
}
|
||||
// shadow the prototype getter with a data property
|
||||
return shadow(this, 'linearization', linearization);
|
||||
},
|
||||
get startXRef() {
|
||||
var stream = this.stream;
|
||||
var startXRef = 0;
|
||||
var linearization = this.linearization;
|
||||
if (linearization) {
|
||||
// Find end of first obj.
|
||||
stream.reset();
|
||||
if (find(stream, 'endobj', 1024)) {
|
||||
startXRef = stream.pos + 6;
|
||||
}
|
||||
} else {
|
||||
// Find startxref by jumping backward from the end of the file.
|
||||
var step = 1024;
|
||||
var found = false, pos = stream.end;
|
||||
while (!found && pos > 0) {
|
||||
pos -= step - 'startxref'.length;
|
||||
if (pos < 0) {
|
||||
pos = 0;
|
||||
}
|
||||
stream.pos = pos;
|
||||
found = find(stream, 'startxref', step, true);
|
||||
}
|
||||
if (found) {
|
||||
stream.skip(9);
|
||||
var ch;
|
||||
do {
|
||||
ch = stream.getByte();
|
||||
} while (Lexer.isSpace(ch));
|
||||
var str = '';
|
||||
while (ch >= 0x20 && ch <= 0x39) { // < '9'
|
||||
str += String.fromCharCode(ch);
|
||||
ch = stream.getByte();
|
||||
}
|
||||
startXRef = parseInt(str, 10);
|
||||
if (isNaN(startXRef)) {
|
||||
startXRef = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
// shadow the prototype getter with a data property
|
||||
return shadow(this, 'startXRef', startXRef);
|
||||
},
|
||||
get mainXRefEntriesOffset() {
|
||||
var mainXRefEntriesOffset = 0;
|
||||
var linearization = this.linearization;
|
||||
if (linearization) {
|
||||
mainXRefEntriesOffset = linearization.mainXRefEntriesOffset;
|
||||
}
|
||||
// shadow the prototype getter with a data property
|
||||
return shadow(this, 'mainXRefEntriesOffset', mainXRefEntriesOffset);
|
||||
},
|
||||
// Find the header, remove leading garbage and setup the stream
|
||||
// starting from the header.
|
||||
checkHeader: function PDFDocument_checkHeader() {
|
||||
var stream = this.stream;
|
||||
stream.reset();
|
||||
if (find(stream, '%PDF-', 1024)) {
|
||||
// Found the header, trim off any garbage before it.
|
||||
stream.moveStart();
|
||||
// Reading file format version
|
||||
var MAX_VERSION_LENGTH = 12;
|
||||
var version = '', ch;
|
||||
while ((ch = stream.getByte()) > 0x20) { // SPACE
|
||||
if (version.length >= MAX_VERSION_LENGTH) {
|
||||
break;
|
||||
}
|
||||
version += String.fromCharCode(ch);
|
||||
}
|
||||
// removing "%PDF-"-prefix
|
||||
this.pdfFormatVersion = version.substring(5);
|
||||
return;
|
||||
}
|
||||
// May not be a PDF file, continue anyway.
|
||||
},
|
||||
parseStartXRef: function PDFDocument_parseStartXRef() {
|
||||
var startXRef = this.startXRef;
|
||||
this.xref.setStartXRef(startXRef);
|
||||
},
|
||||
setup: function PDFDocument_setup(recoveryMode) {
|
||||
this.xref.parse(recoveryMode);
|
||||
this.catalog = new Catalog(this.pdfManager, this.xref);
|
||||
},
|
||||
get numPages() {
|
||||
var linearization = this.linearization;
|
||||
var num = linearization ? linearization.numPages : this.catalog.numPages;
|
||||
// shadow the prototype getter
|
||||
return shadow(this, 'numPages', num);
|
||||
},
|
||||
get documentInfo() {
|
||||
var docInfo = {
|
||||
PDFFormatVersion: this.pdfFormatVersion,
|
||||
IsAcroFormPresent: !!this.acroForm,
|
||||
IsXFAPresent: !!this.xfa
|
||||
};
|
||||
var infoDict;
|
||||
try {
|
||||
infoDict = this.xref.trailer.get('Info');
|
||||
} catch (err) {
|
||||
info('The document information dictionary is invalid.');
|
||||
}
|
||||
if (infoDict) {
|
||||
var validEntries = DocumentInfoValidators.entries;
|
||||
// Only fill the document info with valid entries from the spec.
|
||||
for (var key in validEntries) {
|
||||
if (infoDict.has(key)) {
|
||||
var value = infoDict.get(key);
|
||||
// Make sure the value conforms to the spec.
|
||||
if (validEntries[key](value)) {
|
||||
docInfo[key] = (typeof value !== 'string' ?
|
||||
value : stringToPDFString(value));
|
||||
} else {
|
||||
info('Bad value in document info for "' + key + '"');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return shadow(this, 'documentInfo', docInfo);
|
||||
},
|
||||
get fingerprint() {
|
||||
var xref = this.xref, hash, fileID = '';
|
||||
|
||||
if (xref.trailer.has('ID')) {
|
||||
hash = stringToBytes(xref.trailer.get('ID')[0]);
|
||||
} else {
|
||||
hash = calculateMD5(this.stream.bytes.subarray(0, 100), 0, 100);
|
||||
}
|
||||
|
||||
for (var i = 0, n = hash.length; i < n; i++) {
|
||||
fileID += hash[i].toString(16);
|
||||
}
|
||||
|
||||
return shadow(this, 'fingerprint', fileID);
|
||||
},
|
||||
|
||||
getPage: function PDFDocument_getPage(pageIndex) {
|
||||
return this.catalog.getPage(pageIndex);
|
||||
},
|
||||
|
||||
cleanup: function PDFDocument_cleanup() {
|
||||
return this.catalog.cleanup();
|
||||
}
|
||||
};
|
||||
|
||||
return PDFDocument;
|
||||
})();
|
||||
|
2043
.obsidian/pdfjs/pdfextract/pdfjs/src/core/crypto.js
vendored
Normal file
2043
.obsidian/pdfjs/pdfextract/pdfjs/src/core/crypto.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2646
.obsidian/pdfjs/pdfextract/pdfjs/src/core/evaluator.js
vendored
Normal file
2646
.obsidian/pdfjs/pdfextract/pdfjs/src/core/evaluator.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
713
.obsidian/pdfjs/pdfextract/pdfjs/src/core/font_renderer.js
vendored
Normal file
713
.obsidian/pdfjs/pdfextract/pdfjs/src/core/font_renderer.js
vendored
Normal file
@@ -0,0 +1,713 @@
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
/* Copyright 2012 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/* globals error, bytesToString, Stream, GlyphsUnicode, CFFParser, Encodings,
|
||||
Util */
|
||||
|
||||
'use strict';
|
||||
|
||||
var FontRendererFactory = (function FontRendererFactoryClosure() {
|
||||
function getLong(data, offset) {
|
||||
return (data[offset] << 24) | (data[offset + 1] << 16) |
|
||||
(data[offset + 2] << 8) | data[offset + 3];
|
||||
}
|
||||
|
||||
function getUshort(data, offset) {
|
||||
return (data[offset] << 8) | data[offset + 1];
|
||||
}
|
||||
|
||||
function parseCmap(data, start, end) {
|
||||
var offset = (getUshort(data, start + 2) === 1 ?
|
||||
getLong(data, start + 8) : getLong(data, start + 16));
|
||||
var format = getUshort(data, start + offset);
|
||||
var length, ranges, p, i;
|
||||
if (format === 4) {
|
||||
length = getUshort(data, start + offset + 2);
|
||||
var segCount = getUshort(data, start + offset + 6) >> 1;
|
||||
p = start + offset + 14;
|
||||
ranges = [];
|
||||
for (i = 0; i < segCount; i++, p += 2) {
|
||||
ranges[i] = {end: getUshort(data, p)};
|
||||
}
|
||||
p += 2;
|
||||
for (i = 0; i < segCount; i++, p += 2) {
|
||||
ranges[i].start = getUshort(data, p);
|
||||
}
|
||||
for (i = 0; i < segCount; i++, p += 2) {
|
||||
ranges[i].idDelta = getUshort(data, p);
|
||||
}
|
||||
for (i = 0; i < segCount; i++, p += 2) {
|
||||
var idOffset = getUshort(data, p);
|
||||
if (idOffset === 0) {
|
||||
continue;
|
||||
}
|
||||
ranges[i].ids = [];
|
||||
for (var j = 0, jj = ranges[i].end - ranges[i].start + 1; j < jj; j++) {
|
||||
ranges[i].ids[j] = getUshort(data, p + idOffset);
|
||||
idOffset += 2;
|
||||
}
|
||||
}
|
||||
return ranges;
|
||||
} else if (format === 12) {
|
||||
length = getLong(data, start + offset + 4);
|
||||
var groups = getLong(data, start + offset + 12);
|
||||
p = start + offset + 16;
|
||||
ranges = [];
|
||||
for (i = 0; i < groups; i++) {
|
||||
ranges.push({
|
||||
start: getLong(data, p),
|
||||
end: getLong(data, p + 4),
|
||||
idDelta: getLong(data, p + 8) - getLong(data, p)
|
||||
});
|
||||
p += 12;
|
||||
}
|
||||
return ranges;
|
||||
}
|
||||
error('not supported cmap: ' + format);
|
||||
}
|
||||
|
||||
function parseCff(data, start, end) {
|
||||
var properties = {};
|
||||
var parser = new CFFParser(new Stream(data, start, end - start),
|
||||
properties);
|
||||
var cff = parser.parse();
|
||||
return {
|
||||
glyphs: cff.charStrings.objects,
|
||||
subrs: (cff.topDict.privateDict && cff.topDict.privateDict.subrsIndex &&
|
||||
cff.topDict.privateDict.subrsIndex.objects),
|
||||
gsubrs: cff.globalSubrIndex && cff.globalSubrIndex.objects
|
||||
};
|
||||
}
|
||||
|
||||
function parseGlyfTable(glyf, loca, isGlyphLocationsLong) {
|
||||
var itemSize, itemDecode;
|
||||
if (isGlyphLocationsLong) {
|
||||
itemSize = 4;
|
||||
itemDecode = function fontItemDecodeLong(data, offset) {
|
||||
return (data[offset] << 24) | (data[offset + 1] << 16) |
|
||||
(data[offset + 2] << 8) | data[offset + 3];
|
||||
};
|
||||
} else {
|
||||
itemSize = 2;
|
||||
itemDecode = function fontItemDecode(data, offset) {
|
||||
return (data[offset] << 9) | (data[offset + 1] << 1);
|
||||
};
|
||||
}
|
||||
var glyphs = [];
|
||||
var startOffset = itemDecode(loca, 0);
|
||||
for (var j = itemSize; j < loca.length; j += itemSize) {
|
||||
var endOffset = itemDecode(loca, j);
|
||||
glyphs.push(glyf.subarray(startOffset, endOffset));
|
||||
startOffset = endOffset;
|
||||
}
|
||||
return glyphs;
|
||||
}
|
||||
|
||||
function lookupCmap(ranges, unicode) {
|
||||
var code = unicode.charCodeAt(0);
|
||||
var l = 0, r = ranges.length - 1;
|
||||
while (l < r) {
|
||||
var c = (l + r + 1) >> 1;
|
||||
if (code < ranges[c].start) {
|
||||
r = c - 1;
|
||||
} else {
|
||||
l = c;
|
||||
}
|
||||
}
|
||||
if (ranges[l].start <= code && code <= ranges[l].end) {
|
||||
return (ranges[l].idDelta + (ranges[l].ids ?
|
||||
ranges[l].ids[code - ranges[l].start] : code)) & 0xFFFF;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
function compileGlyf(code, js, font) {
|
||||
function moveTo(x, y) {
|
||||
js.push('c.moveTo(' + x + ',' + y + ');');
|
||||
}
|
||||
function lineTo(x, y) {
|
||||
js.push('c.lineTo(' + x + ',' + y + ');');
|
||||
}
|
||||
function quadraticCurveTo(xa, ya, x, y) {
|
||||
js.push('c.quadraticCurveTo(' + xa + ',' + ya + ',' +
|
||||
x + ',' + y + ');');
|
||||
}
|
||||
|
||||
var i = 0;
|
||||
var numberOfContours = ((code[i] << 24) | (code[i + 1] << 16)) >> 16;
|
||||
var flags;
|
||||
var x = 0, y = 0;
|
||||
i += 10;
|
||||
if (numberOfContours < 0) {
|
||||
// composite glyph
|
||||
do {
|
||||
flags = (code[i] << 8) | code[i + 1];
|
||||
var glyphIndex = (code[i + 2] << 8) | code[i + 3];
|
||||
i += 4;
|
||||
var arg1, arg2;
|
||||
if ((flags & 0x01)) {
|
||||
arg1 = ((code[i] << 24) | (code[i + 1] << 16)) >> 16;
|
||||
arg2 = ((code[i + 2] << 24) | (code[i + 3] << 16)) >> 16;
|
||||
i += 4;
|
||||
} else {
|
||||
arg1 = code[i++]; arg2 = code[i++];
|
||||
}
|
||||
if ((flags & 0x02)) {
|
||||
x = arg1;
|
||||
y = arg2;
|
||||
} else {
|
||||
x = 0; y = 0; // TODO "they are points" ?
|
||||
}
|
||||
var scaleX = 1, scaleY = 1, scale01 = 0, scale10 = 0;
|
||||
if ((flags & 0x08)) {
|
||||
scaleX =
|
||||
scaleY = ((code[i] << 24) | (code[i + 1] << 16)) / 1073741824;
|
||||
i += 2;
|
||||
} else if ((flags & 0x40)) {
|
||||
scaleX = ((code[i] << 24) | (code[i + 1] << 16)) / 1073741824;
|
||||
scaleY = ((code[i + 2] << 24) | (code[i + 3] << 16)) / 1073741824;
|
||||
i += 4;
|
||||
} else if ((flags & 0x80)) {
|
||||
scaleX = ((code[i] << 24) | (code[i + 1] << 16)) / 1073741824;
|
||||
scale01 = ((code[i + 2] << 24) | (code[i + 3] << 16)) / 1073741824;
|
||||
scale10 = ((code[i + 4] << 24) | (code[i + 5] << 16)) / 1073741824;
|
||||
scaleY = ((code[i + 6] << 24) | (code[i + 7] << 16)) / 1073741824;
|
||||
i += 8;
|
||||
}
|
||||
var subglyph = font.glyphs[glyphIndex];
|
||||
if (subglyph) {
|
||||
js.push('c.save();');
|
||||
js.push('c.transform(' + scaleX + ',' + scale01 + ',' +
|
||||
scale10 + ',' + scaleY + ',' + x + ',' + y + ');');
|
||||
compileGlyf(subglyph, js, font);
|
||||
js.push('c.restore();');
|
||||
}
|
||||
} while ((flags & 0x20));
|
||||
} else {
|
||||
// simple glyph
|
||||
var endPtsOfContours = [];
|
||||
var j, jj;
|
||||
for (j = 0; j < numberOfContours; j++) {
|
||||
endPtsOfContours.push((code[i] << 8) | code[i + 1]);
|
||||
i += 2;
|
||||
}
|
||||
var instructionLength = (code[i] << 8) | code[i + 1];
|
||||
i += 2 + instructionLength; // skipping the instructions
|
||||
var numberOfPoints = endPtsOfContours[endPtsOfContours.length - 1] + 1;
|
||||
var points = [];
|
||||
while (points.length < numberOfPoints) {
|
||||
flags = code[i++];
|
||||
var repeat = 1;
|
||||
if ((flags & 0x08)) {
|
||||
repeat += code[i++];
|
||||
}
|
||||
while (repeat-- > 0) {
|
||||
points.push({flags: flags});
|
||||
}
|
||||
}
|
||||
for (j = 0; j < numberOfPoints; j++) {
|
||||
switch (points[j].flags & 0x12) {
|
||||
case 0x00:
|
||||
x += ((code[i] << 24) | (code[i + 1] << 16)) >> 16;
|
||||
i += 2;
|
||||
break;
|
||||
case 0x02:
|
||||
x -= code[i++];
|
||||
break;
|
||||
case 0x12:
|
||||
x += code[i++];
|
||||
break;
|
||||
}
|
||||
points[j].x = x;
|
||||
}
|
||||
for (j = 0; j < numberOfPoints; j++) {
|
||||
switch (points[j].flags & 0x24) {
|
||||
case 0x00:
|
||||
y += ((code[i] << 24) | (code[i + 1] << 16)) >> 16;
|
||||
i += 2;
|
||||
break;
|
||||
case 0x04:
|
||||
y -= code[i++];
|
||||
break;
|
||||
case 0x24:
|
||||
y += code[i++];
|
||||
break;
|
||||
}
|
||||
points[j].y = y;
|
||||
}
|
||||
|
||||
var startPoint = 0;
|
||||
for (i = 0; i < numberOfContours; i++) {
|
||||
var endPoint = endPtsOfContours[i];
|
||||
// contours might have implicit points, which is located in the middle
|
||||
// between two neighboring off-curve points
|
||||
var contour = points.slice(startPoint, endPoint + 1);
|
||||
if ((contour[0].flags & 1)) {
|
||||
contour.push(contour[0]); // using start point at the contour end
|
||||
} else if ((contour[contour.length - 1].flags & 1)) {
|
||||
// first is off-curve point, trying to use one from the end
|
||||
contour.unshift(contour[contour.length - 1]);
|
||||
} else {
|
||||
// start and end are off-curve points, creating implicit one
|
||||
var p = {
|
||||
flags: 1,
|
||||
x: (contour[0].x + contour[contour.length - 1].x) / 2,
|
||||
y: (contour[0].y + contour[contour.length - 1].y) / 2
|
||||
};
|
||||
contour.unshift(p);
|
||||
contour.push(p);
|
||||
}
|
||||
moveTo(contour[0].x, contour[0].y);
|
||||
for (j = 1, jj = contour.length; j < jj; j++) {
|
||||
if ((contour[j].flags & 1)) {
|
||||
lineTo(contour[j].x, contour[j].y);
|
||||
} else if ((contour[j + 1].flags & 1)){
|
||||
quadraticCurveTo(contour[j].x, contour[j].y,
|
||||
contour[j + 1].x, contour[j + 1].y);
|
||||
j++;
|
||||
} else {
|
||||
quadraticCurveTo(contour[j].x, contour[j].y,
|
||||
(contour[j].x + contour[j + 1].x) / 2,
|
||||
(contour[j].y + contour[j + 1].y) / 2);
|
||||
}
|
||||
}
|
||||
startPoint = endPoint + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function compileCharString(code, js, font) {
|
||||
var stack = [];
|
||||
var x = 0, y = 0;
|
||||
var stems = 0;
|
||||
|
||||
function moveTo(x, y) {
|
||||
js.push('c.moveTo(' + x + ',' + y + ');');
|
||||
}
|
||||
function lineTo(x, y) {
|
||||
js.push('c.lineTo(' + x + ',' + y + ');');
|
||||
}
|
||||
function bezierCurveTo(x1, y1, x2, y2, x, y) {
|
||||
js.push('c.bezierCurveTo(' + x1 + ',' + y1 + ',' + x2 + ',' + y2 + ',' +
|
||||
x + ',' + y + ');');
|
||||
}
|
||||
|
||||
function parse(code) {
|
||||
var i = 0;
|
||||
while (i < code.length) {
|
||||
var stackClean = false;
|
||||
var v = code[i++];
|
||||
var xa, xb, ya, yb, y1, y2, y3, n, subrCode;
|
||||
switch (v) {
|
||||
case 1: // hstem
|
||||
stems += stack.length >> 1;
|
||||
stackClean = true;
|
||||
break;
|
||||
case 3: // vstem
|
||||
stems += stack.length >> 1;
|
||||
stackClean = true;
|
||||
break;
|
||||
case 4: // vmoveto
|
||||
y += stack.pop();
|
||||
moveTo(x, y);
|
||||
stackClean = true;
|
||||
break;
|
||||
case 5: // rlineto
|
||||
while (stack.length > 0) {
|
||||
x += stack.shift();
|
||||
y += stack.shift();
|
||||
lineTo(x, y);
|
||||
}
|
||||
break;
|
||||
case 6: // hlineto
|
||||
while (stack.length > 0) {
|
||||
x += stack.shift();
|
||||
lineTo(x, y);
|
||||
if (stack.length === 0) {
|
||||
break;
|
||||
}
|
||||
y += stack.shift();
|
||||
lineTo(x, y);
|
||||
}
|
||||
break;
|
||||
case 7: // vlineto
|
||||
while (stack.length > 0) {
|
||||
y += stack.shift();
|
||||
lineTo(x, y);
|
||||
if (stack.length === 0) {
|
||||
break;
|
||||
}
|
||||
x += stack.shift();
|
||||
lineTo(x, y);
|
||||
}
|
||||
break;
|
||||
case 8: // rrcurveto
|
||||
while (stack.length > 0) {
|
||||
xa = x + stack.shift(); ya = y + stack.shift();
|
||||
xb = xa + stack.shift(); yb = ya + stack.shift();
|
||||
x = xb + stack.shift(); y = yb + stack.shift();
|
||||
bezierCurveTo(xa, ya, xb, yb, x, y);
|
||||
}
|
||||
break;
|
||||
case 10: // callsubr
|
||||
n = stack.pop() + font.subrsBias;
|
||||
subrCode = font.subrs[n];
|
||||
if (subrCode) {
|
||||
parse(subrCode);
|
||||
}
|
||||
break;
|
||||
case 11: // return
|
||||
return;
|
||||
case 12:
|
||||
v = code[i++];
|
||||
switch (v) {
|
||||
case 34: // flex
|
||||
xa = x + stack.shift();
|
||||
xb = xa + stack.shift(); y1 = y + stack.shift();
|
||||
x = xb + stack.shift();
|
||||
bezierCurveTo(xa, y, xb, y1, x, y1);
|
||||
xa = x + stack.shift();
|
||||
xb = xa + stack.shift();
|
||||
x = xb + stack.shift();
|
||||
bezierCurveTo(xa, y1, xb, y, x, y);
|
||||
break;
|
||||
case 35: // flex
|
||||
xa = x + stack.shift(); ya = y + stack.shift();
|
||||
xb = xa + stack.shift(); yb = ya + stack.shift();
|
||||
x = xb + stack.shift(); y = yb + stack.shift();
|
||||
bezierCurveTo(xa, ya, xb, yb, x, y);
|
||||
xa = x + stack.shift(); ya = y + stack.shift();
|
||||
xb = xa + stack.shift(); yb = ya + stack.shift();
|
||||
x = xb + stack.shift(); y = yb + stack.shift();
|
||||
bezierCurveTo(xa, ya, xb, yb, x, y);
|
||||
stack.pop(); // fd
|
||||
break;
|
||||
case 36: // hflex1
|
||||
xa = x + stack.shift(); y1 = y + stack.shift();
|
||||
xb = xa + stack.shift(); y2 = y1 + stack.shift();
|
||||
x = xb + stack.shift();
|
||||
bezierCurveTo(xa, y1, xb, y2, x, y2);
|
||||
xa = x + stack.shift();
|
||||
xb = xa + stack.shift(); y3 = y2 + stack.shift();
|
||||
x = xb + stack.shift();
|
||||
bezierCurveTo(xa, y2, xb, y3, x, y);
|
||||
break;
|
||||
case 37: // flex1
|
||||
var x0 = x, y0 = y;
|
||||
xa = x + stack.shift(); ya = y + stack.shift();
|
||||
xb = xa + stack.shift(); yb = ya + stack.shift();
|
||||
x = xb + stack.shift(); y = yb + stack.shift();
|
||||
bezierCurveTo(xa, ya, xb, yb, x, y);
|
||||
xa = x + stack.shift(); ya = y + stack.shift();
|
||||
xb = xa + stack.shift(); yb = ya + stack.shift();
|
||||
x = xb; y = yb;
|
||||
if (Math.abs(x - x0) > Math.abs(y - y0)) {
|
||||
x += stack.shift();
|
||||
} else {
|
||||
y += stack.shift();
|
||||
}
|
||||
bezierCurveTo(xa, ya, xb, yb, x, y);
|
||||
break;
|
||||
default:
|
||||
error('unknown operator: 12 ' + v);
|
||||
}
|
||||
break;
|
||||
case 14: // endchar
|
||||
if (stack.length >= 4) {
|
||||
var achar = stack.pop();
|
||||
var bchar = stack.pop();
|
||||
y = stack.pop();
|
||||
x = stack.pop();
|
||||
js.push('c.save();');
|
||||
js.push('c.translate('+ x + ',' + y + ');');
|
||||
var gid = lookupCmap(font.cmap, String.fromCharCode(
|
||||
font.glyphNameMap[Encodings.StandardEncoding[achar]]));
|
||||
compileCharString(font.glyphs[gid], js, font);
|
||||
js.push('c.restore();');
|
||||
|
||||
gid = lookupCmap(font.cmap, String.fromCharCode(
|
||||
font.glyphNameMap[Encodings.StandardEncoding[bchar]]));
|
||||
compileCharString(font.glyphs[gid], js, font);
|
||||
}
|
||||
return;
|
||||
case 18: // hstemhm
|
||||
stems += stack.length >> 1;
|
||||
stackClean = true;
|
||||
break;
|
||||
case 19: // hintmask
|
||||
stems += stack.length >> 1;
|
||||
i += (stems + 7) >> 3;
|
||||
stackClean = true;
|
||||
break;
|
||||
case 20: // cntrmask
|
||||
stems += stack.length >> 1;
|
||||
i += (stems + 7) >> 3;
|
||||
stackClean = true;
|
||||
break;
|
||||
case 21: // rmoveto
|
||||
y += stack.pop();
|
||||
x += stack.pop();
|
||||
moveTo(x, y);
|
||||
stackClean = true;
|
||||
break;
|
||||
case 22: // hmoveto
|
||||
x += stack.pop();
|
||||
moveTo(x, y);
|
||||
stackClean = true;
|
||||
break;
|
||||
case 23: // vstemhm
|
||||
stems += stack.length >> 1;
|
||||
stackClean = true;
|
||||
break;
|
||||
case 24: // rcurveline
|
||||
while (stack.length > 2) {
|
||||
xa = x + stack.shift(); ya = y + stack.shift();
|
||||
xb = xa + stack.shift(); yb = ya + stack.shift();
|
||||
x = xb + stack.shift(); y = yb + stack.shift();
|
||||
bezierCurveTo(xa, ya, xb, yb, x, y);
|
||||
}
|
||||
x += stack.shift();
|
||||
y += stack.shift();
|
||||
lineTo(x, y);
|
||||
break;
|
||||
case 25: // rlinecurve
|
||||
while (stack.length > 6) {
|
||||
x += stack.shift();
|
||||
y += stack.shift();
|
||||
lineTo(x, y);
|
||||
}
|
||||
xa = x + stack.shift(); ya = y + stack.shift();
|
||||
xb = xa + stack.shift(); yb = ya + stack.shift();
|
||||
x = xb + stack.shift(); y = yb + stack.shift();
|
||||
bezierCurveTo(xa, ya, xb, yb, x, y);
|
||||
break;
|
||||
case 26: // vvcurveto
|
||||
if (stack.length % 2) {
|
||||
x += stack.shift();
|
||||
}
|
||||
while (stack.length > 0) {
|
||||
xa = x; ya = y + stack.shift();
|
||||
xb = xa + stack.shift(); yb = ya + stack.shift();
|
||||
x = xb; y = yb + stack.shift();
|
||||
bezierCurveTo(xa, ya, xb, yb, x, y);
|
||||
}
|
||||
break;
|
||||
case 27: // hhcurveto
|
||||
if (stack.length % 2) {
|
||||
y += stack.shift();
|
||||
}
|
||||
while (stack.length > 0) {
|
||||
xa = x + stack.shift(); ya = y;
|
||||
xb = xa + stack.shift(); yb = ya + stack.shift();
|
||||
x = xb + stack.shift(); y = yb;
|
||||
bezierCurveTo(xa, ya, xb, yb, x, y);
|
||||
}
|
||||
break;
|
||||
case 28:
|
||||
stack.push(((code[i] << 24) | (code[i + 1] << 16)) >> 16);
|
||||
i += 2;
|
||||
break;
|
||||
case 29: // callgsubr
|
||||
n = stack.pop() + font.gsubrsBias;
|
||||
subrCode = font.gsubrs[n];
|
||||
if (subrCode) {
|
||||
parse(subrCode);
|
||||
}
|
||||
break;
|
||||
case 30: // vhcurveto
|
||||
while (stack.length > 0) {
|
||||
xa = x; ya = y + stack.shift();
|
||||
xb = xa + stack.shift(); yb = ya + stack.shift();
|
||||
x = xb + stack.shift();
|
||||
y = yb + (stack.length === 1 ? stack.shift() : 0);
|
||||
bezierCurveTo(xa, ya, xb, yb, x, y);
|
||||
if (stack.length === 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
xa = x + stack.shift(); ya = y;
|
||||
xb = xa + stack.shift(); yb = ya + stack.shift();
|
||||
y = yb + stack.shift();
|
||||
x = xb + (stack.length === 1 ? stack.shift() : 0);
|
||||
bezierCurveTo(xa, ya, xb, yb, x, y);
|
||||
}
|
||||
break;
|
||||
case 31: // hvcurveto
|
||||
while (stack.length > 0) {
|
||||
xa = x + stack.shift(); ya = y;
|
||||
xb = xa + stack.shift(); yb = ya + stack.shift();
|
||||
y = yb + stack.shift();
|
||||
x = xb + (stack.length === 1 ? stack.shift() : 0);
|
||||
bezierCurveTo(xa, ya, xb, yb, x, y);
|
||||
if (stack.length === 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
xa = x; ya = y + stack.shift();
|
||||
xb = xa + stack.shift(); yb = ya + stack.shift();
|
||||
x = xb + stack.shift();
|
||||
y = yb + (stack.length === 1 ? stack.shift() : 0);
|
||||
bezierCurveTo(xa, ya, xb, yb, x, y);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (v < 32) {
|
||||
error('unknown operator: ' + v);
|
||||
}
|
||||
if (v < 247) {
|
||||
stack.push(v - 139);
|
||||
} else if (v < 251) {
|
||||
stack.push((v - 247) * 256 + code[i++] + 108);
|
||||
} else if (v < 255) {
|
||||
stack.push(-(v - 251) * 256 - code[i++] - 108);
|
||||
} else {
|
||||
stack.push(((code[i] << 24) | (code[i + 1] << 16) |
|
||||
(code[i + 2] << 8) | code[i + 3]) / 65536);
|
||||
i += 4;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (stackClean) {
|
||||
stack.length = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
parse(code);
|
||||
}
|
||||
|
||||
var noop = '';
|
||||
|
||||
function CompiledFont(fontMatrix) {
|
||||
this.compiledGlyphs = {};
|
||||
this.fontMatrix = fontMatrix;
|
||||
}
|
||||
CompiledFont.prototype = {
|
||||
getPathJs: function (unicode) {
|
||||
var gid = lookupCmap(this.cmap, unicode);
|
||||
var fn = this.compiledGlyphs[gid];
|
||||
if (!fn) {
|
||||
this.compiledGlyphs[gid] = fn = this.compileGlyph(this.glyphs[gid]);
|
||||
}
|
||||
return fn;
|
||||
},
|
||||
|
||||
compileGlyph: function (code) {
|
||||
if (!code || code.length === 0 || code[0] === 14) {
|
||||
return noop;
|
||||
}
|
||||
|
||||
var js = [];
|
||||
js.push('c.save();');
|
||||
js.push('c.transform(' + this.fontMatrix.join(',') + ');');
|
||||
js.push('c.scale(size, -size);');
|
||||
|
||||
this.compileGlyphImpl(code, js);
|
||||
|
||||
js.push('c.restore();');
|
||||
|
||||
return js.join('\n');
|
||||
},
|
||||
|
||||
compileGlyphImpl: function () {
|
||||
error('Children classes should implement this.');
|
||||
},
|
||||
|
||||
hasBuiltPath: function (unicode) {
|
||||
var gid = lookupCmap(this.cmap, unicode);
|
||||
return gid in this.compiledGlyphs;
|
||||
}
|
||||
};
|
||||
|
||||
function TrueTypeCompiled(glyphs, cmap, fontMatrix) {
|
||||
fontMatrix = fontMatrix || [0.000488, 0, 0, 0.000488, 0, 0];
|
||||
CompiledFont.call(this, fontMatrix);
|
||||
|
||||
this.glyphs = glyphs;
|
||||
this.cmap = cmap;
|
||||
|
||||
this.compiledGlyphs = [];
|
||||
}
|
||||
|
||||
Util.inherit(TrueTypeCompiled, CompiledFont, {
|
||||
compileGlyphImpl: function (code, js) {
|
||||
compileGlyf(code, js, this);
|
||||
}
|
||||
});
|
||||
|
||||
function Type2Compiled(cffInfo, cmap, fontMatrix, glyphNameMap) {
|
||||
fontMatrix = fontMatrix || [0.001, 0, 0, 0.001, 0, 0];
|
||||
CompiledFont.call(this, fontMatrix);
|
||||
this.glyphs = cffInfo.glyphs;
|
||||
this.gsubrs = cffInfo.gsubrs || [];
|
||||
this.subrs = cffInfo.subrs || [];
|
||||
this.cmap = cmap;
|
||||
this.glyphNameMap = glyphNameMap || GlyphsUnicode;
|
||||
|
||||
this.compiledGlyphs = [];
|
||||
this.gsubrsBias = (this.gsubrs.length < 1240 ?
|
||||
107 : (this.gsubrs.length < 33900 ? 1131 : 32768));
|
||||
this.subrsBias = (this.subrs.length < 1240 ?
|
||||
107 : (this.subrs.length < 33900 ? 1131 : 32768));
|
||||
}
|
||||
|
||||
Util.inherit(Type2Compiled, CompiledFont, {
|
||||
compileGlyphImpl: function (code, js) {
|
||||
compileCharString(code, js, this);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
return {
|
||||
create: function FontRendererFactory_create(font) {
|
||||
var data = new Uint8Array(font.data);
|
||||
var cmap, glyf, loca, cff, indexToLocFormat, unitsPerEm;
|
||||
var numTables = getUshort(data, 4);
|
||||
for (var i = 0, p = 12; i < numTables; i++, p += 16) {
|
||||
var tag = bytesToString(data.subarray(p, p + 4));
|
||||
var offset = getLong(data, p + 8);
|
||||
var length = getLong(data, p + 12);
|
||||
switch (tag) {
|
||||
case 'cmap':
|
||||
cmap = parseCmap(data, offset, offset + length);
|
||||
break;
|
||||
case 'glyf':
|
||||
glyf = data.subarray(offset, offset + length);
|
||||
break;
|
||||
case 'loca':
|
||||
loca = data.subarray(offset, offset + length);
|
||||
break;
|
||||
case 'head':
|
||||
unitsPerEm = getUshort(data, offset + 18);
|
||||
indexToLocFormat = getUshort(data, offset + 50);
|
||||
break;
|
||||
case 'CFF ':
|
||||
cff = parseCff(data, offset, offset + length);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (glyf) {
|
||||
var fontMatrix = (!unitsPerEm ? font.fontMatrix :
|
||||
[1 / unitsPerEm, 0, 0, 1 / unitsPerEm, 0, 0]);
|
||||
return new TrueTypeCompiled(
|
||||
parseGlyfTable(glyf, loca, indexToLocFormat), cmap, fontMatrix);
|
||||
} else {
|
||||
return new Type2Compiled(cff, cmap, font.fontMatrix, font.glyphNameMap);
|
||||
}
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
7210
.obsidian/pdfjs/pdfextract/pdfjs/src/core/fonts.js
vendored
Normal file
7210
.obsidian/pdfjs/pdfextract/pdfjs/src/core/fonts.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1132
.obsidian/pdfjs/pdfextract/pdfjs/src/core/function.js
vendored
Normal file
1132
.obsidian/pdfjs/pdfextract/pdfjs/src/core/function.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
4431
.obsidian/pdfjs/pdfextract/pdfjs/src/core/glyphlist.js
vendored
Normal file
4431
.obsidian/pdfjs/pdfextract/pdfjs/src/core/glyphlist.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
668
.obsidian/pdfjs/pdfextract/pdfjs/src/core/image.js
vendored
Normal file
668
.obsidian/pdfjs/pdfextract/pdfjs/src/core/image.js
vendored
Normal file
@@ -0,0 +1,668 @@
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
/* Copyright 2012 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/* globals assert, ColorSpace, DecodeStream, error, info, isArray, ImageKind,
|
||||
isStream, JpegStream, JpxImage, Name, Promise, Stream, warn */
|
||||
|
||||
'use strict';
|
||||
|
||||
var PDFImage = (function PDFImageClosure() {
|
||||
/**
|
||||
* Decode the image in the main thread if it supported. Resovles the promise
|
||||
* when the image data is ready.
|
||||
*/
|
||||
function handleImageData(handler, xref, res, image) {
|
||||
if (image instanceof JpegStream && image.isNativelyDecodable(xref, res)) {
|
||||
// For natively supported jpegs send them to the main thread for decoding.
|
||||
var dict = image.dict;
|
||||
var colorSpace = dict.get('ColorSpace', 'CS');
|
||||
colorSpace = ColorSpace.parse(colorSpace, xref, res);
|
||||
var numComps = colorSpace.numComps;
|
||||
var decodePromise = handler.sendWithPromise('JpegDecode',
|
||||
[image.getIR(), numComps]);
|
||||
return decodePromise.then(function (message) {
|
||||
var data = message.data;
|
||||
return new Stream(data, 0, data.length, image.dict);
|
||||
});
|
||||
} else {
|
||||
return Promise.resolve(image);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode and clamp a value. The formula is different from the spec because we
|
||||
* don't decode to float range [0,1], we decode it in the [0,max] range.
|
||||
*/
|
||||
function decodeAndClamp(value, addend, coefficient, max) {
|
||||
value = addend + value * coefficient;
|
||||
// Clamp the value to the range
|
||||
return (value < 0 ? 0 : (value > max ? max : value));
|
||||
}
|
||||
|
||||
function PDFImage(xref, res, image, inline, smask, mask, isMask) {
|
||||
this.image = image;
|
||||
var dict = image.dict;
|
||||
if (dict.has('Filter')) {
|
||||
var filter = dict.get('Filter').name;
|
||||
if (filter === 'JPXDecode') {
|
||||
var jpxImage = new JpxImage();
|
||||
jpxImage.parseImageProperties(image.stream);
|
||||
image.stream.reset();
|
||||
image.bitsPerComponent = jpxImage.bitsPerComponent;
|
||||
image.numComps = jpxImage.componentsCount;
|
||||
} else if (filter === 'JBIG2Decode') {
|
||||
image.bitsPerComponent = 1;
|
||||
image.numComps = 1;
|
||||
}
|
||||
}
|
||||
// TODO cache rendered images?
|
||||
|
||||
this.width = dict.get('Width', 'W');
|
||||
this.height = dict.get('Height', 'H');
|
||||
|
||||
if (this.width < 1 || this.height < 1) {
|
||||
error('Invalid image width: ' + this.width + ' or height: ' +
|
||||
this.height);
|
||||
}
|
||||
|
||||
this.interpolate = dict.get('Interpolate', 'I') || false;
|
||||
this.imageMask = dict.get('ImageMask', 'IM') || false;
|
||||
this.matte = dict.get('Matte') || false;
|
||||
|
||||
var bitsPerComponent = image.bitsPerComponent;
|
||||
if (!bitsPerComponent) {
|
||||
bitsPerComponent = dict.get('BitsPerComponent', 'BPC');
|
||||
if (!bitsPerComponent) {
|
||||
if (this.imageMask) {
|
||||
bitsPerComponent = 1;
|
||||
} else {
|
||||
error('Bits per component missing in image: ' + this.imageMask);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.bpc = bitsPerComponent;
|
||||
|
||||
if (!this.imageMask) {
|
||||
var colorSpace = dict.get('ColorSpace', 'CS');
|
||||
if (!colorSpace) {
|
||||
info('JPX images (which do not require color spaces)');
|
||||
switch (image.numComps) {
|
||||
case 1:
|
||||
colorSpace = Name.get('DeviceGray');
|
||||
break;
|
||||
case 3:
|
||||
colorSpace = Name.get('DeviceRGB');
|
||||
break;
|
||||
case 4:
|
||||
colorSpace = Name.get('DeviceCMYK');
|
||||
break;
|
||||
default:
|
||||
error('JPX images with ' + this.numComps +
|
||||
' color components not supported.');
|
||||
}
|
||||
}
|
||||
this.colorSpace = ColorSpace.parse(colorSpace, xref, res);
|
||||
this.numComps = this.colorSpace.numComps;
|
||||
}
|
||||
|
||||
this.decode = dict.get('Decode', 'D');
|
||||
this.needsDecode = false;
|
||||
if (this.decode &&
|
||||
((this.colorSpace && !this.colorSpace.isDefaultDecode(this.decode)) ||
|
||||
(isMask && !ColorSpace.isDefaultDecode(this.decode, 1)))) {
|
||||
this.needsDecode = true;
|
||||
// Do some preprocessing to avoid more math.
|
||||
var max = (1 << bitsPerComponent) - 1;
|
||||
this.decodeCoefficients = [];
|
||||
this.decodeAddends = [];
|
||||
for (var i = 0, j = 0; i < this.decode.length; i += 2, ++j) {
|
||||
var dmin = this.decode[i];
|
||||
var dmax = this.decode[i + 1];
|
||||
this.decodeCoefficients[j] = dmax - dmin;
|
||||
this.decodeAddends[j] = max * dmin;
|
||||
}
|
||||
}
|
||||
|
||||
if (smask) {
|
||||
this.smask = new PDFImage(xref, res, smask, false);
|
||||
} else if (mask) {
|
||||
if (isStream(mask)) {
|
||||
this.mask = new PDFImage(xref, res, mask, false, null, null, true);
|
||||
} else {
|
||||
// Color key mask (just an array).
|
||||
this.mask = mask;
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Handles processing of image data and returns the Promise that is resolved
|
||||
* with a PDFImage when the image is ready to be used.
|
||||
*/
|
||||
PDFImage.buildImage = function PDFImage_buildImage(handler, xref,
|
||||
res, image, inline) {
|
||||
var imagePromise = handleImageData(handler, xref, res, image);
|
||||
var smaskPromise;
|
||||
var maskPromise;
|
||||
|
||||
var smask = image.dict.get('SMask');
|
||||
var mask = image.dict.get('Mask');
|
||||
|
||||
if (smask) {
|
||||
smaskPromise = handleImageData(handler, xref, res, smask);
|
||||
maskPromise = Promise.resolve(null);
|
||||
} else {
|
||||
smaskPromise = Promise.resolve(null);
|
||||
if (mask) {
|
||||
if (isStream(mask)) {
|
||||
maskPromise = handleImageData(handler, xref, res, mask);
|
||||
} else if (isArray(mask)) {
|
||||
maskPromise = Promise.resolve(mask);
|
||||
} else {
|
||||
warn('Unsupported mask format.');
|
||||
maskPromise = Promise.resolve(null);
|
||||
}
|
||||
} else {
|
||||
maskPromise = Promise.resolve(null);
|
||||
}
|
||||
}
|
||||
return Promise.all([imagePromise, smaskPromise, maskPromise]).then(
|
||||
function(results) {
|
||||
var imageData = results[0];
|
||||
var smaskData = results[1];
|
||||
var maskData = results[2];
|
||||
return new PDFImage(xref, res, imageData, inline, smaskData, maskData);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Resize an image using the nearest neighbor algorithm. Currently only
|
||||
* supports one and three component images.
|
||||
* @param {TypedArray} pixels The original image with one component.
|
||||
* @param {Number} bpc Number of bits per component.
|
||||
* @param {Number} components Number of color components, 1 or 3 is supported.
|
||||
* @param {Number} w1 Original width.
|
||||
* @param {Number} h1 Original height.
|
||||
* @param {Number} w2 New width.
|
||||
* @param {Number} h2 New height.
|
||||
* @param {TypedArray} dest (Optional) The destination buffer.
|
||||
* @param {Number} alpha01 (Optional) Size reserved for the alpha channel.
|
||||
* @return {TypedArray} Resized image data.
|
||||
*/
|
||||
PDFImage.resize = function PDFImage_resize(pixels, bpc, components,
|
||||
w1, h1, w2, h2, dest, alpha01) {
|
||||
|
||||
if (components !== 1 && components !== 3) {
|
||||
error('Unsupported component count for resizing.');
|
||||
}
|
||||
|
||||
var length = w2 * h2 * components;
|
||||
var temp = dest ? dest : (bpc <= 8 ? new Uint8Array(length) :
|
||||
(bpc <= 16 ? new Uint16Array(length) : new Uint32Array(length)));
|
||||
var xRatio = w1 / w2;
|
||||
var yRatio = h1 / h2;
|
||||
var i, j, py, newIndex = 0, oldIndex;
|
||||
var xScaled = new Uint16Array(w2);
|
||||
var w1Scanline = w1 * components;
|
||||
if (alpha01 !== 1) {
|
||||
alpha01 = 0;
|
||||
}
|
||||
|
||||
for (j = 0; j < w2; j++) {
|
||||
xScaled[j] = Math.floor(j * xRatio) * components;
|
||||
}
|
||||
|
||||
if (components === 1) {
|
||||
for (i = 0; i < h2; i++) {
|
||||
py = Math.floor(i * yRatio) * w1Scanline;
|
||||
for (j = 0; j < w2; j++) {
|
||||
oldIndex = py + xScaled[j];
|
||||
temp[newIndex++] = pixels[oldIndex];
|
||||
}
|
||||
}
|
||||
} else if (components === 3) {
|
||||
for (i = 0; i < h2; i++) {
|
||||
py = Math.floor(i * yRatio) * w1Scanline;
|
||||
for (j = 0; j < w2; j++) {
|
||||
oldIndex = py + xScaled[j];
|
||||
temp[newIndex++] = pixels[oldIndex++];
|
||||
temp[newIndex++] = pixels[oldIndex++];
|
||||
temp[newIndex++] = pixels[oldIndex++];
|
||||
newIndex += alpha01;
|
||||
}
|
||||
}
|
||||
}
|
||||
return temp;
|
||||
};
|
||||
|
||||
PDFImage.createMask =
|
||||
function PDFImage_createMask(imgArray, width, height,
|
||||
imageIsFromDecodeStream, inverseDecode) {
|
||||
|
||||
// |imgArray| might not contain full data for every pixel of the mask, so
|
||||
// we need to distinguish between |computedLength| and |actualLength|.
|
||||
// In particular, if inverseDecode is true, then the array we return must
|
||||
// have a length of |computedLength|.
|
||||
|
||||
var computedLength = ((width + 7) >> 3) * height;
|
||||
var actualLength = imgArray.byteLength;
|
||||
var haveFullData = computedLength === actualLength;
|
||||
var data, i;
|
||||
|
||||
if (imageIsFromDecodeStream && (!inverseDecode || haveFullData)) {
|
||||
// imgArray came from a DecodeStream and its data is in an appropriate
|
||||
// form, so we can just transfer it.
|
||||
data = imgArray;
|
||||
} else if (!inverseDecode) {
|
||||
data = new Uint8Array(actualLength);
|
||||
data.set(imgArray);
|
||||
} else {
|
||||
data = new Uint8Array(computedLength);
|
||||
data.set(imgArray);
|
||||
for (i = actualLength; i < computedLength; i++) {
|
||||
data[i] = 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
// If necessary, invert the original mask data (but not any extra we might
|
||||
// have added above). It's safe to modify the array -- whether it's the
|
||||
// original or a copy, we're about to transfer it anyway, so nothing else
|
||||
// in this thread can be relying on its contents.
|
||||
if (inverseDecode) {
|
||||
for (i = 0; i < actualLength; i++) {
|
||||
data[i] = ~data[i];
|
||||
}
|
||||
}
|
||||
|
||||
return {data: data, width: width, height: height};
|
||||
};
|
||||
|
||||
PDFImage.prototype = {
|
||||
get drawWidth() {
|
||||
return Math.max(this.width,
|
||||
this.smask && this.smask.width || 0,
|
||||
this.mask && this.mask.width || 0);
|
||||
},
|
||||
|
||||
get drawHeight() {
|
||||
return Math.max(this.height,
|
||||
this.smask && this.smask.height || 0,
|
||||
this.mask && this.mask.height || 0);
|
||||
},
|
||||
|
||||
decodeBuffer: function PDFImage_decodeBuffer(buffer) {
|
||||
var bpc = this.bpc;
|
||||
var numComps = this.numComps;
|
||||
|
||||
var decodeAddends = this.decodeAddends;
|
||||
var decodeCoefficients = this.decodeCoefficients;
|
||||
var max = (1 << bpc) - 1;
|
||||
var i, ii;
|
||||
|
||||
if (bpc === 1) {
|
||||
// If the buffer needed decode that means it just needs to be inverted.
|
||||
for (i = 0, ii = buffer.length; i < ii; i++) {
|
||||
buffer[i] = +!(buffer[i]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
var index = 0;
|
||||
for (i = 0, ii = this.width * this.height; i < ii; i++) {
|
||||
for (var j = 0; j < numComps; j++) {
|
||||
buffer[index] = decodeAndClamp(buffer[index], decodeAddends[j],
|
||||
decodeCoefficients[j], max);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
getComponents: function PDFImage_getComponents(buffer) {
|
||||
var bpc = this.bpc;
|
||||
|
||||
// This image doesn't require any extra work.
|
||||
if (bpc === 8) {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
var width = this.width;
|
||||
var height = this.height;
|
||||
var numComps = this.numComps;
|
||||
|
||||
var length = width * height * numComps;
|
||||
var bufferPos = 0;
|
||||
var output = (bpc <= 8 ? new Uint8Array(length) :
|
||||
(bpc <= 16 ? new Uint16Array(length) : new Uint32Array(length)));
|
||||
var rowComps = width * numComps;
|
||||
|
||||
var max = (1 << bpc) - 1;
|
||||
var i = 0, ii, buf;
|
||||
|
||||
if (bpc === 1) {
|
||||
// Optimization for reading 1 bpc images.
|
||||
var mask, loop1End, loop2End;
|
||||
for (var j = 0; j < height; j++) {
|
||||
loop1End = i + (rowComps & ~7);
|
||||
loop2End = i + rowComps;
|
||||
|
||||
// unroll loop for all full bytes
|
||||
while (i < loop1End) {
|
||||
buf = buffer[bufferPos++];
|
||||
output[i] = (buf >> 7) & 1;
|
||||
output[i + 1] = (buf >> 6) & 1;
|
||||
output[i + 2] = (buf >> 5) & 1;
|
||||
output[i + 3] = (buf >> 4) & 1;
|
||||
output[i + 4] = (buf >> 3) & 1;
|
||||
output[i + 5] = (buf >> 2) & 1;
|
||||
output[i + 6] = (buf >> 1) & 1;
|
||||
output[i + 7] = buf & 1;
|
||||
i += 8;
|
||||
}
|
||||
|
||||
// handle remaing bits
|
||||
if (i < loop2End) {
|
||||
buf = buffer[bufferPos++];
|
||||
mask = 128;
|
||||
while (i < loop2End) {
|
||||
output[i++] = +!!(buf & mask);
|
||||
mask >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// The general case that handles all other bpc values.
|
||||
var bits = 0;
|
||||
buf = 0;
|
||||
for (i = 0, ii = length; i < ii; ++i) {
|
||||
if (i % rowComps === 0) {
|
||||
buf = 0;
|
||||
bits = 0;
|
||||
}
|
||||
|
||||
while (bits < bpc) {
|
||||
buf = (buf << 8) | buffer[bufferPos++];
|
||||
bits += 8;
|
||||
}
|
||||
|
||||
var remainingBits = bits - bpc;
|
||||
var value = buf >> remainingBits;
|
||||
output[i] = (value < 0 ? 0 : (value > max ? max : value));
|
||||
buf = buf & ((1 << remainingBits) - 1);
|
||||
bits = remainingBits;
|
||||
}
|
||||
}
|
||||
return output;
|
||||
},
|
||||
|
||||
fillOpacity: function PDFImage_fillOpacity(rgbaBuf, width, height,
|
||||
actualHeight, image) {
|
||||
var smask = this.smask;
|
||||
var mask = this.mask;
|
||||
var alphaBuf, sw, sh, i, ii, j;
|
||||
|
||||
if (smask) {
|
||||
sw = smask.width;
|
||||
sh = smask.height;
|
||||
alphaBuf = new Uint8Array(sw * sh);
|
||||
smask.fillGrayBuffer(alphaBuf);
|
||||
if (sw !== width || sh !== height) {
|
||||
alphaBuf = PDFImage.resize(alphaBuf, smask.bpc, 1, sw, sh, width,
|
||||
height);
|
||||
}
|
||||
} else if (mask) {
|
||||
if (mask instanceof PDFImage) {
|
||||
sw = mask.width;
|
||||
sh = mask.height;
|
||||
alphaBuf = new Uint8Array(sw * sh);
|
||||
mask.numComps = 1;
|
||||
mask.fillGrayBuffer(alphaBuf);
|
||||
|
||||
// Need to invert values in rgbaBuf
|
||||
for (i = 0, ii = sw * sh; i < ii; ++i) {
|
||||
alphaBuf[i] = 255 - alphaBuf[i];
|
||||
}
|
||||
|
||||
if (sw !== width || sh !== height) {
|
||||
alphaBuf = PDFImage.resize(alphaBuf, mask.bpc, 1, sw, sh, width,
|
||||
height);
|
||||
}
|
||||
} else if (isArray(mask)) {
|
||||
// Color key mask: if any of the compontents are outside the range
|
||||
// then they should be painted.
|
||||
alphaBuf = new Uint8Array(width * height);
|
||||
var numComps = this.numComps;
|
||||
for (i = 0, ii = width * height; i < ii; ++i) {
|
||||
var opacity = 0;
|
||||
var imageOffset = i * numComps;
|
||||
for (j = 0; j < numComps; ++j) {
|
||||
var color = image[imageOffset + j];
|
||||
var maskOffset = j * 2;
|
||||
if (color < mask[maskOffset] || color > mask[maskOffset + 1]) {
|
||||
opacity = 255;
|
||||
break;
|
||||
}
|
||||
}
|
||||
alphaBuf[i] = opacity;
|
||||
}
|
||||
} else {
|
||||
error('Unknown mask format.');
|
||||
}
|
||||
}
|
||||
|
||||
if (alphaBuf) {
|
||||
for (i = 0, j = 3, ii = width * actualHeight; i < ii; ++i, j += 4) {
|
||||
rgbaBuf[j] = alphaBuf[i];
|
||||
}
|
||||
} else {
|
||||
// No mask.
|
||||
for (i = 0, j = 3, ii = width * actualHeight; i < ii; ++i, j += 4) {
|
||||
rgbaBuf[j] = 255;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
undoPreblend: function PDFImage_undoPreblend(buffer, width, height) {
|
||||
var matte = this.smask && this.smask.matte;
|
||||
if (!matte) {
|
||||
return;
|
||||
}
|
||||
var matteRgb = this.colorSpace.getRgb(matte, 0);
|
||||
var matteR = matteRgb[0];
|
||||
var matteG = matteRgb[1];
|
||||
var matteB = matteRgb[2];
|
||||
var length = width * height * 4;
|
||||
var r, g, b;
|
||||
for (var i = 0; i < length; i += 4) {
|
||||
var alpha = buffer[i + 3];
|
||||
if (alpha === 0) {
|
||||
// according formula we have to get Infinity in all components
|
||||
// making it white (typical paper color) should be okay
|
||||
buffer[i] = 255;
|
||||
buffer[i + 1] = 255;
|
||||
buffer[i + 2] = 255;
|
||||
continue;
|
||||
}
|
||||
var k = 255 / alpha;
|
||||
r = (buffer[i] - matteR) * k + matteR;
|
||||
g = (buffer[i + 1] - matteG) * k + matteG;
|
||||
b = (buffer[i + 2] - matteB) * k + matteB;
|
||||
buffer[i] = r <= 0 ? 0 : r >= 255 ? 255 : r | 0;
|
||||
buffer[i + 1] = g <= 0 ? 0 : g >= 255 ? 255 : g | 0;
|
||||
buffer[i + 2] = b <= 0 ? 0 : b >= 255 ? 255 : b | 0;
|
||||
}
|
||||
},
|
||||
|
||||
createImageData: function PDFImage_createImageData(forceRGBA) {
|
||||
var drawWidth = this.drawWidth;
|
||||
var drawHeight = this.drawHeight;
|
||||
var imgData = { // other fields are filled in below
|
||||
width: drawWidth,
|
||||
height: drawHeight
|
||||
};
|
||||
|
||||
var numComps = this.numComps;
|
||||
var originalWidth = this.width;
|
||||
var originalHeight = this.height;
|
||||
var bpc = this.bpc;
|
||||
|
||||
// Rows start at byte boundary.
|
||||
var rowBytes = (originalWidth * numComps * bpc + 7) >> 3;
|
||||
var imgArray;
|
||||
|
||||
if (!forceRGBA) {
|
||||
// If it is a 1-bit-per-pixel grayscale (i.e. black-and-white) image
|
||||
// without any complications, we pass a same-sized copy to the main
|
||||
// thread rather than expanding by 32x to RGBA form. This saves *lots*
|
||||
// of memory for many scanned documents. It's also much faster.
|
||||
//
|
||||
// Similarly, if it is a 24-bit-per pixel RGB image without any
|
||||
// complications, we avoid expanding by 1.333x to RGBA form.
|
||||
var kind;
|
||||
if (this.colorSpace.name === 'DeviceGray' && bpc === 1) {
|
||||
kind = ImageKind.GRAYSCALE_1BPP;
|
||||
} else if (this.colorSpace.name === 'DeviceRGB' && bpc === 8 &&
|
||||
!this.needsDecode) {
|
||||
kind = ImageKind.RGB_24BPP;
|
||||
}
|
||||
if (kind && !this.smask && !this.mask &&
|
||||
drawWidth === originalWidth && drawHeight === originalHeight) {
|
||||
imgData.kind = kind;
|
||||
|
||||
imgArray = this.getImageBytes(originalHeight * rowBytes);
|
||||
// If imgArray came from a DecodeStream, we're safe to transfer it
|
||||
// (and thus neuter it) because it will constitute the entire
|
||||
// DecodeStream's data. But if it came from a Stream, we need to
|
||||
// copy it because it'll only be a portion of the Stream's data, and
|
||||
// the rest will be read later on.
|
||||
if (this.image instanceof DecodeStream) {
|
||||
imgData.data = imgArray;
|
||||
} else {
|
||||
var newArray = new Uint8Array(imgArray.length);
|
||||
newArray.set(imgArray);
|
||||
imgData.data = newArray;
|
||||
}
|
||||
if (this.needsDecode) {
|
||||
// Invert the buffer (which must be grayscale if we reached here).
|
||||
assert(kind === ImageKind.GRAYSCALE_1BPP);
|
||||
var buffer = imgData.data;
|
||||
for (var i = 0, ii = buffer.length; i < ii; i++) {
|
||||
buffer[i] ^= 0xff;
|
||||
}
|
||||
}
|
||||
return imgData;
|
||||
}
|
||||
if (this.image instanceof JpegStream && !this.smask && !this.mask) {
|
||||
imgData.kind = ImageKind.RGB_24BPP;
|
||||
imgData.data = this.getImageBytes(originalHeight * rowBytes,
|
||||
drawWidth, drawHeight, true);
|
||||
return imgData;
|
||||
}
|
||||
}
|
||||
|
||||
imgArray = this.getImageBytes(originalHeight * rowBytes);
|
||||
// imgArray can be incomplete (e.g. after CCITT fax encoding).
|
||||
var actualHeight = 0 | (imgArray.length / rowBytes *
|
||||
drawHeight / originalHeight);
|
||||
|
||||
var comps = this.getComponents(imgArray);
|
||||
|
||||
// If opacity data is present, use RGBA_32BPP form. Otherwise, use the
|
||||
// more compact RGB_24BPP form if allowable.
|
||||
var alpha01, maybeUndoPreblend;
|
||||
if (!forceRGBA && !this.smask && !this.mask) {
|
||||
imgData.kind = ImageKind.RGB_24BPP;
|
||||
imgData.data = new Uint8Array(drawWidth * drawHeight * 3);
|
||||
alpha01 = 0;
|
||||
maybeUndoPreblend = false;
|
||||
} else {
|
||||
imgData.kind = ImageKind.RGBA_32BPP;
|
||||
imgData.data = new Uint8Array(drawWidth * drawHeight * 4);
|
||||
alpha01 = 1;
|
||||
maybeUndoPreblend = true;
|
||||
|
||||
// Color key masking (opacity) must be performed before decoding.
|
||||
this.fillOpacity(imgData.data, drawWidth, drawHeight, actualHeight,
|
||||
comps);
|
||||
}
|
||||
|
||||
if (this.needsDecode) {
|
||||
this.decodeBuffer(comps);
|
||||
}
|
||||
this.colorSpace.fillRgb(imgData.data, originalWidth, originalHeight,
|
||||
drawWidth, drawHeight, actualHeight, bpc, comps,
|
||||
alpha01);
|
||||
if (maybeUndoPreblend) {
|
||||
this.undoPreblend(imgData.data, drawWidth, actualHeight);
|
||||
}
|
||||
|
||||
return imgData;
|
||||
},
|
||||
|
||||
fillGrayBuffer: function PDFImage_fillGrayBuffer(buffer) {
|
||||
var numComps = this.numComps;
|
||||
if (numComps !== 1) {
|
||||
error('Reading gray scale from a color image: ' + numComps);
|
||||
}
|
||||
|
||||
var width = this.width;
|
||||
var height = this.height;
|
||||
var bpc = this.bpc;
|
||||
|
||||
// rows start at byte boundary
|
||||
var rowBytes = (width * numComps * bpc + 7) >> 3;
|
||||
var imgArray = this.getImageBytes(height * rowBytes);
|
||||
|
||||
var comps = this.getComponents(imgArray);
|
||||
var i, length;
|
||||
|
||||
if (bpc === 1) {
|
||||
// inline decoding (= inversion) for 1 bpc images
|
||||
length = width * height;
|
||||
if (this.needsDecode) {
|
||||
// invert and scale to {0, 255}
|
||||
for (i = 0; i < length; ++i) {
|
||||
buffer[i] = (comps[i] - 1) & 255;
|
||||
}
|
||||
} else {
|
||||
// scale to {0, 255}
|
||||
for (i = 0; i < length; ++i) {
|
||||
buffer[i] = (-comps[i]) & 255;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.needsDecode) {
|
||||
this.decodeBuffer(comps);
|
||||
}
|
||||
length = width * height;
|
||||
// we aren't using a colorspace so we need to scale the value
|
||||
var scale = 255 / ((1 << bpc) - 1);
|
||||
for (i = 0; i < length; ++i) {
|
||||
buffer[i] = (scale * comps[i]) | 0;
|
||||
}
|
||||
},
|
||||
|
||||
getImageBytes: function PDFImage_getImageBytes(length,
|
||||
drawWidth, drawHeight,
|
||||
forceRGB) {
|
||||
this.image.reset();
|
||||
this.image.drawWidth = drawWidth || this.width;
|
||||
this.image.drawHeight = drawHeight || this.height;
|
||||
this.image.forceRGB = !!forceRGB;
|
||||
return this.image.getBytes(length);
|
||||
}
|
||||
};
|
||||
return PDFImage;
|
||||
})();
|
1089
.obsidian/pdfjs/pdfextract/pdfjs/src/core/jbig2.js
vendored
Normal file
1089
.obsidian/pdfjs/pdfextract/pdfjs/src/core/jbig2.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1036
.obsidian/pdfjs/pdfextract/pdfjs/src/core/jpg.js
vendored
Normal file
1036
.obsidian/pdfjs/pdfextract/pdfjs/src/core/jpg.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1964
.obsidian/pdfjs/pdfextract/pdfjs/src/core/jpx.js
vendored
Normal file
1964
.obsidian/pdfjs/pdfextract/pdfjs/src/core/jpx.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2961
.obsidian/pdfjs/pdfextract/pdfjs/src/core/metrics.js
vendored
Normal file
2961
.obsidian/pdfjs/pdfextract/pdfjs/src/core/metrics.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
166
.obsidian/pdfjs/pdfextract/pdfjs/src/core/murmurhash3.js
vendored
Normal file
166
.obsidian/pdfjs/pdfextract/pdfjs/src/core/murmurhash3.js
vendored
Normal file
@@ -0,0 +1,166 @@
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
|
||||
/* Copyright 2014 Opera Software ASA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*
|
||||
* Based on https://code.google.com/p/smhasher/wiki/MurmurHash3.
|
||||
* Hashes roughly 100 KB per millisecond on i7 3.4 GHz.
|
||||
*/
|
||||
/* globals Uint32ArrayView */
|
||||
|
||||
'use strict';
|
||||
|
||||
var MurmurHash3_64 = (function MurmurHash3_64Closure (seed) {
|
||||
// Workaround for missing math precison in JS.
|
||||
var MASK_HIGH = 0xffff0000;
|
||||
var MASK_LOW = 0xffff;
|
||||
|
||||
function MurmurHash3_64 (seed) {
|
||||
var SEED = 0xc3d2e1f0;
|
||||
this.h1 = seed ? seed & 0xffffffff : SEED;
|
||||
this.h2 = seed ? seed & 0xffffffff : SEED;
|
||||
}
|
||||
|
||||
var alwaysUseUint32ArrayView = false;
|
||||
//#if !(FIREFOX || MOZCENTRAL || B2G || CHROME)
|
||||
// old webkits have issues with non-aligned arrays
|
||||
try {
|
||||
new Uint32Array(new Uint8Array(5).buffer, 0, 1);
|
||||
} catch (e) {
|
||||
alwaysUseUint32ArrayView = true;
|
||||
}
|
||||
//#endif
|
||||
|
||||
MurmurHash3_64.prototype = {
|
||||
update: function MurmurHash3_64_update(input) {
|
||||
var useUint32ArrayView = alwaysUseUint32ArrayView;
|
||||
var i;
|
||||
if (typeof input === 'string') {
|
||||
var data = new Uint8Array(input.length * 2);
|
||||
var length = 0;
|
||||
for (i = 0; i < input.length; i++) {
|
||||
var code = input.charCodeAt(i);
|
||||
if (code <= 0xff) {
|
||||
data[length++] = code;
|
||||
}
|
||||
else {
|
||||
data[length++] = code >>> 8;
|
||||
data[length++] = code & 0xff;
|
||||
}
|
||||
}
|
||||
} else if (input instanceof Uint8Array) {
|
||||
data = input;
|
||||
length = data.length;
|
||||
} else if (typeof input === 'object' && ('length' in input)) {
|
||||
// processing regular arrays as well, e.g. for IE9
|
||||
data = input;
|
||||
length = data.length;
|
||||
useUint32ArrayView = true;
|
||||
} else {
|
||||
throw new Error('Wrong data format in MurmurHash3_64_update. ' +
|
||||
'Input must be a string or array.');
|
||||
}
|
||||
|
||||
var blockCounts = length >> 2;
|
||||
var tailLength = length - blockCounts * 4;
|
||||
// we don't care about endianness here
|
||||
var dataUint32 = useUint32ArrayView ?
|
||||
new Uint32ArrayView(data, blockCounts) :
|
||||
new Uint32Array(data.buffer, 0, blockCounts);
|
||||
var k1 = 0;
|
||||
var k2 = 0;
|
||||
var h1 = this.h1;
|
||||
var h2 = this.h2;
|
||||
var C1 = 0xcc9e2d51;
|
||||
var C2 = 0x1b873593;
|
||||
var C1_LOW = C1 & MASK_LOW;
|
||||
var C2_LOW = C2 & MASK_LOW;
|
||||
|
||||
for (i = 0; i < blockCounts; i++) {
|
||||
if (i & 1) {
|
||||
k1 = dataUint32[i];
|
||||
k1 = (k1 * C1 & MASK_HIGH) | (k1 * C1_LOW & MASK_LOW);
|
||||
k1 = k1 << 15 | k1 >>> 17;
|
||||
k1 = (k1 * C2 & MASK_HIGH) | (k1 * C2_LOW & MASK_LOW);
|
||||
h1 ^= k1;
|
||||
h1 = h1 << 13 | h1 >>> 19;
|
||||
h1 = h1 * 5 + 0xe6546b64;
|
||||
} else {
|
||||
k2 = dataUint32[i];
|
||||
k2 = (k2 * C1 & MASK_HIGH) | (k2 * C1_LOW & MASK_LOW);
|
||||
k2 = k2 << 15 | k2 >>> 17;
|
||||
k2 = (k2 * C2 & MASK_HIGH) | (k2 * C2_LOW & MASK_LOW);
|
||||
h2 ^= k2;
|
||||
h2 = h2 << 13 | h2 >>> 19;
|
||||
h2 = h2 * 5 + 0xe6546b64;
|
||||
}
|
||||
}
|
||||
|
||||
k1 = 0;
|
||||
|
||||
switch (tailLength) {
|
||||
case 3:
|
||||
k1 ^= data[blockCounts * 4 + 2] << 16;
|
||||
/* falls through */
|
||||
case 2:
|
||||
k1 ^= data[blockCounts * 4 + 1] << 8;
|
||||
/* falls through */
|
||||
case 1:
|
||||
k1 ^= data[blockCounts * 4];
|
||||
/* falls through */
|
||||
k1 = (k1 * C1 & MASK_HIGH) | (k1 * C1_LOW & MASK_LOW);
|
||||
k1 = k1 << 15 | k1 >>> 17;
|
||||
k1 = (k1 * C2 & MASK_HIGH) | (k1 * C2_LOW & MASK_LOW);
|
||||
if (blockCounts & 1) {
|
||||
h1 ^= k1;
|
||||
} else {
|
||||
h2 ^= k1;
|
||||
}
|
||||
}
|
||||
|
||||
this.h1 = h1;
|
||||
this.h2 = h2;
|
||||
return this;
|
||||
},
|
||||
|
||||
hexdigest: function MurmurHash3_64_hexdigest () {
|
||||
var h1 = this.h1;
|
||||
var h2 = this.h2;
|
||||
|
||||
h1 ^= h2 >>> 1;
|
||||
h1 = (h1 * 0xed558ccd & MASK_HIGH) | (h1 * 0x8ccd & MASK_LOW);
|
||||
h2 = (h2 * 0xff51afd7 & MASK_HIGH) |
|
||||
(((h2 << 16 | h1 >>> 16) * 0xafd7ed55 & MASK_HIGH) >>> 16);
|
||||
h1 ^= h2 >>> 1;
|
||||
h1 = (h1 * 0x1a85ec53 & MASK_HIGH) | (h1 * 0xec53 & MASK_LOW);
|
||||
h2 = (h2 * 0xc4ceb9fe & MASK_HIGH) |
|
||||
(((h2 << 16 | h1 >>> 16) * 0xb9fe1a85 & MASK_HIGH) >>> 16);
|
||||
h1 ^= h2 >>> 1;
|
||||
|
||||
for (var i = 0, arr = [h1, h2], str = ''; i < arr.length; i++) {
|
||||
var hex = (arr[i] >>> 0).toString(16);
|
||||
while (hex.length < 8) {
|
||||
hex = '0' + hex;
|
||||
}
|
||||
str += hex;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
};
|
||||
|
||||
return MurmurHash3_64;
|
||||
})();
|
274
.obsidian/pdfjs/pdfextract/pdfjs/src/core/network.js
vendored
Normal file
274
.obsidian/pdfjs/pdfextract/pdfjs/src/core/network.js
vendored
Normal file
@@ -0,0 +1,274 @@
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
/* Copyright 2012 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// NOTE: Be careful what goes in this file, as it is also used from the context
|
||||
// of the addon. So using warn/error in here will break the addon.
|
||||
|
||||
'use strict';
|
||||
|
||||
|
||||
//#if (FIREFOX || MOZCENTRAL)
|
||||
//
|
||||
//Components.utils.import('resource://gre/modules/Services.jsm');
|
||||
//
|
||||
//var EXPORTED_SYMBOLS = ['NetworkManager'];
|
||||
//
|
||||
//var console = {
|
||||
// log: function console_log(aMsg) {
|
||||
// var msg = 'network.js: ' + (aMsg.join ? aMsg.join('') : aMsg);
|
||||
// Services.console.logStringMessage(msg);
|
||||
// // TODO(mack): dump() doesn't seem to work here...
|
||||
// dump(msg + '\n');
|
||||
// }
|
||||
//}
|
||||
//#endif
|
||||
|
||||
var NetworkManager = (function NetworkManagerClosure() {
|
||||
|
||||
var OK_RESPONSE = 200;
|
||||
var PARTIAL_CONTENT_RESPONSE = 206;
|
||||
|
||||
function NetworkManager(url, args) {
|
||||
this.url = url;
|
||||
args = args || {};
|
||||
this.isHttp = /^https?:/i.test(url);
|
||||
this.httpHeaders = (this.isHttp && args.httpHeaders) || {};
|
||||
this.withCredentials = args.withCredentials || false;
|
||||
this.getXhr = args.getXhr ||
|
||||
function NetworkManager_getXhr() {
|
||||
//#if B2G
|
||||
// return new XMLHttpRequest({ mozSystem: true });
|
||||
//#else
|
||||
return new XMLHttpRequest();
|
||||
//#endif
|
||||
};
|
||||
|
||||
this.currXhrId = 0;
|
||||
this.pendingRequests = {};
|
||||
this.loadedRequests = {};
|
||||
}
|
||||
|
||||
function getArrayBuffer(xhr) {
|
||||
var data = xhr.response;
|
||||
if (typeof data !== 'string') {
|
||||
return data;
|
||||
}
|
||||
var length = data.length;
|
||||
var array = new Uint8Array(length);
|
||||
for (var i = 0; i < length; i++) {
|
||||
array[i] = data.charCodeAt(i) & 0xFF;
|
||||
}
|
||||
return array.buffer;
|
||||
}
|
||||
|
||||
NetworkManager.prototype = {
|
||||
requestRange: function NetworkManager_requestRange(begin, end, listeners) {
|
||||
var args = {
|
||||
begin: begin,
|
||||
end: end
|
||||
};
|
||||
for (var prop in listeners) {
|
||||
args[prop] = listeners[prop];
|
||||
}
|
||||
return this.request(args);
|
||||
},
|
||||
|
||||
requestFull: function NetworkManager_requestFull(listeners) {
|
||||
return this.request(listeners);
|
||||
},
|
||||
|
||||
request: function NetworkManager_request(args) {
|
||||
var xhr = this.getXhr();
|
||||
var xhrId = this.currXhrId++;
|
||||
var pendingRequest = this.pendingRequests[xhrId] = {
|
||||
xhr: xhr
|
||||
};
|
||||
|
||||
xhr.open('GET', this.url);
|
||||
xhr.withCredentials = this.withCredentials;
|
||||
for (var property in this.httpHeaders) {
|
||||
var value = this.httpHeaders[property];
|
||||
if (typeof value === 'undefined') {
|
||||
continue;
|
||||
}
|
||||
xhr.setRequestHeader(property, value);
|
||||
}
|
||||
if (this.isHttp && 'begin' in args && 'end' in args) {
|
||||
var rangeStr = args.begin + '-' + (args.end - 1);
|
||||
xhr.setRequestHeader('Range', 'bytes=' + rangeStr);
|
||||
pendingRequest.expectedStatus = 206;
|
||||
} else {
|
||||
pendingRequest.expectedStatus = 200;
|
||||
}
|
||||
|
||||
if (args.onProgressiveData) {
|
||||
xhr.responseType = 'moz-chunked-arraybuffer';
|
||||
if (xhr.responseType === 'moz-chunked-arraybuffer') {
|
||||
pendingRequest.onProgressiveData = args.onProgressiveData;
|
||||
pendingRequest.mozChunked = true;
|
||||
} else {
|
||||
xhr.responseType = 'arraybuffer';
|
||||
}
|
||||
} else {
|
||||
xhr.responseType = 'arraybuffer';
|
||||
}
|
||||
|
||||
if (args.onError) {
|
||||
xhr.onerror = function(evt) {
|
||||
args.onError(xhr.status);
|
||||
};
|
||||
}
|
||||
xhr.onreadystatechange = this.onStateChange.bind(this, xhrId);
|
||||
xhr.onprogress = this.onProgress.bind(this, xhrId);
|
||||
|
||||
pendingRequest.onHeadersReceived = args.onHeadersReceived;
|
||||
pendingRequest.onDone = args.onDone;
|
||||
pendingRequest.onError = args.onError;
|
||||
pendingRequest.onProgress = args.onProgress;
|
||||
|
||||
xhr.send(null);
|
||||
|
||||
return xhrId;
|
||||
},
|
||||
|
||||
onProgress: function NetworkManager_onProgress(xhrId, evt) {
|
||||
var pendingRequest = this.pendingRequests[xhrId];
|
||||
if (!pendingRequest) {
|
||||
// Maybe abortRequest was called...
|
||||
return;
|
||||
}
|
||||
|
||||
if (pendingRequest.mozChunked) {
|
||||
var chunk = getArrayBuffer(pendingRequest.xhr);
|
||||
pendingRequest.onProgressiveData(chunk);
|
||||
}
|
||||
|
||||
var onProgress = pendingRequest.onProgress;
|
||||
if (onProgress) {
|
||||
onProgress(evt);
|
||||
}
|
||||
},
|
||||
|
||||
onStateChange: function NetworkManager_onStateChange(xhrId, evt) {
|
||||
var pendingRequest = this.pendingRequests[xhrId];
|
||||
if (!pendingRequest) {
|
||||
// Maybe abortRequest was called...
|
||||
return;
|
||||
}
|
||||
|
||||
var xhr = pendingRequest.xhr;
|
||||
if (xhr.readyState >= 2 && pendingRequest.onHeadersReceived) {
|
||||
pendingRequest.onHeadersReceived();
|
||||
delete pendingRequest.onHeadersReceived;
|
||||
}
|
||||
|
||||
if (xhr.readyState !== 4) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(xhrId in this.pendingRequests)) {
|
||||
// The XHR request might have been aborted in onHeadersReceived()
|
||||
// callback, in which case we should abort request
|
||||
return;
|
||||
}
|
||||
|
||||
delete this.pendingRequests[xhrId];
|
||||
|
||||
// success status == 0 can be on ftp, file and other protocols
|
||||
if (xhr.status === 0 && this.isHttp) {
|
||||
if (pendingRequest.onError) {
|
||||
pendingRequest.onError(xhr.status);
|
||||
}
|
||||
return;
|
||||
}
|
||||
var xhrStatus = xhr.status || OK_RESPONSE;
|
||||
|
||||
// From http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35.2:
|
||||
// "A server MAY ignore the Range header". This means it's possible to
|
||||
// get a 200 rather than a 206 response from a range request.
|
||||
var ok_response_on_range_request =
|
||||
xhrStatus === OK_RESPONSE &&
|
||||
pendingRequest.expectedStatus === PARTIAL_CONTENT_RESPONSE;
|
||||
|
||||
if (!ok_response_on_range_request &&
|
||||
xhrStatus !== pendingRequest.expectedStatus) {
|
||||
if (pendingRequest.onError) {
|
||||
pendingRequest.onError(xhr.status);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
this.loadedRequests[xhrId] = true;
|
||||
|
||||
var chunk = getArrayBuffer(xhr);
|
||||
if (xhrStatus === PARTIAL_CONTENT_RESPONSE) {
|
||||
var rangeHeader = xhr.getResponseHeader('Content-Range');
|
||||
var matches = /bytes (\d+)-(\d+)\/(\d+)/.exec(rangeHeader);
|
||||
var begin = parseInt(matches[1], 10);
|
||||
pendingRequest.onDone({
|
||||
begin: begin,
|
||||
chunk: chunk
|
||||
});
|
||||
} else if (pendingRequest.onProgressiveData) {
|
||||
pendingRequest.onDone(null);
|
||||
} else {
|
||||
pendingRequest.onDone({
|
||||
begin: 0,
|
||||
chunk: chunk
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
hasPendingRequests: function NetworkManager_hasPendingRequests() {
|
||||
for (var xhrId in this.pendingRequests) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
getRequestXhr: function NetworkManager_getXhr(xhrId) {
|
||||
return this.pendingRequests[xhrId].xhr;
|
||||
},
|
||||
|
||||
isStreamingRequest: function NetworkManager_isStreamingRequest(xhrId) {
|
||||
return !!(this.pendingRequests[xhrId].onProgressiveData);
|
||||
},
|
||||
|
||||
isPendingRequest: function NetworkManager_isPendingRequest(xhrId) {
|
||||
return xhrId in this.pendingRequests;
|
||||
},
|
||||
|
||||
isLoadedRequest: function NetworkManager_isLoadedRequest(xhrId) {
|
||||
return xhrId in this.loadedRequests;
|
||||
},
|
||||
|
||||
abortAllRequests: function NetworkManager_abortAllRequests() {
|
||||
for (var xhrId in this.pendingRequests) {
|
||||
this.abortRequest(xhrId | 0);
|
||||
}
|
||||
},
|
||||
|
||||
abortRequest: function NetworkManager_abortRequest(xhrId) {
|
||||
var xhr = this.pendingRequests[xhrId].xhr;
|
||||
delete this.pendingRequests[xhrId];
|
||||
xhr.abort();
|
||||
}
|
||||
};
|
||||
|
||||
return NetworkManager;
|
||||
})();
|
||||
|
1698
.obsidian/pdfjs/pdfextract/pdfjs/src/core/obj.js
vendored
Normal file
1698
.obsidian/pdfjs/pdfextract/pdfjs/src/core/obj.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
893
.obsidian/pdfjs/pdfextract/pdfjs/src/core/parser.js
vendored
Normal file
893
.obsidian/pdfjs/pdfextract/pdfjs/src/core/parser.js
vendored
Normal file
@@ -0,0 +1,893 @@
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
/* Copyright 2012 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/* globals Ascii85Stream, AsciiHexStream, CCITTFaxStream, Cmd, Dict, error,
|
||||
FlateStream, isArray, isCmd, isDict, isInt, isName, isNum, isRef,
|
||||
isString, Jbig2Stream, JpegStream, JpxStream, LZWStream, Name,
|
||||
NullStream, PredictorStream, Ref, RunLengthStream, warn, info,
|
||||
StreamType, MissingDataException, assert */
|
||||
|
||||
'use strict';
|
||||
|
||||
var EOF = {};
|
||||
|
||||
function isEOF(v) {
|
||||
return (v === EOF);
|
||||
}
|
||||
|
||||
var Parser = (function ParserClosure() {
|
||||
function Parser(lexer, allowStreams, xref) {
|
||||
this.lexer = lexer;
|
||||
this.allowStreams = allowStreams;
|
||||
this.xref = xref;
|
||||
this.imageCache = {
|
||||
length: 0,
|
||||
adler32: 0,
|
||||
stream: null
|
||||
};
|
||||
this.refill();
|
||||
}
|
||||
|
||||
Parser.prototype = {
|
||||
refill: function Parser_refill() {
|
||||
this.buf1 = this.lexer.getObj();
|
||||
this.buf2 = this.lexer.getObj();
|
||||
},
|
||||
shift: function Parser_shift() {
|
||||
if (isCmd(this.buf2, 'ID')) {
|
||||
this.buf1 = this.buf2;
|
||||
this.buf2 = null;
|
||||
} else {
|
||||
this.buf1 = this.buf2;
|
||||
this.buf2 = this.lexer.getObj();
|
||||
}
|
||||
},
|
||||
getObj: function Parser_getObj(cipherTransform) {
|
||||
var buf1 = this.buf1;
|
||||
this.shift();
|
||||
|
||||
if (buf1 instanceof Cmd) {
|
||||
switch (buf1.cmd) {
|
||||
case 'BI': // inline image
|
||||
return this.makeInlineImage(cipherTransform);
|
||||
case '[': // array
|
||||
var array = [];
|
||||
while (!isCmd(this.buf1, ']') && !isEOF(this.buf1)) {
|
||||
array.push(this.getObj(cipherTransform));
|
||||
}
|
||||
if (isEOF(this.buf1)) {
|
||||
error('End of file inside array');
|
||||
}
|
||||
this.shift();
|
||||
return array;
|
||||
case '<<': // dictionary or stream
|
||||
var dict = new Dict(this.xref);
|
||||
while (!isCmd(this.buf1, '>>') && !isEOF(this.buf1)) {
|
||||
if (!isName(this.buf1)) {
|
||||
info('Malformed dictionary: key must be a name object');
|
||||
this.shift();
|
||||
continue;
|
||||
}
|
||||
|
||||
var key = this.buf1.name;
|
||||
this.shift();
|
||||
if (isEOF(this.buf1)) {
|
||||
break;
|
||||
}
|
||||
dict.set(key, this.getObj(cipherTransform));
|
||||
}
|
||||
if (isEOF(this.buf1)) {
|
||||
error('End of file inside dictionary');
|
||||
}
|
||||
|
||||
// Stream objects are not allowed inside content streams or
|
||||
// object streams.
|
||||
if (isCmd(this.buf2, 'stream')) {
|
||||
return (this.allowStreams ?
|
||||
this.makeStream(dict, cipherTransform) : dict);
|
||||
}
|
||||
this.shift();
|
||||
return dict;
|
||||
default: // simple object
|
||||
return buf1;
|
||||
}
|
||||
}
|
||||
|
||||
if (isInt(buf1)) { // indirect reference or integer
|
||||
var num = buf1;
|
||||
if (isInt(this.buf1) && isCmd(this.buf2, 'R')) {
|
||||
var ref = new Ref(num, this.buf1);
|
||||
this.shift();
|
||||
this.shift();
|
||||
return ref;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
if (isString(buf1)) { // string
|
||||
var str = buf1;
|
||||
if (cipherTransform) {
|
||||
str = cipherTransform.decryptString(str);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
// simple object
|
||||
return buf1;
|
||||
},
|
||||
makeInlineImage: function Parser_makeInlineImage(cipherTransform) {
|
||||
var lexer = this.lexer;
|
||||
var stream = lexer.stream;
|
||||
|
||||
// parse dictionary
|
||||
var dict = new Dict(null);
|
||||
while (!isCmd(this.buf1, 'ID') && !isEOF(this.buf1)) {
|
||||
if (!isName(this.buf1)) {
|
||||
error('Dictionary key must be a name object');
|
||||
}
|
||||
|
||||
var key = this.buf1.name;
|
||||
this.shift();
|
||||
if (isEOF(this.buf1)) {
|
||||
break;
|
||||
}
|
||||
dict.set(key, this.getObj(cipherTransform));
|
||||
}
|
||||
|
||||
// parse image stream
|
||||
var startPos = stream.pos;
|
||||
|
||||
// searching for the /EI\s/
|
||||
var state = 0, ch, i, ii;
|
||||
var E = 0x45, I = 0x49, SPACE = 0x20, NL = 0xA, CR = 0xD;
|
||||
while ((ch = stream.getByte()) !== -1) {
|
||||
if (state === 0) {
|
||||
state = (ch === E) ? 1 : 0;
|
||||
} else if (state === 1) {
|
||||
state = (ch === I) ? 2 : 0;
|
||||
} else {
|
||||
assert(state === 2);
|
||||
if (ch === SPACE || ch === NL || ch === CR) {
|
||||
// Let's check the next five bytes are ASCII... just be sure.
|
||||
var n = 5;
|
||||
var followingBytes = stream.peekBytes(n);
|
||||
for (i = 0; i < n; i++) {
|
||||
ch = followingBytes[i];
|
||||
if (ch !== NL && ch !== CR && (ch < SPACE || ch > 0x7F)) {
|
||||
// Not a LF, CR, SPACE or any visible ASCII character, i.e.
|
||||
// it's binary stuff. Resetting the state.
|
||||
state = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (state === 2) {
|
||||
break; // finished!
|
||||
}
|
||||
} else {
|
||||
state = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var length = (stream.pos - 4) - startPos;
|
||||
var imageStream = stream.makeSubStream(startPos, length, dict);
|
||||
|
||||
// trying to cache repeat images, first we are trying to "warm up" caching
|
||||
// using length, then comparing adler32
|
||||
var MAX_LENGTH_TO_CACHE = 1000;
|
||||
var cacheImage = false, adler32;
|
||||
if (length < MAX_LENGTH_TO_CACHE && this.imageCache.length === length) {
|
||||
var imageBytes = imageStream.getBytes();
|
||||
imageStream.reset();
|
||||
|
||||
var a = 1;
|
||||
var b = 0;
|
||||
for (i = 0, ii = imageBytes.length; i < ii; ++i) {
|
||||
a = (a + (imageBytes[i] & 0xff)) % 65521;
|
||||
b = (b + a) % 65521;
|
||||
}
|
||||
adler32 = (b << 16) | a;
|
||||
|
||||
if (this.imageCache.stream && this.imageCache.adler32 === adler32) {
|
||||
this.buf2 = Cmd.get('EI');
|
||||
this.shift();
|
||||
|
||||
this.imageCache.stream.reset();
|
||||
return this.imageCache.stream;
|
||||
}
|
||||
cacheImage = true;
|
||||
}
|
||||
if (!cacheImage && !this.imageCache.stream) {
|
||||
this.imageCache.length = length;
|
||||
this.imageCache.stream = null;
|
||||
}
|
||||
|
||||
if (cipherTransform) {
|
||||
imageStream = cipherTransform.createStream(imageStream, length);
|
||||
}
|
||||
|
||||
imageStream = this.filter(imageStream, dict, length);
|
||||
imageStream.dict = dict;
|
||||
if (cacheImage) {
|
||||
imageStream.cacheKey = 'inline_' + length + '_' + adler32;
|
||||
this.imageCache.adler32 = adler32;
|
||||
this.imageCache.stream = imageStream;
|
||||
}
|
||||
|
||||
this.buf2 = Cmd.get('EI');
|
||||
this.shift();
|
||||
|
||||
return imageStream;
|
||||
},
|
||||
fetchIfRef: function Parser_fetchIfRef(obj) {
|
||||
// not relying on the xref.fetchIfRef -- xref might not be set
|
||||
return (isRef(obj) ? this.xref.fetch(obj) : obj);
|
||||
},
|
||||
makeStream: function Parser_makeStream(dict, cipherTransform) {
|
||||
var lexer = this.lexer;
|
||||
var stream = lexer.stream;
|
||||
|
||||
// get stream start position
|
||||
lexer.skipToNextLine();
|
||||
var pos = stream.pos - 1;
|
||||
|
||||
// get length
|
||||
var length = this.fetchIfRef(dict.get('Length'));
|
||||
if (!isInt(length)) {
|
||||
info('Bad ' + length + ' attribute in stream');
|
||||
length = 0;
|
||||
}
|
||||
|
||||
// skip over the stream data
|
||||
stream.pos = pos + length;
|
||||
lexer.nextChar();
|
||||
|
||||
this.shift(); // '>>'
|
||||
this.shift(); // 'stream'
|
||||
if (!isCmd(this.buf1, 'endstream')) {
|
||||
// bad stream length, scanning for endstream
|
||||
stream.pos = pos;
|
||||
var SCAN_BLOCK_SIZE = 2048;
|
||||
var ENDSTREAM_SIGNATURE_LENGTH = 9;
|
||||
var ENDSTREAM_SIGNATURE = [0x65, 0x6E, 0x64, 0x73, 0x74, 0x72, 0x65,
|
||||
0x61, 0x6D];
|
||||
var skipped = 0, found = false, i, j;
|
||||
while (stream.pos < stream.end) {
|
||||
var scanBytes = stream.peekBytes(SCAN_BLOCK_SIZE);
|
||||
var scanLength = scanBytes.length - ENDSTREAM_SIGNATURE_LENGTH;
|
||||
if (scanLength <= 0) {
|
||||
break;
|
||||
}
|
||||
found = false;
|
||||
for (i = 0, j = 0; i < scanLength; i++) {
|
||||
var b = scanBytes[i];
|
||||
if (b !== ENDSTREAM_SIGNATURE[j]) {
|
||||
i -= j;
|
||||
j = 0;
|
||||
} else {
|
||||
j++;
|
||||
if (j >= ENDSTREAM_SIGNATURE_LENGTH) {
|
||||
i++;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
skipped += i - ENDSTREAM_SIGNATURE_LENGTH;
|
||||
stream.pos += i - ENDSTREAM_SIGNATURE_LENGTH;
|
||||
break;
|
||||
}
|
||||
skipped += scanLength;
|
||||
stream.pos += scanLength;
|
||||
}
|
||||
if (!found) {
|
||||
error('Missing endstream');
|
||||
}
|
||||
length = skipped;
|
||||
|
||||
lexer.nextChar();
|
||||
this.shift();
|
||||
this.shift();
|
||||
}
|
||||
this.shift(); // 'endstream'
|
||||
|
||||
stream = stream.makeSubStream(pos, length, dict);
|
||||
if (cipherTransform) {
|
||||
stream = cipherTransform.createStream(stream, length);
|
||||
}
|
||||
stream = this.filter(stream, dict, length);
|
||||
stream.dict = dict;
|
||||
return stream;
|
||||
},
|
||||
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)) {
|
||||
return this.makeFilter(stream, filter.name, length, params);
|
||||
}
|
||||
|
||||
var maybeLength = length;
|
||||
if (isArray(filter)) {
|
||||
var filterArray = filter;
|
||||
var paramsArray = params;
|
||||
for (var i = 0, ii = filterArray.length; i < ii; ++i) {
|
||||
filter = filterArray[i];
|
||||
if (!isName(filter)) {
|
||||
error('Bad filter name: ' + filter);
|
||||
}
|
||||
|
||||
params = null;
|
||||
if (isArray(paramsArray) && (i in paramsArray)) {
|
||||
params = paramsArray[i];
|
||||
}
|
||||
stream = this.makeFilter(stream, filter.name, maybeLength, params);
|
||||
// after the first stream the length variable is invalid
|
||||
maybeLength = null;
|
||||
}
|
||||
}
|
||||
return stream;
|
||||
},
|
||||
makeFilter: function Parser_makeFilter(stream, name, maybeLength, params) {
|
||||
if (stream.dict.get('Length') === 0) {
|
||||
return new NullStream(stream);
|
||||
}
|
||||
try {
|
||||
if (params) {
|
||||
params = this.fetchIfRef(params);
|
||||
}
|
||||
var xrefStreamStats = this.xref.stats.streamTypes;
|
||||
if (name === 'FlateDecode' || name === 'Fl') {
|
||||
xrefStreamStats[StreamType.FLATE] = true;
|
||||
if (params) {
|
||||
return new PredictorStream(new FlateStream(stream, maybeLength),
|
||||
maybeLength, params);
|
||||
}
|
||||
return new FlateStream(stream, maybeLength);
|
||||
}
|
||||
if (name === 'LZWDecode' || name === 'LZW') {
|
||||
xrefStreamStats[StreamType.LZW] = true;
|
||||
var earlyChange = 1;
|
||||
if (params) {
|
||||
if (params.has('EarlyChange')) {
|
||||
earlyChange = params.get('EarlyChange');
|
||||
}
|
||||
return new PredictorStream(
|
||||
new LZWStream(stream, maybeLength, earlyChange),
|
||||
maybeLength, params);
|
||||
}
|
||||
return new LZWStream(stream, maybeLength, earlyChange);
|
||||
}
|
||||
if (name === 'DCTDecode' || name === 'DCT') {
|
||||
// According to the specification: for inline images, the ID operator
|
||||
// shall be followed by a single whitespace character (unless it uses
|
||||
// ASCII85Decode or ASCIIHexDecode filters).
|
||||
// In practice this only seems to be followed for inline JPEG images,
|
||||
// and generally ignoring the first byte of the stream if it is a
|
||||
// whitespace char can even *cause* issues (e.g. in the CCITTFaxDecode
|
||||
// filters used in issue2984.pdf).
|
||||
// Hence when the first byte of the stream of an inline JPEG image is
|
||||
// a whitespace character, we thus simply skip over it.
|
||||
if (isCmd(this.buf1, 'ID')) {
|
||||
var firstByte = stream.peekByte();
|
||||
if (firstByte === 0x0A /* LF */ || firstByte === 0x0D /* CR */ ||
|
||||
firstByte === 0x20 /* SPACE */) {
|
||||
stream.skip();
|
||||
}
|
||||
}
|
||||
xrefStreamStats[StreamType.DCT] = true;
|
||||
return new JpegStream(stream, maybeLength, stream.dict, this.xref);
|
||||
}
|
||||
if (name === 'JPXDecode' || name === 'JPX') {
|
||||
xrefStreamStats[StreamType.JPX] = true;
|
||||
return new JpxStream(stream, maybeLength, stream.dict);
|
||||
}
|
||||
if (name === 'ASCII85Decode' || name === 'A85') {
|
||||
xrefStreamStats[StreamType.A85] = true;
|
||||
return new Ascii85Stream(stream, maybeLength);
|
||||
}
|
||||
if (name === 'ASCIIHexDecode' || name === 'AHx') {
|
||||
xrefStreamStats[StreamType.AHX] = true;
|
||||
return new AsciiHexStream(stream, maybeLength);
|
||||
}
|
||||
if (name === 'CCITTFaxDecode' || name === 'CCF') {
|
||||
xrefStreamStats[StreamType.CCF] = true;
|
||||
return new CCITTFaxStream(stream, maybeLength, params);
|
||||
}
|
||||
if (name === 'RunLengthDecode' || name === 'RL') {
|
||||
xrefStreamStats[StreamType.RL] = true;
|
||||
return new RunLengthStream(stream, maybeLength);
|
||||
}
|
||||
if (name === 'JBIG2Decode') {
|
||||
xrefStreamStats[StreamType.JBIG] = true;
|
||||
return new Jbig2Stream(stream, maybeLength, stream.dict);
|
||||
}
|
||||
warn('filter "' + name + '" not supported yet');
|
||||
return stream;
|
||||
} catch (ex) {
|
||||
if (ex instanceof MissingDataException) {
|
||||
throw ex;
|
||||
}
|
||||
warn('Invalid stream: \"' + ex + '\"');
|
||||
return new NullStream(stream);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return Parser;
|
||||
})();
|
||||
|
||||
var Lexer = (function LexerClosure() {
|
||||
function Lexer(stream, knownCommands) {
|
||||
this.stream = stream;
|
||||
this.nextChar();
|
||||
|
||||
// While lexing, we build up many strings one char at a time. Using += for
|
||||
// this can result in lots of garbage strings. It's better to build an
|
||||
// array of single-char strings and then join() them together at the end.
|
||||
// And reusing a single array (i.e. |this.strBuf|) over and over for this
|
||||
// purpose uses less memory than using a new array for each string.
|
||||
this.strBuf = [];
|
||||
|
||||
// The PDFs might have "glued" commands with other commands, operands or
|
||||
// literals, e.g. "q1". The knownCommands is a dictionary of the valid
|
||||
// commands and their prefixes. The prefixes are built the following way:
|
||||
// if there a command that is a prefix of the other valid command or
|
||||
// literal (e.g. 'f' and 'false') the following prefixes must be included,
|
||||
// 'fa', 'fal', 'fals'. The prefixes are not needed, if the command has no
|
||||
// other commands or literals as a prefix. The knowCommands is optional.
|
||||
this.knownCommands = knownCommands;
|
||||
}
|
||||
|
||||
Lexer.isSpace = function Lexer_isSpace(ch) {
|
||||
// Space is one of the following characters: SPACE, TAB, CR or LF.
|
||||
return (ch === 0x20 || ch === 0x09 || ch === 0x0D || ch === 0x0A);
|
||||
};
|
||||
|
||||
// A '1' in this array means the character is white space. A '1' or
|
||||
// '2' means the character ends a name or command.
|
||||
var specialChars = [
|
||||
1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, // 0x
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
|
||||
1, 0, 0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, // 2x
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, // 3x
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4x
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 5x
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6x
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 7x
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ax
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // bx
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // cx
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // dx
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ex
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // fx
|
||||
];
|
||||
|
||||
function toHexDigit(ch) {
|
||||
if (ch >= 0x30 && ch <= 0x39) { // '0'-'9'
|
||||
return ch & 0x0F;
|
||||
}
|
||||
if ((ch >= 0x41 && ch <= 0x46) || (ch >= 0x61 && ch <= 0x66)) {
|
||||
// 'A'-'F', 'a'-'f'
|
||||
return (ch & 0x0F) + 9;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
Lexer.prototype = {
|
||||
nextChar: function Lexer_nextChar() {
|
||||
return (this.currentChar = this.stream.getByte());
|
||||
},
|
||||
peekChar: function Lexer_peekChar() {
|
||||
return this.stream.peekByte();
|
||||
},
|
||||
getNumber: function Lexer_getNumber() {
|
||||
var ch = this.currentChar;
|
||||
var eNotation = false;
|
||||
var divideBy = 0; // different from 0 if it's a floating point value
|
||||
var sign = 1;
|
||||
|
||||
if (ch === 0x2D) { // '-'
|
||||
sign = -1;
|
||||
ch = this.nextChar();
|
||||
} else if (ch === 0x2B) { // '+'
|
||||
ch = this.nextChar();
|
||||
}
|
||||
if (ch === 0x2E) { // '.'
|
||||
divideBy = 10;
|
||||
ch = this.nextChar();
|
||||
}
|
||||
if (ch < 0x30 || ch > 0x39) { // '0' - '9'
|
||||
error('Invalid number: ' + String.fromCharCode(ch));
|
||||
return 0;
|
||||
}
|
||||
|
||||
var baseValue = ch - 0x30; // '0'
|
||||
var powerValue = 0;
|
||||
var powerValueSign = 1;
|
||||
|
||||
while ((ch = this.nextChar()) >= 0) {
|
||||
if (0x30 <= ch && ch <= 0x39) { // '0' - '9'
|
||||
var currentDigit = ch - 0x30; // '0'
|
||||
if (eNotation) { // We are after an 'e' or 'E'
|
||||
powerValue = powerValue * 10 + currentDigit;
|
||||
} else {
|
||||
if (divideBy !== 0) { // We are after a point
|
||||
divideBy *= 10;
|
||||
}
|
||||
baseValue = baseValue * 10 + currentDigit;
|
||||
}
|
||||
} else if (ch === 0x2E) { // '.'
|
||||
if (divideBy === 0) {
|
||||
divideBy = 1;
|
||||
} else {
|
||||
// A number can have only one '.'
|
||||
break;
|
||||
}
|
||||
} else if (ch === 0x2D) { // '-'
|
||||
// ignore minus signs in the middle of numbers to match
|
||||
// Adobe's behavior
|
||||
warn('Badly formated number');
|
||||
} else if (ch === 0x45 || ch === 0x65) { // 'E', 'e'
|
||||
// 'E' can be either a scientific notation or the beginning of a new
|
||||
// operator
|
||||
ch = this.peekChar();
|
||||
if (ch === 0x2B || ch === 0x2D) { // '+', '-'
|
||||
powerValueSign = (ch === 0x2D) ? -1 : 1;
|
||||
this.nextChar(); // Consume the sign character
|
||||
} else if (ch < 0x30 || ch > 0x39) { // '0' - '9'
|
||||
// The 'E' must be the beginning of a new operator
|
||||
break;
|
||||
}
|
||||
eNotation = true;
|
||||
} else {
|
||||
// the last character doesn't belong to us
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (divideBy !== 0) {
|
||||
baseValue /= divideBy;
|
||||
}
|
||||
if (eNotation) {
|
||||
baseValue *= Math.pow(10, powerValueSign * powerValue);
|
||||
}
|
||||
return sign * baseValue;
|
||||
},
|
||||
getString: function Lexer_getString() {
|
||||
var numParen = 1;
|
||||
var done = false;
|
||||
var strBuf = this.strBuf;
|
||||
strBuf.length = 0;
|
||||
|
||||
var ch = this.nextChar();
|
||||
while (true) {
|
||||
var charBuffered = false;
|
||||
switch (ch | 0) {
|
||||
case -1:
|
||||
warn('Unterminated string');
|
||||
done = true;
|
||||
break;
|
||||
case 0x28: // '('
|
||||
++numParen;
|
||||
strBuf.push('(');
|
||||
break;
|
||||
case 0x29: // ')'
|
||||
if (--numParen === 0) {
|
||||
this.nextChar(); // consume strings ')'
|
||||
done = true;
|
||||
} else {
|
||||
strBuf.push(')');
|
||||
}
|
||||
break;
|
||||
case 0x5C: // '\\'
|
||||
ch = this.nextChar();
|
||||
switch (ch) {
|
||||
case -1:
|
||||
warn('Unterminated string');
|
||||
done = true;
|
||||
break;
|
||||
case 0x6E: // 'n'
|
||||
strBuf.push('\n');
|
||||
break;
|
||||
case 0x72: // 'r'
|
||||
strBuf.push('\r');
|
||||
break;
|
||||
case 0x74: // 't'
|
||||
strBuf.push('\t');
|
||||
break;
|
||||
case 0x62: // 'b'
|
||||
strBuf.push('\b');
|
||||
break;
|
||||
case 0x66: // 'f'
|
||||
strBuf.push('\f');
|
||||
break;
|
||||
case 0x5C: // '\'
|
||||
case 0x28: // '('
|
||||
case 0x29: // ')'
|
||||
strBuf.push(String.fromCharCode(ch));
|
||||
break;
|
||||
case 0x30: case 0x31: case 0x32: case 0x33: // '0'-'3'
|
||||
case 0x34: case 0x35: case 0x36: case 0x37: // '4'-'7'
|
||||
var x = ch & 0x0F;
|
||||
ch = this.nextChar();
|
||||
charBuffered = true;
|
||||
if (ch >= 0x30 && ch <= 0x37) { // '0'-'7'
|
||||
x = (x << 3) + (ch & 0x0F);
|
||||
ch = this.nextChar();
|
||||
if (ch >= 0x30 && ch <= 0x37) { // '0'-'7'
|
||||
charBuffered = false;
|
||||
x = (x << 3) + (ch & 0x0F);
|
||||
}
|
||||
}
|
||||
strBuf.push(String.fromCharCode(x));
|
||||
break;
|
||||
case 0x0D: // CR
|
||||
if (this.peekChar() === 0x0A) { // LF
|
||||
this.nextChar();
|
||||
}
|
||||
break;
|
||||
case 0x0A: // LF
|
||||
break;
|
||||
default:
|
||||
strBuf.push(String.fromCharCode(ch));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
strBuf.push(String.fromCharCode(ch));
|
||||
break;
|
||||
}
|
||||
if (done) {
|
||||
break;
|
||||
}
|
||||
if (!charBuffered) {
|
||||
ch = this.nextChar();
|
||||
}
|
||||
}
|
||||
return strBuf.join('');
|
||||
},
|
||||
getName: function Lexer_getName() {
|
||||
var ch;
|
||||
var strBuf = this.strBuf;
|
||||
strBuf.length = 0;
|
||||
while ((ch = this.nextChar()) >= 0 && !specialChars[ch]) {
|
||||
if (ch === 0x23) { // '#'
|
||||
ch = this.nextChar();
|
||||
var x = toHexDigit(ch);
|
||||
if (x !== -1) {
|
||||
var x2 = toHexDigit(this.nextChar());
|
||||
if (x2 === -1) {
|
||||
error('Illegal digit in hex char in name: ' + x2);
|
||||
}
|
||||
strBuf.push(String.fromCharCode((x << 4) | x2));
|
||||
} else {
|
||||
strBuf.push('#', String.fromCharCode(ch));
|
||||
}
|
||||
} else {
|
||||
strBuf.push(String.fromCharCode(ch));
|
||||
}
|
||||
}
|
||||
if (strBuf.length > 128) {
|
||||
error('Warning: name token is longer than allowed by the spec: ' +
|
||||
strBuf.length);
|
||||
}
|
||||
return Name.get(strBuf.join(''));
|
||||
},
|
||||
getHexString: function Lexer_getHexString() {
|
||||
var strBuf = this.strBuf;
|
||||
strBuf.length = 0;
|
||||
var ch = this.currentChar;
|
||||
var isFirstHex = true;
|
||||
var firstDigit;
|
||||
var secondDigit;
|
||||
while (true) {
|
||||
if (ch < 0) {
|
||||
warn('Unterminated hex string');
|
||||
break;
|
||||
} else if (ch === 0x3E) { // '>'
|
||||
this.nextChar();
|
||||
break;
|
||||
} else if (specialChars[ch] === 1) {
|
||||
ch = this.nextChar();
|
||||
continue;
|
||||
} else {
|
||||
if (isFirstHex) {
|
||||
firstDigit = toHexDigit(ch);
|
||||
if (firstDigit === -1) {
|
||||
warn('Ignoring invalid character "' + ch + '" in hex string');
|
||||
ch = this.nextChar();
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
secondDigit = toHexDigit(ch);
|
||||
if (secondDigit === -1) {
|
||||
warn('Ignoring invalid character "' + ch + '" in hex string');
|
||||
ch = this.nextChar();
|
||||
continue;
|
||||
}
|
||||
strBuf.push(String.fromCharCode((firstDigit << 4) | secondDigit));
|
||||
}
|
||||
isFirstHex = !isFirstHex;
|
||||
ch = this.nextChar();
|
||||
}
|
||||
}
|
||||
return strBuf.join('');
|
||||
},
|
||||
getObj: function Lexer_getObj() {
|
||||
// skip whitespace and comments
|
||||
var comment = false;
|
||||
var ch = this.currentChar;
|
||||
while (true) {
|
||||
if (ch < 0) {
|
||||
return EOF;
|
||||
}
|
||||
if (comment) {
|
||||
if (ch === 0x0A || ch === 0x0D) { // LF, CR
|
||||
comment = false;
|
||||
}
|
||||
} else if (ch === 0x25) { // '%'
|
||||
comment = true;
|
||||
} else if (specialChars[ch] !== 1) {
|
||||
break;
|
||||
}
|
||||
ch = this.nextChar();
|
||||
}
|
||||
|
||||
// start reading token
|
||||
switch (ch | 0) {
|
||||
case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: // '0'-'4'
|
||||
case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: // '5'-'9'
|
||||
case 0x2B: case 0x2D: case 0x2E: // '+', '-', '.'
|
||||
return this.getNumber();
|
||||
case 0x28: // '('
|
||||
return this.getString();
|
||||
case 0x2F: // '/'
|
||||
return this.getName();
|
||||
// array punctuation
|
||||
case 0x5B: // '['
|
||||
this.nextChar();
|
||||
return Cmd.get('[');
|
||||
case 0x5D: // ']'
|
||||
this.nextChar();
|
||||
return Cmd.get(']');
|
||||
// hex string or dict punctuation
|
||||
case 0x3C: // '<'
|
||||
ch = this.nextChar();
|
||||
if (ch === 0x3C) {
|
||||
// dict punctuation
|
||||
this.nextChar();
|
||||
return Cmd.get('<<');
|
||||
}
|
||||
return this.getHexString();
|
||||
// dict punctuation
|
||||
case 0x3E: // '>'
|
||||
ch = this.nextChar();
|
||||
if (ch === 0x3E) {
|
||||
this.nextChar();
|
||||
return Cmd.get('>>');
|
||||
}
|
||||
return Cmd.get('>');
|
||||
case 0x7B: // '{'
|
||||
this.nextChar();
|
||||
return Cmd.get('{');
|
||||
case 0x7D: // '}'
|
||||
this.nextChar();
|
||||
return Cmd.get('}');
|
||||
case 0x29: // ')'
|
||||
error('Illegal character: ' + ch);
|
||||
break;
|
||||
}
|
||||
|
||||
// command
|
||||
var str = String.fromCharCode(ch);
|
||||
var knownCommands = this.knownCommands;
|
||||
var knownCommandFound = knownCommands && knownCommands[str] !== undefined;
|
||||
while ((ch = this.nextChar()) >= 0 && !specialChars[ch]) {
|
||||
// stop if known command is found and next character does not make
|
||||
// the str a command
|
||||
var possibleCommand = str + String.fromCharCode(ch);
|
||||
if (knownCommandFound && knownCommands[possibleCommand] === undefined) {
|
||||
break;
|
||||
}
|
||||
if (str.length === 128) {
|
||||
error('Command token too long: ' + str.length);
|
||||
}
|
||||
str = possibleCommand;
|
||||
knownCommandFound = knownCommands && knownCommands[str] !== undefined;
|
||||
}
|
||||
if (str === 'true') {
|
||||
return true;
|
||||
}
|
||||
if (str === 'false') {
|
||||
return false;
|
||||
}
|
||||
if (str === 'null') {
|
||||
return null;
|
||||
}
|
||||
return Cmd.get(str);
|
||||
},
|
||||
skipToNextLine: function Lexer_skipToNextLine() {
|
||||
var ch = this.currentChar;
|
||||
while (ch >= 0) {
|
||||
if (ch === 0x0D) { // CR
|
||||
ch = this.nextChar();
|
||||
if (ch === 0x0A) { // LF
|
||||
this.nextChar();
|
||||
}
|
||||
break;
|
||||
} else if (ch === 0x0A) { // LF
|
||||
this.nextChar();
|
||||
break;
|
||||
}
|
||||
ch = this.nextChar();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return Lexer;
|
||||
})();
|
||||
|
||||
var Linearization = {
|
||||
create: function LinearizationCreate(stream) {
|
||||
function getInt(name, allowZeroValue) {
|
||||
var obj = linDict.get(name);
|
||||
if (isInt(obj) && (allowZeroValue ? obj >= 0 : obj > 0)) {
|
||||
return obj;
|
||||
}
|
||||
throw new Error('The "' + name + '" parameter in the linearization ' +
|
||||
'dictionary is invalid.');
|
||||
}
|
||||
function getHints() {
|
||||
var hints = linDict.get('H'), hintsLength, item;
|
||||
if (isArray(hints) &&
|
||||
((hintsLength = hints.length) === 2 || hintsLength === 4)) {
|
||||
for (var index = 0; index < hintsLength; index++) {
|
||||
if (!(isInt(item = hints[index]) && item > 0)) {
|
||||
throw new Error('Hint (' + index +
|
||||
') in the linearization dictionary is invalid.');
|
||||
}
|
||||
}
|
||||
return hints;
|
||||
}
|
||||
throw new Error('Hint array in the linearization dictionary is invalid.');
|
||||
}
|
||||
var parser = new Parser(new Lexer(stream), false, null);
|
||||
var obj1 = parser.getObj();
|
||||
var obj2 = parser.getObj();
|
||||
var obj3 = parser.getObj();
|
||||
var linDict = parser.getObj();
|
||||
var obj, length;
|
||||
if (!(isInt(obj1) && isInt(obj2) && isCmd(obj3, 'obj') && isDict(linDict) &&
|
||||
isNum(obj = linDict.get('Linearized')) && obj > 0)) {
|
||||
return null; // No valid linearization dictionary found.
|
||||
} else if ((length = getInt('L')) !== stream.length) {
|
||||
throw new Error('The "L" parameter in the linearization dictionary ' +
|
||||
'does not equal the stream length.');
|
||||
}
|
||||
return {
|
||||
length: length,
|
||||
hints: getHints(),
|
||||
objectNumberFirst: getInt('O'),
|
||||
endFirst: getInt('E'),
|
||||
numPages: getInt('N'),
|
||||
mainXRefEntriesOffset: getInt('T'),
|
||||
pageFirst: (linDict.has('P') ? getInt('P', true) : 0)
|
||||
};
|
||||
}
|
||||
};
|
795
.obsidian/pdfjs/pdfextract/pdfjs/src/core/pattern.js
vendored
Normal file
795
.obsidian/pdfjs/pdfextract/pdfjs/src/core/pattern.js
vendored
Normal file
@@ -0,0 +1,795 @@
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
/* Copyright 2012 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/* globals ColorSpace, PDFFunction, Util, error, warn, info, isArray, isStream,
|
||||
assert, isPDFFunction, UnsupportedManager, UNSUPPORTED_FEATURES */
|
||||
|
||||
'use strict';
|
||||
|
||||
var PatternType = {
|
||||
FUNCTION_BASED: 1,
|
||||
AXIAL: 2,
|
||||
RADIAL: 3,
|
||||
FREE_FORM_MESH: 4,
|
||||
LATTICE_FORM_MESH: 5,
|
||||
COONS_PATCH_MESH: 6,
|
||||
TENSOR_PATCH_MESH: 7
|
||||
};
|
||||
|
||||
var Pattern = (function PatternClosure() {
|
||||
// Constructor should define this.getPattern
|
||||
function Pattern() {
|
||||
error('should not call Pattern constructor');
|
||||
}
|
||||
|
||||
Pattern.prototype = {
|
||||
// Input: current Canvas context
|
||||
// Output: the appropriate fillStyle or strokeStyle
|
||||
getPattern: function Pattern_getPattern(ctx) {
|
||||
error('Should not call Pattern.getStyle: ' + ctx);
|
||||
}
|
||||
};
|
||||
|
||||
Pattern.parseShading = function Pattern_parseShading(shading, matrix, xref,
|
||||
res) {
|
||||
|
||||
var dict = isStream(shading) ? shading.dict : shading;
|
||||
var type = dict.get('ShadingType');
|
||||
|
||||
switch (type) {
|
||||
case PatternType.AXIAL:
|
||||
case PatternType.RADIAL:
|
||||
// Both radial and axial shadings are handled by RadialAxial shading.
|
||||
return new Shadings.RadialAxial(dict, matrix, xref, res);
|
||||
case PatternType.FREE_FORM_MESH:
|
||||
case PatternType.LATTICE_FORM_MESH:
|
||||
case PatternType.COONS_PATCH_MESH:
|
||||
case PatternType.TENSOR_PATCH_MESH:
|
||||
return new Shadings.Mesh(shading, matrix, xref, res);
|
||||
default:
|
||||
UnsupportedManager.notify(UNSUPPORTED_FEATURES.shadingPattern);
|
||||
return new Shadings.Dummy();
|
||||
}
|
||||
};
|
||||
return Pattern;
|
||||
})();
|
||||
|
||||
var Shadings = {};
|
||||
|
||||
// A small number to offset the first/last color stops so we can insert ones to
|
||||
// support extend. Number.MIN_VALUE appears to be too small and breaks the
|
||||
// extend. 1e-7 works in FF but chrome seems to use an even smaller sized number
|
||||
// internally so we have to go bigger.
|
||||
Shadings.SMALL_NUMBER = 1e-2;
|
||||
|
||||
// Radial and axial shading have very similar implementations
|
||||
// If needed, the implementations can be broken into two classes
|
||||
Shadings.RadialAxial = (function RadialAxialClosure() {
|
||||
function RadialAxial(dict, matrix, xref, res) {
|
||||
this.matrix = matrix;
|
||||
this.coordsArr = dict.get('Coords');
|
||||
this.shadingType = dict.get('ShadingType');
|
||||
this.type = 'Pattern';
|
||||
var cs = dict.get('ColorSpace', 'CS');
|
||||
cs = ColorSpace.parse(cs, xref, res);
|
||||
this.cs = cs;
|
||||
|
||||
var t0 = 0.0, t1 = 1.0;
|
||||
if (dict.has('Domain')) {
|
||||
var domainArr = dict.get('Domain');
|
||||
t0 = domainArr[0];
|
||||
t1 = domainArr[1];
|
||||
}
|
||||
|
||||
var extendStart = false, extendEnd = false;
|
||||
if (dict.has('Extend')) {
|
||||
var extendArr = dict.get('Extend');
|
||||
extendStart = extendArr[0];
|
||||
extendEnd = extendArr[1];
|
||||
}
|
||||
|
||||
if (this.shadingType === PatternType.RADIAL &&
|
||||
(!extendStart || !extendEnd)) {
|
||||
// Radial gradient only currently works if either circle is fully within
|
||||
// the other circle.
|
||||
var x1 = this.coordsArr[0];
|
||||
var y1 = this.coordsArr[1];
|
||||
var r1 = this.coordsArr[2];
|
||||
var x2 = this.coordsArr[3];
|
||||
var y2 = this.coordsArr[4];
|
||||
var r2 = this.coordsArr[5];
|
||||
var distance = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
|
||||
if (r1 <= r2 + distance &&
|
||||
r2 <= r1 + distance) {
|
||||
warn('Unsupported radial gradient.');
|
||||
}
|
||||
}
|
||||
|
||||
this.extendStart = extendStart;
|
||||
this.extendEnd = extendEnd;
|
||||
|
||||
var fnObj = dict.get('Function');
|
||||
var fn = PDFFunction.parseArray(xref, fnObj);
|
||||
|
||||
// 10 samples seems good enough for now, but probably won't work
|
||||
// if there are sharp color changes. Ideally, we would implement
|
||||
// the spec faithfully and add lossless optimizations.
|
||||
var diff = t1 - t0;
|
||||
var step = diff / 10;
|
||||
|
||||
var colorStops = this.colorStops = [];
|
||||
|
||||
// Protect against bad domains so we don't end up in an infinte loop below.
|
||||
if (t0 >= t1 || step <= 0) {
|
||||
// Acrobat doesn't seem to handle these cases so we'll ignore for
|
||||
// now.
|
||||
info('Bad shading domain.');
|
||||
return;
|
||||
}
|
||||
|
||||
var color = new Float32Array(cs.numComps), ratio = new Float32Array(1);
|
||||
var rgbColor;
|
||||
for (var i = t0; i <= t1; i += step) {
|
||||
ratio[0] = i;
|
||||
fn(ratio, 0, color, 0);
|
||||
rgbColor = cs.getRgb(color, 0);
|
||||
var cssColor = Util.makeCssRgb(rgbColor);
|
||||
colorStops.push([(i - t0) / diff, cssColor]);
|
||||
}
|
||||
|
||||
var background = 'transparent';
|
||||
if (dict.has('Background')) {
|
||||
rgbColor = cs.getRgb(dict.get('Background'), 0);
|
||||
background = Util.makeCssRgb(rgbColor);
|
||||
}
|
||||
|
||||
if (!extendStart) {
|
||||
// Insert a color stop at the front and offset the first real color stop
|
||||
// so it doesn't conflict with the one we insert.
|
||||
colorStops.unshift([0, background]);
|
||||
colorStops[1][0] += Shadings.SMALL_NUMBER;
|
||||
}
|
||||
if (!extendEnd) {
|
||||
// Same idea as above in extendStart but for the end.
|
||||
colorStops[colorStops.length - 1][0] -= Shadings.SMALL_NUMBER;
|
||||
colorStops.push([1, background]);
|
||||
}
|
||||
|
||||
this.colorStops = colorStops;
|
||||
}
|
||||
|
||||
RadialAxial.prototype = {
|
||||
getIR: function RadialAxial_getIR() {
|
||||
var coordsArr = this.coordsArr;
|
||||
var shadingType = this.shadingType;
|
||||
var type, p0, p1, r0, r1;
|
||||
if (shadingType === PatternType.AXIAL) {
|
||||
p0 = [coordsArr[0], coordsArr[1]];
|
||||
p1 = [coordsArr[2], coordsArr[3]];
|
||||
r0 = null;
|
||||
r1 = null;
|
||||
type = 'axial';
|
||||
} else if (shadingType === PatternType.RADIAL) {
|
||||
p0 = [coordsArr[0], coordsArr[1]];
|
||||
p1 = [coordsArr[3], coordsArr[4]];
|
||||
r0 = coordsArr[2];
|
||||
r1 = coordsArr[5];
|
||||
type = 'radial';
|
||||
} else {
|
||||
error('getPattern type unknown: ' + shadingType);
|
||||
}
|
||||
|
||||
var matrix = this.matrix;
|
||||
if (matrix) {
|
||||
p0 = Util.applyTransform(p0, matrix);
|
||||
p1 = Util.applyTransform(p1, matrix);
|
||||
}
|
||||
|
||||
return ['RadialAxial', type, this.colorStops, p0, p1, r0, r1];
|
||||
}
|
||||
};
|
||||
|
||||
return RadialAxial;
|
||||
})();
|
||||
|
||||
// All mesh shading. For now, they will be presented as set of the triangles
|
||||
// to be drawn on the canvas and rgb color for each vertex.
|
||||
Shadings.Mesh = (function MeshClosure() {
|
||||
function MeshStreamReader(stream, context) {
|
||||
this.stream = stream;
|
||||
this.context = context;
|
||||
this.buffer = 0;
|
||||
this.bufferLength = 0;
|
||||
|
||||
var numComps = context.numComps;
|
||||
this.tmpCompsBuf = new Float32Array(numComps);
|
||||
var csNumComps = context.colorSpace;
|
||||
this.tmpCsCompsBuf = context.colorFn ? new Float32Array(csNumComps) :
|
||||
this.tmpCompsBuf;
|
||||
}
|
||||
MeshStreamReader.prototype = {
|
||||
get hasData() {
|
||||
if (this.stream.end) {
|
||||
return this.stream.pos < this.stream.end;
|
||||
}
|
||||
if (this.bufferLength > 0) {
|
||||
return true;
|
||||
}
|
||||
var nextByte = this.stream.getByte();
|
||||
if (nextByte < 0) {
|
||||
return false;
|
||||
}
|
||||
this.buffer = nextByte;
|
||||
this.bufferLength = 8;
|
||||
return true;
|
||||
},
|
||||
readBits: function MeshStreamReader_readBits(n) {
|
||||
var buffer = this.buffer;
|
||||
var bufferLength = this.bufferLength;
|
||||
if (n === 32) {
|
||||
if (bufferLength === 0) {
|
||||
return ((this.stream.getByte() << 24) |
|
||||
(this.stream.getByte() << 16) | (this.stream.getByte() << 8) |
|
||||
this.stream.getByte()) >>> 0;
|
||||
}
|
||||
buffer = (buffer << 24) | (this.stream.getByte() << 16) |
|
||||
(this.stream.getByte() << 8) | this.stream.getByte();
|
||||
var nextByte = this.stream.getByte();
|
||||
this.buffer = nextByte & ((1 << bufferLength) - 1);
|
||||
return ((buffer << (8 - bufferLength)) |
|
||||
((nextByte & 0xFF) >> bufferLength)) >>> 0;
|
||||
}
|
||||
if (n === 8 && bufferLength === 0) {
|
||||
return this.stream.getByte();
|
||||
}
|
||||
while (bufferLength < n) {
|
||||
buffer = (buffer << 8) | this.stream.getByte();
|
||||
bufferLength += 8;
|
||||
}
|
||||
bufferLength -= n;
|
||||
this.bufferLength = bufferLength;
|
||||
this.buffer = buffer & ((1 << bufferLength) - 1);
|
||||
return buffer >> bufferLength;
|
||||
},
|
||||
align: function MeshStreamReader_align() {
|
||||
this.buffer = 0;
|
||||
this.bufferLength = 0;
|
||||
},
|
||||
readFlag: function MeshStreamReader_readFlag() {
|
||||
return this.readBits(this.context.bitsPerFlag);
|
||||
},
|
||||
readCoordinate: function MeshStreamReader_readCoordinate() {
|
||||
var bitsPerCoordinate = this.context.bitsPerCoordinate;
|
||||
var xi = this.readBits(bitsPerCoordinate);
|
||||
var yi = this.readBits(bitsPerCoordinate);
|
||||
var decode = this.context.decode;
|
||||
var scale = bitsPerCoordinate < 32 ? 1 / ((1 << bitsPerCoordinate) - 1) :
|
||||
2.3283064365386963e-10; // 2 ^ -32
|
||||
return [
|
||||
xi * scale * (decode[1] - decode[0]) + decode[0],
|
||||
yi * scale * (decode[3] - decode[2]) + decode[2]
|
||||
];
|
||||
},
|
||||
readComponents: function MeshStreamReader_readComponents() {
|
||||
var numComps = this.context.numComps;
|
||||
var bitsPerComponent = this.context.bitsPerComponent;
|
||||
var scale = bitsPerComponent < 32 ? 1 / ((1 << bitsPerComponent) - 1) :
|
||||
2.3283064365386963e-10; // 2 ^ -32
|
||||
var decode = this.context.decode;
|
||||
var components = this.tmpCompsBuf;
|
||||
for (var i = 0, j = 4; i < numComps; i++, j += 2) {
|
||||
var ci = this.readBits(bitsPerComponent);
|
||||
components[i] = ci * scale * (decode[j + 1] - decode[j]) + decode[j];
|
||||
}
|
||||
var color = this.tmpCsCompsBuf;
|
||||
if (this.context.colorFn) {
|
||||
this.context.colorFn(components, 0, color, 0);
|
||||
}
|
||||
return this.context.colorSpace.getRgb(color, 0);
|
||||
}
|
||||
};
|
||||
|
||||
function decodeType4Shading(mesh, reader) {
|
||||
var coords = mesh.coords;
|
||||
var colors = mesh.colors;
|
||||
var operators = [];
|
||||
var ps = []; // not maintaining cs since that will match ps
|
||||
var verticesLeft = 0; // assuming we have all data to start a new triangle
|
||||
while (reader.hasData) {
|
||||
var f = reader.readFlag();
|
||||
var coord = reader.readCoordinate();
|
||||
var color = reader.readComponents();
|
||||
if (verticesLeft === 0) { // ignoring flags if we started a triangle
|
||||
assert(0 <= f && f <= 2, 'Unknown type4 flag');
|
||||
switch (f) {
|
||||
case 0:
|
||||
verticesLeft = 3;
|
||||
break;
|
||||
case 1:
|
||||
ps.push(ps[ps.length - 2], ps[ps.length - 1]);
|
||||
verticesLeft = 1;
|
||||
break;
|
||||
case 2:
|
||||
ps.push(ps[ps.length - 3], ps[ps.length - 1]);
|
||||
verticesLeft = 1;
|
||||
break;
|
||||
}
|
||||
operators.push(f);
|
||||
}
|
||||
ps.push(coords.length);
|
||||
coords.push(coord);
|
||||
colors.push(color);
|
||||
verticesLeft--;
|
||||
|
||||
reader.align();
|
||||
}
|
||||
|
||||
var psPacked = new Int32Array(ps);
|
||||
|
||||
mesh.figures.push({
|
||||
type: 'triangles',
|
||||
coords: psPacked,
|
||||
colors: psPacked
|
||||
});
|
||||
}
|
||||
|
||||
function decodeType5Shading(mesh, reader, verticesPerRow) {
|
||||
var coords = mesh.coords;
|
||||
var colors = mesh.colors;
|
||||
var ps = []; // not maintaining cs since that will match ps
|
||||
while (reader.hasData) {
|
||||
var coord = reader.readCoordinate();
|
||||
var color = reader.readComponents();
|
||||
ps.push(coords.length);
|
||||
coords.push(coord);
|
||||
colors.push(color);
|
||||
}
|
||||
|
||||
var psPacked = new Int32Array(ps);
|
||||
|
||||
mesh.figures.push({
|
||||
type: 'lattice',
|
||||
coords: psPacked,
|
||||
colors: psPacked,
|
||||
verticesPerRow: verticesPerRow
|
||||
});
|
||||
}
|
||||
|
||||
var MIN_SPLIT_PATCH_CHUNKS_AMOUNT = 3;
|
||||
var MAX_SPLIT_PATCH_CHUNKS_AMOUNT = 20;
|
||||
|
||||
var TRIANGLE_DENSITY = 20; // count of triangles per entire mesh bounds
|
||||
|
||||
var getB = (function getBClosure() {
|
||||
function buildB(count) {
|
||||
var lut = [];
|
||||
for (var i = 0; i <= count; i++) {
|
||||
var t = i / count, t_ = 1 - t;
|
||||
lut.push(new Float32Array([t_ * t_ * t_, 3 * t * t_ * t_,
|
||||
3 * t * t * t_, t * t * t]));
|
||||
}
|
||||
return lut;
|
||||
}
|
||||
var cache = [];
|
||||
return function getB(count) {
|
||||
if (!cache[count]) {
|
||||
cache[count] = buildB(count);
|
||||
}
|
||||
return cache[count];
|
||||
};
|
||||
})();
|
||||
|
||||
function buildFigureFromPatch(mesh, index) {
|
||||
var figure = mesh.figures[index];
|
||||
assert(figure.type === 'patch', 'Unexpected patch mesh figure');
|
||||
|
||||
var coords = mesh.coords, colors = mesh.colors;
|
||||
var pi = figure.coords;
|
||||
var ci = figure.colors;
|
||||
|
||||
var figureMinX = Math.min(coords[pi[0]][0], coords[pi[3]][0],
|
||||
coords[pi[12]][0], coords[pi[15]][0]);
|
||||
var figureMinY = Math.min(coords[pi[0]][1], coords[pi[3]][1],
|
||||
coords[pi[12]][1], coords[pi[15]][1]);
|
||||
var figureMaxX = Math.max(coords[pi[0]][0], coords[pi[3]][0],
|
||||
coords[pi[12]][0], coords[pi[15]][0]);
|
||||
var figureMaxY = Math.max(coords[pi[0]][1], coords[pi[3]][1],
|
||||
coords[pi[12]][1], coords[pi[15]][1]);
|
||||
var splitXBy = Math.ceil((figureMaxX - figureMinX) * TRIANGLE_DENSITY /
|
||||
(mesh.bounds[2] - mesh.bounds[0]));
|
||||
splitXBy = Math.max(MIN_SPLIT_PATCH_CHUNKS_AMOUNT,
|
||||
Math.min(MAX_SPLIT_PATCH_CHUNKS_AMOUNT, splitXBy));
|
||||
var splitYBy = Math.ceil((figureMaxY - figureMinY) * TRIANGLE_DENSITY /
|
||||
(mesh.bounds[3] - mesh.bounds[1]));
|
||||
splitYBy = Math.max(MIN_SPLIT_PATCH_CHUNKS_AMOUNT,
|
||||
Math.min(MAX_SPLIT_PATCH_CHUNKS_AMOUNT, splitYBy));
|
||||
|
||||
var verticesPerRow = splitXBy + 1;
|
||||
var figureCoords = new Int32Array((splitYBy + 1) * verticesPerRow);
|
||||
var figureColors = new Int32Array((splitYBy + 1) * verticesPerRow);
|
||||
var k = 0;
|
||||
var cl = new Uint8Array(3), cr = new Uint8Array(3);
|
||||
var c0 = colors[ci[0]], c1 = colors[ci[1]],
|
||||
c2 = colors[ci[2]], c3 = colors[ci[3]];
|
||||
var bRow = getB(splitYBy), bCol = getB(splitXBy);
|
||||
for (var row = 0; row <= splitYBy; row++) {
|
||||
cl[0] = ((c0[0] * (splitYBy - row) + c2[0] * row) / splitYBy) | 0;
|
||||
cl[1] = ((c0[1] * (splitYBy - row) + c2[1] * row) / splitYBy) | 0;
|
||||
cl[2] = ((c0[2] * (splitYBy - row) + c2[2] * row) / splitYBy) | 0;
|
||||
|
||||
cr[0] = ((c1[0] * (splitYBy - row) + c3[0] * row) / splitYBy) | 0;
|
||||
cr[1] = ((c1[1] * (splitYBy - row) + c3[1] * row) / splitYBy) | 0;
|
||||
cr[2] = ((c1[2] * (splitYBy - row) + c3[2] * row) / splitYBy) | 0;
|
||||
|
||||
for (var col = 0; col <= splitXBy; col++, k++) {
|
||||
if ((row === 0 || row === splitYBy) &&
|
||||
(col === 0 || col === splitXBy)) {
|
||||
continue;
|
||||
}
|
||||
var x = 0, y = 0;
|
||||
var q = 0;
|
||||
for (var i = 0; i <= 3; i++) {
|
||||
for (var j = 0; j <= 3; j++, q++) {
|
||||
var m = bRow[row][i] * bCol[col][j];
|
||||
x += coords[pi[q]][0] * m;
|
||||
y += coords[pi[q]][1] * m;
|
||||
}
|
||||
}
|
||||
figureCoords[k] = coords.length;
|
||||
coords.push([x, y]);
|
||||
figureColors[k] = colors.length;
|
||||
var newColor = new Uint8Array(3);
|
||||
newColor[0] = ((cl[0] * (splitXBy - col) + cr[0] * col) / splitXBy) | 0;
|
||||
newColor[1] = ((cl[1] * (splitXBy - col) + cr[1] * col) / splitXBy) | 0;
|
||||
newColor[2] = ((cl[2] * (splitXBy - col) + cr[2] * col) / splitXBy) | 0;
|
||||
colors.push(newColor);
|
||||
}
|
||||
}
|
||||
figureCoords[0] = pi[0];
|
||||
figureColors[0] = ci[0];
|
||||
figureCoords[splitXBy] = pi[3];
|
||||
figureColors[splitXBy] = ci[1];
|
||||
figureCoords[verticesPerRow * splitYBy] = pi[12];
|
||||
figureColors[verticesPerRow * splitYBy] = ci[2];
|
||||
figureCoords[verticesPerRow * splitYBy + splitXBy] = pi[15];
|
||||
figureColors[verticesPerRow * splitYBy + splitXBy] = ci[3];
|
||||
|
||||
mesh.figures[index] = {
|
||||
type: 'lattice',
|
||||
coords: figureCoords,
|
||||
colors: figureColors,
|
||||
verticesPerRow: verticesPerRow
|
||||
};
|
||||
}
|
||||
|
||||
function decodeType6Shading(mesh, reader) {
|
||||
// A special case of Type 7. The p11, p12, p21, p22 automatically filled
|
||||
var coords = mesh.coords;
|
||||
var colors = mesh.colors;
|
||||
var ps = new Int32Array(16); // p00, p10, ..., p30, p01, ..., p33
|
||||
var cs = new Int32Array(4); // c00, c30, c03, c33
|
||||
while (reader.hasData) {
|
||||
var f = reader.readFlag();
|
||||
assert(0 <= f && f <= 3, 'Unknown type6 flag');
|
||||
var i, ii;
|
||||
var pi = coords.length;
|
||||
for (i = 0, ii = (f !== 0 ? 8 : 12); i < ii; i++) {
|
||||
coords.push(reader.readCoordinate());
|
||||
}
|
||||
var ci = colors.length;
|
||||
for (i = 0, ii = (f !== 0 ? 2 : 4); i < ii; i++) {
|
||||
colors.push(reader.readComponents());
|
||||
}
|
||||
var tmp1, tmp2, tmp3, tmp4;
|
||||
switch (f) {
|
||||
case 0:
|
||||
ps[12] = pi + 3; ps[13] = pi + 4; ps[14] = pi + 5; ps[15] = pi + 6;
|
||||
ps[ 8] = pi + 2; /* values for 5, 6, 9, 10 are */ ps[11] = pi + 7;
|
||||
ps[ 4] = pi + 1; /* calculated below */ ps[ 7] = pi + 8;
|
||||
ps[ 0] = pi; ps[ 1] = pi + 11; ps[ 2] = pi + 10; ps[ 3] = pi + 9;
|
||||
cs[2] = ci + 1; cs[3] = ci + 2;
|
||||
cs[0] = ci; cs[1] = ci + 3;
|
||||
break;
|
||||
case 1:
|
||||
tmp1 = ps[12]; tmp2 = ps[13]; tmp3 = ps[14]; tmp4 = ps[15];
|
||||
ps[12] = pi + 5; ps[13] = pi + 4; ps[14] = pi + 3; ps[15] = pi + 2;
|
||||
ps[ 8] = pi + 6; /* values for 5, 6, 9, 10 are */ ps[11] = pi + 1;
|
||||
ps[ 4] = pi + 7; /* calculated below */ ps[ 7] = pi;
|
||||
ps[ 0] = tmp1; ps[ 1] = tmp2; ps[ 2] = tmp3; ps[ 3] = tmp4;
|
||||
tmp1 = cs[2]; tmp2 = cs[3];
|
||||
cs[2] = ci + 1; cs[3] = ci;
|
||||
cs[0] = tmp1; cs[1] = tmp2;
|
||||
break;
|
||||
case 2:
|
||||
ps[12] = ps[15]; ps[13] = pi + 7; ps[14] = pi + 6; ps[15] = pi + 5;
|
||||
ps[ 8] = ps[11]; /* values for 5, 6, 9, 10 are */ ps[11] = pi + 4;
|
||||
ps[ 4] = ps[7]; /* calculated below */ ps[ 7] = pi + 3;
|
||||
ps[ 0] = ps[3]; ps[ 1] = pi; ps[ 2] = pi + 1; ps[ 3] = pi + 2;
|
||||
cs[2] = cs[3]; cs[3] = ci + 1;
|
||||
cs[0] = cs[1]; cs[1] = ci;
|
||||
break;
|
||||
case 3:
|
||||
ps[12] = ps[0]; ps[13] = ps[1]; ps[14] = ps[2]; ps[15] = ps[3];
|
||||
ps[ 8] = pi; /* values for 5, 6, 9, 10 are */ ps[11] = pi + 7;
|
||||
ps[ 4] = pi + 1; /* calculated below */ ps[ 7] = pi + 6;
|
||||
ps[ 0] = pi + 2; ps[ 1] = pi + 3; ps[ 2] = pi + 4; ps[ 3] = pi + 5;
|
||||
cs[2] = cs[0]; cs[3] = cs[1];
|
||||
cs[0] = ci; cs[1] = ci + 1;
|
||||
break;
|
||||
}
|
||||
// set p11, p12, p21, p22
|
||||
ps[5] = coords.length;
|
||||
coords.push([
|
||||
(-4 * coords[ps[0]][0] - coords[ps[15]][0] +
|
||||
6 * (coords[ps[4]][0] + coords[ps[1]][0]) -
|
||||
2 * (coords[ps[12]][0] + coords[ps[3]][0]) +
|
||||
3 * (coords[ps[13]][0] + coords[ps[7]][0])) / 9,
|
||||
(-4 * coords[ps[0]][1] - coords[ps[15]][1] +
|
||||
6 * (coords[ps[4]][1] + coords[ps[1]][1]) -
|
||||
2 * (coords[ps[12]][1] + coords[ps[3]][1]) +
|
||||
3 * (coords[ps[13]][1] + coords[ps[7]][1])) / 9
|
||||
]);
|
||||
ps[6] = coords.length;
|
||||
coords.push([
|
||||
(-4 * coords[ps[3]][0] - coords[ps[12]][0] +
|
||||
6 * (coords[ps[2]][0] + coords[ps[7]][0]) -
|
||||
2 * (coords[ps[0]][0] + coords[ps[15]][0]) +
|
||||
3 * (coords[ps[4]][0] + coords[ps[14]][0])) / 9,
|
||||
(-4 * coords[ps[3]][1] - coords[ps[12]][1] +
|
||||
6 * (coords[ps[2]][1] + coords[ps[7]][1]) -
|
||||
2 * (coords[ps[0]][1] + coords[ps[15]][1]) +
|
||||
3 * (coords[ps[4]][1] + coords[ps[14]][1])) / 9
|
||||
]);
|
||||
ps[9] = coords.length;
|
||||
coords.push([
|
||||
(-4 * coords[ps[12]][0] - coords[ps[3]][0] +
|
||||
6 * (coords[ps[8]][0] + coords[ps[13]][0]) -
|
||||
2 * (coords[ps[0]][0] + coords[ps[15]][0]) +
|
||||
3 * (coords[ps[11]][0] + coords[ps[1]][0])) / 9,
|
||||
(-4 * coords[ps[12]][1] - coords[ps[3]][1] +
|
||||
6 * (coords[ps[8]][1] + coords[ps[13]][1]) -
|
||||
2 * (coords[ps[0]][1] + coords[ps[15]][1]) +
|
||||
3 * (coords[ps[11]][1] + coords[ps[1]][1])) / 9
|
||||
]);
|
||||
ps[10] = coords.length;
|
||||
coords.push([
|
||||
(-4 * coords[ps[15]][0] - coords[ps[0]][0] +
|
||||
6 * (coords[ps[11]][0] + coords[ps[14]][0]) -
|
||||
2 * (coords[ps[12]][0] + coords[ps[3]][0]) +
|
||||
3 * (coords[ps[2]][0] + coords[ps[8]][0])) / 9,
|
||||
(-4 * coords[ps[15]][1] - coords[ps[0]][1] +
|
||||
6 * (coords[ps[11]][1] + coords[ps[14]][1]) -
|
||||
2 * (coords[ps[12]][1] + coords[ps[3]][1]) +
|
||||
3 * (coords[ps[2]][1] + coords[ps[8]][1])) / 9
|
||||
]);
|
||||
mesh.figures.push({
|
||||
type: 'patch',
|
||||
coords: new Int32Array(ps), // making copies of ps and cs
|
||||
colors: new Int32Array(cs)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function decodeType7Shading(mesh, reader) {
|
||||
var coords = mesh.coords;
|
||||
var colors = mesh.colors;
|
||||
var ps = new Int32Array(16); // p00, p10, ..., p30, p01, ..., p33
|
||||
var cs = new Int32Array(4); // c00, c30, c03, c33
|
||||
while (reader.hasData) {
|
||||
var f = reader.readFlag();
|
||||
assert(0 <= f && f <= 3, 'Unknown type7 flag');
|
||||
var i, ii;
|
||||
var pi = coords.length;
|
||||
for (i = 0, ii = (f !== 0 ? 12 : 16); i < ii; i++) {
|
||||
coords.push(reader.readCoordinate());
|
||||
}
|
||||
var ci = colors.length;
|
||||
for (i = 0, ii = (f !== 0 ? 2 : 4); i < ii; i++) {
|
||||
colors.push(reader.readComponents());
|
||||
}
|
||||
var tmp1, tmp2, tmp3, tmp4;
|
||||
switch (f) {
|
||||
case 0:
|
||||
ps[12] = pi + 3; ps[13] = pi + 4; ps[14] = pi + 5; ps[15] = pi + 6;
|
||||
ps[ 8] = pi + 2; ps[ 9] = pi + 13; ps[10] = pi + 14; ps[11] = pi + 7;
|
||||
ps[ 4] = pi + 1; ps[ 5] = pi + 12; ps[ 6] = pi + 15; ps[ 7] = pi + 8;
|
||||
ps[ 0] = pi; ps[ 1] = pi + 11; ps[ 2] = pi + 10; ps[ 3] = pi + 9;
|
||||
cs[2] = ci + 1; cs[3] = ci + 2;
|
||||
cs[0] = ci; cs[1] = ci + 3;
|
||||
break;
|
||||
case 1:
|
||||
tmp1 = ps[12]; tmp2 = ps[13]; tmp3 = ps[14]; tmp4 = ps[15];
|
||||
ps[12] = pi + 5; ps[13] = pi + 4; ps[14] = pi + 3; ps[15] = pi + 2;
|
||||
ps[ 8] = pi + 6; ps[ 9] = pi + 11; ps[10] = pi + 10; ps[11] = pi + 1;
|
||||
ps[ 4] = pi + 7; ps[ 5] = pi + 8; ps[ 6] = pi + 9; ps[ 7] = pi;
|
||||
ps[ 0] = tmp1; ps[ 1] = tmp2; ps[ 2] = tmp3; ps[ 3] = tmp4;
|
||||
tmp1 = cs[2]; tmp2 = cs[3];
|
||||
cs[2] = ci + 1; cs[3] = ci;
|
||||
cs[0] = tmp1; cs[1] = tmp2;
|
||||
break;
|
||||
case 2:
|
||||
ps[12] = ps[15]; ps[13] = pi + 7; ps[14] = pi + 6; ps[15] = pi + 5;
|
||||
ps[ 8] = ps[11]; ps[ 9] = pi + 8; ps[10] = pi + 11; ps[11] = pi + 4;
|
||||
ps[ 4] = ps[7]; ps[ 5] = pi + 9; ps[ 6] = pi + 10; ps[ 7] = pi + 3;
|
||||
ps[ 0] = ps[3]; ps[ 1] = pi; ps[ 2] = pi + 1; ps[ 3] = pi + 2;
|
||||
cs[2] = cs[3]; cs[3] = ci + 1;
|
||||
cs[0] = cs[1]; cs[1] = ci;
|
||||
break;
|
||||
case 3:
|
||||
ps[12] = ps[0]; ps[13] = ps[1]; ps[14] = ps[2]; ps[15] = ps[3];
|
||||
ps[ 8] = pi; ps[ 9] = pi + 9; ps[10] = pi + 8; ps[11] = pi + 7;
|
||||
ps[ 4] = pi + 1; ps[ 5] = pi + 10; ps[ 6] = pi + 11; ps[ 7] = pi + 6;
|
||||
ps[ 0] = pi + 2; ps[ 1] = pi + 3; ps[ 2] = pi + 4; ps[ 3] = pi + 5;
|
||||
cs[2] = cs[0]; cs[3] = cs[1];
|
||||
cs[0] = ci; cs[1] = ci + 1;
|
||||
break;
|
||||
}
|
||||
mesh.figures.push({
|
||||
type: 'patch',
|
||||
coords: new Int32Array(ps), // making copies of ps and cs
|
||||
colors: new Int32Array(cs)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function updateBounds(mesh) {
|
||||
var minX = mesh.coords[0][0], minY = mesh.coords[0][1],
|
||||
maxX = minX, maxY = minY;
|
||||
for (var i = 1, ii = mesh.coords.length; i < ii; i++) {
|
||||
var x = mesh.coords[i][0], y = mesh.coords[i][1];
|
||||
minX = minX > x ? x : minX;
|
||||
minY = minY > y ? y : minY;
|
||||
maxX = maxX < x ? x : maxX;
|
||||
maxY = maxY < y ? y : maxY;
|
||||
}
|
||||
mesh.bounds = [minX, minY, maxX, maxY];
|
||||
}
|
||||
|
||||
function packData(mesh) {
|
||||
var i, ii, j, jj;
|
||||
|
||||
var coords = mesh.coords;
|
||||
var coordsPacked = new Float32Array(coords.length * 2);
|
||||
for (i = 0, j = 0, ii = coords.length; i < ii; i++) {
|
||||
var xy = coords[i];
|
||||
coordsPacked[j++] = xy[0];
|
||||
coordsPacked[j++] = xy[1];
|
||||
}
|
||||
mesh.coords = coordsPacked;
|
||||
|
||||
var colors = mesh.colors;
|
||||
var colorsPacked = new Uint8Array(colors.length * 3);
|
||||
for (i = 0, j = 0, ii = colors.length; i < ii; i++) {
|
||||
var c = colors[i];
|
||||
colorsPacked[j++] = c[0];
|
||||
colorsPacked[j++] = c[1];
|
||||
colorsPacked[j++] = c[2];
|
||||
}
|
||||
mesh.colors = colorsPacked;
|
||||
|
||||
var figures = mesh.figures;
|
||||
for (i = 0, ii = figures.length; i < ii; i++) {
|
||||
var figure = figures[i], ps = figure.coords, cs = figure.colors;
|
||||
for (j = 0, jj = ps.length; j < jj; j++) {
|
||||
ps[j] *= 2;
|
||||
cs[j] *= 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function Mesh(stream, matrix, xref, res) {
|
||||
assert(isStream(stream), 'Mesh data is not a stream');
|
||||
var dict = stream.dict;
|
||||
this.matrix = matrix;
|
||||
this.shadingType = dict.get('ShadingType');
|
||||
this.type = 'Pattern';
|
||||
this.bbox = dict.get('BBox');
|
||||
var cs = dict.get('ColorSpace', 'CS');
|
||||
cs = ColorSpace.parse(cs, xref, res);
|
||||
this.cs = cs;
|
||||
this.background = dict.has('Background') ?
|
||||
cs.getRgb(dict.get('Background'), 0) : null;
|
||||
|
||||
var fnObj = dict.get('Function');
|
||||
var fn = fnObj ? PDFFunction.parseArray(xref, fnObj) : null;
|
||||
|
||||
this.coords = [];
|
||||
this.colors = [];
|
||||
this.figures = [];
|
||||
|
||||
var decodeContext = {
|
||||
bitsPerCoordinate: dict.get('BitsPerCoordinate'),
|
||||
bitsPerComponent: dict.get('BitsPerComponent'),
|
||||
bitsPerFlag: dict.get('BitsPerFlag'),
|
||||
decode: dict.get('Decode'),
|
||||
colorFn: fn,
|
||||
colorSpace: cs,
|
||||
numComps: fn ? 1 : cs.numComps
|
||||
};
|
||||
var reader = new MeshStreamReader(stream, decodeContext);
|
||||
|
||||
var patchMesh = false;
|
||||
switch (this.shadingType) {
|
||||
case PatternType.FREE_FORM_MESH:
|
||||
decodeType4Shading(this, reader);
|
||||
break;
|
||||
case PatternType.LATTICE_FORM_MESH:
|
||||
var verticesPerRow = dict.get('VerticesPerRow') | 0;
|
||||
assert(verticesPerRow >= 2, 'Invalid VerticesPerRow');
|
||||
decodeType5Shading(this, reader, verticesPerRow);
|
||||
break;
|
||||
case PatternType.COONS_PATCH_MESH:
|
||||
decodeType6Shading(this, reader);
|
||||
patchMesh = true;
|
||||
break;
|
||||
case PatternType.TENSOR_PATCH_MESH:
|
||||
decodeType7Shading(this, reader);
|
||||
patchMesh = true;
|
||||
break;
|
||||
default:
|
||||
error('Unsupported mesh type.');
|
||||
break;
|
||||
}
|
||||
|
||||
if (patchMesh) {
|
||||
// dirty bounds calculation for determining, how dense shall be triangles
|
||||
updateBounds(this);
|
||||
for (var i = 0, ii = this.figures.length; i < ii; i++) {
|
||||
buildFigureFromPatch(this, i);
|
||||
}
|
||||
}
|
||||
// calculate bounds
|
||||
updateBounds(this);
|
||||
|
||||
packData(this);
|
||||
}
|
||||
|
||||
Mesh.prototype = {
|
||||
getIR: function Mesh_getIR() {
|
||||
return ['Mesh', this.shadingType, this.coords, this.colors, this.figures,
|
||||
this.bounds, this.matrix, this.bbox, this.background];
|
||||
}
|
||||
};
|
||||
|
||||
return Mesh;
|
||||
})();
|
||||
|
||||
Shadings.Dummy = (function DummyClosure() {
|
||||
function Dummy() {
|
||||
this.type = 'Pattern';
|
||||
}
|
||||
|
||||
Dummy.prototype = {
|
||||
getIR: function Dummy_getIR() {
|
||||
return ['Dummy'];
|
||||
}
|
||||
};
|
||||
return Dummy;
|
||||
})();
|
||||
|
||||
function getTilingPatternIR(operatorList, dict, args) {
|
||||
var matrix = dict.get('Matrix');
|
||||
var bbox = dict.get('BBox');
|
||||
var xstep = dict.get('XStep');
|
||||
var ystep = dict.get('YStep');
|
||||
var paintType = dict.get('PaintType');
|
||||
var tilingType = dict.get('TilingType');
|
||||
|
||||
return [
|
||||
'TilingPattern', args, operatorList, matrix, bbox, xstep, ystep,
|
||||
paintType, tilingType
|
||||
];
|
||||
}
|
225
.obsidian/pdfjs/pdfextract/pdfjs/src/core/pdf_manager.js
vendored
Normal file
225
.obsidian/pdfjs/pdfextract/pdfjs/src/core/pdf_manager.js
vendored
Normal file
@@ -0,0 +1,225 @@
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
/* Copyright 2012 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/* globals NotImplementedException, MissingDataException, Promise, Stream,
|
||||
PDFDocument, ChunkedStreamManager, createPromiseCapability */
|
||||
|
||||
'use strict';
|
||||
|
||||
// The maximum number of bytes fetched per range request
|
||||
var RANGE_CHUNK_SIZE = 65536;
|
||||
|
||||
// TODO(mack): Make use of PDFJS.Util.inherit() when it becomes available
|
||||
var BasePdfManager = (function BasePdfManagerClosure() {
|
||||
function BasePdfManager() {
|
||||
throw new Error('Cannot initialize BaseManagerManager');
|
||||
}
|
||||
|
||||
BasePdfManager.prototype = {
|
||||
onLoadedStream: function BasePdfManager_onLoadedStream() {
|
||||
throw new NotImplementedException();
|
||||
},
|
||||
|
||||
ensureDoc: function BasePdfManager_ensureDoc(prop, args) {
|
||||
return this.ensure(this.pdfDocument, prop, args);
|
||||
},
|
||||
|
||||
ensureXRef: function BasePdfManager_ensureXRef(prop, args) {
|
||||
return this.ensure(this.pdfDocument.xref, prop, args);
|
||||
},
|
||||
|
||||
ensureCatalog: function BasePdfManager_ensureCatalog(prop, args) {
|
||||
return this.ensure(this.pdfDocument.catalog, prop, args);
|
||||
},
|
||||
|
||||
getPage: function BasePdfManager_pagePage(pageIndex) {
|
||||
return this.pdfDocument.getPage(pageIndex);
|
||||
},
|
||||
|
||||
cleanup: function BasePdfManager_cleanup() {
|
||||
return this.pdfDocument.cleanup();
|
||||
},
|
||||
|
||||
ensure: function BasePdfManager_ensure(obj, prop, args) {
|
||||
return new NotImplementedException();
|
||||
},
|
||||
|
||||
requestRange: function BasePdfManager_ensure(begin, end) {
|
||||
return new NotImplementedException();
|
||||
},
|
||||
|
||||
requestLoadedStream: function BasePdfManager_requestLoadedStream() {
|
||||
return new NotImplementedException();
|
||||
},
|
||||
|
||||
sendProgressiveData: function BasePdfManager_sendProgressiveData(chunk) {
|
||||
return new NotImplementedException();
|
||||
},
|
||||
|
||||
updatePassword: function BasePdfManager_updatePassword(password) {
|
||||
this.pdfDocument.xref.password = this.password = password;
|
||||
if (this._passwordChangedCapability) {
|
||||
this._passwordChangedCapability.resolve();
|
||||
}
|
||||
},
|
||||
|
||||
passwordChanged: function BasePdfManager_passwordChanged() {
|
||||
this._passwordChangedCapability = createPromiseCapability();
|
||||
return this._passwordChangedCapability.promise;
|
||||
},
|
||||
|
||||
terminate: function BasePdfManager_terminate() {
|
||||
return new NotImplementedException();
|
||||
}
|
||||
};
|
||||
|
||||
return BasePdfManager;
|
||||
})();
|
||||
|
||||
var LocalPdfManager = (function LocalPdfManagerClosure() {
|
||||
function LocalPdfManager(data, password) {
|
||||
var stream = new Stream(data);
|
||||
this.pdfDocument = new PDFDocument(this, stream, password);
|
||||
this._loadedStreamCapability = createPromiseCapability();
|
||||
this._loadedStreamCapability.resolve(stream);
|
||||
}
|
||||
|
||||
LocalPdfManager.prototype = Object.create(BasePdfManager.prototype);
|
||||
LocalPdfManager.prototype.constructor = LocalPdfManager;
|
||||
|
||||
LocalPdfManager.prototype.ensure =
|
||||
function LocalPdfManager_ensure(obj, prop, args) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
try {
|
||||
var value = obj[prop];
|
||||
var result;
|
||||
if (typeof value === 'function') {
|
||||
result = value.apply(obj, args);
|
||||
} else {
|
||||
result = value;
|
||||
}
|
||||
resolve(result);
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
LocalPdfManager.prototype.requestRange =
|
||||
function LocalPdfManager_requestRange(begin, end) {
|
||||
return Promise.resolve();
|
||||
};
|
||||
|
||||
LocalPdfManager.prototype.requestLoadedStream =
|
||||
function LocalPdfManager_requestLoadedStream() {
|
||||
};
|
||||
|
||||
LocalPdfManager.prototype.onLoadedStream =
|
||||
function LocalPdfManager_getLoadedStream() {
|
||||
return this._loadedStreamCapability.promise;
|
||||
};
|
||||
|
||||
LocalPdfManager.prototype.terminate =
|
||||
function LocalPdfManager_terminate() {
|
||||
return;
|
||||
};
|
||||
|
||||
return LocalPdfManager;
|
||||
})();
|
||||
|
||||
var NetworkPdfManager = (function NetworkPdfManagerClosure() {
|
||||
function NetworkPdfManager(args, msgHandler) {
|
||||
|
||||
this.msgHandler = msgHandler;
|
||||
|
||||
var params = {
|
||||
msgHandler: msgHandler,
|
||||
httpHeaders: args.httpHeaders,
|
||||
withCredentials: args.withCredentials,
|
||||
chunkedViewerLoading: args.chunkedViewerLoading,
|
||||
disableAutoFetch: args.disableAutoFetch,
|
||||
initialData: args.initialData
|
||||
};
|
||||
this.streamManager = new ChunkedStreamManager(args.length, RANGE_CHUNK_SIZE,
|
||||
args.url, params);
|
||||
|
||||
this.pdfDocument = new PDFDocument(this, this.streamManager.getStream(),
|
||||
args.password);
|
||||
}
|
||||
|
||||
NetworkPdfManager.prototype = Object.create(BasePdfManager.prototype);
|
||||
NetworkPdfManager.prototype.constructor = NetworkPdfManager;
|
||||
|
||||
NetworkPdfManager.prototype.ensure =
|
||||
function NetworkPdfManager_ensure(obj, prop, args) {
|
||||
var pdfManager = this;
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
function ensureHelper() {
|
||||
try {
|
||||
var result;
|
||||
var value = obj[prop];
|
||||
if (typeof value === 'function') {
|
||||
result = value.apply(obj, args);
|
||||
} else {
|
||||
result = value;
|
||||
}
|
||||
resolve(result);
|
||||
} catch(e) {
|
||||
if (!(e instanceof MissingDataException)) {
|
||||
reject(e);
|
||||
return;
|
||||
}
|
||||
pdfManager.streamManager.requestRange(e.begin, e.end, ensureHelper);
|
||||
}
|
||||
}
|
||||
|
||||
ensureHelper();
|
||||
});
|
||||
};
|
||||
|
||||
NetworkPdfManager.prototype.requestRange =
|
||||
function NetworkPdfManager_requestRange(begin, end) {
|
||||
return new Promise(function (resolve) {
|
||||
this.streamManager.requestRange(begin, end, function() {
|
||||
resolve();
|
||||
});
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
NetworkPdfManager.prototype.requestLoadedStream =
|
||||
function NetworkPdfManager_requestLoadedStream() {
|
||||
this.streamManager.requestAllChunks();
|
||||
};
|
||||
|
||||
NetworkPdfManager.prototype.sendProgressiveData =
|
||||
function NetworkPdfManager_sendProgressiveData(chunk) {
|
||||
this.streamManager.onReceiveData({ chunk: chunk });
|
||||
};
|
||||
|
||||
NetworkPdfManager.prototype.onLoadedStream =
|
||||
function NetworkPdfManager_getLoadedStream() {
|
||||
return this.streamManager.onLoadedStream();
|
||||
};
|
||||
|
||||
NetworkPdfManager.prototype.terminate =
|
||||
function NetworkPdfManager_terminate() {
|
||||
this.streamManager.networkManager.abortAllRequests();
|
||||
};
|
||||
|
||||
return NetworkPdfManager;
|
||||
})();
|
||||
|
222
.obsidian/pdfjs/pdfextract/pdfjs/src/core/ps_parser.js
vendored
Normal file
222
.obsidian/pdfjs/pdfextract/pdfjs/src/core/ps_parser.js
vendored
Normal file
@@ -0,0 +1,222 @@
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
/* Copyright 2014 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/* globals EOF, error, Lexer */
|
||||
|
||||
'use strict';
|
||||
|
||||
var PostScriptParser = (function PostScriptParserClosure() {
|
||||
function PostScriptParser(lexer) {
|
||||
this.lexer = lexer;
|
||||
this.operators = [];
|
||||
this.token = null;
|
||||
this.prev = null;
|
||||
}
|
||||
PostScriptParser.prototype = {
|
||||
nextToken: function PostScriptParser_nextToken() {
|
||||
this.prev = this.token;
|
||||
this.token = this.lexer.getToken();
|
||||
},
|
||||
accept: function PostScriptParser_accept(type) {
|
||||
if (this.token.type === type) {
|
||||
this.nextToken();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
expect: function PostScriptParser_expect(type) {
|
||||
if (this.accept(type)) {
|
||||
return true;
|
||||
}
|
||||
error('Unexpected symbol: found ' + this.token.type + ' expected ' +
|
||||
type + '.');
|
||||
},
|
||||
parse: function PostScriptParser_parse() {
|
||||
this.nextToken();
|
||||
this.expect(PostScriptTokenTypes.LBRACE);
|
||||
this.parseBlock();
|
||||
this.expect(PostScriptTokenTypes.RBRACE);
|
||||
return this.operators;
|
||||
},
|
||||
parseBlock: function PostScriptParser_parseBlock() {
|
||||
while (true) {
|
||||
if (this.accept(PostScriptTokenTypes.NUMBER)) {
|
||||
this.operators.push(this.prev.value);
|
||||
} else if (this.accept(PostScriptTokenTypes.OPERATOR)) {
|
||||
this.operators.push(this.prev.value);
|
||||
} else if (this.accept(PostScriptTokenTypes.LBRACE)) {
|
||||
this.parseCondition();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
},
|
||||
parseCondition: function PostScriptParser_parseCondition() {
|
||||
// Add two place holders that will be updated later
|
||||
var conditionLocation = this.operators.length;
|
||||
this.operators.push(null, null);
|
||||
|
||||
this.parseBlock();
|
||||
this.expect(PostScriptTokenTypes.RBRACE);
|
||||
if (this.accept(PostScriptTokenTypes.IF)) {
|
||||
// The true block is right after the 'if' so it just falls through on
|
||||
// true else it jumps and skips the true block.
|
||||
this.operators[conditionLocation] = this.operators.length;
|
||||
this.operators[conditionLocation + 1] = 'jz';
|
||||
} else if (this.accept(PostScriptTokenTypes.LBRACE)) {
|
||||
var jumpLocation = this.operators.length;
|
||||
this.operators.push(null, null);
|
||||
var endOfTrue = this.operators.length;
|
||||
this.parseBlock();
|
||||
this.expect(PostScriptTokenTypes.RBRACE);
|
||||
this.expect(PostScriptTokenTypes.IFELSE);
|
||||
// The jump is added at the end of the true block to skip the false
|
||||
// block.
|
||||
this.operators[jumpLocation] = this.operators.length;
|
||||
this.operators[jumpLocation + 1] = 'j';
|
||||
|
||||
this.operators[conditionLocation] = endOfTrue;
|
||||
this.operators[conditionLocation + 1] = 'jz';
|
||||
} else {
|
||||
error('PS Function: error parsing conditional.');
|
||||
}
|
||||
}
|
||||
};
|
||||
return PostScriptParser;
|
||||
})();
|
||||
|
||||
var PostScriptTokenTypes = {
|
||||
LBRACE: 0,
|
||||
RBRACE: 1,
|
||||
NUMBER: 2,
|
||||
OPERATOR: 3,
|
||||
IF: 4,
|
||||
IFELSE: 5
|
||||
};
|
||||
|
||||
var PostScriptToken = (function PostScriptTokenClosure() {
|
||||
function PostScriptToken(type, value) {
|
||||
this.type = type;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
var opCache = {};
|
||||
|
||||
PostScriptToken.getOperator = function PostScriptToken_getOperator(op) {
|
||||
var opValue = opCache[op];
|
||||
if (opValue) {
|
||||
return opValue;
|
||||
}
|
||||
return opCache[op] = new PostScriptToken(PostScriptTokenTypes.OPERATOR, op);
|
||||
};
|
||||
|
||||
PostScriptToken.LBRACE = new PostScriptToken(PostScriptTokenTypes.LBRACE,
|
||||
'{');
|
||||
PostScriptToken.RBRACE = new PostScriptToken(PostScriptTokenTypes.RBRACE,
|
||||
'}');
|
||||
PostScriptToken.IF = new PostScriptToken(PostScriptTokenTypes.IF, 'IF');
|
||||
PostScriptToken.IFELSE = new PostScriptToken(PostScriptTokenTypes.IFELSE,
|
||||
'IFELSE');
|
||||
return PostScriptToken;
|
||||
})();
|
||||
|
||||
var PostScriptLexer = (function PostScriptLexerClosure() {
|
||||
function PostScriptLexer(stream) {
|
||||
this.stream = stream;
|
||||
this.nextChar();
|
||||
|
||||
this.strBuf = [];
|
||||
}
|
||||
PostScriptLexer.prototype = {
|
||||
nextChar: function PostScriptLexer_nextChar() {
|
||||
return (this.currentChar = this.stream.getByte());
|
||||
},
|
||||
getToken: function PostScriptLexer_getToken() {
|
||||
var comment = false;
|
||||
var ch = this.currentChar;
|
||||
|
||||
// skip comments
|
||||
while (true) {
|
||||
if (ch < 0) {
|
||||
return EOF;
|
||||
}
|
||||
|
||||
if (comment) {
|
||||
if (ch === 0x0A || ch === 0x0D) {
|
||||
comment = false;
|
||||
}
|
||||
} else if (ch === 0x25) { // '%'
|
||||
comment = true;
|
||||
} else if (!Lexer.isSpace(ch)) {
|
||||
break;
|
||||
}
|
||||
ch = this.nextChar();
|
||||
}
|
||||
switch (ch | 0) {
|
||||
case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: // '0'-'4'
|
||||
case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: // '5'-'9'
|
||||
case 0x2B: case 0x2D: case 0x2E: // '+', '-', '.'
|
||||
return new PostScriptToken(PostScriptTokenTypes.NUMBER,
|
||||
this.getNumber());
|
||||
case 0x7B: // '{'
|
||||
this.nextChar();
|
||||
return PostScriptToken.LBRACE;
|
||||
case 0x7D: // '}'
|
||||
this.nextChar();
|
||||
return PostScriptToken.RBRACE;
|
||||
}
|
||||
// operator
|
||||
var strBuf = this.strBuf;
|
||||
strBuf.length = 0;
|
||||
strBuf[0] = String.fromCharCode(ch);
|
||||
|
||||
while ((ch = this.nextChar()) >= 0 && // and 'A'-'Z', 'a'-'z'
|
||||
((ch >= 0x41 && ch <= 0x5A) || (ch >= 0x61 && ch <= 0x7A))) {
|
||||
strBuf.push(String.fromCharCode(ch));
|
||||
}
|
||||
var str = strBuf.join('');
|
||||
switch (str.toLowerCase()) {
|
||||
case 'if':
|
||||
return PostScriptToken.IF;
|
||||
case 'ifelse':
|
||||
return PostScriptToken.IFELSE;
|
||||
default:
|
||||
return PostScriptToken.getOperator(str);
|
||||
}
|
||||
},
|
||||
getNumber: function PostScriptLexer_getNumber() {
|
||||
var ch = this.currentChar;
|
||||
var strBuf = this.strBuf;
|
||||
strBuf.length = 0;
|
||||
strBuf[0] = String.fromCharCode(ch);
|
||||
|
||||
while ((ch = this.nextChar()) >= 0) {
|
||||
if ((ch >= 0x30 && ch <= 0x39) || // '0'-'9'
|
||||
ch === 0x2D || ch === 0x2E) { // '-', '.'
|
||||
strBuf.push(String.fromCharCode(ch));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
var value = parseFloat(strBuf.join(''));
|
||||
if (isNaN(value)) {
|
||||
error('Invalid floating point number: ' + value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
};
|
||||
return PostScriptLexer;
|
||||
})();
|
2454
.obsidian/pdfjs/pdfextract/pdfjs/src/core/stream.js
vendored
Normal file
2454
.obsidian/pdfjs/pdfextract/pdfjs/src/core/stream.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
499
.obsidian/pdfjs/pdfextract/pdfjs/src/core/worker.js
vendored
Normal file
499
.obsidian/pdfjs/pdfextract/pdfjs/src/core/worker.js
vendored
Normal file
@@ -0,0 +1,499 @@
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
/* Copyright 2012 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/* globals PDFJS, createPromiseCapability, LocalPdfManager, NetworkPdfManager,
|
||||
NetworkManager, isInt, RANGE_CHUNK_SIZE, MissingPDFException,
|
||||
UnexpectedResponseException, PasswordException, Promise, warn,
|
||||
PasswordResponses, InvalidPDFException, UnknownErrorException,
|
||||
XRefParseException, Ref, info, globalScope, error, MessageHandler */
|
||||
|
||||
'use strict';
|
||||
|
||||
var WorkerMessageHandler = PDFJS.WorkerMessageHandler = {
|
||||
setup: function wphSetup(handler) {
|
||||
var pdfManager;
|
||||
|
||||
function loadDocument(recoveryMode) {
|
||||
var loadDocumentCapability = createPromiseCapability();
|
||||
|
||||
var parseSuccess = function parseSuccess() {
|
||||
var numPagesPromise = pdfManager.ensureDoc('numPages');
|
||||
var fingerprintPromise = pdfManager.ensureDoc('fingerprint');
|
||||
var encryptedPromise = pdfManager.ensureXRef('encrypt');
|
||||
Promise.all([numPagesPromise, fingerprintPromise,
|
||||
encryptedPromise]).then(function onDocReady(results) {
|
||||
var doc = {
|
||||
numPages: results[0],
|
||||
fingerprint: results[1],
|
||||
encrypted: !!results[2],
|
||||
};
|
||||
loadDocumentCapability.resolve(doc);
|
||||
},
|
||||
parseFailure);
|
||||
};
|
||||
|
||||
var parseFailure = function parseFailure(e) {
|
||||
loadDocumentCapability.reject(e);
|
||||
};
|
||||
|
||||
pdfManager.ensureDoc('checkHeader', []).then(function() {
|
||||
pdfManager.ensureDoc('parseStartXRef', []).then(function() {
|
||||
pdfManager.ensureDoc('parse', [recoveryMode]).then(
|
||||
parseSuccess, parseFailure);
|
||||
}, parseFailure);
|
||||
}, parseFailure);
|
||||
|
||||
return loadDocumentCapability.promise;
|
||||
}
|
||||
|
||||
function getPdfManager(data) {
|
||||
var pdfManagerCapability = createPromiseCapability();
|
||||
|
||||
var source = data.source;
|
||||
var disableRange = data.disableRange;
|
||||
if (source.data) {
|
||||
try {
|
||||
pdfManager = new LocalPdfManager(source.data, source.password);
|
||||
pdfManagerCapability.resolve();
|
||||
} catch (ex) {
|
||||
pdfManagerCapability.reject(ex);
|
||||
}
|
||||
return pdfManagerCapability.promise;
|
||||
} else if (source.chunkedViewerLoading) {
|
||||
try {
|
||||
pdfManager = new NetworkPdfManager(source, handler);
|
||||
pdfManagerCapability.resolve();
|
||||
} catch (ex) {
|
||||
pdfManagerCapability.reject(ex);
|
||||
}
|
||||
return pdfManagerCapability.promise;
|
||||
}
|
||||
|
||||
var networkManager = new NetworkManager(source.url, {
|
||||
httpHeaders: source.httpHeaders,
|
||||
withCredentials: source.withCredentials
|
||||
});
|
||||
var cachedChunks = [];
|
||||
var fullRequestXhrId = networkManager.requestFull({
|
||||
onHeadersReceived: function onHeadersReceived() {
|
||||
if (disableRange) {
|
||||
return;
|
||||
}
|
||||
|
||||
var fullRequestXhr = networkManager.getRequestXhr(fullRequestXhrId);
|
||||
if (fullRequestXhr.getResponseHeader('Accept-Ranges') !== 'bytes') {
|
||||
return;
|
||||
}
|
||||
|
||||
var contentEncoding =
|
||||
fullRequestXhr.getResponseHeader('Content-Encoding') || 'identity';
|
||||
if (contentEncoding !== 'identity') {
|
||||
return;
|
||||
}
|
||||
|
||||
var length = fullRequestXhr.getResponseHeader('Content-Length');
|
||||
length = parseInt(length, 10);
|
||||
if (!isInt(length)) {
|
||||
return;
|
||||
}
|
||||
source.length = length;
|
||||
if (length <= 2 * RANGE_CHUNK_SIZE) {
|
||||
// The file size is smaller than the size of two chunks, so it does
|
||||
// not make any sense to abort the request and retry with a range
|
||||
// request.
|
||||
return;
|
||||
}
|
||||
|
||||
if (networkManager.isStreamingRequest(fullRequestXhrId)) {
|
||||
// We can continue fetching when progressive loading is enabled,
|
||||
// and we don't need the autoFetch feature.
|
||||
source.disableAutoFetch = true;
|
||||
} else {
|
||||
// NOTE: by cancelling the full request, and then issuing range
|
||||
// requests, there will be an issue for sites where you can only
|
||||
// request the pdf once. However, if this is the case, then the
|
||||
// server should not be returning that it can support range
|
||||
// requests.
|
||||
networkManager.abortRequest(fullRequestXhrId);
|
||||
}
|
||||
|
||||
try {
|
||||
pdfManager = new NetworkPdfManager(source, handler);
|
||||
pdfManagerCapability.resolve(pdfManager);
|
||||
} catch (ex) {
|
||||
pdfManagerCapability.reject(ex);
|
||||
}
|
||||
},
|
||||
|
||||
onProgressiveData: source.disableStream ? null :
|
||||
function onProgressiveData(chunk) {
|
||||
if (!pdfManager) {
|
||||
cachedChunks.push(chunk);
|
||||
return;
|
||||
}
|
||||
pdfManager.sendProgressiveData(chunk);
|
||||
},
|
||||
|
||||
onDone: function onDone(args) {
|
||||
if (pdfManager) {
|
||||
return; // already processed
|
||||
}
|
||||
|
||||
var pdfFile;
|
||||
if (args === null) {
|
||||
// TODO add some streaming manager, e.g. for unknown length files.
|
||||
// The data was returned in the onProgressiveData, combining...
|
||||
var pdfFileLength = 0, pos = 0;
|
||||
cachedChunks.forEach(function (chunk) {
|
||||
pdfFileLength += chunk.byteLength;
|
||||
});
|
||||
if (source.length && pdfFileLength !== source.length) {
|
||||
warn('reported HTTP length is different from actual');
|
||||
}
|
||||
var pdfFileArray = new Uint8Array(pdfFileLength);
|
||||
cachedChunks.forEach(function (chunk) {
|
||||
pdfFileArray.set(new Uint8Array(chunk), pos);
|
||||
pos += chunk.byteLength;
|
||||
});
|
||||
pdfFile = pdfFileArray.buffer;
|
||||
} else {
|
||||
pdfFile = args.chunk;
|
||||
}
|
||||
|
||||
// the data is array, instantiating directly from it
|
||||
try {
|
||||
pdfManager = new LocalPdfManager(pdfFile, source.password);
|
||||
pdfManagerCapability.resolve();
|
||||
} catch (ex) {
|
||||
pdfManagerCapability.reject(ex);
|
||||
}
|
||||
},
|
||||
|
||||
onError: function onError(status) {
|
||||
var exception;
|
||||
if (status === 404) {
|
||||
exception = new MissingPDFException('Missing PDF "' +
|
||||
source.url + '".');
|
||||
handler.send('MissingPDF', exception);
|
||||
} else {
|
||||
exception = new UnexpectedResponseException(
|
||||
'Unexpected server response (' + status +
|
||||
') while retrieving PDF "' + source.url + '".', status);
|
||||
handler.send('UnexpectedResponse', exception);
|
||||
}
|
||||
},
|
||||
|
||||
onProgress: function onProgress(evt) {
|
||||
handler.send('DocProgress', {
|
||||
loaded: evt.loaded,
|
||||
total: evt.lengthComputable ? evt.total : source.length
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return pdfManagerCapability.promise;
|
||||
}
|
||||
|
||||
handler.on('test', function wphSetupTest(data) {
|
||||
// check if Uint8Array can be sent to worker
|
||||
if (!(data instanceof Uint8Array)) {
|
||||
handler.send('test', false);
|
||||
return;
|
||||
}
|
||||
// making sure postMessage transfers are working
|
||||
var supportTransfers = data[0] === 255;
|
||||
handler.postMessageTransfers = supportTransfers;
|
||||
// check if the response property is supported by xhr
|
||||
var xhr = new XMLHttpRequest();
|
||||
var responseExists = 'response' in xhr;
|
||||
// check if the property is actually implemented
|
||||
try {
|
||||
var dummy = xhr.responseType;
|
||||
} catch (e) {
|
||||
responseExists = false;
|
||||
}
|
||||
if (!responseExists) {
|
||||
handler.send('test', false);
|
||||
return;
|
||||
}
|
||||
handler.send('test', {
|
||||
supportTypedArray: true,
|
||||
supportTransfers: supportTransfers
|
||||
});
|
||||
});
|
||||
|
||||
handler.on('GetDocRequest', function wphSetupDoc(data) {
|
||||
|
||||
var onSuccess = function(doc) {
|
||||
handler.send('GetDoc', { pdfInfo: doc });
|
||||
};
|
||||
|
||||
var onFailure = function(e) {
|
||||
if (e instanceof PasswordException) {
|
||||
if (e.code === PasswordResponses.NEED_PASSWORD) {
|
||||
handler.send('NeedPassword', e);
|
||||
} else if (e.code === PasswordResponses.INCORRECT_PASSWORD) {
|
||||
handler.send('IncorrectPassword', e);
|
||||
}
|
||||
} else if (e instanceof InvalidPDFException) {
|
||||
handler.send('InvalidPDF', e);
|
||||
} else if (e instanceof MissingPDFException) {
|
||||
handler.send('MissingPDF', e);
|
||||
} else if (e instanceof UnexpectedResponseException) {
|
||||
handler.send('UnexpectedResponse', e);
|
||||
} else {
|
||||
handler.send('UnknownError',
|
||||
new UnknownErrorException(e.message, e.toString()));
|
||||
}
|
||||
};
|
||||
|
||||
PDFJS.maxImageSize = data.maxImageSize === undefined ?
|
||||
-1 : data.maxImageSize;
|
||||
PDFJS.disableFontFace = data.disableFontFace;
|
||||
PDFJS.disableCreateObjectURL = data.disableCreateObjectURL;
|
||||
PDFJS.verbosity = data.verbosity;
|
||||
PDFJS.cMapUrl = data.cMapUrl === undefined ?
|
||||
null : data.cMapUrl;
|
||||
PDFJS.cMapPacked = data.cMapPacked === true;
|
||||
|
||||
getPdfManager(data).then(function () {
|
||||
handler.send('PDFManagerReady', null);
|
||||
pdfManager.onLoadedStream().then(function(stream) {
|
||||
handler.send('DataLoaded', { length: stream.bytes.byteLength });
|
||||
});
|
||||
}).then(function pdfManagerReady() {
|
||||
loadDocument(false).then(onSuccess, function loadFailure(ex) {
|
||||
// Try again with recoveryMode == true
|
||||
if (!(ex instanceof XRefParseException)) {
|
||||
if (ex instanceof PasswordException) {
|
||||
// after password exception prepare to receive a new password
|
||||
// to repeat loading
|
||||
pdfManager.passwordChanged().then(pdfManagerReady);
|
||||
}
|
||||
|
||||
onFailure(ex);
|
||||
return;
|
||||
}
|
||||
|
||||
pdfManager.requestLoadedStream();
|
||||
pdfManager.onLoadedStream().then(function() {
|
||||
loadDocument(true).then(onSuccess, onFailure);
|
||||
});
|
||||
}, onFailure);
|
||||
}, onFailure);
|
||||
});
|
||||
|
||||
handler.on('GetPage', function wphSetupGetPage(data) {
|
||||
return pdfManager.getPage(data.pageIndex).then(function(page) {
|
||||
var rotatePromise = pdfManager.ensure(page, 'rotate');
|
||||
var refPromise = pdfManager.ensure(page, 'ref');
|
||||
var viewPromise = pdfManager.ensure(page, 'view');
|
||||
|
||||
return Promise.all([rotatePromise, refPromise, viewPromise]).then(
|
||||
function(results) {
|
||||
return {
|
||||
rotate: results[0],
|
||||
ref: results[1],
|
||||
view: results[2]
|
||||
};
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
handler.on('GetPageIndex', function wphSetupGetPageIndex(data) {
|
||||
var ref = new Ref(data.ref.num, data.ref.gen);
|
||||
var catalog = pdfManager.pdfDocument.catalog;
|
||||
return catalog.getPageIndex(ref);
|
||||
});
|
||||
|
||||
handler.on('GetDestinations',
|
||||
function wphSetupGetDestinations(data) {
|
||||
return pdfManager.ensureCatalog('destinations');
|
||||
}
|
||||
);
|
||||
|
||||
handler.on('GetDestination',
|
||||
function wphSetupGetDestination(data) {
|
||||
return pdfManager.ensureCatalog('getDestination', [ data.id ]);
|
||||
}
|
||||
);
|
||||
|
||||
handler.on('GetAttachments',
|
||||
function wphSetupGetAttachments(data) {
|
||||
return pdfManager.ensureCatalog('attachments');
|
||||
}
|
||||
);
|
||||
|
||||
handler.on('GetJavaScript',
|
||||
function wphSetupGetJavaScript(data) {
|
||||
return pdfManager.ensureCatalog('javaScript');
|
||||
}
|
||||
);
|
||||
|
||||
handler.on('GetOutline',
|
||||
function wphSetupGetOutline(data) {
|
||||
return pdfManager.ensureCatalog('documentOutline');
|
||||
}
|
||||
);
|
||||
|
||||
handler.on('GetMetadata',
|
||||
function wphSetupGetMetadata(data) {
|
||||
return Promise.all([pdfManager.ensureDoc('documentInfo'),
|
||||
pdfManager.ensureCatalog('metadata')]);
|
||||
}
|
||||
);
|
||||
|
||||
handler.on('GetData', function wphSetupGetData(data) {
|
||||
pdfManager.requestLoadedStream();
|
||||
return pdfManager.onLoadedStream().then(function(stream) {
|
||||
return stream.bytes;
|
||||
});
|
||||
});
|
||||
|
||||
handler.on('GetStats',
|
||||
function wphSetupGetStats(data) {
|
||||
return pdfManager.pdfDocument.xref.stats;
|
||||
}
|
||||
);
|
||||
|
||||
handler.on('UpdatePassword', function wphSetupUpdatePassword(data) {
|
||||
pdfManager.updatePassword(data);
|
||||
});
|
||||
|
||||
handler.on('GetAnnotations', function wphSetupGetAnnotations(data) {
|
||||
return pdfManager.getPage(data.pageIndex).then(function(page) {
|
||||
return pdfManager.ensure(page, 'getAnnotationsData', []);
|
||||
});
|
||||
});
|
||||
|
||||
handler.on('RenderPageRequest', function wphSetupRenderPage(data) {
|
||||
pdfManager.getPage(data.pageIndex).then(function(page) {
|
||||
|
||||
var pageNum = data.pageIndex + 1;
|
||||
var start = Date.now();
|
||||
// Pre compile the pdf page and fetch the fonts/images.
|
||||
page.getOperatorList(handler, data.intent).then(function(operatorList) {
|
||||
|
||||
info('page=' + pageNum + ' - getOperatorList: time=' +
|
||||
(Date.now() - start) + 'ms, len=' + operatorList.fnArray.length);
|
||||
|
||||
}, function(e) {
|
||||
|
||||
var minimumStackMessage =
|
||||
'worker.js: while trying to getPage() and getOperatorList()';
|
||||
|
||||
var wrappedException;
|
||||
|
||||
// Turn the error into an obj that can be serialized
|
||||
if (typeof e === 'string') {
|
||||
wrappedException = {
|
||||
message: e,
|
||||
stack: minimumStackMessage
|
||||
};
|
||||
} else if (typeof e === 'object') {
|
||||
wrappedException = {
|
||||
message: e.message || e.toString(),
|
||||
stack: e.stack || minimumStackMessage
|
||||
};
|
||||
} else {
|
||||
wrappedException = {
|
||||
message: 'Unknown exception type: ' + (typeof e),
|
||||
stack: minimumStackMessage
|
||||
};
|
||||
}
|
||||
|
||||
handler.send('PageError', {
|
||||
pageNum: pageNum,
|
||||
error: wrappedException,
|
||||
intent: data.intent
|
||||
});
|
||||
});
|
||||
});
|
||||
}, this);
|
||||
|
||||
handler.on('GetTextContent', function wphExtractText(data) {
|
||||
return pdfManager.getPage(data.pageIndex).then(function(page) {
|
||||
var pageNum = data.pageIndex + 1;
|
||||
var start = Date.now();
|
||||
return page.extractTextContent().then(function(textContent) {
|
||||
info('text indexing: page=' + pageNum + ' - time=' +
|
||||
(Date.now() - start) + 'ms');
|
||||
return textContent;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
handler.on('Cleanup', function wphCleanup(data) {
|
||||
return pdfManager.cleanup();
|
||||
});
|
||||
|
||||
handler.on('Terminate', function wphTerminate(data) {
|
||||
pdfManager.terminate();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
var consoleTimer = {};
|
||||
|
||||
var workerConsole = {
|
||||
log: function log() {
|
||||
var args = Array.prototype.slice.call(arguments);
|
||||
globalScope.postMessage({
|
||||
action: 'console_log',
|
||||
data: args
|
||||
});
|
||||
},
|
||||
|
||||
error: function error() {
|
||||
var args = Array.prototype.slice.call(arguments);
|
||||
globalScope.postMessage({
|
||||
action: 'console_error',
|
||||
data: args
|
||||
});
|
||||
throw 'pdf.js execution error';
|
||||
},
|
||||
|
||||
time: function time(name) {
|
||||
consoleTimer[name] = Date.now();
|
||||
},
|
||||
|
||||
timeEnd: function timeEnd(name) {
|
||||
var time = consoleTimer[name];
|
||||
if (!time) {
|
||||
error('Unknown timer name ' + name);
|
||||
}
|
||||
this.log('Timer:', name, Date.now() - time);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Worker thread?
|
||||
if (typeof window === 'undefined') {
|
||||
if (!('console' in globalScope)) {
|
||||
globalScope.console = workerConsole;
|
||||
}
|
||||
|
||||
// Listen for unsupported features so we can pass them on to the main thread.
|
||||
PDFJS.UnsupportedManager.listen(function (msg) {
|
||||
globalScope.postMessage({
|
||||
action: '_unsupported_feature',
|
||||
data: msg
|
||||
});
|
||||
});
|
||||
|
||||
var handler = new MessageHandler('worker_processor', this);
|
||||
WorkerMessageHandler.setup(handler);
|
||||
}
|
252
.obsidian/pdfjs/pdfextract/pdfjs/src/display/annotation_helper.js
vendored
Normal file
252
.obsidian/pdfjs/pdfextract/pdfjs/src/display/annotation_helper.js
vendored
Normal file
@@ -0,0 +1,252 @@
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
/* Copyright 2014 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/* globals PDFJS, Util, AnnotationType */
|
||||
|
||||
'use strict';
|
||||
|
||||
var HIGHLIGHT_OFFSET = 4; // px
|
||||
var ANNOT_MIN_SIZE = 10; // px
|
||||
|
||||
var AnnotationUtils = (function AnnotationUtilsClosure() {
|
||||
// TODO(mack): This dupes some of the logic in CanvasGraphics.setFont()
|
||||
function setTextStyles(element, item, fontObj) {
|
||||
|
||||
var style = element.style;
|
||||
style.fontSize = item.fontSize + 'px';
|
||||
style.direction = item.fontDirection < 0 ? 'rtl': 'ltr';
|
||||
|
||||
if (!fontObj) {
|
||||
return;
|
||||
}
|
||||
|
||||
style.fontWeight = fontObj.black ?
|
||||
(fontObj.bold ? 'bolder' : 'bold') :
|
||||
(fontObj.bold ? 'bold' : 'normal');
|
||||
style.fontStyle = fontObj.italic ? 'italic' : 'normal';
|
||||
|
||||
var fontName = fontObj.loadedName;
|
||||
var fontFamily = fontName ? '"' + fontName + '", ' : '';
|
||||
// Use a reasonable default font if the font doesn't specify a fallback
|
||||
var fallbackName = fontObj.fallbackName || 'Helvetica, sans-serif';
|
||||
style.fontFamily = fontFamily + fallbackName;
|
||||
}
|
||||
|
||||
// TODO(mack): Remove this, it's not really that helpful.
|
||||
function getEmptyContainer(tagName, rect, borderWidth) {
|
||||
var bWidth = borderWidth || 0;
|
||||
var element = document.createElement(tagName);
|
||||
element.style.borderWidth = bWidth + 'px';
|
||||
var width = rect[2] - rect[0] - 2 * bWidth;
|
||||
var height = rect[3] - rect[1] - 2 * bWidth;
|
||||
element.style.width = width + 'px';
|
||||
element.style.height = height + 'px';
|
||||
return element;
|
||||
}
|
||||
|
||||
function initContainer(item) {
|
||||
var container = getEmptyContainer('section', item.rect, item.borderWidth);
|
||||
container.style.backgroundColor = item.color;
|
||||
|
||||
var color = item.color;
|
||||
var rgb = [];
|
||||
for (var i = 0; i < 3; ++i) {
|
||||
rgb[i] = Math.round(color[i] * 255);
|
||||
}
|
||||
item.colorCssRgb = Util.makeCssRgb(rgb);
|
||||
|
||||
var highlight = document.createElement('div');
|
||||
highlight.className = 'annotationHighlight';
|
||||
highlight.style.left = highlight.style.top = -HIGHLIGHT_OFFSET + 'px';
|
||||
highlight.style.right = highlight.style.bottom = -HIGHLIGHT_OFFSET + 'px';
|
||||
highlight.setAttribute('hidden', true);
|
||||
|
||||
item.highlightElement = highlight;
|
||||
container.appendChild(item.highlightElement);
|
||||
|
||||
return container;
|
||||
}
|
||||
|
||||
function getHtmlElementForTextWidgetAnnotation(item, commonObjs) {
|
||||
var element = getEmptyContainer('div', item.rect, 0);
|
||||
element.style.display = 'table';
|
||||
|
||||
var content = document.createElement('div');
|
||||
content.textContent = item.fieldValue;
|
||||
var textAlignment = item.textAlignment;
|
||||
content.style.textAlign = ['left', 'center', 'right'][textAlignment];
|
||||
content.style.verticalAlign = 'middle';
|
||||
content.style.display = 'table-cell';
|
||||
|
||||
var fontObj = item.fontRefName ?
|
||||
commonObjs.getData(item.fontRefName) : null;
|
||||
setTextStyles(content, item, fontObj);
|
||||
|
||||
element.appendChild(content);
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
function getHtmlElementForTextAnnotation(item) {
|
||||
var rect = item.rect;
|
||||
|
||||
// sanity check because of OOo-generated PDFs
|
||||
if ((rect[3] - rect[1]) < ANNOT_MIN_SIZE) {
|
||||
rect[3] = rect[1] + ANNOT_MIN_SIZE;
|
||||
}
|
||||
if ((rect[2] - rect[0]) < ANNOT_MIN_SIZE) {
|
||||
rect[2] = rect[0] + (rect[3] - rect[1]); // make it square
|
||||
}
|
||||
|
||||
var container = initContainer(item);
|
||||
container.className = 'annotText';
|
||||
|
||||
var image = document.createElement('img');
|
||||
image.style.height = container.style.height;
|
||||
image.style.width = container.style.width;
|
||||
var iconName = item.name;
|
||||
image.src = PDFJS.imageResourcesPath + 'annotation-' +
|
||||
iconName.toLowerCase() + '.svg';
|
||||
image.alt = '[{{type}} Annotation]';
|
||||
image.dataset.l10nId = 'text_annotation_type';
|
||||
image.dataset.l10nArgs = JSON.stringify({type: iconName});
|
||||
|
||||
var contentWrapper = document.createElement('div');
|
||||
contentWrapper.className = 'annotTextContentWrapper';
|
||||
contentWrapper.style.left = Math.floor(rect[2] - rect[0] + 5) + 'px';
|
||||
contentWrapper.style.top = '-10px';
|
||||
|
||||
var content = document.createElement('div');
|
||||
content.className = 'annotTextContent';
|
||||
content.setAttribute('hidden', true);
|
||||
|
||||
var i, ii;
|
||||
if (item.hasBgColor) {
|
||||
var color = item.color;
|
||||
var rgb = [];
|
||||
for (i = 0; i < 3; ++i) {
|
||||
// Enlighten the color (70%)
|
||||
var c = Math.round(color[i] * 255);
|
||||
rgb[i] = Math.round((255 - c) * 0.7) + c;
|
||||
}
|
||||
content.style.backgroundColor = Util.makeCssRgb(rgb);
|
||||
}
|
||||
|
||||
var title = document.createElement('h1');
|
||||
var text = document.createElement('p');
|
||||
title.textContent = item.title;
|
||||
|
||||
if (!item.content && !item.title) {
|
||||
content.setAttribute('hidden', true);
|
||||
} else {
|
||||
var e = document.createElement('span');
|
||||
var lines = item.content.split(/(?:\r\n?|\n)/);
|
||||
for (i = 0, ii = lines.length; i < ii; ++i) {
|
||||
var line = lines[i];
|
||||
e.appendChild(document.createTextNode(line));
|
||||
if (i < (ii - 1)) {
|
||||
e.appendChild(document.createElement('br'));
|
||||
}
|
||||
}
|
||||
text.appendChild(e);
|
||||
|
||||
var pinned = false;
|
||||
|
||||
var showAnnotation = function showAnnotation(pin) {
|
||||
if (pin) {
|
||||
pinned = true;
|
||||
}
|
||||
if (content.hasAttribute('hidden')) {
|
||||
container.style.zIndex += 1;
|
||||
content.removeAttribute('hidden');
|
||||
}
|
||||
};
|
||||
|
||||
var hideAnnotation = function hideAnnotation(unpin) {
|
||||
if (unpin) {
|
||||
pinned = false;
|
||||
}
|
||||
if (!content.hasAttribute('hidden') && !pinned) {
|
||||
container.style.zIndex -= 1;
|
||||
content.setAttribute('hidden', true);
|
||||
}
|
||||
};
|
||||
|
||||
var toggleAnnotation = function toggleAnnotation() {
|
||||
if (pinned) {
|
||||
hideAnnotation(true);
|
||||
} else {
|
||||
showAnnotation(true);
|
||||
}
|
||||
};
|
||||
|
||||
image.addEventListener('click', function image_clickHandler() {
|
||||
toggleAnnotation();
|
||||
}, false);
|
||||
image.addEventListener('mouseover', function image_mouseOverHandler() {
|
||||
showAnnotation();
|
||||
}, false);
|
||||
image.addEventListener('mouseout', function image_mouseOutHandler() {
|
||||
hideAnnotation();
|
||||
}, false);
|
||||
|
||||
content.addEventListener('click', function content_clickHandler() {
|
||||
hideAnnotation(true);
|
||||
}, false);
|
||||
}
|
||||
|
||||
content.appendChild(title);
|
||||
content.appendChild(text);
|
||||
contentWrapper.appendChild(content);
|
||||
container.appendChild(image);
|
||||
container.appendChild(contentWrapper);
|
||||
|
||||
return container;
|
||||
}
|
||||
|
||||
function getHtmlElementForLinkAnnotation(item) {
|
||||
var container = initContainer(item);
|
||||
container.className = 'annotLink';
|
||||
|
||||
container.style.borderColor = item.colorCssRgb;
|
||||
container.style.borderStyle = 'solid';
|
||||
|
||||
var link = document.createElement('a');
|
||||
link.href = link.title = item.url || '';
|
||||
|
||||
container.appendChild(link);
|
||||
|
||||
return container;
|
||||
}
|
||||
|
||||
function getHtmlElement(data, objs) {
|
||||
switch (data.annotationType) {
|
||||
case AnnotationType.WIDGET:
|
||||
return getHtmlElementForTextWidgetAnnotation(data, objs);
|
||||
case AnnotationType.TEXT:
|
||||
return getHtmlElementForTextAnnotation(data);
|
||||
case AnnotationType.LINK:
|
||||
return getHtmlElementForLinkAnnotation(data);
|
||||
default:
|
||||
throw new Error('Unsupported annotationType: ' + data.annotationType);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
getHtmlElement: getHtmlElement
|
||||
};
|
||||
})();
|
||||
PDFJS.AnnotationUtils = AnnotationUtils;
|
1450
.obsidian/pdfjs/pdfextract/pdfjs/src/display/api.js
vendored
Normal file
1450
.obsidian/pdfjs/pdfextract/pdfjs/src/display/api.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2354
.obsidian/pdfjs/pdfextract/pdfjs/src/display/canvas.js
vendored
Normal file
2354
.obsidian/pdfjs/pdfextract/pdfjs/src/display/canvas.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
375
.obsidian/pdfjs/pdfextract/pdfjs/src/display/font_loader.js
vendored
Normal file
375
.obsidian/pdfjs/pdfextract/pdfjs/src/display/font_loader.js
vendored
Normal file
@@ -0,0 +1,375 @@
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
/* Copyright 2012 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/* globals PDFJS, shadow, isWorker, assert, warn, bytesToString, string32,
|
||||
globalScope, FontFace, Promise */
|
||||
|
||||
'use strict';
|
||||
|
||||
PDFJS.disableFontFace = false;
|
||||
|
||||
var FontLoader = {
|
||||
insertRule: function fontLoaderInsertRule(rule) {
|
||||
var styleElement = document.getElementById('PDFJS_FONT_STYLE_TAG');
|
||||
if (!styleElement) {
|
||||
styleElement = document.createElement('style');
|
||||
styleElement.id = 'PDFJS_FONT_STYLE_TAG';
|
||||
document.documentElement.getElementsByTagName('head')[0].appendChild(
|
||||
styleElement);
|
||||
}
|
||||
|
||||
var styleSheet = styleElement.sheet;
|
||||
styleSheet.insertRule(rule, styleSheet.cssRules.length);
|
||||
},
|
||||
|
||||
clear: function fontLoaderClear() {
|
||||
var styleElement = document.getElementById('PDFJS_FONT_STYLE_TAG');
|
||||
if (styleElement) {
|
||||
styleElement.parentNode.removeChild(styleElement);
|
||||
}
|
||||
//#if !(MOZCENTRAL)
|
||||
this.nativeFontFaces.forEach(function(nativeFontFace) {
|
||||
document.fonts.delete(nativeFontFace);
|
||||
});
|
||||
this.nativeFontFaces.length = 0;
|
||||
//#endif
|
||||
},
|
||||
//#if !(MOZCENTRAL)
|
||||
get loadTestFont() {
|
||||
// This is a CFF font with 1 glyph for '.' that fills its entire width and
|
||||
// height.
|
||||
return shadow(this, 'loadTestFont', atob(
|
||||
'T1RUTwALAIAAAwAwQ0ZGIDHtZg4AAAOYAAAAgUZGVE1lkzZwAAAEHAAAABxHREVGABQAFQ' +
|
||||
'AABDgAAAAeT1MvMlYNYwkAAAEgAAAAYGNtYXABDQLUAAACNAAAAUJoZWFk/xVFDQAAALwA' +
|
||||
'AAA2aGhlYQdkA+oAAAD0AAAAJGhtdHgD6AAAAAAEWAAAAAZtYXhwAAJQAAAAARgAAAAGbm' +
|
||||
'FtZVjmdH4AAAGAAAAAsXBvc3T/hgAzAAADeAAAACAAAQAAAAEAALZRFsRfDzz1AAsD6AAA' +
|
||||
'AADOBOTLAAAAAM4KHDwAAAAAA+gDIQAAAAgAAgAAAAAAAAABAAADIQAAAFoD6AAAAAAD6A' +
|
||||
'ABAAAAAAAAAAAAAAAAAAAAAQAAUAAAAgAAAAQD6AH0AAUAAAKKArwAAACMAooCvAAAAeAA' +
|
||||
'MQECAAACAAYJAAAAAAAAAAAAAQAAAAAAAAAAAAAAAFBmRWQAwAAuAC4DIP84AFoDIQAAAA' +
|
||||
'AAAQAAAAAAAAAAACAAIAABAAAADgCuAAEAAAAAAAAAAQAAAAEAAAAAAAEAAQAAAAEAAAAA' +
|
||||
'AAIAAQAAAAEAAAAAAAMAAQAAAAEAAAAAAAQAAQAAAAEAAAAAAAUAAQAAAAEAAAAAAAYAAQ' +
|
||||
'AAAAMAAQQJAAAAAgABAAMAAQQJAAEAAgABAAMAAQQJAAIAAgABAAMAAQQJAAMAAgABAAMA' +
|
||||
'AQQJAAQAAgABAAMAAQQJAAUAAgABAAMAAQQJAAYAAgABWABYAAAAAAAAAwAAAAMAAAAcAA' +
|
||||
'EAAAAAADwAAwABAAAAHAAEACAAAAAEAAQAAQAAAC7//wAAAC7////TAAEAAAAAAAABBgAA' +
|
||||
'AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAA' +
|
||||
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +
|
||||
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +
|
||||
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +
|
||||
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAA' +
|
||||
'AAAAD/gwAyAAAAAQAAAAAAAAAAAAAAAAAAAAABAAQEAAEBAQJYAAEBASH4DwD4GwHEAvgc' +
|
||||
'A/gXBIwMAYuL+nz5tQXkD5j3CBLnEQACAQEBIVhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWF' +
|
||||
'hYWFhYWFhYAAABAQAADwACAQEEE/t3Dov6fAH6fAT+fPp8+nwHDosMCvm1Cvm1DAz6fBQA' +
|
||||
'AAAAAAABAAAAAMmJbzEAAAAAzgTjFQAAAADOBOQpAAEAAAAAAAAADAAUAAQAAAABAAAAAg' +
|
||||
'ABAAAAAAAAAAAD6AAAAAAAAA=='
|
||||
));
|
||||
},
|
||||
|
||||
loadTestFontId: 0,
|
||||
|
||||
loadingContext: {
|
||||
requests: [],
|
||||
nextRequestId: 0
|
||||
},
|
||||
|
||||
isSyncFontLoadingSupported: (function detectSyncFontLoadingSupport() {
|
||||
if (isWorker) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// User agent string sniffing is bad, but there is no reliable way to tell
|
||||
// if font is fully loaded and ready to be used with canvas.
|
||||
var userAgent = window.navigator.userAgent;
|
||||
var m = /Mozilla\/5.0.*?rv:(\d+).*? Gecko/.exec(userAgent);
|
||||
if (m && m[1] >= 14) {
|
||||
return true;
|
||||
}
|
||||
// TODO other browsers
|
||||
if (userAgent === 'node') {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
})(),
|
||||
|
||||
nativeFontFaces: [],
|
||||
|
||||
isFontLoadingAPISupported: !isWorker && !!document.fonts,
|
||||
|
||||
addNativeFontFace: function fontLoader_addNativeFontFace(nativeFontFace) {
|
||||
this.nativeFontFaces.push(nativeFontFace);
|
||||
document.fonts.add(nativeFontFace);
|
||||
},
|
||||
|
||||
bind: function fontLoaderBind(fonts, callback) {
|
||||
assert(!isWorker, 'bind() shall be called from main thread');
|
||||
|
||||
var rules = [];
|
||||
var fontsToLoad = [];
|
||||
var fontLoadPromises = [];
|
||||
for (var i = 0, ii = fonts.length; i < ii; i++) {
|
||||
var font = fonts[i];
|
||||
|
||||
// Add the font to the DOM only once or skip if the font
|
||||
// is already loaded.
|
||||
if (font.attached || font.loading === false) {
|
||||
continue;
|
||||
}
|
||||
font.attached = true;
|
||||
|
||||
if (this.isFontLoadingAPISupported) {
|
||||
var nativeFontFace = font.createNativeFontFace();
|
||||
if (nativeFontFace) {
|
||||
fontLoadPromises.push(nativeFontFace.loaded);
|
||||
}
|
||||
} else {
|
||||
var rule = font.bindDOM();
|
||||
if (rule) {
|
||||
rules.push(rule);
|
||||
fontsToLoad.push(font);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var request = FontLoader.queueLoadingCallback(callback);
|
||||
if (this.isFontLoadingAPISupported) {
|
||||
Promise.all(fontsToLoad).then(function() {
|
||||
request.complete();
|
||||
});
|
||||
} else if (rules.length > 0 && !this.isSyncFontLoadingSupported) {
|
||||
FontLoader.prepareFontLoadEvent(rules, fontsToLoad, request);
|
||||
} else {
|
||||
request.complete();
|
||||
}
|
||||
},
|
||||
|
||||
queueLoadingCallback: function FontLoader_queueLoadingCallback(callback) {
|
||||
function LoadLoader_completeRequest() {
|
||||
assert(!request.end, 'completeRequest() cannot be called twice');
|
||||
request.end = Date.now();
|
||||
|
||||
// sending all completed requests in order how they were queued
|
||||
while (context.requests.length > 0 && context.requests[0].end) {
|
||||
var otherRequest = context.requests.shift();
|
||||
setTimeout(otherRequest.callback, 0);
|
||||
}
|
||||
}
|
||||
|
||||
var context = FontLoader.loadingContext;
|
||||
var requestId = 'pdfjs-font-loading-' + (context.nextRequestId++);
|
||||
var request = {
|
||||
id: requestId,
|
||||
complete: LoadLoader_completeRequest,
|
||||
callback: callback,
|
||||
started: Date.now()
|
||||
};
|
||||
context.requests.push(request);
|
||||
return request;
|
||||
},
|
||||
|
||||
prepareFontLoadEvent: function fontLoaderPrepareFontLoadEvent(rules,
|
||||
fonts,
|
||||
request) {
|
||||
/** Hack begin */
|
||||
// There's currently no event when a font has finished downloading so the
|
||||
// following code is a dirty hack to 'guess' when a font is
|
||||
// ready. It's assumed fonts are loaded in order, so add a known test
|
||||
// font after the desired fonts and then test for the loading of that
|
||||
// test font.
|
||||
|
||||
function int32(data, offset) {
|
||||
return (data.charCodeAt(offset) << 24) |
|
||||
(data.charCodeAt(offset + 1) << 16) |
|
||||
(data.charCodeAt(offset + 2) << 8) |
|
||||
(data.charCodeAt(offset + 3) & 0xff);
|
||||
}
|
||||
|
||||
function spliceString(s, offset, remove, insert) {
|
||||
var chunk1 = s.substr(0, offset);
|
||||
var chunk2 = s.substr(offset + remove);
|
||||
return chunk1 + insert + chunk2;
|
||||
}
|
||||
|
||||
var i, ii;
|
||||
|
||||
var canvas = document.createElement('canvas');
|
||||
canvas.width = 1;
|
||||
canvas.height = 1;
|
||||
var ctx = canvas.getContext('2d');
|
||||
|
||||
var called = 0;
|
||||
function isFontReady(name, callback) {
|
||||
called++;
|
||||
// With setTimeout clamping this gives the font ~100ms to load.
|
||||
if(called > 30) {
|
||||
warn('Load test font never loaded.');
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
ctx.font = '30px ' + name;
|
||||
ctx.fillText('.', 0, 20);
|
||||
var imageData = ctx.getImageData(0, 0, 1, 1);
|
||||
if (imageData.data[3] > 0) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
setTimeout(isFontReady.bind(null, name, callback));
|
||||
}
|
||||
|
||||
var loadTestFontId = 'lt' + Date.now() + this.loadTestFontId++;
|
||||
// Chromium seems to cache fonts based on a hash of the actual font data,
|
||||
// so the font must be modified for each load test else it will appear to
|
||||
// be loaded already.
|
||||
// TODO: This could maybe be made faster by avoiding the btoa of the full
|
||||
// font by splitting it in chunks before hand and padding the font id.
|
||||
var data = this.loadTestFont;
|
||||
var COMMENT_OFFSET = 976; // has to be on 4 byte boundary (for checksum)
|
||||
data = spliceString(data, COMMENT_OFFSET, loadTestFontId.length,
|
||||
loadTestFontId);
|
||||
// CFF checksum is important for IE, adjusting it
|
||||
var CFF_CHECKSUM_OFFSET = 16;
|
||||
var XXXX_VALUE = 0x58585858; // the "comment" filled with 'X'
|
||||
var checksum = int32(data, CFF_CHECKSUM_OFFSET);
|
||||
for (i = 0, ii = loadTestFontId.length - 3; i < ii; i += 4) {
|
||||
checksum = (checksum - XXXX_VALUE + int32(loadTestFontId, i)) | 0;
|
||||
}
|
||||
if (i < loadTestFontId.length) { // align to 4 bytes boundary
|
||||
checksum = (checksum - XXXX_VALUE +
|
||||
int32(loadTestFontId + 'XXX', i)) | 0;
|
||||
}
|
||||
data = spliceString(data, CFF_CHECKSUM_OFFSET, 4, string32(checksum));
|
||||
|
||||
var url = 'url(data:font/opentype;base64,' + btoa(data) + ');';
|
||||
var rule = '@font-face { font-family:"' + loadTestFontId + '";src:' +
|
||||
url + '}';
|
||||
FontLoader.insertRule(rule);
|
||||
|
||||
var names = [];
|
||||
for (i = 0, ii = fonts.length; i < ii; i++) {
|
||||
names.push(fonts[i].loadedName);
|
||||
}
|
||||
names.push(loadTestFontId);
|
||||
|
||||
var div = document.createElement('div');
|
||||
div.setAttribute('style',
|
||||
'visibility: hidden;' +
|
||||
'width: 10px; height: 10px;' +
|
||||
'position: absolute; top: 0px; left: 0px;');
|
||||
for (i = 0, ii = names.length; i < ii; ++i) {
|
||||
var span = document.createElement('span');
|
||||
span.textContent = 'Hi';
|
||||
span.style.fontFamily = names[i];
|
||||
div.appendChild(span);
|
||||
}
|
||||
document.body.appendChild(div);
|
||||
|
||||
isFontReady(loadTestFontId, function() {
|
||||
document.body.removeChild(div);
|
||||
request.complete();
|
||||
});
|
||||
/** Hack end */
|
||||
}
|
||||
//#else
|
||||
//bind: function fontLoaderBind(fonts, callback) {
|
||||
// assert(!isWorker, 'bind() shall be called from main thread');
|
||||
//
|
||||
// for (var i = 0, ii = fonts.length; i < ii; i++) {
|
||||
// var font = fonts[i];
|
||||
// if (font.attached) {
|
||||
// continue;
|
||||
// }
|
||||
//
|
||||
// font.attached = true;
|
||||
// font.bindDOM()
|
||||
// }
|
||||
//
|
||||
// setTimeout(callback);
|
||||
//}
|
||||
//#endif
|
||||
};
|
||||
|
||||
var FontFaceObject = (function FontFaceObjectClosure() {
|
||||
function FontFaceObject(name, file, properties) {
|
||||
this.compiledGlyphs = {};
|
||||
if (arguments.length === 1) {
|
||||
// importing translated data
|
||||
var data = arguments[0];
|
||||
for (var i in data) {
|
||||
this[i] = data[i];
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
FontFaceObject.prototype = {
|
||||
//#if !(MOZCENTRAL)
|
||||
createNativeFontFace: function FontFaceObject_createNativeFontFace() {
|
||||
if (!this.data) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (PDFJS.disableFontFace) {
|
||||
this.disableFontFace = true;
|
||||
return null;
|
||||
}
|
||||
|
||||
var nativeFontFace = new FontFace(this.loadedName, this.data, {});
|
||||
|
||||
FontLoader.addNativeFontFace(nativeFontFace);
|
||||
|
||||
if (PDFJS.pdfBug && 'FontInspector' in globalScope &&
|
||||
globalScope['FontInspector'].enabled) {
|
||||
globalScope['FontInspector'].fontAdded(this);
|
||||
}
|
||||
return nativeFontFace;
|
||||
},
|
||||
//#endif
|
||||
|
||||
bindDOM: function FontFaceObject_bindDOM() {
|
||||
if (!this.data) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (PDFJS.disableFontFace) {
|
||||
this.disableFontFace = true;
|
||||
return null;
|
||||
}
|
||||
|
||||
var data = bytesToString(new Uint8Array(this.data));
|
||||
var fontName = this.loadedName;
|
||||
|
||||
// Add the font-face rule to the document
|
||||
var url = ('url(data:' + this.mimetype + ';base64,' +
|
||||
window.btoa(data) + ');');
|
||||
var rule = '@font-face { font-family:"' + fontName + '";src:' + url + '}';
|
||||
FontLoader.insertRule(rule);
|
||||
|
||||
if (PDFJS.pdfBug && 'FontInspector' in globalScope &&
|
||||
globalScope['FontInspector'].enabled) {
|
||||
globalScope['FontInspector'].fontAdded(this, url);
|
||||
}
|
||||
|
||||
return rule;
|
||||
},
|
||||
|
||||
getPathGenerator: function FontLoader_getPathGenerator(objs, character) {
|
||||
if (!(character in this.compiledGlyphs)) {
|
||||
var js = objs.get(this.loadedName + '_path_' + character);
|
||||
/*jshint -W054 */
|
||||
this.compiledGlyphs[character] = new Function('c', 'size', js);
|
||||
}
|
||||
return this.compiledGlyphs[character];
|
||||
}
|
||||
};
|
||||
return FontFaceObject;
|
||||
})();
|
99
.obsidian/pdfjs/pdfextract/pdfjs/src/display/metadata.js
vendored
Normal file
99
.obsidian/pdfjs/pdfextract/pdfjs/src/display/metadata.js
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
/* globals Document, error, PDFJS */
|
||||
/* Copyright 2012 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var Metadata = PDFJS.Metadata = (function MetadataClosure() {
|
||||
function fixMetadata(meta) {
|
||||
return meta.replace(/>\\376\\377([^<]+)/g, function(all, codes) {
|
||||
var bytes = codes.replace(/\\([0-3])([0-7])([0-7])/g,
|
||||
function(code, d1, d2, d3) {
|
||||
return String.fromCharCode(d1 * 64 + d2 * 8 + d3 * 1);
|
||||
});
|
||||
var chars = '';
|
||||
for (var i = 0; i < bytes.length; i += 2) {
|
||||
var code = bytes.charCodeAt(i) * 256 + bytes.charCodeAt(i + 1);
|
||||
chars += code >= 32 && code < 127 && code !== 60 && code !== 62 &&
|
||||
code !== 38 && false ? String.fromCharCode(code) :
|
||||
'&#x' + (0x10000 + code).toString(16).substring(1) + ';';
|
||||
}
|
||||
return '>' + chars;
|
||||
});
|
||||
}
|
||||
|
||||
function Metadata(meta) {
|
||||
if (typeof meta === 'string') {
|
||||
// Ghostscript produces invalid metadata
|
||||
meta = fixMetadata(meta);
|
||||
|
||||
var parser = new DOMParser();
|
||||
meta = parser.parseFromString(meta, 'application/xml');
|
||||
} else if (!(meta instanceof Document)) {
|
||||
error('Metadata: Invalid metadata object');
|
||||
}
|
||||
|
||||
this.metaDocument = meta;
|
||||
this.metadata = {};
|
||||
this.parse();
|
||||
}
|
||||
|
||||
Metadata.prototype = {
|
||||
parse: function Metadata_parse() {
|
||||
var doc = this.metaDocument;
|
||||
var rdf = doc.documentElement;
|
||||
|
||||
if (rdf.nodeName.toLowerCase() !== 'rdf:rdf') { // Wrapped in <xmpmeta>
|
||||
rdf = rdf.firstChild;
|
||||
while (rdf && rdf.nodeName.toLowerCase() !== 'rdf:rdf') {
|
||||
rdf = rdf.nextSibling;
|
||||
}
|
||||
}
|
||||
|
||||
var nodeName = (rdf) ? rdf.nodeName.toLowerCase() : null;
|
||||
if (!rdf || nodeName !== 'rdf:rdf' || !rdf.hasChildNodes()) {
|
||||
return;
|
||||
}
|
||||
|
||||
var children = rdf.childNodes, desc, entry, name, i, ii, length, iLength;
|
||||
for (i = 0, length = children.length; i < length; i++) {
|
||||
desc = children[i];
|
||||
if (desc.nodeName.toLowerCase() !== 'rdf:description') {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (ii = 0, iLength = desc.childNodes.length; ii < iLength; ii++) {
|
||||
if (desc.childNodes[ii].nodeName.toLowerCase() !== '#text') {
|
||||
entry = desc.childNodes[ii];
|
||||
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;
|
||||
})();
|
425
.obsidian/pdfjs/pdfextract/pdfjs/src/display/pattern_helper.js
vendored
Normal file
425
.obsidian/pdfjs/pdfextract/pdfjs/src/display/pattern_helper.js
vendored
Normal file
@@ -0,0 +1,425 @@
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
/* Copyright 2014 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/* globals CanvasGraphics, CachedCanvases, ColorSpace, Util, error, info,
|
||||
isArray, makeCssRgb, WebGLUtils */
|
||||
|
||||
'use strict';
|
||||
|
||||
var ShadingIRs = {};
|
||||
|
||||
ShadingIRs.RadialAxial = {
|
||||
fromIR: function RadialAxial_fromIR(raw) {
|
||||
var type = raw[1];
|
||||
var colorStops = raw[2];
|
||||
var p0 = raw[3];
|
||||
var p1 = raw[4];
|
||||
var r0 = raw[5];
|
||||
var r1 = raw[6];
|
||||
return {
|
||||
type: 'Pattern',
|
||||
getPattern: function RadialAxial_getPattern(ctx) {
|
||||
var grad;
|
||||
if (type === 'axial') {
|
||||
grad = ctx.createLinearGradient(p0[0], p0[1], p1[0], p1[1]);
|
||||
} else if (type === 'radial') {
|
||||
grad = ctx.createRadialGradient(p0[0], p0[1], r0, p1[0], p1[1], r1);
|
||||
}
|
||||
|
||||
for (var i = 0, ii = colorStops.length; i < ii; ++i) {
|
||||
var c = colorStops[i];
|
||||
grad.addColorStop(c[0], c[1]);
|
||||
}
|
||||
return grad;
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
var createMeshCanvas = (function createMeshCanvasClosure() {
|
||||
function drawTriangle(data, context, p1, p2, p3, c1, c2, c3) {
|
||||
// Very basic Gouraud-shaded triangle rasterization algorithm.
|
||||
var coords = context.coords, colors = context.colors;
|
||||
var bytes = data.data, rowSize = data.width * 4;
|
||||
var tmp;
|
||||
if (coords[p1 + 1] > coords[p2 + 1]) {
|
||||
tmp = p1; p1 = p2; p2 = tmp; tmp = c1; c1 = c2; c2 = tmp;
|
||||
}
|
||||
if (coords[p2 + 1] > coords[p3 + 1]) {
|
||||
tmp = p2; p2 = p3; p3 = tmp; tmp = c2; c2 = c3; c3 = tmp;
|
||||
}
|
||||
if (coords[p1 + 1] > coords[p2 + 1]) {
|
||||
tmp = p1; p1 = p2; p2 = tmp; tmp = c1; c1 = c2; c2 = tmp;
|
||||
}
|
||||
var x1 = (coords[p1] + context.offsetX) * context.scaleX;
|
||||
var y1 = (coords[p1 + 1] + context.offsetY) * context.scaleY;
|
||||
var x2 = (coords[p2] + context.offsetX) * context.scaleX;
|
||||
var y2 = (coords[p2 + 1] + context.offsetY) * context.scaleY;
|
||||
var x3 = (coords[p3] + context.offsetX) * context.scaleX;
|
||||
var y3 = (coords[p3 + 1] + context.offsetY) * context.scaleY;
|
||||
if (y1 >= y3) {
|
||||
return;
|
||||
}
|
||||
var c1r = colors[c1], c1g = colors[c1 + 1], c1b = colors[c1 + 2];
|
||||
var c2r = colors[c2], c2g = colors[c2 + 1], c2b = colors[c2 + 2];
|
||||
var c3r = colors[c3], c3g = colors[c3 + 1], c3b = colors[c3 + 2];
|
||||
|
||||
var minY = Math.round(y1), maxY = Math.round(y3);
|
||||
var xa, car, cag, cab;
|
||||
var xb, cbr, cbg, cbb;
|
||||
var k;
|
||||
for (var y = minY; y <= maxY; y++) {
|
||||
if (y < y2) {
|
||||
k = y < y1 ? 0 : y1 === y2 ? 1 : (y1 - y) / (y1 - y2);
|
||||
xa = x1 - (x1 - x2) * k;
|
||||
car = c1r - (c1r - c2r) * k;
|
||||
cag = c1g - (c1g - c2g) * k;
|
||||
cab = c1b - (c1b - c2b) * k;
|
||||
} else {
|
||||
k = y > y3 ? 1 : y2 === y3 ? 0 : (y2 - y) / (y2 - y3);
|
||||
xa = x2 - (x2 - x3) * k;
|
||||
car = c2r - (c2r - c3r) * k;
|
||||
cag = c2g - (c2g - c3g) * k;
|
||||
cab = c2b - (c2b - c3b) * k;
|
||||
}
|
||||
k = y < y1 ? 0 : y > y3 ? 1 : (y1 - y) / (y1 - y3);
|
||||
xb = x1 - (x1 - x3) * k;
|
||||
cbr = c1r - (c1r - c3r) * k;
|
||||
cbg = c1g - (c1g - c3g) * k;
|
||||
cbb = c1b - (c1b - c3b) * k;
|
||||
var x1_ = Math.round(Math.min(xa, xb));
|
||||
var x2_ = Math.round(Math.max(xa, xb));
|
||||
var j = rowSize * y + x1_ * 4;
|
||||
for (var x = x1_; x <= x2_; x++) {
|
||||
k = (xa - x) / (xa - xb);
|
||||
k = k < 0 ? 0 : k > 1 ? 1 : k;
|
||||
bytes[j++] = (car - (car - cbr) * k) | 0;
|
||||
bytes[j++] = (cag - (cag - cbg) * k) | 0;
|
||||
bytes[j++] = (cab - (cab - cbb) * k) | 0;
|
||||
bytes[j++] = 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function drawFigure(data, figure, context) {
|
||||
var ps = figure.coords;
|
||||
var cs = figure.colors;
|
||||
var i, ii;
|
||||
switch (figure.type) {
|
||||
case 'lattice':
|
||||
var verticesPerRow = figure.verticesPerRow;
|
||||
var rows = Math.floor(ps.length / verticesPerRow) - 1;
|
||||
var cols = verticesPerRow - 1;
|
||||
for (i = 0; i < rows; i++) {
|
||||
var q = i * verticesPerRow;
|
||||
for (var j = 0; j < cols; j++, q++) {
|
||||
drawTriangle(data, context,
|
||||
ps[q], ps[q + 1], ps[q + verticesPerRow],
|
||||
cs[q], cs[q + 1], cs[q + verticesPerRow]);
|
||||
drawTriangle(data, context,
|
||||
ps[q + verticesPerRow + 1], ps[q + 1], ps[q + verticesPerRow],
|
||||
cs[q + verticesPerRow + 1], cs[q + 1], cs[q + verticesPerRow]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'triangles':
|
||||
for (i = 0, ii = ps.length; i < ii; i += 3) {
|
||||
drawTriangle(data, context,
|
||||
ps[i], ps[i + 1], ps[i + 2],
|
||||
cs[i], cs[i + 1], cs[i + 2]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
error('illigal figure');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function createMeshCanvas(bounds, combinesScale, coords, colors, figures,
|
||||
backgroundColor) {
|
||||
// we will increase scale on some weird factor to let antialiasing take
|
||||
// care of "rough" edges
|
||||
var EXPECTED_SCALE = 1.1;
|
||||
// MAX_PATTERN_SIZE is used to avoid OOM situation.
|
||||
var MAX_PATTERN_SIZE = 3000; // 10in @ 300dpi shall be enough
|
||||
|
||||
var offsetX = Math.floor(bounds[0]);
|
||||
var offsetY = Math.floor(bounds[1]);
|
||||
var boundsWidth = Math.ceil(bounds[2]) - offsetX;
|
||||
var boundsHeight = Math.ceil(bounds[3]) - offsetY;
|
||||
|
||||
var width = Math.min(Math.ceil(Math.abs(boundsWidth * combinesScale[0] *
|
||||
EXPECTED_SCALE)), MAX_PATTERN_SIZE);
|
||||
var height = Math.min(Math.ceil(Math.abs(boundsHeight * combinesScale[1] *
|
||||
EXPECTED_SCALE)), MAX_PATTERN_SIZE);
|
||||
var scaleX = boundsWidth / width;
|
||||
var scaleY = boundsHeight / height;
|
||||
|
||||
var context = {
|
||||
coords: coords,
|
||||
colors: colors,
|
||||
offsetX: -offsetX,
|
||||
offsetY: -offsetY,
|
||||
scaleX: 1 / scaleX,
|
||||
scaleY: 1 / scaleY
|
||||
};
|
||||
|
||||
var canvas, tmpCanvas, i, ii;
|
||||
if (WebGLUtils.isEnabled) {
|
||||
canvas = WebGLUtils.drawFigures(width, height, backgroundColor,
|
||||
figures, context);
|
||||
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=972126
|
||||
tmpCanvas = CachedCanvases.getCanvas('mesh', width, height, false);
|
||||
tmpCanvas.context.drawImage(canvas, 0, 0);
|
||||
canvas = tmpCanvas.canvas;
|
||||
} else {
|
||||
tmpCanvas = CachedCanvases.getCanvas('mesh', width, height, false);
|
||||
var tmpCtx = tmpCanvas.context;
|
||||
|
||||
var data = tmpCtx.createImageData(width, height);
|
||||
if (backgroundColor) {
|
||||
var bytes = data.data;
|
||||
for (i = 0, ii = bytes.length; i < ii; i += 4) {
|
||||
bytes[i] = backgroundColor[0];
|
||||
bytes[i + 1] = backgroundColor[1];
|
||||
bytes[i + 2] = backgroundColor[2];
|
||||
bytes[i + 3] = 255;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < figures.length; i++) {
|
||||
drawFigure(data, figures[i], context);
|
||||
}
|
||||
tmpCtx.putImageData(data, 0, 0);
|
||||
canvas = tmpCanvas.canvas;
|
||||
}
|
||||
|
||||
return {canvas: canvas, offsetX: offsetX, offsetY: offsetY,
|
||||
scaleX: scaleX, scaleY: scaleY};
|
||||
}
|
||||
return createMeshCanvas;
|
||||
})();
|
||||
|
||||
ShadingIRs.Mesh = {
|
||||
fromIR: function Mesh_fromIR(raw) {
|
||||
//var type = raw[1];
|
||||
var coords = raw[2];
|
||||
var colors = raw[3];
|
||||
var figures = raw[4];
|
||||
var bounds = raw[5];
|
||||
var matrix = raw[6];
|
||||
//var bbox = raw[7];
|
||||
var background = raw[8];
|
||||
return {
|
||||
type: 'Pattern',
|
||||
getPattern: function Mesh_getPattern(ctx, owner, shadingFill) {
|
||||
var scale;
|
||||
if (shadingFill) {
|
||||
scale = Util.singularValueDecompose2dScale(ctx.mozCurrentTransform);
|
||||
} else {
|
||||
// Obtain scale from matrix and current transformation matrix.
|
||||
scale = Util.singularValueDecompose2dScale(owner.baseTransform);
|
||||
if (matrix) {
|
||||
var matrixScale = Util.singularValueDecompose2dScale(matrix);
|
||||
scale = [scale[0] * matrixScale[0],
|
||||
scale[1] * matrixScale[1]];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Rasterizing on the main thread since sending/queue large canvases
|
||||
// might cause OOM.
|
||||
var temporaryPatternCanvas = createMeshCanvas(bounds, scale, coords,
|
||||
colors, figures, shadingFill ? null : background);
|
||||
|
||||
if (!shadingFill) {
|
||||
ctx.setTransform.apply(ctx, owner.baseTransform);
|
||||
if (matrix) {
|
||||
ctx.transform.apply(ctx, matrix);
|
||||
}
|
||||
}
|
||||
|
||||
ctx.translate(temporaryPatternCanvas.offsetX,
|
||||
temporaryPatternCanvas.offsetY);
|
||||
ctx.scale(temporaryPatternCanvas.scaleX,
|
||||
temporaryPatternCanvas.scaleY);
|
||||
|
||||
return ctx.createPattern(temporaryPatternCanvas.canvas, 'no-repeat');
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
ShadingIRs.Dummy = {
|
||||
fromIR: function Dummy_fromIR() {
|
||||
return {
|
||||
type: 'Pattern',
|
||||
getPattern: function Dummy_fromIR_getPattern() {
|
||||
return 'hotpink';
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
function getShadingPatternFromIR(raw) {
|
||||
var shadingIR = ShadingIRs[raw[0]];
|
||||
if (!shadingIR) {
|
||||
error('Unknown IR type: ' + raw[0]);
|
||||
}
|
||||
return shadingIR.fromIR(raw);
|
||||
}
|
||||
|
||||
var TilingPattern = (function TilingPatternClosure() {
|
||||
var PaintType = {
|
||||
COLORED: 1,
|
||||
UNCOLORED: 2
|
||||
};
|
||||
|
||||
var MAX_PATTERN_SIZE = 3000; // 10in @ 300dpi shall be enough
|
||||
|
||||
function TilingPattern(IR, color, ctx, objs, commonObjs, baseTransform) {
|
||||
this.operatorList = IR[2];
|
||||
this.matrix = IR[3] || [1, 0, 0, 1, 0, 0];
|
||||
this.bbox = IR[4];
|
||||
this.xstep = IR[5];
|
||||
this.ystep = IR[6];
|
||||
this.paintType = IR[7];
|
||||
this.tilingType = IR[8];
|
||||
this.color = color;
|
||||
this.objs = objs;
|
||||
this.commonObjs = commonObjs;
|
||||
this.baseTransform = baseTransform;
|
||||
this.type = 'Pattern';
|
||||
this.ctx = ctx;
|
||||
}
|
||||
|
||||
TilingPattern.prototype = {
|
||||
createPatternCanvas: function TilinPattern_createPatternCanvas(owner) {
|
||||
var operatorList = this.operatorList;
|
||||
var bbox = this.bbox;
|
||||
var xstep = this.xstep;
|
||||
var ystep = this.ystep;
|
||||
var paintType = this.paintType;
|
||||
var tilingType = this.tilingType;
|
||||
var color = this.color;
|
||||
var objs = this.objs;
|
||||
var commonObjs = this.commonObjs;
|
||||
|
||||
info('TilingType: ' + tilingType);
|
||||
|
||||
var x0 = bbox[0], y0 = bbox[1], x1 = bbox[2], y1 = bbox[3];
|
||||
|
||||
var topLeft = [x0, y0];
|
||||
// we want the canvas to be as large as the step size
|
||||
var botRight = [x0 + xstep, y0 + ystep];
|
||||
|
||||
var width = botRight[0] - topLeft[0];
|
||||
var height = botRight[1] - topLeft[1];
|
||||
|
||||
// Obtain scale from matrix and current transformation matrix.
|
||||
var matrixScale = Util.singularValueDecompose2dScale(this.matrix);
|
||||
var curMatrixScale = Util.singularValueDecompose2dScale(
|
||||
this.baseTransform);
|
||||
var combinedScale = [matrixScale[0] * curMatrixScale[0],
|
||||
matrixScale[1] * curMatrixScale[1]];
|
||||
|
||||
// MAX_PATTERN_SIZE is used to avoid OOM situation.
|
||||
// Use width and height values that are as close as possible to the end
|
||||
// result when the pattern is used. Too low value makes the pattern look
|
||||
// blurry. Too large value makes it look too crispy.
|
||||
width = Math.min(Math.ceil(Math.abs(width * combinedScale[0])),
|
||||
MAX_PATTERN_SIZE);
|
||||
|
||||
height = Math.min(Math.ceil(Math.abs(height * combinedScale[1])),
|
||||
MAX_PATTERN_SIZE);
|
||||
|
||||
var tmpCanvas = CachedCanvases.getCanvas('pattern', width, height, true);
|
||||
var tmpCtx = tmpCanvas.context;
|
||||
var graphics = new CanvasGraphics(tmpCtx, commonObjs, objs);
|
||||
graphics.groupLevel = owner.groupLevel;
|
||||
|
||||
this.setFillAndStrokeStyleToContext(tmpCtx, paintType, color);
|
||||
|
||||
this.setScale(width, height, xstep, ystep);
|
||||
this.transformToScale(graphics);
|
||||
|
||||
// transform coordinates to pattern space
|
||||
var tmpTranslate = [1, 0, 0, 1, -topLeft[0], -topLeft[1]];
|
||||
graphics.transform.apply(graphics, tmpTranslate);
|
||||
|
||||
this.clipBbox(graphics, bbox, x0, y0, x1, y1);
|
||||
|
||||
graphics.executeOperatorList(operatorList);
|
||||
return tmpCanvas.canvas;
|
||||
},
|
||||
|
||||
setScale: function TilingPattern_setScale(width, height, xstep, ystep) {
|
||||
this.scale = [width / xstep, height / ystep];
|
||||
},
|
||||
|
||||
transformToScale: function TilingPattern_transformToScale(graphics) {
|
||||
var scale = this.scale;
|
||||
var tmpScale = [scale[0], 0, 0, scale[1], 0, 0];
|
||||
graphics.transform.apply(graphics, tmpScale);
|
||||
},
|
||||
|
||||
scaleToContext: function TilingPattern_scaleToContext() {
|
||||
var scale = this.scale;
|
||||
this.ctx.scale(1 / scale[0], 1 / scale[1]);
|
||||
},
|
||||
|
||||
clipBbox: function clipBbox(graphics, bbox, x0, y0, x1, y1) {
|
||||
if (bbox && isArray(bbox) && bbox.length === 4) {
|
||||
var bboxWidth = x1 - x0;
|
||||
var bboxHeight = y1 - y0;
|
||||
graphics.ctx.rect(x0, y0, bboxWidth, bboxHeight);
|
||||
graphics.clip();
|
||||
graphics.endPath();
|
||||
}
|
||||
},
|
||||
|
||||
setFillAndStrokeStyleToContext:
|
||||
function setFillAndStrokeStyleToContext(context, paintType, color) {
|
||||
switch (paintType) {
|
||||
case PaintType.COLORED:
|
||||
var ctx = this.ctx;
|
||||
context.fillStyle = ctx.fillStyle;
|
||||
context.strokeStyle = ctx.strokeStyle;
|
||||
break;
|
||||
case PaintType.UNCOLORED:
|
||||
var cssColor = Util.makeCssRgb(color);
|
||||
context.fillStyle = cssColor;
|
||||
context.strokeStyle = cssColor;
|
||||
break;
|
||||
default:
|
||||
error('Unsupported paint type: ' + paintType);
|
||||
}
|
||||
},
|
||||
|
||||
getPattern: function TilingPattern_getPattern(ctx, owner) {
|
||||
var temporaryPatternCanvas = this.createPatternCanvas(owner);
|
||||
|
||||
ctx = this.ctx;
|
||||
ctx.setTransform.apply(ctx, this.baseTransform);
|
||||
ctx.transform.apply(ctx, this.matrix);
|
||||
this.scaleToContext();
|
||||
|
||||
return ctx.createPattern(temporaryPatternCanvas, 'repeat');
|
||||
}
|
||||
};
|
||||
|
||||
return TilingPattern;
|
||||
})();
|
1191
.obsidian/pdfjs/pdfextract/pdfjs/src/display/svg.js
vendored
Normal file
1191
.obsidian/pdfjs/pdfextract/pdfjs/src/display/svg.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
437
.obsidian/pdfjs/pdfextract/pdfjs/src/display/webgl.js
vendored
Normal file
437
.obsidian/pdfjs/pdfextract/pdfjs/src/display/webgl.js
vendored
Normal file
@@ -0,0 +1,437 @@
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
/* Copyright 2014 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/* globals PDFJS, shadow */
|
||||
/* jshint -W043 */
|
||||
|
||||
'use strict';
|
||||
|
||||
var WebGLUtils = (function WebGLUtilsClosure() {
|
||||
function loadShader(gl, code, shaderType) {
|
||||
var shader = gl.createShader(shaderType);
|
||||
gl.shaderSource(shader, code);
|
||||
gl.compileShader(shader);
|
||||
var compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
|
||||
if (!compiled) {
|
||||
var errorMsg = gl.getShaderInfoLog(shader);
|
||||
throw new Error('Error during shader compilation: ' + errorMsg);
|
||||
}
|
||||
return shader;
|
||||
}
|
||||
function createVertexShader(gl, code) {
|
||||
return loadShader(gl, code, gl.VERTEX_SHADER);
|
||||
}
|
||||
function createFragmentShader(gl, code) {
|
||||
return loadShader(gl, code, gl.FRAGMENT_SHADER);
|
||||
}
|
||||
function createProgram(gl, shaders) {
|
||||
var program = gl.createProgram();
|
||||
for (var i = 0, ii = shaders.length; i < ii; ++i) {
|
||||
gl.attachShader(program, shaders[i]);
|
||||
}
|
||||
gl.linkProgram(program);
|
||||
var linked = gl.getProgramParameter(program, gl.LINK_STATUS);
|
||||
if (!linked) {
|
||||
var errorMsg = gl.getProgramInfoLog(program);
|
||||
throw new Error('Error during program linking: ' + errorMsg);
|
||||
}
|
||||
return program;
|
||||
}
|
||||
function createTexture(gl, image, textureId) {
|
||||
gl.activeTexture(textureId);
|
||||
var texture = gl.createTexture();
|
||||
gl.bindTexture(gl.TEXTURE_2D, texture);
|
||||
|
||||
// Set the parameters so we can render any size image.
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
||||
|
||||
// Upload the image into the texture.
|
||||
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
|
||||
return texture;
|
||||
}
|
||||
|
||||
var currentGL, currentCanvas;
|
||||
function generageGL() {
|
||||
if (currentGL) {
|
||||
return;
|
||||
}
|
||||
currentCanvas = document.createElement('canvas');
|
||||
currentGL = currentCanvas.getContext('webgl',
|
||||
{ premultipliedalpha: false });
|
||||
}
|
||||
|
||||
var smaskVertexShaderCode = '\
|
||||
attribute vec2 a_position; \
|
||||
attribute vec2 a_texCoord; \
|
||||
\
|
||||
uniform vec2 u_resolution; \
|
||||
\
|
||||
varying vec2 v_texCoord; \
|
||||
\
|
||||
void main() { \
|
||||
vec2 clipSpace = (a_position / u_resolution) * 2.0 - 1.0; \
|
||||
gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1); \
|
||||
\
|
||||
v_texCoord = a_texCoord; \
|
||||
} ';
|
||||
|
||||
var smaskFragmentShaderCode = '\
|
||||
precision mediump float; \
|
||||
\
|
||||
uniform vec4 u_backdrop; \
|
||||
uniform int u_subtype; \
|
||||
uniform sampler2D u_image; \
|
||||
uniform sampler2D u_mask; \
|
||||
\
|
||||
varying vec2 v_texCoord; \
|
||||
\
|
||||
void main() { \
|
||||
vec4 imageColor = texture2D(u_image, v_texCoord); \
|
||||
vec4 maskColor = texture2D(u_mask, v_texCoord); \
|
||||
if (u_backdrop.a > 0.0) { \
|
||||
maskColor.rgb = maskColor.rgb * maskColor.a + \
|
||||
u_backdrop.rgb * (1.0 - maskColor.a); \
|
||||
} \
|
||||
float lum; \
|
||||
if (u_subtype == 0) { \
|
||||
lum = maskColor.a; \
|
||||
} else { \
|
||||
lum = maskColor.r * 0.3 + maskColor.g * 0.59 + \
|
||||
maskColor.b * 0.11; \
|
||||
} \
|
||||
imageColor.a *= lum; \
|
||||
imageColor.rgb *= imageColor.a; \
|
||||
gl_FragColor = imageColor; \
|
||||
} ';
|
||||
|
||||
var smaskCache = null;
|
||||
|
||||
function initSmaskGL() {
|
||||
var canvas, gl;
|
||||
|
||||
generageGL();
|
||||
canvas = currentCanvas;
|
||||
currentCanvas = null;
|
||||
gl = currentGL;
|
||||
currentGL = null;
|
||||
|
||||
// setup a GLSL program
|
||||
var vertexShader = createVertexShader(gl, smaskVertexShaderCode);
|
||||
var fragmentShader = createFragmentShader(gl, smaskFragmentShaderCode);
|
||||
var program = createProgram(gl, [vertexShader, fragmentShader]);
|
||||
gl.useProgram(program);
|
||||
|
||||
var cache = {};
|
||||
cache.gl = gl;
|
||||
cache.canvas = canvas;
|
||||
cache.resolutionLocation = gl.getUniformLocation(program, 'u_resolution');
|
||||
cache.positionLocation = gl.getAttribLocation(program, 'a_position');
|
||||
cache.backdropLocation = gl.getUniformLocation(program, 'u_backdrop');
|
||||
cache.subtypeLocation = gl.getUniformLocation(program, 'u_subtype');
|
||||
|
||||
var texCoordLocation = gl.getAttribLocation(program, 'a_texCoord');
|
||||
var texLayerLocation = gl.getUniformLocation(program, 'u_image');
|
||||
var texMaskLocation = gl.getUniformLocation(program, 'u_mask');
|
||||
|
||||
// provide texture coordinates for the rectangle.
|
||||
var texCoordBuffer = gl.createBuffer();
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
|
||||
0.0, 0.0,
|
||||
1.0, 0.0,
|
||||
0.0, 1.0,
|
||||
0.0, 1.0,
|
||||
1.0, 0.0,
|
||||
1.0, 1.0]), gl.STATIC_DRAW);
|
||||
gl.enableVertexAttribArray(texCoordLocation);
|
||||
gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 0, 0);
|
||||
|
||||
gl.uniform1i(texLayerLocation, 0);
|
||||
gl.uniform1i(texMaskLocation, 1);
|
||||
|
||||
smaskCache = cache;
|
||||
}
|
||||
|
||||
function composeSMask(layer, mask, properties) {
|
||||
var width = layer.width, height = layer.height;
|
||||
|
||||
if (!smaskCache) {
|
||||
initSmaskGL();
|
||||
}
|
||||
var cache = smaskCache,canvas = cache.canvas, gl = cache.gl;
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
|
||||
gl.uniform2f(cache.resolutionLocation, width, height);
|
||||
|
||||
if (properties.backdrop) {
|
||||
gl.uniform4f(cache.resolutionLocation, properties.backdrop[0],
|
||||
properties.backdrop[1], properties.backdrop[2], 1);
|
||||
} else {
|
||||
gl.uniform4f(cache.resolutionLocation, 0, 0, 0, 0);
|
||||
}
|
||||
gl.uniform1i(cache.subtypeLocation,
|
||||
properties.subtype === 'Luminosity' ? 1 : 0);
|
||||
|
||||
// Create a textures
|
||||
var texture = createTexture(gl, layer, gl.TEXTURE0);
|
||||
var maskTexture = createTexture(gl, mask, gl.TEXTURE1);
|
||||
|
||||
|
||||
// Create a buffer and put a single clipspace rectangle in
|
||||
// it (2 triangles)
|
||||
var buffer = gl.createBuffer();
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
|
||||
0, 0,
|
||||
width, 0,
|
||||
0, height,
|
||||
0, height,
|
||||
width, 0,
|
||||
width, height]), gl.STATIC_DRAW);
|
||||
gl.enableVertexAttribArray(cache.positionLocation);
|
||||
gl.vertexAttribPointer(cache.positionLocation, 2, gl.FLOAT, false, 0, 0);
|
||||
|
||||
// draw
|
||||
gl.clearColor(0, 0, 0, 0);
|
||||
gl.enable(gl.BLEND);
|
||||
gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||
|
||||
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
||||
|
||||
gl.flush();
|
||||
|
||||
gl.deleteTexture(texture);
|
||||
gl.deleteTexture(maskTexture);
|
||||
gl.deleteBuffer(buffer);
|
||||
|
||||
return canvas;
|
||||
}
|
||||
|
||||
var figuresVertexShaderCode = '\
|
||||
attribute vec2 a_position; \
|
||||
attribute vec3 a_color; \
|
||||
\
|
||||
uniform vec2 u_resolution; \
|
||||
uniform vec2 u_scale; \
|
||||
uniform vec2 u_offset; \
|
||||
\
|
||||
varying vec4 v_color; \
|
||||
\
|
||||
void main() { \
|
||||
vec2 position = (a_position + u_offset) * u_scale; \
|
||||
vec2 clipSpace = (position / u_resolution) * 2.0 - 1.0; \
|
||||
gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1); \
|
||||
\
|
||||
v_color = vec4(a_color / 255.0, 1.0); \
|
||||
} ';
|
||||
|
||||
var figuresFragmentShaderCode = '\
|
||||
precision mediump float; \
|
||||
\
|
||||
varying vec4 v_color; \
|
||||
\
|
||||
void main() { \
|
||||
gl_FragColor = v_color; \
|
||||
} ';
|
||||
|
||||
var figuresCache = null;
|
||||
|
||||
function initFiguresGL() {
|
||||
var canvas, gl;
|
||||
|
||||
generageGL();
|
||||
canvas = currentCanvas;
|
||||
currentCanvas = null;
|
||||
gl = currentGL;
|
||||
currentGL = null;
|
||||
|
||||
// setup a GLSL program
|
||||
var vertexShader = createVertexShader(gl, figuresVertexShaderCode);
|
||||
var fragmentShader = createFragmentShader(gl, figuresFragmentShaderCode);
|
||||
var program = createProgram(gl, [vertexShader, fragmentShader]);
|
||||
gl.useProgram(program);
|
||||
|
||||
var cache = {};
|
||||
cache.gl = gl;
|
||||
cache.canvas = canvas;
|
||||
cache.resolutionLocation = gl.getUniformLocation(program, 'u_resolution');
|
||||
cache.scaleLocation = gl.getUniformLocation(program, 'u_scale');
|
||||
cache.offsetLocation = gl.getUniformLocation(program, 'u_offset');
|
||||
cache.positionLocation = gl.getAttribLocation(program, 'a_position');
|
||||
cache.colorLocation = gl.getAttribLocation(program, 'a_color');
|
||||
|
||||
figuresCache = cache;
|
||||
}
|
||||
|
||||
function drawFigures(width, height, backgroundColor, figures, context) {
|
||||
if (!figuresCache) {
|
||||
initFiguresGL();
|
||||
}
|
||||
var cache = figuresCache, canvas = cache.canvas, gl = cache.gl;
|
||||
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
|
||||
gl.uniform2f(cache.resolutionLocation, width, height);
|
||||
|
||||
// count triangle points
|
||||
var count = 0;
|
||||
var i, ii, rows;
|
||||
for (i = 0, ii = figures.length; i < ii; i++) {
|
||||
switch (figures[i].type) {
|
||||
case 'lattice':
|
||||
rows = (figures[i].coords.length / figures[i].verticesPerRow) | 0;
|
||||
count += (rows - 1) * (figures[i].verticesPerRow - 1) * 6;
|
||||
break;
|
||||
case 'triangles':
|
||||
count += figures[i].coords.length;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// transfer data
|
||||
var coords = new Float32Array(count * 2);
|
||||
var colors = new Uint8Array(count * 3);
|
||||
var coordsMap = context.coords, colorsMap = context.colors;
|
||||
var pIndex = 0, cIndex = 0;
|
||||
for (i = 0, ii = figures.length; i < ii; i++) {
|
||||
var figure = figures[i], ps = figure.coords, cs = figure.colors;
|
||||
switch (figure.type) {
|
||||
case 'lattice':
|
||||
var cols = figure.verticesPerRow;
|
||||
rows = (ps.length / cols) | 0;
|
||||
for (var row = 1; row < rows; row++) {
|
||||
var offset = row * cols + 1;
|
||||
for (var col = 1; col < cols; col++, offset++) {
|
||||
coords[pIndex] = coordsMap[ps[offset - cols - 1]];
|
||||
coords[pIndex + 1] = coordsMap[ps[offset - cols - 1] + 1];
|
||||
coords[pIndex + 2] = coordsMap[ps[offset - cols]];
|
||||
coords[pIndex + 3] = coordsMap[ps[offset - cols] + 1];
|
||||
coords[pIndex + 4] = coordsMap[ps[offset - 1]];
|
||||
coords[pIndex + 5] = coordsMap[ps[offset - 1] + 1];
|
||||
colors[cIndex] = colorsMap[cs[offset - cols - 1]];
|
||||
colors[cIndex + 1] = colorsMap[cs[offset - cols - 1] + 1];
|
||||
colors[cIndex + 2] = colorsMap[cs[offset - cols - 1] + 2];
|
||||
colors[cIndex + 3] = colorsMap[cs[offset - cols]];
|
||||
colors[cIndex + 4] = colorsMap[cs[offset - cols] + 1];
|
||||
colors[cIndex + 5] = colorsMap[cs[offset - cols] + 2];
|
||||
colors[cIndex + 6] = colorsMap[cs[offset - 1]];
|
||||
colors[cIndex + 7] = colorsMap[cs[offset - 1] + 1];
|
||||
colors[cIndex + 8] = colorsMap[cs[offset - 1] + 2];
|
||||
|
||||
coords[pIndex + 6] = coords[pIndex + 2];
|
||||
coords[pIndex + 7] = coords[pIndex + 3];
|
||||
coords[pIndex + 8] = coords[pIndex + 4];
|
||||
coords[pIndex + 9] = coords[pIndex + 5];
|
||||
coords[pIndex + 10] = coordsMap[ps[offset]];
|
||||
coords[pIndex + 11] = coordsMap[ps[offset] + 1];
|
||||
colors[cIndex + 9] = colors[cIndex + 3];
|
||||
colors[cIndex + 10] = colors[cIndex + 4];
|
||||
colors[cIndex + 11] = colors[cIndex + 5];
|
||||
colors[cIndex + 12] = colors[cIndex + 6];
|
||||
colors[cIndex + 13] = colors[cIndex + 7];
|
||||
colors[cIndex + 14] = colors[cIndex + 8];
|
||||
colors[cIndex + 15] = colorsMap[cs[offset]];
|
||||
colors[cIndex + 16] = colorsMap[cs[offset] + 1];
|
||||
colors[cIndex + 17] = colorsMap[cs[offset] + 2];
|
||||
pIndex += 12;
|
||||
cIndex += 18;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'triangles':
|
||||
for (var j = 0, jj = ps.length; j < jj; j++) {
|
||||
coords[pIndex] = coordsMap[ps[j]];
|
||||
coords[pIndex + 1] = coordsMap[ps[j] + 1];
|
||||
colors[cIndex] = colorsMap[cs[i]];
|
||||
colors[cIndex + 1] = colorsMap[cs[j] + 1];
|
||||
colors[cIndex + 2] = colorsMap[cs[j] + 2];
|
||||
pIndex += 2;
|
||||
cIndex += 3;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// draw
|
||||
if (backgroundColor) {
|
||||
gl.clearColor(backgroundColor[0] / 255, backgroundColor[1] / 255,
|
||||
backgroundColor[2] / 255, 1.0);
|
||||
} else {
|
||||
gl.clearColor(0, 0, 0, 0);
|
||||
}
|
||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||
|
||||
var coordsBuffer = gl.createBuffer();
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, coordsBuffer);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, coords, gl.STATIC_DRAW);
|
||||
gl.enableVertexAttribArray(cache.positionLocation);
|
||||
gl.vertexAttribPointer(cache.positionLocation, 2, gl.FLOAT, false, 0, 0);
|
||||
|
||||
var colorsBuffer = gl.createBuffer();
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, colorsBuffer);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW);
|
||||
gl.enableVertexAttribArray(cache.colorLocation);
|
||||
gl.vertexAttribPointer(cache.colorLocation, 3, gl.UNSIGNED_BYTE, false,
|
||||
0, 0);
|
||||
|
||||
gl.uniform2f(cache.scaleLocation, context.scaleX, context.scaleY);
|
||||
gl.uniform2f(cache.offsetLocation, context.offsetX, context.offsetY);
|
||||
|
||||
gl.drawArrays(gl.TRIANGLES, 0, count);
|
||||
|
||||
gl.flush();
|
||||
|
||||
gl.deleteBuffer(coordsBuffer);
|
||||
gl.deleteBuffer(colorsBuffer);
|
||||
|
||||
return canvas;
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
if (smaskCache && smaskCache.canvas) {
|
||||
smaskCache.canvas.width = 0;
|
||||
smaskCache.canvas.height = 0;
|
||||
}
|
||||
if (figuresCache && figuresCache.canvas) {
|
||||
figuresCache.canvas.width = 0;
|
||||
figuresCache.canvas.height = 0;
|
||||
}
|
||||
smaskCache = null;
|
||||
figuresCache = null;
|
||||
}
|
||||
|
||||
return {
|
||||
get isEnabled() {
|
||||
if (PDFJS.disableWebGL) {
|
||||
return false;
|
||||
}
|
||||
var enabled = false;
|
||||
try {
|
||||
generageGL();
|
||||
enabled = !!currentGL;
|
||||
} catch (e) { }
|
||||
return shadow(this, 'isEnabled', enabled);
|
||||
},
|
||||
composeSMask: composeSMask,
|
||||
drawFigures: drawFigures,
|
||||
clear: cleanup
|
||||
};
|
||||
})();
|
34
.obsidian/pdfjs/pdfextract/pdfjs/src/doc_helper.js
vendored
Normal file
34
.obsidian/pdfjs/pdfextract/pdfjs/src/doc_helper.js
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
/* Copyright 2012 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
NOTE: This file is created as a helper to assist with JSDoc html files.
|
||||
It is not for use in the executable code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* PDFJS scope object that contains all functions, objects and variables related
|
||||
* to the PDF.js.
|
||||
* @constructor
|
||||
*/
|
||||
function PDFJS() {
|
||||
// Mock class constructor. See src/display/api.js.
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the eventual result of an asynchronous operation.
|
||||
* @external Promise
|
||||
* @see {@link http://promisesaplus.com/ Promise/A+}
|
||||
*/
|
174
.obsidian/pdfjs/pdfextract/pdfjs/src/getPDFAnnotations.js
vendored
Normal file
174
.obsidian/pdfjs/pdfextract/pdfjs/src/getPDFAnnotations.js
vendored
Normal file
@@ -0,0 +1,174 @@
|
||||
/**
|
||||
* PDF.js extension that extracts highlighted text and annotations from pdf files.
|
||||
* Based on modified version of pdf.js available here https://github.com/jlegewie/pdf.js
|
||||
* (see various extract branches). See 'PDF Reference Manual 1.7' section 8.4 for details on
|
||||
* annotations in pdf files.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @return {Promise} A promise that is resolved with an Object
|
||||
* that includes elements for path, time, and annotations.
|
||||
*/
|
||||
PDFJS.getPDFAnnotations = function(url, removeHyphens, progress, debug) {
|
||||
// set default values
|
||||
removeHyphens = typeof removeHyphens !== 'undefined' ? removeHyphens : true;
|
||||
progress = typeof progress !== 'undefined' ? progress : function(x, y) {};
|
||||
debug = typeof debug !== 'undefined' ? debug : false;
|
||||
var legacyPromise = PDFJS.Promise!==undefined;
|
||||
// Return a new promise (with support for legacy pdf.js promises)
|
||||
/* http://www.html5rocks.com/en/tutorials/es6/promises*/
|
||||
var extract = function(resolve, reject) {
|
||||
// var SUPPORTED_ANNOTS = ['Text','Highlight','Underline'],
|
||||
var SUPPORTED_ANNOTS = ['Highlight'],
|
||||
obj = {annotations: [],
|
||||
time:null,
|
||||
url: typeof url=='string' ? url : ''
|
||||
};
|
||||
// Fetch the PDF document from the URL using promices
|
||||
PDFJS.getDocument(url).then(function(pdf) {
|
||||
var n_annos = 0,
|
||||
numPages = pdf.numPages,
|
||||
time_start = performance.now();
|
||||
|
||||
// function to handle page (render and extract annotations)
|
||||
var getAnnotationsFromPage = function(page) {
|
||||
var scale = 1;
|
||||
var viewport = page.getViewport(scale);
|
||||
// Prepare canvas using PDF page dimensions
|
||||
var canvas = document.getElementById('the-canvas');
|
||||
var context = canvas.getContext('2d');
|
||||
canvas.height = viewport.height;
|
||||
canvas.width = viewport.width;
|
||||
// console.log(canvas.height);
|
||||
// Render PDF page into canvas context
|
||||
var renderContext = {
|
||||
canvasContext: context,
|
||||
viewport: viewport
|
||||
};
|
||||
// error handler
|
||||
var errorHandler = function(error) {
|
||||
progress(page.pageNumber, numPages);
|
||||
console.log(error);
|
||||
// continue with next page
|
||||
if(numPages>page.pageNumber)
|
||||
pdf.getPage(page.pageNumber+1).then(
|
||||
getAnnotationsFromPage,
|
||||
function(err) {legacyPromise ? promise.reject(obj) : reject(err);});
|
||||
else {
|
||||
var end = performance.now();
|
||||
obj.time = end-time_start;
|
||||
legacyPromise ? promise.resolve(obj) : resolve(obj);
|
||||
}
|
||||
};
|
||||
// function to convert deviceRGB to RGB
|
||||
var convertDeviceRGBtoRGB = function(dr, dg, db) {
|
||||
var r = Math.round(dr*255);
|
||||
var g = Math.round(dg*255);
|
||||
var b = Math.round(db*255);
|
||||
return [r, g, b];
|
||||
};
|
||||
// get annotations
|
||||
page.getAnnotations().then(function extractAnno(annos) {
|
||||
// compatibility for old pdf.js version and filter for supported annotations
|
||||
annos = annos
|
||||
.map(function(anno) {
|
||||
if (anno.subtype===undefined) anno.subtype=anno.type;
|
||||
return anno;
|
||||
})
|
||||
.filter(function(anno) {
|
||||
return SUPPORTED_ANNOTS.indexOf(anno.subtype) >= 0;
|
||||
});
|
||||
// skip page if there is nothing interesting
|
||||
if (annos.length===0) {
|
||||
progress(page.pageNumber,numPages);
|
||||
if(numPages>page.pageNumber)
|
||||
pdf.getPage(page.pageNumber+1).then(
|
||||
getAnnotationsFromPage,
|
||||
function(err) {legacyPromise ? promise.reject(obj) : reject(err);});
|
||||
else {
|
||||
var end = performance.now();
|
||||
obj.time = end-time_start;
|
||||
legacyPromise ? promise.resolve(obj) : resolve(obj);
|
||||
}
|
||||
return;
|
||||
}
|
||||
// render page
|
||||
var render = page.render(renderContext, annos);
|
||||
if (render.promise!==undefined) render = render.promise;
|
||||
render.then(function() {
|
||||
// clean markup
|
||||
annos = annos.map(function(anno) {
|
||||
anno.page = page.pageNumber;
|
||||
if('color' in anno)
|
||||
anno.color = convertDeviceRGBtoRGB(anno.color[0],anno.color[1],anno.color[2]);
|
||||
// clean markup
|
||||
if(anno.markup) {
|
||||
anno.markup = anno.markup
|
||||
.map(function(part) {return part.trim();})
|
||||
.join(' ').trim()
|
||||
// translate ligatures (e.g. 'fi')
|
||||
.replace('\ufb00','ff').replace('\ufb01','fi').replace('\ufb02','fl')
|
||||
.replace(/\ufb03/g,'ffi').replace(/\ufb04/g,'ffl').replace(/\ufb05/g,'ft')
|
||||
.replace(/\ufb06/g,'st').replace(/\uFB00/g,'ff').replace(/\uFB01/g,'fi')
|
||||
.replace(/\uFB02/g,'fl').replace(/\u201D/g,'"').replace(/\u201C/g,'"')
|
||||
.replace(/\u2019/g,"'").replace(/\u2018/g,"'").replace(/\u2013/g,'-').
|
||||
replace(/''/g,'"').replace(/`/g,"'");
|
||||
if(removeHyphens)
|
||||
anno.markup = anno.markup.replace(/([a-zA-Z])- ([a-zA-Z])/g, '$1$2');
|
||||
}
|
||||
// clean anno
|
||||
if(!debug) {
|
||||
delete anno.annotationFlags;
|
||||
delete anno.borderWidth;
|
||||
delete anno.chars;
|
||||
delete anno.hasAppearance;
|
||||
delete anno.markupGeom;
|
||||
delete anno.quadPoints;
|
||||
delete anno.rect;
|
||||
delete anno.rect;
|
||||
delete anno.spaceSize;
|
||||
delete anno.name;
|
||||
}
|
||||
// return
|
||||
return anno;
|
||||
});
|
||||
// add annotations to return object
|
||||
obj.annotations.push.apply(obj.annotations, annos);
|
||||
|
||||
// render next page
|
||||
progress(page.pageNumber, numPages);
|
||||
if(numPages>page.pageNumber)
|
||||
pdf.getPage(page.pageNumber+1).then(
|
||||
getAnnotationsFromPage,
|
||||
function(err) {legacyPromise ? promise.reject(obj) : reject(err);} );
|
||||
else {
|
||||
var end = performance.now();
|
||||
obj.time = end-time_start;
|
||||
legacyPromise ? promise.resolve(obj) : resolve(obj);
|
||||
}
|
||||
}, errorHandler);
|
||||
}, errorHandler);
|
||||
};
|
||||
|
||||
// Using promise to fetch the page
|
||||
pdf.getPage(1).then(
|
||||
getAnnotationsFromPage,
|
||||
function(err) {console.log('error getting the page:' + err);}
|
||||
);
|
||||
|
||||
},
|
||||
function(err) {
|
||||
console.log('unable to open pdf: ' + err);
|
||||
legacyPromise ? promise.reject(obj) : reject(err);
|
||||
});
|
||||
};
|
||||
if (legacyPromise) {
|
||||
var promise = new PDFJS.Promise();
|
||||
extract();
|
||||
return promise;
|
||||
}
|
||||
else
|
||||
return new Promise(extract);
|
||||
};
|
41
.obsidian/pdfjs/pdfextract/pdfjs/src/images/logo.svg
vendored
Normal file
41
.obsidian/pdfjs/pdfextract/pdfjs/src/images/logo.svg
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="64"
|
||||
height="64">
|
||||
<path
|
||||
d="M 4.8364028,0.4891005 32.096378,4.5726641 59.163597,0.4891005 54.680408,57.805097 32.096378,63.510899 8.3116209,57.805097 z"
|
||||
style="fill:#e5e7e8;fill-opacity:1;fill-rule:nonzero;stroke:#cccccc" />
|
||||
<path
|
||||
d="M 32.096378,10.745857 53.925414,6.8301117 51.016574,53.81906 32.096378,58.517955 z"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" />
|
||||
<rect
|
||||
width="34.027256"
|
||||
height="19.136194"
|
||||
x="3.7557135"
|
||||
y="22.431904"
|
||||
style="fill:#ff2600;fill-opacity:1;fill-rule:nonzero;stroke:none" />
|
||||
<rect
|
||||
width="23.480518"
|
||||
height="19.136194"
|
||||
x="36.763767"
|
||||
y="22.431904"
|
||||
style="fill:#ff501a;fill-opacity:1;fill-rule:nonzero;stroke:none" />
|
||||
<g transform="matrix(0.42778543,0,0,0.42778543,58.617711,9.6737064)">
|
||||
<path
|
||||
d="m -120.53125,34.59375 0,35.1875 6.53125,0 0,-5.9375 0,-5.96875 8.875,0 4.15625,-3.71875 0,-7.71875 0,-7.71875 -4.21875,-4.125 -15.34375,0 z m 6.53125,6.8125 6.21875,0 0,10.21875 -6.21875,0 0,-10.21875 z"
|
||||
style="fill:#ffffff;fill-opacity:1" />
|
||||
<path
|
||||
d="m -98.125,34.59375 0,35.1875 16.125,0 3.75,-3.625 0,-27.96875 -3.96875,-3.59375 -15.90625,0 z m 6.8125,6.8125 6.8125,0 0,21.5625 -6.8125,0 0,-21.5625 z" id="path3056"
|
||||
style="fill:#ffffff;fill-opacity:1" />
|
||||
<path
|
||||
d="m -74.856072,34.602929 c 5.485697,0 10.971394,0 16.457091,0 0,2.269943 0,4.539887 0,6.80983 -3.404915,0 -6.809831,0 -10.214746,0 0,2.472069 0,4.944138 0,7.416206 2.93201,0.110496 5.864021,-0.110494 8.796031,0 l 0,3.366025 0,3.375914 c -2.93201,0.110495 -5.864021,-0.110495 -8.796031,0 l 0,7.146446 0,7.069702 c -2.080782,0 -4.161563,0 -6.242345,0 0,-11.728041 0,-23.456082 0,-35.184123 z"
|
||||
style="fill:#ffffff;fill-opacity:1" />
|
||||
<path
|
||||
d="m -42.8813,67.942723 -2.181762,-1.844329 c 0,-1.986871 0,-3.973742 0,-5.960613 2.175363,6.7e-4 4.350725,0.0013 6.526088,0.002 0,0.94581 0,1.891619 0,2.837429 1.891619,0 3.783239,0 5.674858,0 0,-9.458098 0,-18.916195 0,-28.374293 2.175363,-1.26e-4 4.350725,-2.52e-4 6.526088,-3.78e-4 0,10.498614 0,20.997229 0,31.495843 -1.454508,1.229554 -2.909019,2.459106 -4.363529,3.688658 -3.333325,0 -6.666651,0 -9.999976,0 -0.727237,-0.614768 -1.454563,-1.229595 -2.181767,-1.844308 z"
|
||||
style="fill:#ffffff;fill-opacity:1" />
|
||||
<path
|
||||
d="m -21.316836,67.942723 -2.109122,-1.844329 0,-5.978379 c 2.061011,0 4.392437,0.01978 6.453448,0.01978 0,0.94581 0,1.891619 0,2.837429 2.269943,0 4.539887,0 6.80983,0 0,-2.459105 0,-4.918211 0,-7.377316 -3.196954,0 -6.393909,0 -9.590863,0 l -3.745055,-3.688659 0,-6.80983 0,-6.80983 3.745055,-3.688658 c 3.863156,0 7.726313,0 11.5894692,0 l 4.2511106,3.688658 c -0.00204,1.797039 -0.00472,3.594077 -0.00737,5.391115 -2.0807816,0 -4.1615632,0 -6.2423448,0 0,-0.756648 0,-1.513295 0,-2.269943 -2.269943,0 -4.539887,0 -6.80983,0 0,2.459105 0,4.918211 0,7.377316 2.990126,0 5.980253,0 8.9703792,0 1.3605964,1.204585 4.0817956,3.613749 4.0817956,3.613749 0,4.555246 0,9.110492 0,13.665738 l -2.0892845,1.858745 -2.0892901,1.858745 -5.5180792,0 -5.51808,0 z"
|
||||
style="fill:#ffffff;fill-opacity:1" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 3.2 KiB |
51
.obsidian/pdfjs/pdfextract/pdfjs/src/pdf.js
vendored
Normal file
51
.obsidian/pdfjs/pdfextract/pdfjs/src/pdf.js
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
/* Copyright 2012 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*jshint globalstrict: false */
|
||||
/* globals PDFJS */
|
||||
|
||||
// Initializing PDFJS global object (if still undefined)
|
||||
if (typeof PDFJS === 'undefined') {
|
||||
(typeof window !== 'undefined' ? window : this).PDFJS = {};
|
||||
}
|
||||
|
||||
//#if BUNDLE_VERSION
|
||||
//#expand PDFJS.version = '__BUNDLE_VERSION__';
|
||||
//#endif
|
||||
//#if BUNDLE_BUILD
|
||||
//#expand PDFJS.build = '__BUNDLE_BUILD__';
|
||||
//#endif
|
||||
|
||||
(function pdfjsWrapper() {
|
||||
// Use strict in our context only - users might not want it
|
||||
'use strict';
|
||||
|
||||
//#expand __BUNDLE__
|
||||
|
||||
}).call((typeof window === 'undefined') ? this : window);
|
||||
|
||||
//#if !(MOZCENTRAL || FIREFOX)
|
||||
if (!PDFJS.workerSrc && typeof document !== 'undefined') {
|
||||
// workerSrc is not set -- using last script url to define default location
|
||||
PDFJS.workerSrc = (function () {
|
||||
'use strict';
|
||||
var scriptTagContainer = document.body ||
|
||||
document.getElementsByTagName('head')[0];
|
||||
var pdfjsSrc = scriptTagContainer.lastChild.src;
|
||||
return pdfjsSrc && pdfjsSrc.replace(/\.js$/i, '.worker.js');
|
||||
})();
|
||||
}
|
||||
//#endif
|
314
.obsidian/pdfjs/pdfextract/pdfjs/src/shared/cffStandardStrings.js
vendored
Normal file
314
.obsidian/pdfjs/pdfextract/pdfjs/src/shared/cffStandardStrings.js
vendored
Normal file
@@ -0,0 +1,314 @@
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
/* Copyright 2012 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var CFFEncodingMap = {
|
||||
'0': '-reserved-',
|
||||
'1': 'hstem',
|
||||
'2': '-reserved-',
|
||||
'3': 'vstem',
|
||||
'4': 'vmoveto',
|
||||
'5': 'rlineto',
|
||||
'6': 'hlineto',
|
||||
'7': 'vlineto',
|
||||
'8': 'rrcurveto',
|
||||
'9': '-reserved-',
|
||||
'10': 'callsubr',
|
||||
'11': 'return',
|
||||
'12': {
|
||||
'3': 'and',
|
||||
'4': 'or',
|
||||
'5': 'not',
|
||||
'9': 'abs',
|
||||
'10': 'add',
|
||||
'11': 'div',
|
||||
'12': 'sub',
|
||||
'14': 'neg',
|
||||
'15': 'eq',
|
||||
'18': 'drop',
|
||||
'20': 'put',
|
||||
'21': 'get',
|
||||
'22': 'ifelse',
|
||||
'23': 'random',
|
||||
'24': 'mul',
|
||||
'26': 'sqrt',
|
||||
'27': 'dup',
|
||||
'28': 'exch',
|
||||
'29': 'index',
|
||||
'30': 'roll',
|
||||
'34': 'hflex',
|
||||
'35': 'flex',
|
||||
'36': 'hflex1',
|
||||
'37': 'flex1'
|
||||
},
|
||||
'13': '-reserved-',
|
||||
'14': 'endchar',
|
||||
'15': '-reserved-',
|
||||
'16': '-reserved-',
|
||||
'17': '-reserved-',
|
||||
'18': 'hstemhm',
|
||||
'19': 'hintmask',
|
||||
'20': 'cntrmask',
|
||||
'21': 'rmoveto',
|
||||
'22': 'hmoveto',
|
||||
'23': 'vstemhm',
|
||||
'24': 'rcurveline',
|
||||
'25': 'rlivecurve',
|
||||
'26': 'vvcurveto',
|
||||
'27': 'hhcurveto',
|
||||
'29': 'callgsubr',
|
||||
'30': 'vhcurveto',
|
||||
'31': 'hvcurveto'
|
||||
};
|
||||
|
||||
var CFFDictDataMap = {
|
||||
'0': {
|
||||
name: 'version',
|
||||
operand: 'SID'
|
||||
},
|
||||
'1': {
|
||||
name: 'Notice',
|
||||
operand: 'SID'
|
||||
},
|
||||
'2': {
|
||||
name: 'FullName',
|
||||
operand: 'SID'
|
||||
},
|
||||
'3': {
|
||||
name: 'FamilyName',
|
||||
operand: 'SID'
|
||||
},
|
||||
'4': {
|
||||
name: 'Weight',
|
||||
operand: 'SID'
|
||||
},
|
||||
'5': {
|
||||
name: 'FontBBox',
|
||||
operand: [0, 0, 0, 0]
|
||||
},
|
||||
'6': {
|
||||
name: 'BlueValues'
|
||||
},
|
||||
'7': {
|
||||
name: 'OtherBlues'
|
||||
},
|
||||
'8': {
|
||||
name: 'FamilyBlues'
|
||||
},
|
||||
'9': {
|
||||
name: 'FamilyOtherBlues'
|
||||
},
|
||||
'10': {
|
||||
name: 'StdHW'
|
||||
},
|
||||
'11': {
|
||||
name: 'StdVW'
|
||||
},
|
||||
'12': {
|
||||
'0': {
|
||||
name: 'Copyright',
|
||||
operand: 'SID'
|
||||
},
|
||||
'1': {
|
||||
name: 'IsFixedPitch',
|
||||
operand: false
|
||||
},
|
||||
'2': {
|
||||
name: 'ItalicAngle',
|
||||
operand: 0
|
||||
},
|
||||
'3': {
|
||||
name: 'UnderlinePosition',
|
||||
operand: -100
|
||||
},
|
||||
'4': {
|
||||
name: 'UnderlineThickness',
|
||||
operand: 50
|
||||
},
|
||||
'5': {
|
||||
name: 'PaintType',
|
||||
operand: 0
|
||||
},
|
||||
'6': {
|
||||
name: 'CharstringType',
|
||||
operand: 2
|
||||
},
|
||||
'7': {
|
||||
name: 'FontMatrix',
|
||||
operand: [0.001, 0, 0, 0.001, 0 , 0]
|
||||
},
|
||||
'8': {
|
||||
name: 'StrokeWidth',
|
||||
operand: 0
|
||||
},
|
||||
'9': {
|
||||
name: 'BlueScale'
|
||||
},
|
||||
'10': {
|
||||
name: 'BlueShift'
|
||||
},
|
||||
'11': {
|
||||
name: 'BlueFuzz'
|
||||
},
|
||||
'12': {
|
||||
name: 'StemSnapH'
|
||||
},
|
||||
'13': {
|
||||
name: 'StemSnapV'
|
||||
},
|
||||
'14': {
|
||||
name: 'ForceBold'
|
||||
},
|
||||
'17': {
|
||||
name: 'LanguageGroup'
|
||||
},
|
||||
'18': {
|
||||
name: 'ExpansionFactor'
|
||||
},
|
||||
'19': {
|
||||
name: 'initialRandomSeed'
|
||||
},
|
||||
'20': {
|
||||
name: 'SyntheticBase',
|
||||
operand: null
|
||||
},
|
||||
'21': {
|
||||
name: 'PostScript',
|
||||
operand: 'SID'
|
||||
},
|
||||
'22': {
|
||||
name: 'BaseFontName',
|
||||
operand: 'SID'
|
||||
},
|
||||
'23': {
|
||||
name: 'BaseFontBlend',
|
||||
operand: 'delta'
|
||||
}
|
||||
},
|
||||
'13': {
|
||||
name: 'UniqueID',
|
||||
operand: null
|
||||
},
|
||||
'14': {
|
||||
name: 'XUID',
|
||||
operand: []
|
||||
},
|
||||
'15': {
|
||||
name: 'charset',
|
||||
operand: 0
|
||||
},
|
||||
'16': {
|
||||
name: 'Encoding',
|
||||
operand: 0
|
||||
},
|
||||
'17': {
|
||||
name: 'CharStrings',
|
||||
operand: null
|
||||
},
|
||||
'18': {
|
||||
name: 'Private',
|
||||
operand: 'number number'
|
||||
},
|
||||
'19': {
|
||||
name: 'Subrs'
|
||||
},
|
||||
'20': {
|
||||
name: 'defaultWidthX'
|
||||
},
|
||||
'21': {
|
||||
name: 'nominalWidthX'
|
||||
}
|
||||
};
|
||||
|
||||
var CFFDictPrivateDataMap = {
|
||||
'6': {
|
||||
name: 'BluesValues',
|
||||
operand: 'delta'
|
||||
},
|
||||
'7': {
|
||||
name: 'OtherBlues',
|
||||
operand: 'delta'
|
||||
},
|
||||
'8': {
|
||||
name: 'FamilyBlues',
|
||||
operand: 'delta'
|
||||
},
|
||||
'9': {
|
||||
name: 'FamilyOtherBlues',
|
||||
operand: 'delta'
|
||||
},
|
||||
'10': {
|
||||
name: 'StdHW',
|
||||
operand: null
|
||||
},
|
||||
'11': {
|
||||
name: 'StdVW',
|
||||
operand: null
|
||||
},
|
||||
'12': {
|
||||
'9': {
|
||||
name: 'BlueScale',
|
||||
operand: 0.039625
|
||||
},
|
||||
'10': {
|
||||
name: 'BlueShift',
|
||||
operand: 7
|
||||
},
|
||||
'11': {
|
||||
name: 'BlueFuzz',
|
||||
operand: 1
|
||||
},
|
||||
'12': {
|
||||
name: 'StemSnapH',
|
||||
operand: 'delta'
|
||||
},
|
||||
'13': {
|
||||
name: 'StemSnapV',
|
||||
operand: 'delta'
|
||||
},
|
||||
'14': {
|
||||
name: 'ForceBold',
|
||||
operand: 'boolean'
|
||||
},
|
||||
'17': {
|
||||
name: 'LanguageGroup',
|
||||
operand: 0
|
||||
},
|
||||
'18': {
|
||||
name: 'ExpansionFactor',
|
||||
operand: 0.06
|
||||
},
|
||||
'19': {
|
||||
name: 'initialRandomSeed',
|
||||
operand: 0
|
||||
}
|
||||
},
|
||||
'19': {
|
||||
name: 'Subrs',
|
||||
operand: null
|
||||
},
|
||||
'20': {
|
||||
name: 'defaultWidthX',
|
||||
operand: 0
|
||||
},
|
||||
'21': {
|
||||
name: 'nominalWidthX',
|
||||
operand: 0
|
||||
}
|
||||
};
|
||||
|
434
.obsidian/pdfjs/pdfextract/pdfjs/src/shared/fonts_utils.js
vendored
Normal file
434
.obsidian/pdfjs/pdfextract/pdfjs/src/shared/fonts_utils.js
vendored
Normal file
@@ -0,0 +1,434 @@
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
/* Copyright 2012 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/* globals CFFDictDataMap, CFFDictPrivateDataMap, CFFEncodingMap, CFFStrings,
|
||||
Components, Dict, dump, error, isNum, netscape, Stream */
|
||||
|
||||
'use strict';
|
||||
|
||||
/*
|
||||
* The Type2 reader code below is only used for debugging purpose since Type2
|
||||
* is only a CharString format and is never used directly as a Font file.
|
||||
*
|
||||
* So the code here is useful for dumping the data content of a .cff file in
|
||||
* order to investigate the similarity between a Type1 CharString and a Type2
|
||||
* CharString or to understand the structure of the CFF format.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Build a charset by assigning the glyph name and the human readable form
|
||||
* of the glyph data.
|
||||
*/
|
||||
function readCharset(aStream, aCharstrings) {
|
||||
var charset = {};
|
||||
|
||||
var format = aStream.getByte();
|
||||
var count = aCharstrings.length - 1;
|
||||
var i, sid;
|
||||
if (format === 0) {
|
||||
charset['.notdef'] = readCharstringEncoding(aCharstrings[0]);
|
||||
|
||||
for (i = 1; i < count + 1; i++) {
|
||||
sid = aStream.getByte() << 8 | aStream.getByte();
|
||||
charset[CFFStrings[sid]] = readCharstringEncoding(aCharstrings[i]);
|
||||
}
|
||||
} else if (format === 1) {
|
||||
for (i = 1; i < count + 1; i++) {
|
||||
var first = aStream.getByte();
|
||||
first = (first << 8) | aStream.getByte();
|
||||
var numLeft = aStream.getByte();
|
||||
for (var j = 0; j <= numLeft; j++) {
|
||||
sid = first++;
|
||||
charset[CFFStrings[sid]] = readCharstringEncoding(aCharstrings[j]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
error('Invalid charset format');
|
||||
}
|
||||
|
||||
return charset;
|
||||
}
|
||||
|
||||
/*
|
||||
* Take a Type2 binary charstring as input and transform it to a human
|
||||
* readable representation as specified by the 'The Type 2 Charstring Format',
|
||||
* chapter 3.1.
|
||||
*/
|
||||
function readCharstringEncoding(aString) {
|
||||
if (!aString) {
|
||||
return '';
|
||||
}
|
||||
|
||||
var charstringTokens = [];
|
||||
|
||||
var count = aString.length;
|
||||
for (var i = 0; i < count; ) {
|
||||
var value = aString[i++] | 0;
|
||||
var token = null;
|
||||
|
||||
if (value < 0) {
|
||||
continue;
|
||||
} else if (value <= 11) {
|
||||
token = CFFEncodingMap[value];
|
||||
} else if (value === 12) {
|
||||
token = CFFEncodingMap[value][aString[i++]];
|
||||
} else if (value <= 18) {
|
||||
token = CFFEncodingMap[value];
|
||||
} else if (value <= 20) {
|
||||
++i; // var mask = aString[i++];
|
||||
token = CFFEncodingMap[value];
|
||||
} else if (value <= 27) {
|
||||
token = CFFEncodingMap[value];
|
||||
} else if (value === 28) {
|
||||
token = aString[i++] << 8 | aString[i++];
|
||||
} else if (value <= 31) {
|
||||
token = CFFEncodingMap[value];
|
||||
} else if (value < 247) {
|
||||
token = parseInt(value, 10) - 139;
|
||||
} else if (value < 251) {
|
||||
token = (value - 247) * 256 + aString[i++] + 108;
|
||||
} else if (value < 255) {
|
||||
token = -(value - 251) * 256 - aString[i++] - 108;
|
||||
} else { // value === 255
|
||||
token = aString[i++] << 24 | aString[i++] << 16 |
|
||||
aString[i++] << 8 | aString[i];
|
||||
}
|
||||
|
||||
charstringTokens.push(token);
|
||||
}
|
||||
|
||||
return charstringTokens;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Take a binary DICT Data as input and transform it into a human readable
|
||||
* form as specified by 'The Compact Font Format Specification', chapter 5.
|
||||
*/
|
||||
function readFontDictData(aString, aMap) {
|
||||
var fontDictDataTokens = [];
|
||||
|
||||
var count = aString.length;
|
||||
for (var i = 0; i < count; i) {
|
||||
var value = aString[i++] | 0;
|
||||
var token = null;
|
||||
|
||||
if (value === 12) {
|
||||
token = aMap[value][aString[i++]];
|
||||
} else if (value === 28) {
|
||||
token = aString[i++] << 8 | aString[i++];
|
||||
} else if (value === 29) {
|
||||
token = aString[i++] << 24 |
|
||||
aString[i++] << 16 |
|
||||
aString[i++] << 8 |
|
||||
aString[i++];
|
||||
} else if (value === 30) {
|
||||
token = '';
|
||||
var parsed = false;
|
||||
while (!parsed) {
|
||||
var octet = aString[i++];
|
||||
|
||||
var nibbles = [parseInt(octet / 16, 10), parseInt(octet % 16, 10)];
|
||||
for (var j = 0; j < nibbles.length; j++) {
|
||||
var nibble = nibbles[j];
|
||||
switch (nibble) {
|
||||
case 0xA:
|
||||
token += '.';
|
||||
break;
|
||||
case 0xB:
|
||||
token += 'E';
|
||||
break;
|
||||
case 0xC:
|
||||
token += 'E-';
|
||||
break;
|
||||
case 0xD:
|
||||
break;
|
||||
case 0xE:
|
||||
token += '-';
|
||||
break;
|
||||
case 0xF:
|
||||
parsed = true;
|
||||
break;
|
||||
default:
|
||||
token += nibble;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
token = parseFloat(token);
|
||||
} else if (value <= 31) {
|
||||
token = aMap[value];
|
||||
} else if (value <= 246) {
|
||||
token = parseInt(value, 10) - 139;
|
||||
} else if (value <= 250) {
|
||||
token = (value - 247) * 256 + aString[i++] + 108;
|
||||
} else if (value <= 254) {
|
||||
token = -(value - 251) * 256 - aString[i++] - 108;
|
||||
} else if (value === 255) {
|
||||
error('255 is not a valid DICT command');
|
||||
}
|
||||
|
||||
fontDictDataTokens.push(token);
|
||||
}
|
||||
|
||||
return fontDictDataTokens;
|
||||
}
|
||||
|
||||
/*
|
||||
* Take a stream as input and return an array of objects.
|
||||
* In CFF an INDEX is a structure with the following format:
|
||||
* {
|
||||
* count: 2 bytes (Number of objects stored in INDEX),
|
||||
* offsize: 1 byte (Offset array element size),
|
||||
* offset: [count + 1] bytes (Offsets array),
|
||||
* data: - (Objects data)
|
||||
* }
|
||||
*
|
||||
* More explanation are given in the 'CFF Font Format Specification',
|
||||
* chapter 5.
|
||||
*/
|
||||
function readFontIndexData(aStream, aIsByte) {
|
||||
var count = aStream.getByte() << 8 | aStream.getByte();
|
||||
var offsize = aStream.getByte();
|
||||
|
||||
function getNextOffset() {
|
||||
switch (offsize) {
|
||||
case 0:
|
||||
return 0;
|
||||
case 1:
|
||||
return aStream.getByte();
|
||||
case 2:
|
||||
return aStream.getByte() << 8 | aStream.getByte();
|
||||
case 3:
|
||||
return aStream.getByte() << 16 | aStream.getByte() << 8 |
|
||||
aStream.getByte();
|
||||
case 4:
|
||||
return aStream.getByte() << 24 | aStream.getByte() << 16 |
|
||||
aStream.getByte() << 8 | aStream.getByte();
|
||||
}
|
||||
error(offsize + ' is not a valid offset size');
|
||||
return null;
|
||||
}
|
||||
|
||||
var offsets = [];
|
||||
var i;
|
||||
for (i = 0; i < count + 1; i++) {
|
||||
offsets.push(getNextOffset());
|
||||
}
|
||||
|
||||
dump('Found ' + count + ' objects at offsets :' +
|
||||
offsets + ' (offsize: ' + offsize + ')');
|
||||
|
||||
// Now extract the objects
|
||||
var relativeOffset = aStream.pos;
|
||||
var objects = [];
|
||||
for (i = 0; i < count; i++) {
|
||||
var offset = offsets[i];
|
||||
aStream.pos = relativeOffset + offset - 1;
|
||||
|
||||
var data = [];
|
||||
var length = offsets[i + 1] - 1;
|
||||
for (var j = offset - 1; j < length; j++) {
|
||||
data.push(aIsByte ? aStream.getByte() : aStream.getChar());
|
||||
}
|
||||
objects.push(data);
|
||||
}
|
||||
|
||||
return objects;
|
||||
}
|
||||
|
||||
var Type2Parser = function type2Parser(aFilePath) {
|
||||
var font = new Dict(null);
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', aFilePath, false);
|
||||
xhr.responseType = 'arraybuffer';
|
||||
xhr.expected = (document.URL.indexOf('file:') === 0) ? 0 : 200;
|
||||
xhr.send(null);
|
||||
this.data = new Stream(xhr.response);
|
||||
|
||||
// Turn on this flag for additional debugging logs
|
||||
var debug = false;
|
||||
|
||||
function dump(aStr) {
|
||||
if (debug) {
|
||||
console.log(aStr);
|
||||
}
|
||||
}
|
||||
|
||||
function parseAsToken(aString, aMap) {
|
||||
var decoded = readFontDictData(aString, aMap);
|
||||
|
||||
var stack = [];
|
||||
var count = decoded.length;
|
||||
for (var i = 0; i < count; i++) {
|
||||
var token = decoded[i];
|
||||
if (isNum(token)) {
|
||||
stack.push(token);
|
||||
} else {
|
||||
switch (token.operand) {
|
||||
case 'SID':
|
||||
font.set(token.name, CFFStrings[stack.pop()]);
|
||||
break;
|
||||
case 'number number':
|
||||
font.set(token.name, {
|
||||
offset: stack.pop(),
|
||||
size: stack.pop()
|
||||
});
|
||||
break;
|
||||
case 'boolean':
|
||||
font.set(token.name, stack.pop());
|
||||
break;
|
||||
case 'delta':
|
||||
font.set(token.name, stack.pop());
|
||||
break;
|
||||
default:
|
||||
if (token.operand && token.operand.length) {
|
||||
var array = [];
|
||||
for (var j = 0; j < token.operand.length; j++) {
|
||||
array.push(stack.pop());
|
||||
}
|
||||
font.set(token.name, array);
|
||||
} else {
|
||||
font.set(token.name, stack.pop());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.parse = function type2ParserParse(aStream) {
|
||||
font.set('major', aStream.getByte());
|
||||
font.set('minor', aStream.getByte());
|
||||
font.set('hdrSize', aStream.getByte());
|
||||
font.set('offsize', aStream.getByte());
|
||||
|
||||
// Read the NAME Index
|
||||
dump('Reading Index: Names');
|
||||
font.set('Names', readFontIndexData(aStream));
|
||||
dump('Names: ' + font.get('Names'));
|
||||
|
||||
// Read the Top Dict Index
|
||||
dump('Reading Index: TopDict');
|
||||
var topDict = readFontIndexData(aStream, true);
|
||||
dump('TopDict: ' + topDict);
|
||||
|
||||
// Read the String Index
|
||||
dump('Reading Index: Strings');
|
||||
var strings = readFontIndexData(aStream);
|
||||
dump('strings: ' + strings);
|
||||
|
||||
// Fill up the Strings dictionary with the new unique strings
|
||||
var i;
|
||||
for (i = 0; i < strings.length; i++) {
|
||||
CFFStrings.push(strings[i].join(''));
|
||||
}
|
||||
|
||||
// Parse the TopDict operator
|
||||
var count = topDict.length;
|
||||
for (i = 0; i < count; i++) {
|
||||
parseAsToken(topDict[i], CFFDictDataMap);
|
||||
}
|
||||
|
||||
// Read the Global Subr Index that comes just after the Strings Index
|
||||
// (cf. "The Compact Font Format Specification" Chapter 16)
|
||||
dump('Reading Global Subr Index');
|
||||
var subrs = readFontIndexData(aStream, true);
|
||||
dump(subrs);
|
||||
|
||||
// Reading Private Dict
|
||||
var priv = font.get('Private');
|
||||
dump('Reading Private Dict (offset: ' + priv.offset +
|
||||
' size: ' + priv.size + ')');
|
||||
aStream.pos = priv.offset;
|
||||
|
||||
var privateDict = [];
|
||||
for (i = 0; i < priv.size; i++) {
|
||||
privateDict.push(aStream.getByte());
|
||||
}
|
||||
dump('privateData:' + privateDict);
|
||||
parseAsToken(privateDict, CFFDictPrivateDataMap);
|
||||
|
||||
for (var p in font.map) {
|
||||
dump(p + '::' + font.get(p));
|
||||
}
|
||||
|
||||
// Read CharStrings Index
|
||||
var charStringsOffset = font.get('CharStrings');
|
||||
dump('Read CharStrings Index (offset: ' + charStringsOffset + ')');
|
||||
aStream.pos = charStringsOffset;
|
||||
var charStrings = readFontIndexData(aStream, true);
|
||||
|
||||
// Read Charset
|
||||
dump('Read Charset for ' + charStrings.length + ' glyphs');
|
||||
var charsetEntry = font.get('charset');
|
||||
if (charsetEntry === 0) {
|
||||
error('Need to support CFFISOAdobeCharset');
|
||||
} else if (charsetEntry === 1) {
|
||||
error('Need to support CFFExpert');
|
||||
} else if (charsetEntry === 2) {
|
||||
error('Need to support CFFExpertSubsetCharset');
|
||||
} else {
|
||||
aStream.pos = charsetEntry;
|
||||
readCharset(aStream, charStrings);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
* To try the Type2 decoder on a local file in the current directory:
|
||||
*
|
||||
* var cff = new Type2Parser("file.cff");
|
||||
* cff.parse(this.data);
|
||||
*
|
||||
* To try the Type2 decoder on a custom built CFF array:
|
||||
*
|
||||
* var file = new Uint8Array(cffFileArray, 0, cffFileSize);
|
||||
* var parser = new Type2Parser();
|
||||
* parser.parse(new Stream(file));
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Write to a file to the disk (works only on Firefox in privilege mode)
|
||||
* but this is useful for dumping a font file to the disk and check with
|
||||
* fontforge or the ots program what's wrong with the file.
|
||||
*
|
||||
* writeToFile(fontData, "/tmp/pdf.js." + fontCount + ".cff");
|
||||
*/
|
||||
function writeToFile(aBytes, aFilePath) {
|
||||
if (!('netscape' in window)) {
|
||||
return;
|
||||
}
|
||||
|
||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||
var Cc = Components.classes,
|
||||
Ci = Components.interfaces;
|
||||
var file = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile);
|
||||
file.initWithPath(aFilePath);
|
||||
|
||||
var stream = Cc['@mozilla.org/network/file-output-stream;1']
|
||||
.createInstance(Ci.nsIFileOutputStream);
|
||||
stream.init(file, 0x04 | 0x08 | 0x20, 0x180, 0);
|
||||
|
||||
var bos = Cc['@mozilla.org/binaryoutputstream;1']
|
||||
.createInstance(Ci.nsIBinaryOutputStream);
|
||||
bos.setOutputStream(stream);
|
||||
bos.writeByteArray(aBytes, aBytes.length);
|
||||
stream.close();
|
||||
}
|
||||
|
1591
.obsidian/pdfjs/pdfextract/pdfjs/src/shared/util.js
vendored
Normal file
1591
.obsidian/pdfjs/pdfextract/pdfjs/src/shared/util.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
81
.obsidian/pdfjs/pdfextract/pdfjs/src/worker_loader.js
vendored
Normal file
81
.obsidian/pdfjs/pdfextract/pdfjs/src/worker_loader.js
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
/* Copyright 2012 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/* globals PDFJS, Util */
|
||||
|
||||
'use strict';
|
||||
|
||||
// List of shared files to include;
|
||||
var sharedFiles = [
|
||||
'shared/util.js'
|
||||
];
|
||||
|
||||
// List of other files to include;
|
||||
var otherFiles = [
|
||||
'core/network.js',
|
||||
'core/chunked_stream.js',
|
||||
'core/pdf_manager.js',
|
||||
'core/core.js',
|
||||
'core/obj.js',
|
||||
'core/charsets.js',
|
||||
'core/annotation.js',
|
||||
'core/function.js',
|
||||
'core/colorspace.js',
|
||||
'core/crypto.js',
|
||||
'core/pattern.js',
|
||||
'core/evaluator.js',
|
||||
'core/cmap.js',
|
||||
'core/fonts.js',
|
||||
'core/font_renderer.js',
|
||||
'core/glyphlist.js',
|
||||
'core/image.js',
|
||||
'core/metrics.js',
|
||||
'core/parser.js',
|
||||
'core/ps_parser.js',
|
||||
'core/stream.js',
|
||||
'core/worker.js',
|
||||
'core/arithmetic_decoder.js',
|
||||
'core/jpg.js',
|
||||
'core/jpx.js',
|
||||
'core/jbig2.js',
|
||||
'core/bidi.js',
|
||||
'core/murmurhash3.js'
|
||||
];
|
||||
|
||||
function loadInOrder(index, path, files) {
|
||||
if (index >= files.length) {
|
||||
PDFJS.fakeWorkerFilesLoadedCapability.resolve();
|
||||
return;
|
||||
}
|
||||
PDFJS.Util.loadScript(path + files[index],
|
||||
loadInOrder.bind(null, ++index, path, files));
|
||||
}
|
||||
|
||||
// Load all the files.
|
||||
if (typeof PDFJS === 'undefined' || !PDFJS.fakeWorkerFilesLoadedCapability) {
|
||||
var files = sharedFiles.concat(otherFiles);
|
||||
for (var i = 0; i < files.length; i++) {
|
||||
importScripts(files[i]);
|
||||
}
|
||||
} else {
|
||||
var src = PDFJS.workerSrc;
|
||||
var path = src.substr(0, src.indexOf('worker_loader.js'));
|
||||
// If Util is available, we assume that shared files are already loaded. Can
|
||||
// happen that they are not if PDF.js is bundled inside a special namespace.
|
||||
var skipShared = typeof Util !== 'undefined';
|
||||
var files = skipShared ? otherFiles : sharedFiles.concat(otherFiles);
|
||||
loadInOrder(0, path, files);
|
||||
}
|
Reference in New Issue
Block a user