Merge with upstream
This commit is contained in:
commit
06a3b49e49
1
LICENSE
1
LICENSE
@ -8,6 +8,7 @@
|
|||||||
Justin D'Arcangelo <justindarc@gmail.com>
|
Justin D'Arcangelo <justindarc@gmail.com>
|
||||||
Yury Delendik
|
Yury Delendik
|
||||||
Kalervo Kujala
|
Kalervo Kujala
|
||||||
|
Adil Allawi <@ironymark>
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
copy of this software and associated documentation files (the "Software"),
|
copy of this software and associated documentation files (the "Software"),
|
||||||
|
72
Makefile
72
Makefile
@ -55,30 +55,30 @@ browser-test:
|
|||||||
--browserManifestFile=$(PDF_BROWSERS) \
|
--browserManifestFile=$(PDF_BROWSERS) \
|
||||||
--manifestFile=$(PDF_TESTS)
|
--manifestFile=$(PDF_TESTS)
|
||||||
|
|
||||||
# make shell-test
|
# # make shell-test
|
||||||
#
|
# #
|
||||||
# This target runs all of the tests that can be run in a JS shell.
|
# # This target runs all of the tests that can be run in a JS shell.
|
||||||
# The shell used is taken from the JS_SHELL environment variable. If
|
# # The shell used is taken from the JS_SHELL environment variable. If
|
||||||
# that variable is not defined, the script will attempt to use the copy
|
# # that variable is not defined, the script will attempt to use the copy
|
||||||
# of Rhino that comes with the Closure compiler used for producing the
|
# # of Rhino that comes with the Closure compiler used for producing the
|
||||||
# website.
|
# # website.
|
||||||
SHELL_TARGET = $(NULL)
|
# SHELL_TARGET = $(NULL)
|
||||||
ifeq ($(JS_SHELL),)
|
# ifeq ($(JS_SHELL),)
|
||||||
JS_SHELL := "java -cp $(BUILD_DIR)/compiler.jar"
|
# JS_SHELL := "java -cp $(BUILD_DIR)/compiler.jar"
|
||||||
JS_SHELL += "com.google.javascript.jscomp.mozilla.rhino.tools.shell.Main"
|
# JS_SHELL += "com.google.javascript.jscomp.mozilla.rhino.tools.shell.Main"
|
||||||
SHELL_TARGET = compiler
|
# SHELL_TARGET = compiler
|
||||||
endif
|
# endif
|
||||||
|
#
|
||||||
shell-test: shell-msg $(SHELL_TARGET) font-test
|
# shell-test: shell-msg $(SHELL_TARGET) font-test
|
||||||
shell-msg:
|
# shell-msg:
|
||||||
ifeq ($(SHELL_TARGET), compiler)
|
# ifeq ($(SHELL_TARGET), compiler)
|
||||||
@echo "No JS_SHELL env variable present."
|
# @echo "No JS_SHELL env variable present."
|
||||||
@echo "The default is to find a copy of Rhino and try that."
|
# @echo "The default is to find a copy of Rhino and try that."
|
||||||
endif
|
# endif
|
||||||
@echo "JS shell command is: $(JS_SHELL)"
|
# @echo "JS shell command is: $(JS_SHELL)"
|
||||||
|
#
|
||||||
font-test:
|
# font-test:
|
||||||
@echo "font test stub."
|
# @echo "font test stub."
|
||||||
|
|
||||||
# make lint
|
# make lint
|
||||||
#
|
#
|
||||||
@ -133,18 +133,18 @@ $(GH_PAGES)/web/%: web/%
|
|||||||
$(GH_PAGES)/web/images/%: web/images/%
|
$(GH_PAGES)/web/images/%: web/images/%
|
||||||
@cp $< $@
|
@cp $< $@
|
||||||
|
|
||||||
# make compiler
|
# # make compiler
|
||||||
#
|
# #
|
||||||
# This target downloads the Closure compiler, and places it in the
|
# # This target downloads the Closure compiler, and places it in the
|
||||||
# build directory. This target is also useful when the user doesn't
|
# # build directory. This target is also useful when the user doesn't
|
||||||
# have a JS shell available--we can have them use the Rhino shell that
|
# # have a JS shell available--we can have them use the Rhino shell that
|
||||||
# comes with Closure.
|
# # comes with Closure.
|
||||||
COMPILER_URL = http://closure-compiler.googlecode.com/files/compiler-latest.zip
|
# COMPILER_URL = http://closure-compiler.googlecode.com/files/compiler-latest.zip
|
||||||
|
#
|
||||||
compiler: $(BUILD_DIR)/compiler.zip
|
# compiler: $(BUILD_DIR)/compiler.zip
|
||||||
$(BUILD_DIR)/compiler.zip: | $(BUILD_DIR)
|
# $(BUILD_DIR)/compiler.zip: | $(BUILD_DIR)
|
||||||
curl $(COMPILER_URL) > $(BUILD_DIR)/compiler.zip;
|
# curl $(COMPILER_URL) > $(BUILD_DIR)/compiler.zip;
|
||||||
cd $(BUILD_DIR); unzip compiler.zip compiler.jar;
|
# cd $(BUILD_DIR); unzip compiler.zip compiler.jar;
|
||||||
|
|
||||||
# make firefox-extension
|
# make firefox-extension
|
||||||
#
|
#
|
||||||
|
94
README.md
94
README.md
@ -1,17 +1,84 @@
|
|||||||
# pdf.js
|
# pdf.js
|
||||||
|
|
||||||
pdf.js is a technology demonstrator prototype to explore whether the HTML5
|
|
||||||
platform is complete enough to faithfully and efficiently render the ISO
|
|
||||||
32000-1:2008 Portable Document Format (PDF) without native code assistance.
|
|
||||||
|
|
||||||
pdf.js is not currently part of the Mozilla project, and there is no plan
|
|
||||||
yet to integrate it into Firefox. We will explore that possibility once
|
## Overview
|
||||||
pdf.js is production ready. Until then we aim to publish a Firefox
|
|
||||||
PDF reader extension powered by pdf.js.
|
pdf.js is an HTML5 technology experiment that explores building a faithful
|
||||||
|
and efficient Portable Document Format (PDF) renderer without native code
|
||||||
|
assistance.
|
||||||
|
|
||||||
|
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, and eventually release a PDF reader extension powered by
|
||||||
|
pdf.js. Integration with Firefox is a possibility if the experiment proves
|
||||||
|
successful.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Getting started
|
||||||
|
|
||||||
|
**Online demo**
|
||||||
|
|
||||||
|
For an online demo, visit:
|
||||||
|
|
||||||
|
http://andreasgal.github.com/pdf.js/web/viewer.html
|
||||||
|
|
||||||
|
This demo provides an interactive interface for displaying and browsing PDFs
|
||||||
|
using the pdf.js API.
|
||||||
|
|
||||||
|
**Hello world**
|
||||||
|
|
||||||
|
For a "hello world" example, take a look at:
|
||||||
|
|
||||||
|
examples/helloworld/
|
||||||
|
|
||||||
|
This example illustrates the bare minimum ingredients for integrating pdf.js
|
||||||
|
in a custom project.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Running the Tests
|
||||||
|
|
||||||
|
pdf.js comes with browser-level regression tests that allow one to probe
|
||||||
|
whether it's able to successfully parse PDFs, as well as compare its output
|
||||||
|
against reference images, pixel-by-pixel.
|
||||||
|
|
||||||
|
To run the tests, first configure the browser manifest file at:
|
||||||
|
|
||||||
|
test/resources/browser_manifests/browser_manifest.json
|
||||||
|
|
||||||
|
Sample manifests for different platforms are provided in that directory.
|
||||||
|
|
||||||
|
To run all the bundled tests, type:
|
||||||
|
|
||||||
|
$ make test
|
||||||
|
|
||||||
|
and cross your fingers. Different types of tests are available, see the test
|
||||||
|
manifest file at:
|
||||||
|
|
||||||
|
test/test_manifest.json
|
||||||
|
|
||||||
|
The test type `eq` tests whether the output images are identical to reference
|
||||||
|
images. The test type `load` simply tests whether the file loads without
|
||||||
|
raising any errors.
|
||||||
|
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
pdf.js is a community-driver project, so contributors are always welcome.
|
||||||
|
Simply fork our repo and contribute away. A great place to start is our
|
||||||
|
open issues.
|
||||||
|
|
||||||
|
For better consistency and long-term stability, please do look around the
|
||||||
|
code and try to follow our conventions.
|
||||||
|
|
||||||
|
|
||||||
|
## Additional resources
|
||||||
|
|
||||||
Our demo site is here:
|
Our demo site is here:
|
||||||
|
|
||||||
http://andreasgal.github.com/pdf.js/
|
http://andreasgal.github.com/pdf.js/web/viewer.html
|
||||||
|
|
||||||
You can read more about pdf.js here:
|
You can read more about pdf.js here:
|
||||||
|
|
||||||
@ -19,14 +86,19 @@ You can read more about pdf.js here:
|
|||||||
|
|
||||||
http://blog.mozilla.com/cjones/2011/06/15/overview-of-pdf-js-guts/
|
http://blog.mozilla.com/cjones/2011/06/15/overview-of-pdf-js-guts/
|
||||||
|
|
||||||
follow us on twitter: @pdfjs
|
Follow us on twitter: @pdfjs
|
||||||
|
|
||||||
http://twitter.com/#!/pdfjs
|
http://twitter.com/#!/pdfjs
|
||||||
|
|
||||||
join our mailing list:
|
Join our mailing list:
|
||||||
|
|
||||||
dev-pdf-js@lists.mozilla.org
|
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
|
||||||
|
|
||||||
and talk to us on IRC:
|
Talk to us on IRC:
|
||||||
|
|
||||||
#pdfjs on irc.mozilla.org
|
#pdfjs on irc.mozilla.org
|
||||||
|
16
examples/helloworld/README.md
Normal file
16
examples/helloworld/README.md
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
## "Hello World" overview
|
||||||
|
|
||||||
|
This example is a minimalistic application of the pdf.js project. The file
|
||||||
|
`helloworld.pdf` is from the GNUpdf project (see [Introduction to PDF at GNUpdf](http://gnupdf.org/Introduction_to_PDF), and contains a simple and
|
||||||
|
human-readable PDF.
|
||||||
|
|
||||||
|
|
||||||
|
## Getting started
|
||||||
|
|
||||||
|
Point your browser to `index.html`. Voila. Take a peek at `hello.js` to see
|
||||||
|
how to make basic calls to `pdf.js`.
|
||||||
|
|
||||||
|
|
||||||
|
## Additional resources
|
||||||
|
|
||||||
|
+ [GNUpdf - Introduction to PDF](http://gnupdf.org/Introduction_to_PDF)
|
49
examples/helloworld/hello.js
Normal file
49
examples/helloworld/hello.js
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
//
|
||||||
|
// See README for overview
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Ajax GET request, for binary files
|
||||||
|
// (like jQuery's $.get(), but supports the binary type ArrayBuffer)
|
||||||
|
//
|
||||||
|
var ajaxGet = function(url, callback){
|
||||||
|
var xhr = new XMLHttpRequest();
|
||||||
|
xhr.open('GET', url);
|
||||||
|
xhr.mozResponseType = xhr.responseType = 'arraybuffer';
|
||||||
|
xhr.expected = (document.URL.indexOf('file:') === 0) ? 0 : 200;
|
||||||
|
xhr.onreadystatechange = function() {
|
||||||
|
if (xhr.readyState === 4 && xhr.status === xhr.expected) {
|
||||||
|
var data = (xhr.mozResponseArrayBuffer || xhr.mozResponse ||
|
||||||
|
xhr.responseArrayBuffer || xhr.response);
|
||||||
|
|
||||||
|
callback(data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
xhr.send(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// This is where the fun happens
|
||||||
|
//
|
||||||
|
ajaxGet('helloworld.pdf', function(data){
|
||||||
|
//
|
||||||
|
// Instantiate PDFDoc with PDF data
|
||||||
|
//
|
||||||
|
var pdf = new PDFDoc(new Stream(data));
|
||||||
|
var page = pdf.getPage(1);
|
||||||
|
var scale = 1.5;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Prepare canvas using PDF page dimensions
|
||||||
|
//
|
||||||
|
var canvas = document.getElementById('the-canvas');
|
||||||
|
var context = canvas.getContext('2d');
|
||||||
|
canvas.height = page.height * scale;
|
||||||
|
canvas.width = page.width * scale;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Render PDF page into canvas context
|
||||||
|
//
|
||||||
|
page.startRendering(context);
|
||||||
|
});
|
68
examples/helloworld/helloworld.pdf
Normal file
68
examples/helloworld/helloworld.pdf
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
%PDF-1.7
|
||||||
|
|
||||||
|
1 0 obj % entry point
|
||||||
|
<<
|
||||||
|
/Type /Catalog
|
||||||
|
/Pages 2 0 R
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
2 0 obj
|
||||||
|
<<
|
||||||
|
/Type /Pages
|
||||||
|
/MediaBox [ 0 0 200 200 ]
|
||||||
|
/Count 1
|
||||||
|
/Kids [ 3 0 R ]
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
3 0 obj
|
||||||
|
<<
|
||||||
|
/Type /Page
|
||||||
|
/Parent 2 0 R
|
||||||
|
/Resources <<
|
||||||
|
/Font <<
|
||||||
|
/F1 4 0 R
|
||||||
|
>>
|
||||||
|
>>
|
||||||
|
/Contents 5 0 R
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
4 0 obj
|
||||||
|
<<
|
||||||
|
/Type /Font
|
||||||
|
/Subtype /Type1
|
||||||
|
/BaseFont /Times-Roman
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
5 0 obj % page content
|
||||||
|
<<
|
||||||
|
/Length 44
|
||||||
|
>>
|
||||||
|
stream
|
||||||
|
BT
|
||||||
|
70 50 TD
|
||||||
|
/F1 12 Tf
|
||||||
|
(Hello, world!) Tj
|
||||||
|
ET
|
||||||
|
endstream
|
||||||
|
endobj
|
||||||
|
|
||||||
|
xref
|
||||||
|
0 6
|
||||||
|
0000000000 65535 f
|
||||||
|
0000000010 00000 n
|
||||||
|
0000000079 00000 n
|
||||||
|
0000000173 00000 n
|
||||||
|
0000000301 00000 n
|
||||||
|
0000000380 00000 n
|
||||||
|
trailer
|
||||||
|
<<
|
||||||
|
/Size 6
|
||||||
|
/Root 1 0 R
|
||||||
|
>>
|
||||||
|
startxref
|
||||||
|
492
|
||||||
|
%%EOF
|
18
examples/helloworld/index.html
Normal file
18
examples/helloworld/index.html
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<!-- PDF.js-specific -->
|
||||||
|
<script type="text/javascript" src="../../pdf.js"></script>
|
||||||
|
<script type="text/javascript" src="../../metrics.js"></script>
|
||||||
|
<script type="text/javascript" src="../../fonts.js"></script>
|
||||||
|
<script type="text/javascript" src="../../glyphlist.js"></script>
|
||||||
|
|
||||||
|
<script type="text/javascript" src="hello.js"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<canvas id="the-canvas" style="border:1px solid black;"/>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
247
fonts.js
Executable file → Normal file
247
fonts.js
Executable file → Normal file
@ -12,6 +12,10 @@ var kMaxWaitForFontFace = 1000;
|
|||||||
// Unicode Private Use Area
|
// Unicode Private Use Area
|
||||||
var kCmapGlyphOffset = 0xE000;
|
var kCmapGlyphOffset = 0xE000;
|
||||||
|
|
||||||
|
// PDF Glyph Space Units are one Thousandth of a TextSpace Unit
|
||||||
|
// except for Type 3 fonts
|
||||||
|
var kPDFGlyphSpaceUnits = 1000;
|
||||||
|
|
||||||
// Until hinting is fully supported this constant can be used
|
// Until hinting is fully supported this constant can be used
|
||||||
var kHintingEnabled = false;
|
var kHintingEnabled = false;
|
||||||
|
|
||||||
@ -436,6 +440,7 @@ var Font = (function Font() {
|
|||||||
// name ArialBlack for example will be replaced by Helvetica.
|
// name ArialBlack for example will be replaced by Helvetica.
|
||||||
this.black = (name.search(/Black/g) != -1);
|
this.black = (name.search(/Black/g) != -1);
|
||||||
|
|
||||||
|
this.defaultWidth = properties.defaultWidth;
|
||||||
this.loadedName = fontName.split('-')[0];
|
this.loadedName = fontName.split('-')[0];
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
return;
|
return;
|
||||||
@ -472,6 +477,7 @@ var Font = (function Font() {
|
|||||||
this.data = data;
|
this.data = data;
|
||||||
this.type = properties.type;
|
this.type = properties.type;
|
||||||
this.textMatrix = properties.textMatrix;
|
this.textMatrix = properties.textMatrix;
|
||||||
|
this.defaultWidth = properties.defaultWidth;
|
||||||
this.loadedName = getUniqueName();
|
this.loadedName = getUniqueName();
|
||||||
this.composite = properties.composite;
|
this.composite = properties.composite;
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
@ -534,6 +540,10 @@ var Font = (function Font() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function createOpenTypeHeader(sfnt, file, numTables) {
|
function createOpenTypeHeader(sfnt, file, numTables) {
|
||||||
|
// Windows hates the Mac TrueType sfnt version number
|
||||||
|
if (sfnt == 'true')
|
||||||
|
sfnt = string32(0x00010000);
|
||||||
|
|
||||||
// sfnt version (4 bytes)
|
// sfnt version (4 bytes)
|
||||||
var header = sfnt;
|
var header = sfnt;
|
||||||
|
|
||||||
@ -587,19 +597,24 @@ var Font = (function Font() {
|
|||||||
var codes = [];
|
var codes = [];
|
||||||
var length = glyphs.length;
|
var length = glyphs.length;
|
||||||
for (var n = 0; n < length; ++n)
|
for (var n = 0; n < length; ++n)
|
||||||
codes.push(String.fromCharCode(glyphs[n].unicode));
|
codes.push({ unicode: glyphs[n].unicode, code: n });
|
||||||
codes.sort();
|
codes.sort(function(a, b) {
|
||||||
|
return a.unicode - b.unicode;
|
||||||
|
});
|
||||||
|
|
||||||
// Split the sorted codes into ranges.
|
// Split the sorted codes into ranges.
|
||||||
var ranges = [];
|
var ranges = [];
|
||||||
for (var n = 0; n < length; ) {
|
for (var n = 0; n < length; ) {
|
||||||
var start = codes[n++].charCodeAt(0);
|
var start = codes[n].unicode;
|
||||||
|
var startCode = codes[n].code;
|
||||||
|
++n;
|
||||||
var end = start;
|
var end = start;
|
||||||
while (n < length && end + 1 == codes[n].charCodeAt(0)) {
|
while (n < length && end + 1 == codes[n].unicode) {
|
||||||
++end;
|
++end;
|
||||||
++n;
|
++n;
|
||||||
}
|
}
|
||||||
ranges.push([start, end]);
|
var endCode = codes[n - 1].code;
|
||||||
|
ranges.push([start, end, startCode, endCode]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ranges;
|
return ranges;
|
||||||
@ -628,22 +643,39 @@ var Font = (function Font() {
|
|||||||
var idRangeOffsets = '';
|
var idRangeOffsets = '';
|
||||||
var glyphsIds = '';
|
var glyphsIds = '';
|
||||||
var bias = 0;
|
var bias = 0;
|
||||||
for (var i = 0; i < segCount - 1; i++) {
|
|
||||||
var range = ranges[i];
|
|
||||||
var start = range[0];
|
|
||||||
var end = range[1];
|
|
||||||
var offset = (segCount - i) * 2 + bias * 2;
|
|
||||||
bias += (end - start + 1);
|
|
||||||
|
|
||||||
startCount += string16(start);
|
if (deltas) {
|
||||||
endCount += string16(end);
|
for (var i = 0; i < segCount - 1; i++) {
|
||||||
idDeltas += string16(0);
|
var range = ranges[i];
|
||||||
idRangeOffsets += string16(offset);
|
var start = range[0];
|
||||||
|
var end = range[1];
|
||||||
|
var offset = (segCount - i) * 2 + bias * 2;
|
||||||
|
bias += (end - start + 1);
|
||||||
|
|
||||||
|
startCount += string16(start);
|
||||||
|
endCount += string16(end);
|
||||||
|
idDeltas += string16(0);
|
||||||
|
idRangeOffsets += string16(offset);
|
||||||
|
|
||||||
|
var startCode = range[2];
|
||||||
|
var endCode = range[3];
|
||||||
|
for (var j = startCode; j <= endCode; ++j)
|
||||||
|
glyphsIds += string16(deltas[j]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (var i = 0; i < segCount - 1; i++) {
|
||||||
|
var range = ranges[i];
|
||||||
|
var start = range[0];
|
||||||
|
var end = range[1];
|
||||||
|
var startCode = range[2];
|
||||||
|
|
||||||
|
startCount += string16(start);
|
||||||
|
endCount += string16(end);
|
||||||
|
idDeltas += string16((startCode - start + 1) & 0xFFFF);
|
||||||
|
idRangeOffsets += string16(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < glyphs.length; i++)
|
|
||||||
glyphsIds += string16(deltas ? deltas[i] : i + 1);
|
|
||||||
|
|
||||||
endCount += '\xFF\xFF';
|
endCount += '\xFF\xFF';
|
||||||
startCount += '\xFF\xFF';
|
startCount += '\xFF\xFF';
|
||||||
idDeltas += '\x00\x01';
|
idDeltas += '\x00\x01';
|
||||||
@ -663,7 +695,9 @@ var Font = (function Font() {
|
|||||||
format314);
|
format314);
|
||||||
};
|
};
|
||||||
|
|
||||||
function createOS2Table(properties) {
|
function createOS2Table(properties, override) {
|
||||||
|
var override = override || {};
|
||||||
|
|
||||||
var ulUnicodeRange1 = 0;
|
var ulUnicodeRange1 = 0;
|
||||||
var ulUnicodeRange2 = 0;
|
var ulUnicodeRange2 = 0;
|
||||||
var ulUnicodeRange3 = 0;
|
var ulUnicodeRange3 = 0;
|
||||||
@ -694,6 +728,24 @@ var Font = (function Font() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var unitsPerEm = override.unitsPerEm || kPDFGlyphSpaceUnits;
|
||||||
|
var typoAscent = override.ascent || properties.ascent;
|
||||||
|
var typoDescent = override.descent || properties.descent;
|
||||||
|
var winAscent = override.yMax || typoAscent;
|
||||||
|
var winDescent = -override.yMin || -typoDescent;
|
||||||
|
|
||||||
|
// if there is a units per em value but no other override
|
||||||
|
// then scale the calculated ascent
|
||||||
|
if (unitsPerEm != kPDFGlyphSpaceUnits &&
|
||||||
|
'undefined' == typeof(override.ascent)) {
|
||||||
|
// if the font units differ to the PDF glyph space units
|
||||||
|
// then scale up the values
|
||||||
|
typoAscent = Math.round(typoAscent * unitsPerEm / kPDFGlyphSpaceUnits);
|
||||||
|
typoDescent = Math.round(typoDescent * unitsPerEm / kPDFGlyphSpaceUnits);
|
||||||
|
winAscent = typoAscent;
|
||||||
|
winDescent = -typoDescent;
|
||||||
|
}
|
||||||
|
|
||||||
return '\x00\x03' + // version
|
return '\x00\x03' + // version
|
||||||
'\x02\x24' + // xAvgCharWidth
|
'\x02\x24' + // xAvgCharWidth
|
||||||
'\x01\xF4' + // usWeightClass
|
'\x01\xF4' + // usWeightClass
|
||||||
@ -722,11 +774,11 @@ var Font = (function Font() {
|
|||||||
string16(firstCharIndex ||
|
string16(firstCharIndex ||
|
||||||
properties.firstChar) + // usFirstCharIndex
|
properties.firstChar) + // usFirstCharIndex
|
||||||
string16(lastCharIndex || properties.lastChar) + // usLastCharIndex
|
string16(lastCharIndex || properties.lastChar) + // usLastCharIndex
|
||||||
string16(properties.ascent) + // sTypoAscender
|
string16(typoAscent) + // sTypoAscender
|
||||||
string16(properties.descent) + // sTypoDescender
|
string16(typoDescent) + // sTypoDescender
|
||||||
'\x00\x64' + // sTypoLineGap (7%-10% of the unitsPerEM value)
|
'\x00\x64' + // sTypoLineGap (7%-10% of the unitsPerEM value)
|
||||||
string16(properties.ascent) + // usWinAscent
|
string16(winAscent) + // usWinAscent
|
||||||
string16(-properties.descent) + // usWinDescent
|
string16(winDescent) + // usWinDescent
|
||||||
'\x00\x00\x00\x00' + // ulCodePageRange1 (Bits 0-31)
|
'\x00\x00\x00\x00' + // ulCodePageRange1 (Bits 0-31)
|
||||||
'\x00\x00\x00\x00' + // ulCodePageRange2 (Bits 32-63)
|
'\x00\x00\x00\x00' + // ulCodePageRange2 (Bits 32-63)
|
||||||
string16(properties.xHeight) + // sxHeight
|
string16(properties.xHeight) + // sxHeight
|
||||||
@ -833,9 +885,11 @@ var Font = (function Font() {
|
|||||||
var data = file.getBytes(length);
|
var data = file.getBytes(length);
|
||||||
file.pos = previousPosition;
|
file.pos = previousPosition;
|
||||||
|
|
||||||
if (tag == 'head')
|
if (tag == 'head') {
|
||||||
// clearing checksum adjustment
|
// clearing checksum adjustment
|
||||||
data[8] = data[9] = data[10] = data[11] = 0;
|
data[8] = data[9] = data[10] = data[11] = 0;
|
||||||
|
data[17] |= 0x20; //Set font optimized for cleartype flag
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
tag: tag,
|
tag: tag,
|
||||||
@ -1001,6 +1055,49 @@ var Font = (function Font() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function sanitizeGlyphLocations(loca, glyf, numGlyphs,
|
||||||
|
isGlyphLocationsLong) {
|
||||||
|
var itemSize, itemDecode, itemEncode;
|
||||||
|
if (isGlyphLocationsLong) {
|
||||||
|
itemSize = 4;
|
||||||
|
itemDecode = function(data, offset) {
|
||||||
|
return (data[offset] << 24) | (data[offset + 1] << 16) |
|
||||||
|
(data[offset + 2] << 8) | data[offset + 3];
|
||||||
|
};
|
||||||
|
itemEncode = function(data, offset, value) {
|
||||||
|
data[offset] = (value >>> 24) & 0xFF;
|
||||||
|
data[offset + 1] = (value >> 16) & 0xFF;
|
||||||
|
data[offset + 2] = (value >> 8) & 0xFF;
|
||||||
|
data[offset + 3] = value & 0xFF;
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
itemSize = 2;
|
||||||
|
itemDecode = function(data, offset) {
|
||||||
|
return (data[offset] << 9) | (data[offset + 1] << 1);
|
||||||
|
};
|
||||||
|
itemEncode = function(data, offset, value) {
|
||||||
|
data[offset] = (value >> 9) & 0xFF;
|
||||||
|
data[offset + 1] = (value >> 1) & 0xFF;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
var locaData = loca.data;
|
||||||
|
var startOffset = itemDecode(locaData, 0);
|
||||||
|
var firstOffset = itemDecode(locaData, itemSize);
|
||||||
|
if (firstOffset - startOffset < 12 || startOffset > 0) {
|
||||||
|
// removing first glyph
|
||||||
|
glyf.data = glyf.data.subarray(firstOffset);
|
||||||
|
glyf.length -= firstOffset;
|
||||||
|
|
||||||
|
itemEncode(locaData, 0, 0);
|
||||||
|
var i, pos = itemSize;
|
||||||
|
for (i = 1; i <= numGlyphs; ++i) {
|
||||||
|
itemEncode(locaData, pos,
|
||||||
|
itemDecode(locaData, pos) - firstOffset);
|
||||||
|
pos += itemSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check that required tables are present
|
// Check that required tables are present
|
||||||
var requiredTables = ['OS/2', 'cmap', 'head', 'hhea',
|
var requiredTables = ['OS/2', 'cmap', 'head', 'hhea',
|
||||||
'hmtx', 'maxp', 'name', 'post'];
|
'hmtx', 'maxp', 'name', 'post'];
|
||||||
@ -1008,7 +1105,7 @@ var Font = (function Font() {
|
|||||||
var header = readOpenTypeHeader(font);
|
var header = readOpenTypeHeader(font);
|
||||||
var numTables = header.numTables;
|
var numTables = header.numTables;
|
||||||
|
|
||||||
var cmap, maxp, hhea, hmtx, vhea, vmtx;
|
var cmap, maxp, hhea, hmtx, vhea, vmtx, head, loca, glyf;
|
||||||
var tables = [];
|
var tables = [];
|
||||||
for (var i = 0; i < numTables; i++) {
|
for (var i = 0; i < numTables; i++) {
|
||||||
var table = readTableEntry(font);
|
var table = readTableEntry(font);
|
||||||
@ -1022,6 +1119,8 @@ var Font = (function Font() {
|
|||||||
hhea = table;
|
hhea = table;
|
||||||
else if (table.tag == 'hmtx')
|
else if (table.tag == 'hmtx')
|
||||||
hmtx = table;
|
hmtx = table;
|
||||||
|
else if (table.tag == 'head')
|
||||||
|
head = table;
|
||||||
|
|
||||||
requiredTables.splice(index, 1);
|
requiredTables.splice(index, 1);
|
||||||
} else {
|
} else {
|
||||||
@ -1029,6 +1128,10 @@ var Font = (function Font() {
|
|||||||
vmtx = table;
|
vmtx = table;
|
||||||
else if (table.tag == 'vhea')
|
else if (table.tag == 'vhea')
|
||||||
vhea = table;
|
vhea = table;
|
||||||
|
else if (table.tag == 'loca')
|
||||||
|
loca = table;
|
||||||
|
else if (table.tag == 'glyf')
|
||||||
|
glyf = table;
|
||||||
}
|
}
|
||||||
tables.push(table);
|
tables.push(table);
|
||||||
}
|
}
|
||||||
@ -1048,9 +1151,19 @@ var Font = (function Font() {
|
|||||||
createOpenTypeHeader(header.version, ttf, numTables);
|
createOpenTypeHeader(header.version, ttf, numTables);
|
||||||
|
|
||||||
if (requiredTables.indexOf('OS/2') != -1) {
|
if (requiredTables.indexOf('OS/2') != -1) {
|
||||||
|
// extract some more font properties from the OpenType head and
|
||||||
|
// hhea tables; yMin and descent value are always negative
|
||||||
|
var override = {
|
||||||
|
unitsPerEm: int16([head.data[18], head.data[19]]),
|
||||||
|
yMax: int16([head.data[42], head.data[43]]),
|
||||||
|
yMin: int16([head.data[38], head.data[39]]) - 0x10000,
|
||||||
|
ascent: int16([hhea.data[4], hhea.data[5]]),
|
||||||
|
descent: int16([hhea.data[6], hhea.data[7]]) - 0x10000
|
||||||
|
};
|
||||||
|
|
||||||
tables.push({
|
tables.push({
|
||||||
tag: 'OS/2',
|
tag: 'OS/2',
|
||||||
data: stringToArray(createOS2Table(properties))
|
data: stringToArray(createOS2Table(properties, override))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1063,6 +1176,11 @@ var Font = (function Font() {
|
|||||||
sanitizeMetrics(font, hhea, hmtx, numGlyphs);
|
sanitizeMetrics(font, hhea, hmtx, numGlyphs);
|
||||||
sanitizeMetrics(font, vhea, vmtx, numGlyphs);
|
sanitizeMetrics(font, vhea, vmtx, numGlyphs);
|
||||||
|
|
||||||
|
if (head && loca && glyf) {
|
||||||
|
var isGlyphLocationsLong = int16([head.data[50], head.data[51]]);
|
||||||
|
sanitizeGlyphLocations(loca, glyf, numGlyphs, isGlyphLocationsLong);
|
||||||
|
}
|
||||||
|
|
||||||
// Sanitizer reduces the glyph advanceWidth to the maxAdvanceWidth
|
// Sanitizer reduces the glyph advanceWidth to the maxAdvanceWidth
|
||||||
// Sometimes it's 0. That needs to be fixed
|
// Sometimes it's 0. That needs to be fixed
|
||||||
if (hhea.data[10] == 0 && hhea.data[11] == 0) {
|
if (hhea.data[10] == 0 && hhea.data[11] == 0) {
|
||||||
@ -1087,7 +1205,7 @@ var Font = (function Font() {
|
|||||||
tables.push(cmap);
|
tables.push(cmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
var encoding = properties.encoding;
|
var encoding = properties.encoding, i;
|
||||||
if (!encoding[0]) {
|
if (!encoding[0]) {
|
||||||
// the font is directly characters to glyphs with no encoding
|
// the font is directly characters to glyphs with no encoding
|
||||||
// so create an identity encoding
|
// so create an identity encoding
|
||||||
@ -1095,18 +1213,28 @@ var Font = (function Font() {
|
|||||||
for (i = 0; i < numGlyphs; i++) {
|
for (i = 0; i < numGlyphs; i++) {
|
||||||
var width = widths[i];
|
var width = widths[i];
|
||||||
encoding[i] = {
|
encoding[i] = {
|
||||||
unicode: i + kCmapGlyphOffset,
|
unicode: i <= 0x1f || (i >= 127 && i <= 255) ?
|
||||||
|
i + kCmapGlyphOffset : i,
|
||||||
width: IsNum(width) ? width : properties.defaultWidth
|
width: IsNum(width) ? width : properties.defaultWidth
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (var code in encoding)
|
for (i in encoding) {
|
||||||
encoding[code].unicode += kCmapGlyphOffset;
|
if (encoding.hasOwnProperty(i)) {
|
||||||
|
var unicode = encoding[i].unicode;
|
||||||
|
if (unicode <= 0x1f || (unicode >= 127 && unicode <= 255))
|
||||||
|
encoding[i].unicode = unicode += kCmapGlyphOffset;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var glyphs = [];
|
var glyphs = [];
|
||||||
for (var i = 1; i < numGlyphs; i++)
|
for (i = 1; i < numGlyphs; i++) {
|
||||||
glyphs.push({ unicode: i + kCmapGlyphOffset });
|
glyphs.push({
|
||||||
|
unicode: i <= 0x1f || (i >= 127 && i <= 255) ?
|
||||||
|
i + kCmapGlyphOffset : i
|
||||||
|
});
|
||||||
|
}
|
||||||
cmap.data = createCMapTable(glyphs);
|
cmap.data = createCMapTable(glyphs);
|
||||||
} else {
|
} else {
|
||||||
replaceCMapTable(cmap, font, properties);
|
replaceCMapTable(cmap, font, properties);
|
||||||
@ -1292,7 +1420,8 @@ var Font = (function Font() {
|
|||||||
var rule = "@font-face { font-family:'" + fontName + "';src:" + url + '}';
|
var rule = "@font-face { font-family:'" + fontName + "';src:" + url + '}';
|
||||||
var styleSheet = document.styleSheets[0];
|
var styleSheet = document.styleSheets[0];
|
||||||
if (!styleSheet) {
|
if (!styleSheet) {
|
||||||
document.documentElement.firstChild.appendChild( document.createElement('style') );
|
document.documentElement.firstChild.appendChild(
|
||||||
|
document.createElement('style'));
|
||||||
styleSheet = document.styleSheets[0];
|
styleSheet = document.styleSheets[0];
|
||||||
}
|
}
|
||||||
styleSheet.insertRule(rule, styleSheet.cssRules.length);
|
styleSheet.insertRule(rule, styleSheet.cssRules.length);
|
||||||
@ -1300,15 +1429,15 @@ var Font = (function Font() {
|
|||||||
return rule;
|
return rule;
|
||||||
},
|
},
|
||||||
|
|
||||||
charsToUnicode: function fonts_chars2Unicode(chars) {
|
charsToGlyphs: function fonts_chars2Glyphs(chars) {
|
||||||
var charsCache = this.charsCache;
|
var charsCache = this.charsCache;
|
||||||
var str;
|
var glyphs;
|
||||||
|
|
||||||
// if we translated this string before, just grab it from the cache
|
// if we translated this string before, just grab it from the cache
|
||||||
if (charsCache) {
|
if (charsCache) {
|
||||||
str = charsCache[chars];
|
glyphs = charsCache[chars];
|
||||||
if (str)
|
if (glyphs)
|
||||||
return str;
|
return glyphs;
|
||||||
}
|
}
|
||||||
|
|
||||||
// lazily create the translation cache
|
// lazily create the translation cache
|
||||||
@ -1319,7 +1448,8 @@ var Font = (function Font() {
|
|||||||
var encoding = this.encoding;
|
var encoding = this.encoding;
|
||||||
if (!encoding)
|
if (!encoding)
|
||||||
return chars;
|
return chars;
|
||||||
str = '';
|
|
||||||
|
glyphs = [];
|
||||||
|
|
||||||
if (this.composite) {
|
if (this.composite) {
|
||||||
// composite fonts have multi-byte strings convert the string from
|
// composite fonts have multi-byte strings convert the string from
|
||||||
@ -1330,38 +1460,39 @@ var Font = (function Font() {
|
|||||||
// loop should never end on the last byte
|
// loop should never end on the last byte
|
||||||
for (var i = 0; i < length; i++) {
|
for (var i = 0; i < length; i++) {
|
||||||
var charcode = int16([chars.charCodeAt(i++), chars.charCodeAt(i)]);
|
var charcode = int16([chars.charCodeAt(i++), chars.charCodeAt(i)]);
|
||||||
var unicode = encoding[charcode];
|
var glyph = encoding[charcode];
|
||||||
if ('undefined' == typeof(unicode)) {
|
if ('undefined' == typeof(glyph)) {
|
||||||
warn('Unencoded charcode ' + charcode);
|
warn('Unencoded charcode ' + charcode);
|
||||||
unicode = charcode;
|
glyph = {
|
||||||
} else {
|
unicode: charcode,
|
||||||
unicode = unicode.unicode;
|
width: this.defaultWidth
|
||||||
|
};
|
||||||
}
|
}
|
||||||
str += String.fromCharCode(unicode);
|
glyphs.push(glyph);
|
||||||
|
// placing null after each word break charcode (ASCII SPACE)
|
||||||
|
if (charcode == 0x20)
|
||||||
|
glyphs.push(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for (var i = 0; i < chars.length; ++i) {
|
for (var i = 0; i < chars.length; ++i) {
|
||||||
var charcode = chars.charCodeAt(i);
|
var charcode = chars.charCodeAt(i);
|
||||||
var unicode = encoding[charcode];
|
var glyph = encoding[charcode];
|
||||||
if ('undefined' == typeof(unicode)) {
|
if ('undefined' == typeof(glyph)) {
|
||||||
warn('Unencoded charcode ' + charcode);
|
warn('Unencoded charcode ' + charcode);
|
||||||
unicode = charcode;
|
glyph = {
|
||||||
} else {
|
unicode: charcode,
|
||||||
unicode = unicode.unicode;
|
width: this.defaultWidth
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
glyphs.push(glyph);
|
||||||
// Handle surrogate pairs
|
if (charcode == 0x20)
|
||||||
if (unicode > 0xFFFF) {
|
glyphs.push(null);
|
||||||
str += String.fromCharCode(unicode & 0xFFFF);
|
|
||||||
unicode >>= 16;
|
|
||||||
}
|
|
||||||
str += String.fromCharCode(unicode);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enter the translated string into the cache
|
// Enter the translated string into the cache
|
||||||
return (charsCache[chars] = str);
|
return (charsCache[chars] = glyphs);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
798
pdf.js
798
pdf.js
@ -799,59 +799,58 @@ var PredictorStream = (function() {
|
|||||||
prevRow = currentRow;
|
prevRow = currentRow;
|
||||||
|
|
||||||
switch (predictor) {
|
switch (predictor) {
|
||||||
case 0:
|
case 0:
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
for (var i = 0; i < pixBytes; ++i)
|
for (var i = 0; i < pixBytes; ++i)
|
||||||
currentRow[i] = rawBytes[i];
|
currentRow[i] = rawBytes[i];
|
||||||
for (; i < rowBytes; ++i)
|
for (; i < rowBytes; ++i)
|
||||||
currentRow[i] = (currentRow[i - pixBytes] + rawBytes[i]) & 0xFF;
|
currentRow[i] = (currentRow[i - pixBytes] + rawBytes[i]) & 0xFF;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
for (var i = 0; i < rowBytes; ++i)
|
for (var i = 0; i < rowBytes; ++i)
|
||||||
currentRow[i] = (prevRow[i] + rawBytes[i]) & 0xFF;
|
currentRow[i] = (prevRow[i] + rawBytes[i]) & 0xFF;
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
for (var i = 0; i < pixBytes; ++i)
|
for (var i = 0; i < pixBytes; ++i)
|
||||||
currentRow[i] = (prevRow[i] >> 1) + rawBytes[i];
|
currentRow[i] = (prevRow[i] >> 1) + rawBytes[i];
|
||||||
for (; i < rowBytes; ++i) {
|
for (; i < rowBytes; ++i) {
|
||||||
currentRow[i] = (((prevRow[i] + currentRow[i - pixBytes]) >> 1) +
|
currentRow[i] = (((prevRow[i] + currentRow[i - pixBytes]) >> 1) +
|
||||||
rawBytes[i]) & 0xFF;
|
rawBytes[i]) & 0xFF;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
// we need to save the up left pixels values. the simplest way
|
// we need to save the up left pixels values. the simplest way
|
||||||
// is to create a new buffer
|
// is to create a new buffer
|
||||||
for (var i = 0; i < pixBytes; ++i)
|
for (var i = 0; i < pixBytes; ++i)
|
||||||
currentRow[i] = rawBytes[i];
|
currentRow[i] = rawBytes[i];
|
||||||
for (; i < rowBytes; ++i) {
|
for (; i < rowBytes; ++i) {
|
||||||
var up = prevRow[i];
|
var up = prevRow[i];
|
||||||
var upLeft = prevRow[i - pixBytes];
|
var upLeft = prevRow[i - pixBytes];
|
||||||
var left = currentRow[i - pixBytes];
|
var left = currentRow[i - pixBytes];
|
||||||
var p = left + up - upLeft;
|
var p = left + up - upLeft;
|
||||||
|
|
||||||
var pa = p - left;
|
var pa = p - left;
|
||||||
if (pa < 0)
|
if (pa < 0)
|
||||||
pa = -pa;
|
pa = -pa;
|
||||||
var pb = p - up;
|
var pb = p - up;
|
||||||
if (pb < 0)
|
if (pb < 0)
|
||||||
pb = -pb;
|
pb = -pb;
|
||||||
var pc = p - upLeft;
|
var pc = p - upLeft;
|
||||||
if (pc < 0)
|
if (pc < 0)
|
||||||
pc = -pc;
|
pc = -pc;
|
||||||
|
|
||||||
var c = rawBytes[i];
|
var c = rawBytes[i];
|
||||||
if (pa <= pb && pa <= pc)
|
if (pa <= pb && pa <= pc)
|
||||||
currentRow[i] = left + c;
|
currentRow[i] = left + c;
|
||||||
else if (pb <= pc)
|
else if (pb <= pc)
|
||||||
currentRow[i] = up + c;
|
currentRow[i] = up + c;
|
||||||
else
|
else
|
||||||
currentRow[i] = upLeft + c;
|
currentRow[i] = upLeft + c;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
error('Unsupported predictor: ' + predictor);
|
error('Unsupported predictor: ' + predictor);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
this.bufferLength += rowBytes;
|
this.bufferLength += rowBytes;
|
||||||
};
|
};
|
||||||
@ -1695,129 +1694,128 @@ var CCITTFaxStream = (function() {
|
|||||||
while (codingLine[this.codingPos] < columns) {
|
while (codingLine[this.codingPos] < columns) {
|
||||||
code1 = this.getTwoDimCode();
|
code1 = this.getTwoDimCode();
|
||||||
switch (code1) {
|
switch (code1) {
|
||||||
case twoDimPass:
|
case twoDimPass:
|
||||||
this.addPixels(refLine[refPos + 1], blackPixels);
|
this.addPixels(refLine[refPos + 1], blackPixels);
|
||||||
if (refLine[refPos + 1] < columns)
|
if (refLine[refPos + 1] < columns)
|
||||||
refPos += 2;
|
|
||||||
break;
|
|
||||||
case twoDimHoriz:
|
|
||||||
code1 = code2 = 0;
|
|
||||||
if (blackPixels) {
|
|
||||||
do {
|
|
||||||
code1 += (code3 = this.getBlackCode());
|
|
||||||
} while (code3 >= 64);
|
|
||||||
do {
|
|
||||||
code2 += (code3 = this.getWhiteCode());
|
|
||||||
} while (code3 >= 64);
|
|
||||||
} else {
|
|
||||||
do {
|
|
||||||
code1 += (code3 = this.getWhiteCode());
|
|
||||||
} while (code3 >= 64);
|
|
||||||
do {
|
|
||||||
code2 += (code3 = this.getBlackCode());
|
|
||||||
} while (code3 >= 64);
|
|
||||||
}
|
|
||||||
this.addPixels(codingLine[this.codingPos] +
|
|
||||||
code1, blackPixels);
|
|
||||||
if (codingLine[this.codingPos] < columns) {
|
|
||||||
this.addPixels(codingLine[this.codingPos] + code2,
|
|
||||||
blackPixels ^ 1);
|
|
||||||
}
|
|
||||||
while (refLine[refPos] <= codingLine[this.codingPos] &&
|
|
||||||
refLine[refPos] < columns) {
|
|
||||||
refPos += 2;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case twoDimVertR3:
|
|
||||||
this.addPixels(refLine[refPos] + 3, blackPixels);
|
|
||||||
blackPixels ^= 1;
|
|
||||||
if (codingLine[this.codingPos] < columns) {
|
|
||||||
++refPos;
|
|
||||||
while (refLine[refPos] <= codingLine[this.codingPos] &&
|
|
||||||
refLine[refPos] < columns)
|
|
||||||
refPos += 2;
|
refPos += 2;
|
||||||
}
|
break;
|
||||||
break;
|
case twoDimHoriz:
|
||||||
case twoDimVertR2:
|
code1 = code2 = 0;
|
||||||
this.addPixels(refLine[refPos] + 2, blackPixels);
|
if (blackPixels) {
|
||||||
blackPixels ^= 1;
|
do {
|
||||||
if (codingLine[this.codingPos] < columns) {
|
code1 += (code3 = this.getBlackCode());
|
||||||
++refPos;
|
} while (code3 >= 64);
|
||||||
|
do {
|
||||||
|
code2 += (code3 = this.getWhiteCode());
|
||||||
|
} while (code3 >= 64);
|
||||||
|
} else {
|
||||||
|
do {
|
||||||
|
code1 += (code3 = this.getWhiteCode());
|
||||||
|
} while (code3 >= 64);
|
||||||
|
do {
|
||||||
|
code2 += (code3 = this.getBlackCode());
|
||||||
|
} while (code3 >= 64);
|
||||||
|
}
|
||||||
|
this.addPixels(codingLine[this.codingPos] +
|
||||||
|
code1, blackPixels);
|
||||||
|
if (codingLine[this.codingPos] < columns) {
|
||||||
|
this.addPixels(codingLine[this.codingPos] + code2,
|
||||||
|
blackPixels ^ 1);
|
||||||
|
}
|
||||||
while (refLine[refPos] <= codingLine[this.codingPos] &&
|
while (refLine[refPos] <= codingLine[this.codingPos] &&
|
||||||
refLine[refPos] < columns) {
|
refLine[refPos] < columns) {
|
||||||
refPos += 2;
|
refPos += 2;
|
||||||
}
|
}
|
||||||
}
|
break;
|
||||||
break;
|
case twoDimVertR3:
|
||||||
case twoDimVertR1:
|
this.addPixels(refLine[refPos] + 3, blackPixels);
|
||||||
this.addPixels(refLine[refPos] + 1, blackPixels);
|
blackPixels ^= 1;
|
||||||
blackPixels ^= 1;
|
if (codingLine[this.codingPos] < columns) {
|
||||||
if (codingLine[this.codingPos] < columns) {
|
|
||||||
++refPos;
|
|
||||||
while (refLine[refPos] <= codingLine[this.codingPos] &&
|
|
||||||
refLine[refPos] < columns)
|
|
||||||
refPos += 2;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case twoDimVert0:
|
|
||||||
this.addPixels(refLine[refPos], blackPixels);
|
|
||||||
blackPixels ^= 1;
|
|
||||||
if (codingLine[this.codingPos] < columns) {
|
|
||||||
++refPos;
|
|
||||||
while (refLine[refPos] <= codingLine[this.codingPos] &&
|
|
||||||
refLine[refPos] < columns)
|
|
||||||
refPos += 2;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case twoDimVertL3:
|
|
||||||
this.addPixelsNeg(refLine[refPos] - 3, blackPixels);
|
|
||||||
blackPixels ^= 1;
|
|
||||||
if (codingLine[this.codingPos] < columns) {
|
|
||||||
if (refPos > 0)
|
|
||||||
--refPos;
|
|
||||||
else
|
|
||||||
++refPos;
|
++refPos;
|
||||||
while (refLine[refPos] <= codingLine[this.codingPos] &&
|
while (refLine[refPos] <= codingLine[this.codingPos] &&
|
||||||
refLine[refPos] < columns)
|
refLine[refPos] < columns)
|
||||||
refPos += 2;
|
refPos += 2;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case twoDimVertL2:
|
case twoDimVertR2:
|
||||||
this.addPixelsNeg(refLine[refPos] - 2, blackPixels);
|
this.addPixels(refLine[refPos] + 2, blackPixels);
|
||||||
blackPixels ^= 1;
|
blackPixels ^= 1;
|
||||||
if (codingLine[this.codingPos] < columns) {
|
if (codingLine[this.codingPos] < columns) {
|
||||||
if (refPos > 0)
|
|
||||||
--refPos;
|
|
||||||
else
|
|
||||||
++refPos;
|
++refPos;
|
||||||
while (refLine[refPos] <= codingLine[this.codingPos] &&
|
while (refLine[refPos] <= codingLine[this.codingPos] &&
|
||||||
refLine[refPos] < columns)
|
refLine[refPos] < columns) {
|
||||||
refPos += 2;
|
refPos += 2;
|
||||||
}
|
}
|
||||||
break;
|
}
|
||||||
case twoDimVertL1:
|
break;
|
||||||
this.addPixelsNeg(refLine[refPos] - 1, blackPixels);
|
case twoDimVertR1:
|
||||||
blackPixels ^= 1;
|
this.addPixels(refLine[refPos] + 1, blackPixels);
|
||||||
if (codingLine[this.codingPos] < columns) {
|
blackPixels ^= 1;
|
||||||
if (refPos > 0)
|
if (codingLine[this.codingPos] < columns) {
|
||||||
--refPos;
|
|
||||||
else
|
|
||||||
++refPos;
|
++refPos;
|
||||||
|
while (refLine[refPos] <= codingLine[this.codingPos] &&
|
||||||
|
refLine[refPos] < columns)
|
||||||
|
refPos += 2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case twoDimVert0:
|
||||||
|
this.addPixels(refLine[refPos], blackPixels);
|
||||||
|
blackPixels ^= 1;
|
||||||
|
if (codingLine[this.codingPos] < columns) {
|
||||||
|
++refPos;
|
||||||
|
while (refLine[refPos] <= codingLine[this.codingPos] &&
|
||||||
|
refLine[refPos] < columns)
|
||||||
|
refPos += 2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case twoDimVertL3:
|
||||||
|
this.addPixelsNeg(refLine[refPos] - 3, blackPixels);
|
||||||
|
blackPixels ^= 1;
|
||||||
|
if (codingLine[this.codingPos] < columns) {
|
||||||
|
if (refPos > 0)
|
||||||
|
--refPos;
|
||||||
|
else
|
||||||
|
++refPos;
|
||||||
|
while (refLine[refPos] <= codingLine[this.codingPos] &&
|
||||||
|
refLine[refPos] < columns)
|
||||||
|
refPos += 2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case twoDimVertL2:
|
||||||
|
this.addPixelsNeg(refLine[refPos] - 2, blackPixels);
|
||||||
|
blackPixels ^= 1;
|
||||||
|
if (codingLine[this.codingPos] < columns) {
|
||||||
|
if (refPos > 0)
|
||||||
|
--refPos;
|
||||||
|
else
|
||||||
|
++refPos;
|
||||||
|
while (refLine[refPos] <= codingLine[this.codingPos] &&
|
||||||
|
refLine[refPos] < columns)
|
||||||
|
refPos += 2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case twoDimVertL1:
|
||||||
|
this.addPixelsNeg(refLine[refPos] - 1, blackPixels);
|
||||||
|
blackPixels ^= 1;
|
||||||
|
if (codingLine[this.codingPos] < columns) {
|
||||||
|
if (refPos > 0)
|
||||||
|
--refPos;
|
||||||
|
else
|
||||||
|
++refPos;
|
||||||
|
|
||||||
while (refLine[refPos] <= codingLine[this.codingPos] &&
|
while (refLine[refPos] <= codingLine[this.codingPos] &&
|
||||||
refLine[refPos] < columns)
|
refLine[refPos] < columns)
|
||||||
refPos += 2;
|
refPos += 2;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EOF:
|
case EOF:
|
||||||
this.addPixels(columns, 0);
|
this.addPixels(columns, 0);
|
||||||
this.eof = true;
|
this.eof = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
warn('bad 2d code');
|
warn('bad 2d code');
|
||||||
this.addPixels(columns, 0);
|
this.addPixels(columns, 0);
|
||||||
this.err = true;
|
this.err = true;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -2488,79 +2486,77 @@ var Lexer = (function() {
|
|||||||
do {
|
do {
|
||||||
ch = stream.getChar();
|
ch = stream.getChar();
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
case undefined:
|
|
||||||
warn('Unterminated string');
|
|
||||||
done = true;
|
|
||||||
break;
|
|
||||||
case '(':
|
|
||||||
++numParen;
|
|
||||||
str += ch;
|
|
||||||
break;
|
|
||||||
case ')':
|
|
||||||
if (--numParen == 0) {
|
|
||||||
done = true;
|
|
||||||
} else {
|
|
||||||
str += ch;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case '\\':
|
|
||||||
ch = stream.getChar();
|
|
||||||
switch (ch) {
|
|
||||||
case undefined:
|
case undefined:
|
||||||
warn('Unterminated string');
|
warn('Unterminated string');
|
||||||
done = true;
|
done = true;
|
||||||
break;
|
break;
|
||||||
case 'n':
|
|
||||||
str += '\n';
|
|
||||||
break;
|
|
||||||
case 'r':
|
|
||||||
str += '\r';
|
|
||||||
break;
|
|
||||||
case 't':
|
|
||||||
str += '\t';
|
|
||||||
break;
|
|
||||||
case 'b':
|
|
||||||
str += '\b';
|
|
||||||
break;
|
|
||||||
case 'f':
|
|
||||||
str += '\f';
|
|
||||||
break;
|
|
||||||
case '\\':
|
|
||||||
case '(':
|
case '(':
|
||||||
case ')':
|
++numParen;
|
||||||
str += ch;
|
str += ch;
|
||||||
break;
|
break;
|
||||||
case '0': case '1': case '2': case '3':
|
case ')':
|
||||||
case '4': case '5': case '6': case '7':
|
if (--numParen == 0) {
|
||||||
var x = ch - '0';
|
done = true;
|
||||||
ch = stream.lookChar();
|
} else {
|
||||||
if (ch >= '0' && ch <= '7') {
|
str += ch;
|
||||||
stream.skip();
|
|
||||||
x = (x << 3) + (ch - '0');
|
|
||||||
ch = stream.lookChar();
|
|
||||||
if (ch >= '0' && ch <= '7') {
|
|
||||||
stream.skip();
|
|
||||||
x = (x << 3) + (ch - '0');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case '\\':
|
||||||
|
ch = stream.getChar();
|
||||||
|
switch (ch) {
|
||||||
|
case undefined:
|
||||||
|
warn('Unterminated string');
|
||||||
|
done = true;
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
str += '\n';
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
str += '\r';
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
str += '\t';
|
||||||
|
break;
|
||||||
|
case 'b':
|
||||||
|
str += '\b';
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
str += '\f';
|
||||||
|
break;
|
||||||
|
case '\\':
|
||||||
|
case '(':
|
||||||
|
case ')':
|
||||||
|
str += ch;
|
||||||
|
break;
|
||||||
|
case '0': case '1': case '2': case '3':
|
||||||
|
case '4': case '5': case '6': case '7':
|
||||||
|
var x = ch - '0';
|
||||||
|
ch = stream.lookChar();
|
||||||
|
if (ch >= '0' && ch <= '7') {
|
||||||
|
stream.skip();
|
||||||
|
x = (x << 3) + (ch - '0');
|
||||||
|
ch = stream.lookChar();
|
||||||
|
if (ch >= '0' && ch <= '7') {
|
||||||
|
stream.skip();
|
||||||
|
x = (x << 3) + (ch - '0');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
str += String.fromCharCode(x);
|
str += String.fromCharCode(x);
|
||||||
break;
|
break;
|
||||||
case '\r':
|
case '\r':
|
||||||
ch = stream.lookChar();
|
ch = stream.lookChar();
|
||||||
if (ch == '\n')
|
if (ch == '\n')
|
||||||
stream.skip();
|
stream.skip();
|
||||||
break;
|
break;
|
||||||
case '\n':
|
case '\n':
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
str += ch;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
str += ch;
|
str += ch;
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
str += ch;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
} while (!done);
|
} while (!done);
|
||||||
return str;
|
return str;
|
||||||
@ -2641,41 +2637,41 @@ var Lexer = (function() {
|
|||||||
|
|
||||||
// start reading token
|
// start reading token
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
case '0': case '1': case '2': case '3': case '4':
|
case '0': case '1': case '2': case '3': case '4':
|
||||||
case '5': case '6': case '7': case '8': case '9':
|
case '5': case '6': case '7': case '8': case '9':
|
||||||
case '+': case '-': case '.':
|
case '+': case '-': case '.':
|
||||||
return this.getNumber(ch);
|
return this.getNumber(ch);
|
||||||
case '(':
|
case '(':
|
||||||
return this.getString();
|
return this.getString();
|
||||||
case '/':
|
case '/':
|
||||||
return this.getName(ch);
|
return this.getName(ch);
|
||||||
// array punctuation
|
// array punctuation
|
||||||
case '[':
|
case '[':
|
||||||
case ']':
|
case ']':
|
||||||
return new Cmd(ch);
|
return new Cmd(ch);
|
||||||
// hex string or dict punctuation
|
// hex string or dict punctuation
|
||||||
case '<':
|
case '<':
|
||||||
ch = stream.lookChar();
|
ch = stream.lookChar();
|
||||||
if (ch == '<') {
|
if (ch == '<') {
|
||||||
|
// dict punctuation
|
||||||
|
stream.skip();
|
||||||
|
return new Cmd('<<');
|
||||||
|
}
|
||||||
|
return this.getHexString(ch);
|
||||||
// dict punctuation
|
// dict punctuation
|
||||||
stream.skip();
|
case '>':
|
||||||
return new Cmd('<<');
|
ch = stream.lookChar();
|
||||||
}
|
if (ch == '>') {
|
||||||
return this.getHexString(ch);
|
stream.skip();
|
||||||
// dict punctuation
|
return new Cmd('>>');
|
||||||
case '>':
|
}
|
||||||
ch = stream.lookChar();
|
case '{':
|
||||||
if (ch == '>') {
|
case '}':
|
||||||
stream.skip();
|
return new Cmd(ch);
|
||||||
return new Cmd('>>');
|
// fall through
|
||||||
}
|
case ')':
|
||||||
case '{':
|
error('Illegal character: ' + ch);
|
||||||
case '}':
|
return Error;
|
||||||
return new Cmd(ch);
|
|
||||||
// fall through
|
|
||||||
case ')':
|
|
||||||
error('Illegal character: ' + ch);
|
|
||||||
return Error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// command
|
// command
|
||||||
@ -3139,17 +3135,16 @@ var XRef = (function() {
|
|||||||
entry.offset = offset;
|
entry.offset = offset;
|
||||||
entry.gen = generation;
|
entry.gen = generation;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 0:
|
case 0:
|
||||||
entry.free = true;
|
entry.free = true;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
entry.uncompressed = true;
|
entry.uncompressed = true;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
error('Invalid XRef entry type: ' + type);
|
error('Invalid XRef entry type: ' + type);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
if (!this.entries[first + i])
|
if (!this.entries[first + i])
|
||||||
this.entries[first + i] = entry;
|
this.entries[first + i] = entry;
|
||||||
@ -3224,7 +3219,14 @@ var XRef = (function() {
|
|||||||
error('bad XRef entry');
|
error('bad XRef entry');
|
||||||
}
|
}
|
||||||
if (this.encrypt && !suppressEncryption) {
|
if (this.encrypt && !suppressEncryption) {
|
||||||
e = parser.getObj(this.encrypt.createCipherTransform(num, gen));
|
try {
|
||||||
|
e = parser.getObj(this.encrypt.createCipherTransform(num, gen));
|
||||||
|
} catch (ex) {
|
||||||
|
// almost all streams must be encrypted, but sometimes
|
||||||
|
// they are not probably due to some broken generators
|
||||||
|
// re-trying without encryption
|
||||||
|
return this.fetch(ref, true);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
e = parser.getObj();
|
e = parser.getObj();
|
||||||
}
|
}
|
||||||
@ -3476,7 +3478,6 @@ var Page = (function() {
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
TODO('other link types');
|
TODO('other link types');
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
} else if (annotation.has('Dest')) {
|
} else if (annotation.has('Dest')) {
|
||||||
// simple destination link
|
// simple destination link
|
||||||
@ -3706,7 +3707,9 @@ var PDFDoc = (function() {
|
|||||||
if (find(stream, 'startxref', 1024, true)) {
|
if (find(stream, 'startxref', 1024, true)) {
|
||||||
stream.skip(9);
|
stream.skip(9);
|
||||||
var ch;
|
var ch;
|
||||||
while (Lexer.isSpace(ch = stream.getChar())) {}
|
do {
|
||||||
|
ch = stream.getChar();
|
||||||
|
} while (Lexer.isSpace(ch));
|
||||||
var str = '';
|
var str = '';
|
||||||
while ((ch - '0') <= 9) {
|
while ((ch - '0') <= 9) {
|
||||||
str += ch;
|
str += ch;
|
||||||
@ -4294,7 +4297,6 @@ var PartialEvaluator = (function() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
} else if (type == 'CIDFontType0') {
|
} else if (type == 'CIDFontType0') {
|
||||||
encoding = xref.fetchIfRef(dict.get('Encoding'));
|
|
||||||
if (IsName(encoding)) {
|
if (IsName(encoding)) {
|
||||||
// Encoding is a predefined CMap
|
// Encoding is a predefined CMap
|
||||||
if (encoding.name == 'Identity-H') {
|
if (encoding.name == 'Identity-H') {
|
||||||
@ -4347,19 +4349,25 @@ var PartialEvaluator = (function() {
|
|||||||
baseEncoding = Encodings.StandardEncoding.slice();
|
baseEncoding = Encodings.StandardEncoding.slice();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
warn('Unknown type of font: ' + type);
|
warn('Unknown type of font: ' + type);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// merge in the differences
|
// merge in the differences
|
||||||
var firstChar = properties.firstChar;
|
var firstChar = properties.firstChar;
|
||||||
var lastChar = properties.lastChar;
|
var lastChar = properties.lastChar;
|
||||||
|
var widths = properties.widths || [];
|
||||||
var glyphs = {};
|
var glyphs = {};
|
||||||
for (var i = firstChar; i <= lastChar; i++) {
|
for (var i = firstChar; i <= lastChar; i++) {
|
||||||
var glyph = differences[i] || baseEncoding[i];
|
var glyph = differences[i];
|
||||||
|
if (!glyph) {
|
||||||
|
glyph = baseEncoding[i];
|
||||||
|
// skipping already specified by difference glyphs
|
||||||
|
if (differences.indexOf(glyph) >= 0)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
var index = GlyphsUnicode[glyph] || i;
|
var index = GlyphsUnicode[glyph] || i;
|
||||||
var width = properties.widths[i] || properties.widths[glyph];
|
var width = widths[i] || widths[glyph];
|
||||||
map[i] = {
|
map[i] = {
|
||||||
unicode: index,
|
unicode: index,
|
||||||
width: IsNum(width) ? width : properties.defaultWidth
|
width: IsNum(width) ? width : properties.defaultWidth
|
||||||
@ -4381,7 +4389,7 @@ var PartialEvaluator = (function() {
|
|||||||
if (type == 'TrueType' && dict.has('ToUnicode') && differences) {
|
if (type == 'TrueType' && dict.has('ToUnicode') && differences) {
|
||||||
var cmapObj = dict.get('ToUnicode');
|
var cmapObj = dict.get('ToUnicode');
|
||||||
if (IsRef(cmapObj)) {
|
if (IsRef(cmapObj)) {
|
||||||
cmapObj = xref.fetch(cmapObj, true);
|
cmapObj = xref.fetch(cmapObj);
|
||||||
}
|
}
|
||||||
if (IsName(cmapObj)) {
|
if (IsName(cmapObj)) {
|
||||||
error('ToUnicode file cmap translation not implemented');
|
error('ToUnicode file cmap translation not implemented');
|
||||||
@ -4442,7 +4450,6 @@ var PartialEvaluator = (function() {
|
|||||||
token = parseInt(token, 10); // a number
|
token = parseInt(token, 10); // a number
|
||||||
tokens.push(token);
|
tokens.push(token);
|
||||||
token = '';
|
token = '';
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
switch (byte) {
|
switch (byte) {
|
||||||
case 0x5B:
|
case 0x5B:
|
||||||
@ -4453,9 +4460,9 @@ var PartialEvaluator = (function() {
|
|||||||
// collect array items
|
// collect array items
|
||||||
var items = [], item;
|
var items = [], item;
|
||||||
while (tokens.length &&
|
while (tokens.length &&
|
||||||
(item = tokens.pop()) != beginArrayToken)
|
(item = tokens.pop()) != beginArrayToken)
|
||||||
items.unshift(item);
|
items.unshift(item);
|
||||||
tokens.push(items);
|
tokens.push(items);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (byte == 0x3E) {
|
} else if (byte == 0x3E) {
|
||||||
@ -4530,7 +4537,7 @@ var PartialEvaluator = (function() {
|
|||||||
type: type.name,
|
type: type.name,
|
||||||
encoding: map,
|
encoding: map,
|
||||||
differences: [],
|
differences: [],
|
||||||
widths: widths,
|
widths: widths || {},
|
||||||
defaultWidth: defaultWidth,
|
defaultWidth: defaultWidth,
|
||||||
firstChar: 0,
|
firstChar: 0,
|
||||||
lastChar: 256
|
lastChar: 256
|
||||||
@ -4921,7 +4928,7 @@ var CanvasGraphics = (function() {
|
|||||||
font = font.get(fontRef.name);
|
font = font.get(fontRef.name);
|
||||||
font = this.xref.fetchIfRef(font);
|
font = this.xref.fetchIfRef(font);
|
||||||
if (!font)
|
if (!font)
|
||||||
return;
|
error('Referenced font is not found');
|
||||||
|
|
||||||
var fontObj = font.fontObj;
|
var fontObj = font.fontObj;
|
||||||
this.current.font = fontObj;
|
this.current.font = fontObj;
|
||||||
@ -4973,21 +4980,15 @@ var CanvasGraphics = (function() {
|
|||||||
showText: function(text) {
|
showText: function(text) {
|
||||||
var ctx = this.ctx;
|
var ctx = this.ctx;
|
||||||
var current = this.current;
|
var current = this.current;
|
||||||
var originalText = text;
|
var font = current.font;
|
||||||
|
|
||||||
ctx.save();
|
ctx.save();
|
||||||
ctx.transform.apply(ctx, current.textMatrix);
|
ctx.transform.apply(ctx, current.textMatrix);
|
||||||
ctx.scale(1, -1);
|
ctx.scale(1, -1);
|
||||||
|
|
||||||
ctx.translate(current.x, -1 * current.y);
|
ctx.translate(current.x, -1 * current.y);
|
||||||
|
ctx.transform.apply(ctx, font.textMatrix || IDENTITY_MATRIX);
|
||||||
|
|
||||||
var font = current.font;
|
var glyphs = font.charsToGlyphs(text);
|
||||||
if (font) {
|
|
||||||
ctx.transform.apply(ctx, font.textMatrix || IDENTITY_MATRIX);
|
|
||||||
text = font.charsToUnicode(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
var composite = font.composite;
|
|
||||||
var fontSize = current.fontSize;
|
var fontSize = current.fontSize;
|
||||||
var charSpacing = current.charSpacing;
|
var charSpacing = current.charSpacing;
|
||||||
var wordSpacing = current.wordSpacing;
|
var wordSpacing = current.wordSpacing;
|
||||||
@ -4995,24 +4996,23 @@ var CanvasGraphics = (function() {
|
|||||||
ctx.scale(1 / textHScale, 1);
|
ctx.scale(1 / textHScale, 1);
|
||||||
|
|
||||||
var width = 0;
|
var width = 0;
|
||||||
for (var i = 0; i < text.length; i++) {
|
for (var i = 0; i < glyphs.length; i++) {
|
||||||
if (composite) {
|
var glyph = glyphs[i];
|
||||||
var position = i * 2 + 1;
|
if (glyph === null) {
|
||||||
var charcode = (originalText.charCodeAt(position - 1) << 8) +
|
// word break
|
||||||
originalText.charCodeAt(position);
|
width += wordSpacing;
|
||||||
} else {
|
continue;
|
||||||
var charcode = originalText.charCodeAt(i);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var encoding = font.encoding[charcode];
|
var unicode = glyph.unicode;
|
||||||
var charWidth = (encoding ? encoding.width : font.defaultWidth);
|
var char = unicode >= 0x10000 ?
|
||||||
charWidth *= (fontSize * 0.001);
|
String.fromCharCode(0xD800 | ((unicode - 0x10000) >> 10),
|
||||||
charWidth += charSpacing;
|
0xDC00 | (unicode & 0x3FF)) : String.fromCharCode(unicode);
|
||||||
if (charcode == 32)
|
|
||||||
charWidth += wordSpacing;
|
|
||||||
|
|
||||||
ctx.fillText(text.charAt(i), 0, 0);
|
var charWidth = glyph.width * fontSize * 0.001;
|
||||||
ctx.translate(charWidth, 0);
|
charWidth += charSpacing;
|
||||||
|
|
||||||
|
ctx.fillText(char, width, 0);
|
||||||
width += charWidth;
|
width += charWidth;
|
||||||
}
|
}
|
||||||
current.x += width;
|
current.x += width;
|
||||||
@ -5399,67 +5399,67 @@ var ColorSpace = (function() {
|
|||||||
this.mode = mode;
|
this.mode = mode;
|
||||||
|
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case 'DeviceGray':
|
case 'DeviceGray':
|
||||||
case 'G':
|
case 'G':
|
||||||
return new DeviceGrayCS();
|
return new DeviceGrayCS();
|
||||||
case 'DeviceRGB':
|
case 'DeviceRGB':
|
||||||
case 'RGB':
|
case 'RGB':
|
||||||
return new DeviceRgbCS();
|
return new DeviceRgbCS();
|
||||||
case 'DeviceCMYK':
|
case 'DeviceCMYK':
|
||||||
case 'CMYK':
|
case 'CMYK':
|
||||||
return new DeviceCmykCS();
|
return new DeviceCmykCS();
|
||||||
case 'Pattern':
|
case 'Pattern':
|
||||||
return new PatternCS(null);
|
return new PatternCS(null);
|
||||||
default:
|
default:
|
||||||
error('unrecognized colorspace ' + mode);
|
error('unrecognized colorspace ' + mode);
|
||||||
}
|
}
|
||||||
} else if (IsArray(cs)) {
|
} else if (IsArray(cs)) {
|
||||||
var mode = cs[0].name;
|
var mode = cs[0].name;
|
||||||
this.mode = mode;
|
this.mode = mode;
|
||||||
|
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case 'DeviceGray':
|
case 'DeviceGray':
|
||||||
case 'G':
|
case 'G':
|
||||||
return new DeviceGrayCS();
|
|
||||||
case 'DeviceRGB':
|
|
||||||
case 'RGB':
|
|
||||||
return new DeviceRgbCS();
|
|
||||||
case 'DeviceCMYK':
|
|
||||||
case 'CMYK':
|
|
||||||
return new DeviceCmykCS();
|
|
||||||
case 'CalGray':
|
|
||||||
return new DeviceGrayCS();
|
|
||||||
case 'CalRGB':
|
|
||||||
return new DeviceRgbCS();
|
|
||||||
case 'ICCBased':
|
|
||||||
var stream = xref.fetchIfRef(cs[1]);
|
|
||||||
var dict = stream.dict;
|
|
||||||
var numComps = dict.get('N');
|
|
||||||
if (numComps == 1)
|
|
||||||
return new DeviceGrayCS();
|
return new DeviceGrayCS();
|
||||||
if (numComps == 3)
|
case 'DeviceRGB':
|
||||||
|
case 'RGB':
|
||||||
return new DeviceRgbCS();
|
return new DeviceRgbCS();
|
||||||
if (numComps == 4)
|
case 'DeviceCMYK':
|
||||||
|
case 'CMYK':
|
||||||
return new DeviceCmykCS();
|
return new DeviceCmykCS();
|
||||||
break;
|
case 'CalGray':
|
||||||
case 'Pattern':
|
return new DeviceGrayCS();
|
||||||
var baseCS = cs[1];
|
case 'CalRGB':
|
||||||
if (baseCS)
|
return new DeviceRgbCS();
|
||||||
baseCS = ColorSpace.parse(baseCS, xref, res);
|
case 'ICCBased':
|
||||||
return new PatternCS(baseCS);
|
var stream = xref.fetchIfRef(cs[1]);
|
||||||
case 'Indexed':
|
var dict = stream.dict;
|
||||||
var base = ColorSpace.parse(cs[1], xref, res);
|
var numComps = dict.get('N');
|
||||||
var hiVal = cs[2] + 1;
|
if (numComps == 1)
|
||||||
var lookup = xref.fetchIfRef(cs[3]);
|
return new DeviceGrayCS();
|
||||||
return new IndexedCS(base, hiVal, lookup);
|
if (numComps == 3)
|
||||||
case 'Separation':
|
return new DeviceRgbCS();
|
||||||
var alt = ColorSpace.parse(cs[2], xref, res);
|
if (numComps == 4)
|
||||||
var tintFn = new PDFFunction(xref, xref.fetchIfRef(cs[3]));
|
return new DeviceCmykCS();
|
||||||
return new SeparationCS(alt, tintFn);
|
break;
|
||||||
case 'Lab':
|
case 'Pattern':
|
||||||
case 'DeviceN':
|
var baseCS = cs[1];
|
||||||
default:
|
if (baseCS)
|
||||||
error('unimplemented color space object "' + mode + '"');
|
baseCS = ColorSpace.parse(baseCS, xref, res);
|
||||||
|
return new PatternCS(baseCS);
|
||||||
|
case 'Indexed':
|
||||||
|
var base = ColorSpace.parse(cs[1], xref, res);
|
||||||
|
var hiVal = cs[2] + 1;
|
||||||
|
var lookup = xref.fetchIfRef(cs[3]);
|
||||||
|
return new IndexedCS(base, hiVal, lookup);
|
||||||
|
case 'Separation':
|
||||||
|
var alt = ColorSpace.parse(cs[2], xref, res);
|
||||||
|
var tintFn = new PDFFunction(xref, xref.fetchIfRef(cs[3]));
|
||||||
|
return new SeparationCS(alt, tintFn);
|
||||||
|
case 'Lab':
|
||||||
|
case 'DeviceN':
|
||||||
|
default:
|
||||||
|
error('unimplemented color space object "' + mode + '"');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
error('unrecognized color space object: "' + cs + '"');
|
error('unrecognized color space object: "' + cs + '"');
|
||||||
@ -5742,26 +5742,26 @@ var Pattern = (function() {
|
|||||||
var typeNum = dict.get('PatternType');
|
var typeNum = dict.get('PatternType');
|
||||||
|
|
||||||
switch (typeNum) {
|
switch (typeNum) {
|
||||||
case 1:
|
case 1:
|
||||||
var base = cs.base;
|
var base = cs.base;
|
||||||
var color;
|
var color;
|
||||||
if (base) {
|
if (base) {
|
||||||
var baseComps = base.numComps;
|
var baseComps = base.numComps;
|
||||||
|
|
||||||
color = [];
|
color = [];
|
||||||
for (var i = 0; i < baseComps; ++i)
|
for (var i = 0; i < baseComps; ++i)
|
||||||
color.push(args[i]);
|
color.push(args[i]);
|
||||||
|
|
||||||
color = base.getRgb(color);
|
color = base.getRgb(color);
|
||||||
}
|
}
|
||||||
var code = patternName.code;
|
var code = patternName.code;
|
||||||
return new TilingPattern(pattern, code, dict, color, xref, ctx);
|
return new TilingPattern(pattern, code, dict, color, xref, ctx);
|
||||||
case 2:
|
case 2:
|
||||||
var shading = xref.fetchIfRef(dict.get('Shading'));
|
var shading = xref.fetchIfRef(dict.get('Shading'));
|
||||||
var matrix = dict.get('Matrix');
|
var matrix = dict.get('Matrix');
|
||||||
return Pattern.parseShading(shading, matrix, xref, res, ctx);
|
return Pattern.parseShading(shading, matrix, xref, res, ctx);
|
||||||
default:
|
default:
|
||||||
error('Unknown type of pattern: ' + typeNum);
|
error('Unknown type of pattern: ' + typeNum);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
@ -5773,12 +5773,12 @@ var Pattern = (function() {
|
|||||||
var type = dict.get('ShadingType');
|
var type = dict.get('ShadingType');
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 2:
|
case 2:
|
||||||
case 3:
|
case 3:
|
||||||
// both radial and axial shadings are handled by RadialAxial shading
|
// both radial and axial shadings are handled by RadialAxial shading
|
||||||
return new RadialAxialShading(dict, matrix, xref, res, ctx);
|
return new RadialAxialShading(dict, matrix, xref, res, ctx);
|
||||||
default:
|
default:
|
||||||
return new DummyShading();
|
return new DummyShading();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return constructor;
|
return constructor;
|
||||||
@ -5959,17 +5959,17 @@ var TilingPattern = (function() {
|
|||||||
|
|
||||||
var paintType = dict.get('PaintType');
|
var paintType = dict.get('PaintType');
|
||||||
switch (paintType) {
|
switch (paintType) {
|
||||||
case PAINT_TYPE_COLORED:
|
case PAINT_TYPE_COLORED:
|
||||||
tmpCtx.fillStyle = ctx.fillStyle;
|
tmpCtx.fillStyle = ctx.fillStyle;
|
||||||
tmpCtx.strokeStyle = ctx.strokeStyle;
|
tmpCtx.strokeStyle = ctx.strokeStyle;
|
||||||
break;
|
break;
|
||||||
case PAINT_TYPE_UNCOLORED:
|
case PAINT_TYPE_UNCOLORED:
|
||||||
color = Util.makeCssRgb.apply(this, color);
|
color = Util.makeCssRgb.apply(this, color);
|
||||||
tmpCtx.fillStyle = color;
|
tmpCtx.fillStyle = color;
|
||||||
tmpCtx.strokeStyle = color;
|
tmpCtx.strokeStyle = color;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
error('Unsupported paint type: ' + paintType);
|
error('Unsupported paint type: ' + paintType);
|
||||||
}
|
}
|
||||||
|
|
||||||
var scale = [width / xstep, height / ystep];
|
var scale = [width / xstep, height / ystep];
|
||||||
@ -6062,8 +6062,8 @@ var PDFImage = (function() {
|
|||||||
|
|
||||||
this.decode = dict.get('Decode', 'D');
|
this.decode = dict.get('Decode', 'D');
|
||||||
|
|
||||||
var mask = xref.fetchIfRef(image.dict.get('Mask'));
|
var mask = xref.fetchIfRef(dict.get('Mask'));
|
||||||
var smask = xref.fetchIfRef(image.dict.get('SMask'));
|
var smask = xref.fetchIfRef(dict.get('SMask'));
|
||||||
|
|
||||||
if (mask) {
|
if (mask) {
|
||||||
TODO('masked images');
|
TODO('masked images');
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var appPath, browser, canvas, currentTaskIdx, manifest, stdout;
|
var appPath, browser, canvas, currentTaskIdx, manifest, stdout;
|
||||||
|
var inFlightRequests = 0;
|
||||||
|
|
||||||
function queryParams() {
|
function queryParams() {
|
||||||
var qs = window.location.search.substring(1);
|
var qs = window.location.search.substring(1);
|
||||||
@ -42,12 +43,12 @@ function load() {
|
|||||||
if (r.readyState == 4) {
|
if (r.readyState == 4) {
|
||||||
log('done\n');
|
log('done\n');
|
||||||
manifest = JSON.parse(r.responseText);
|
manifest = JSON.parse(r.responseText);
|
||||||
currentTaskIdx = 0, nextTask();
|
currentTaskIdx = 0;
|
||||||
|
nextTask();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
r.send(null);
|
r.send(null);
|
||||||
}
|
}
|
||||||
window.onload = load;
|
|
||||||
|
|
||||||
function nextTask() {
|
function nextTask() {
|
||||||
if (currentTaskIdx == manifest.length) {
|
if (currentTaskIdx == manifest.length) {
|
||||||
@ -73,7 +74,8 @@ function nextTask() {
|
|||||||
failure = 'load PDF doc : ' + e.toString();
|
failure = 'load PDF doc : ' + e.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
task.pageNum = 1, nextPage(task, failure);
|
task.pageNum = 1;
|
||||||
|
nextPage(task, failure);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
r.send(null);
|
r.send(null);
|
||||||
@ -89,7 +91,8 @@ function nextPage(task, loadError) {
|
|||||||
if (!task.pdfDoc) {
|
if (!task.pdfDoc) {
|
||||||
sendTaskResult(canvas.toDataURL('image/png'), task, failure);
|
sendTaskResult(canvas.toDataURL('image/png'), task, failure);
|
||||||
log('done' + (failure ? ' (failed !: ' + failure + ')' : '') + '\n');
|
log('done' + (failure ? ' (failed !: ' + failure + ')' : '') + '\n');
|
||||||
++currentTaskIdx, nextTask();
|
++currentTaskIdx;
|
||||||
|
nextTask();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,7 +101,8 @@ function nextPage(task, loadError) {
|
|||||||
log(' Round ' + (1 + task.round) + '\n');
|
log(' Round ' + (1 + task.round) + '\n');
|
||||||
task.pageNum = 1;
|
task.pageNum = 1;
|
||||||
} else {
|
} else {
|
||||||
++currentTaskIdx, nextTask();
|
++currentTaskIdx;
|
||||||
|
nextTask();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -123,7 +127,7 @@ function nextPage(task, loadError) {
|
|||||||
page.startRendering(
|
page.startRendering(
|
||||||
ctx,
|
ctx,
|
||||||
function(e) {
|
function(e) {
|
||||||
snapshotCurrentPage(page, task, (!failure && e) ?
|
snapshotCurrentPage(task, (!failure && e) ?
|
||||||
('render : ' + e) : failure);
|
('render : ' + e) : failure);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -135,11 +139,11 @@ function nextPage(task, loadError) {
|
|||||||
if (failure) {
|
if (failure) {
|
||||||
// Skip right to snapshotting if there was a failure, since the
|
// Skip right to snapshotting if there was a failure, since the
|
||||||
// fonts might be in an inconsistent state.
|
// fonts might be in an inconsistent state.
|
||||||
snapshotCurrentPage(page, task, failure);
|
snapshotCurrentPage(task, failure);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function snapshotCurrentPage(page, task, failure) {
|
function snapshotCurrentPage(task, failure) {
|
||||||
log('done, snapshotting... ');
|
log('done, snapshotting... ');
|
||||||
|
|
||||||
sendTaskResult(canvas.toDataURL('image/png'), task, failure);
|
sendTaskResult(canvas.toDataURL('image/png'), task, failure);
|
||||||
@ -149,7 +153,8 @@ function snapshotCurrentPage(page, task, failure) {
|
|||||||
var backoff = (inFlightRequests > 0) ? inFlightRequests * 10 : 0;
|
var backoff = (inFlightRequests > 0) ? inFlightRequests * 10 : 0;
|
||||||
setTimeout(
|
setTimeout(
|
||||||
function() {
|
function() {
|
||||||
++task.pageNum, nextPage(task);
|
++task.pageNum;
|
||||||
|
nextPage(task);
|
||||||
},
|
},
|
||||||
backoff
|
backoff
|
||||||
);
|
);
|
||||||
@ -182,7 +187,6 @@ function done() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var inFlightRequests = 0;
|
|
||||||
function sendTaskResult(snapshot, task, failure) {
|
function sendTaskResult(snapshot, task, failure) {
|
||||||
var result = { browser: browser,
|
var result = { browser: browser,
|
||||||
id: task.id,
|
id: task.id,
|
||||||
@ -201,7 +205,7 @@ function sendTaskResult(snapshot, task, failure) {
|
|||||||
if (r.readyState == 4) {
|
if (r.readyState == 4) {
|
||||||
inFlightRequests--;
|
inFlightRequests--;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
document.getElementById('inFlightCount').innerHTML = inFlightRequests++;
|
document.getElementById('inFlightCount').innerHTML = inFlightRequests++;
|
||||||
r.send(JSON.stringify(result));
|
r.send(JSON.stringify(result));
|
||||||
}
|
}
|
||||||
|
12
test/pdfs/.gitignore
vendored
12
test/pdfs/.gitignore
vendored
@ -1,3 +1,13 @@
|
|||||||
pdf.pdf
|
DiwanProfile.pdf
|
||||||
|
artofwar.pdf
|
||||||
|
cable.pdf
|
||||||
|
ecma262.pdf
|
||||||
|
hmm.pdf
|
||||||
|
i9.pdf
|
||||||
intelisa.pdf
|
intelisa.pdf
|
||||||
openweb_tm-PRINT.pdf
|
openweb_tm-PRINT.pdf
|
||||||
|
pdf.pdf
|
||||||
|
pdkids.pdf
|
||||||
|
shavian.pdf
|
||||||
|
jai.pdf
|
||||||
|
|
||||||
|
1
test/pdfs/fips197.pdf.link
Normal file
1
test/pdfs/fips197.pdf.link
Normal file
@ -0,0 +1 @@
|
|||||||
|
http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf
|
1
test/pdfs/wdsg_fitc.pdf.link
Normal file
1
test/pdfs/wdsg_fitc.pdf.link
Normal file
@ -0,0 +1 @@
|
|||||||
|
http://www.airgid.com/book/wdsg_fitc.pdf
|
1
test/pdfs/wnv_chinese.pdf.link
Normal file
1
test/pdfs/wnv_chinese.pdf.link
Normal file
@ -0,0 +1 @@
|
|||||||
|
http://www.cdc.gov/ncidod/dvbid/westnile/languages/chinese.pdf
|
2
test/resources/browser_manifests/.gitignore
vendored
Normal file
2
test/resources/browser_manifests/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
browser_manifest.json
|
||||||
|
|
@ -69,6 +69,12 @@
|
|||||||
"rounds": 1,
|
"rounds": 1,
|
||||||
"type": "load"
|
"type": "load"
|
||||||
},
|
},
|
||||||
|
{ "id": "wnv_chinese-pdf",
|
||||||
|
"file": "pdfs/wnv_chinese.pdf",
|
||||||
|
"link": true,
|
||||||
|
"rounds": 1,
|
||||||
|
"type": "eq"
|
||||||
|
},
|
||||||
{ "id": "i9-pdf",
|
{ "id": "i9-pdf",
|
||||||
"file": "pdfs/i9.pdf",
|
"file": "pdfs/i9.pdf",
|
||||||
"link": true,
|
"link": true,
|
||||||
@ -115,5 +121,17 @@
|
|||||||
"link": true,
|
"link": true,
|
||||||
"rounds": 1,
|
"rounds": 1,
|
||||||
"type": "eq"
|
"type": "eq"
|
||||||
|
},
|
||||||
|
{ "id": "wdsg_fitc",
|
||||||
|
"file": "pdfs/wdsg_fitc.pdf",
|
||||||
|
"link": true,
|
||||||
|
"rounds": 1,
|
||||||
|
"type": "eq"
|
||||||
|
},
|
||||||
|
{ "id": "fips197",
|
||||||
|
"file": "pdfs/fips197.pdf",
|
||||||
|
"link": true,
|
||||||
|
"rounds": 1,
|
||||||
|
"type": "load"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -82,7 +82,7 @@ function readCharstringEncoding(aString) {
|
|||||||
} else if (value <= 31) {
|
} else if (value <= 31) {
|
||||||
token = CFFEncodingMap[value];
|
token = CFFEncodingMap[value];
|
||||||
} else if (value < 247) {
|
} else if (value < 247) {
|
||||||
token = parseInt(value) - 139;
|
token = parseInt(value, 10) - 139;
|
||||||
} else if (value < 251) {
|
} else if (value < 251) {
|
||||||
token = (value - 247) * 256 + aString[i++] + 108;
|
token = (value - 247) * 256 + aString[i++] + 108;
|
||||||
} else if (value < 255) {
|
} else if (value < 255) {
|
||||||
@ -126,7 +126,7 @@ function readFontDictData(aString, aMap) {
|
|||||||
while (!parsed) {
|
while (!parsed) {
|
||||||
var byte = aString[i++];
|
var byte = aString[i++];
|
||||||
|
|
||||||
var nibbles = [parseInt(byte / 16), parseInt(byte % 16)];
|
var nibbles = [parseInt(byte / 16, 10), parseInt(byte % 16, 10)];
|
||||||
for (var j = 0; j < nibbles.length; j++) {
|
for (var j = 0; j < nibbles.length; j++) {
|
||||||
var nibble = nibbles[j];
|
var nibble = nibbles[j];
|
||||||
switch (nibble) {
|
switch (nibble) {
|
||||||
@ -157,7 +157,7 @@ function readFontDictData(aString, aMap) {
|
|||||||
} else if (value <= 31) {
|
} else if (value <= 31) {
|
||||||
token = aMap[value];
|
token = aMap[value];
|
||||||
} else if (value <= 246) {
|
} else if (value <= 246) {
|
||||||
token = parseInt(value) - 139;
|
token = parseInt(value, 10) - 139;
|
||||||
} else if (value <= 250) {
|
} else if (value <= 250) {
|
||||||
token = (value - 247) * 256 + aString[i++] + 108;
|
token = (value - 247) * 256 + aString[i++] + 108;
|
||||||
} else if (value <= 254) {
|
} else if (value <= 254) {
|
||||||
@ -206,7 +206,7 @@ function readFontIndexData(aStream, aIsByte) {
|
|||||||
}
|
}
|
||||||
error(offsize + ' is not a valid offset size');
|
error(offsize + ' is not a valid offset size');
|
||||||
return null;
|
return null;
|
||||||
};
|
}
|
||||||
|
|
||||||
var offsets = [];
|
var offsets = [];
|
||||||
for (var i = 0; i < count + 1; i++)
|
for (var i = 0; i < count + 1; i++)
|
||||||
@ -249,7 +249,7 @@ var Type2Parser = function(aFilePath) {
|
|||||||
function dump(aStr) {
|
function dump(aStr) {
|
||||||
if (debug)
|
if (debug)
|
||||||
log(aStr);
|
log(aStr);
|
||||||
};
|
}
|
||||||
|
|
||||||
function parseAsToken(aString, aMap) {
|
function parseAsToken(aString, aMap) {
|
||||||
var decoded = readFontDictData(aString, aMap);
|
var decoded = readFontDictData(aString, aMap);
|
||||||
@ -290,7 +290,7 @@ var Type2Parser = function(aFilePath) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
this.parse = function(aStream) {
|
this.parse = function(aStream) {
|
||||||
font.set('major', aStream.getByte());
|
font.set('major', aStream.getByte());
|
||||||
@ -363,7 +363,7 @@ var Type2Parser = function(aFilePath) {
|
|||||||
aStream.pos = charsetEntry;
|
aStream.pos = charsetEntry;
|
||||||
var charset = readCharset(aStream, charStrings);
|
var charset = readCharset(aStream, charStrings);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
19
web/compatibility.js
Executable file → Normal file
19
web/compatibility.js
Executable file → Normal file
@ -1,6 +1,8 @@
|
|||||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
// Checking if the typed arrays are supported
|
// Checking if the typed arrays are supported
|
||||||
(function() {
|
(function() {
|
||||||
if (typeof Uint8Array !== 'undefined')
|
if (typeof Uint8Array !== 'undefined')
|
||||||
@ -10,8 +12,9 @@
|
|||||||
return this.slice(start, end);
|
return this.slice(start, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
function set_(array, offset) {
|
function set_function(array, offset) {
|
||||||
if (arguments.length < 2) offset = 0;
|
if (arguments.length < 2)
|
||||||
|
offset = 0;
|
||||||
for (var i = 0, n = array.length; i < n; ++i, ++offset)
|
for (var i = 0, n = array.length; i < n; ++i, ++offset)
|
||||||
this[offset] = array[i] & 0xFF;
|
this[offset] = array[i] & 0xFF;
|
||||||
}
|
}
|
||||||
@ -19,15 +22,17 @@
|
|||||||
function TypedArray(arg1) {
|
function TypedArray(arg1) {
|
||||||
var result;
|
var result;
|
||||||
if (typeof arg1 === 'number') {
|
if (typeof arg1 === 'number') {
|
||||||
result = new Array(arg1);
|
result = [];
|
||||||
for (var i = 0; i < arg1; ++i)
|
for (var i = 0; i < arg1; ++i)
|
||||||
result[i] = 0;
|
result[i] = 0;
|
||||||
} else
|
} else
|
||||||
result = arg1.slice(0);
|
result = arg1.slice(0);
|
||||||
|
|
||||||
result.subarray = subarray;
|
result.subarray = subarray;
|
||||||
result.buffer = result;
|
result.buffer = result;
|
||||||
result.byteLength = result.length;
|
result.byteLength = result.length;
|
||||||
result.set = set_;
|
result.set = set_function;
|
||||||
|
|
||||||
if (typeof arg1 === 'object' && arg1.buffer)
|
if (typeof arg1 === 'object' && arg1.buffer)
|
||||||
result.buffer = arg1.buffer;
|
result.buffer = arg1.buffer;
|
||||||
|
|
||||||
|
0
web/viewer.css
Executable file → Normal file
0
web/viewer.css
Executable file → Normal file
@ -98,7 +98,7 @@ var PDFView = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
get page() {
|
get page() {
|
||||||
return parseInt(document.location.hash.substring(1)) || 1;
|
return parseInt(document.location.hash.substring(1), 10) || 1;
|
||||||
},
|
},
|
||||||
|
|
||||||
open: function(url, scale) {
|
open: function(url, scale) {
|
||||||
@ -170,7 +170,7 @@ var PDFView = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.setScale(scale || kDefaultScale, true);
|
this.setScale(scale || kDefaultScale, true);
|
||||||
this.page = parseInt(document.location.hash.substring(1)) || 1;
|
this.page = parseInt(document.location.hash.substring(1), 10) || 1;
|
||||||
this.pagesRefMap = pagesRefMap;
|
this.pagesRefMap = pagesRefMap;
|
||||||
this.destinations = pdf.catalog.destinations;
|
this.destinations = pdf.catalog.destinations;
|
||||||
if (pdf.catalog.documentOutline) {
|
if (pdf.catalog.documentOutline) {
|
||||||
@ -209,7 +209,7 @@ var PDFView = {
|
|||||||
|
|
||||||
var currentHeight = kBottomMargin;
|
var currentHeight = kBottomMargin;
|
||||||
var windowTop = window.pageYOffset;
|
var windowTop = window.pageYOffset;
|
||||||
for (var i = 1; i <= pages.length; i++) {
|
for (var i = 1; i <= pages.length; ++i) {
|
||||||
var page = pages[i - 1];
|
var page = pages[i - 1];
|
||||||
var pageHeight = page.height * page.scale + kBottomMargin;
|
var pageHeight = page.height * page.scale + kBottomMargin;
|
||||||
if (currentHeight + pageHeight > windowTop)
|
if (currentHeight + pageHeight > windowTop)
|
||||||
@ -219,10 +219,11 @@ var PDFView = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var windowBottom = window.pageYOffset + window.innerHeight;
|
var windowBottom = window.pageYOffset + window.innerHeight;
|
||||||
for (; i <= pages.length && currentHeight < windowBottom; i++) {
|
for (; i <= pages.length && currentHeight < windowBottom; ++i) {
|
||||||
var page = pages[i - 1];
|
var singlePage = pages[i - 1];
|
||||||
visiblePages.push({ id: page.id, y: currentHeight, view: page });
|
visiblePages.push({ id: singlePage.id, y: currentHeight,
|
||||||
currentHeight += page.height * page.scale + kBottomMargin;
|
view: singlePage });
|
||||||
|
currentHeight += singlePage.height * singlePage.scale + kBottomMargin;
|
||||||
}
|
}
|
||||||
|
|
||||||
return visiblePages;
|
return visiblePages;
|
||||||
@ -256,13 +257,13 @@ var PageView = function(container, content, id, width, height,
|
|||||||
div.removeAttribute('data-loaded');
|
div.removeAttribute('data-loaded');
|
||||||
};
|
};
|
||||||
|
|
||||||
function setupLinks(canvas, content, scale) {
|
function setupLinks(content, scale) {
|
||||||
function bindLink(link, dest) {
|
function bindLink(link, dest) {
|
||||||
link.onclick = function() {
|
link.onclick = function() {
|
||||||
if (dest)
|
if (dest)
|
||||||
PDFView.navigateTo(dest);
|
PDFView.navigateTo(dest);
|
||||||
return false;
|
return false;
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
var links = content.getLinks();
|
var links = content.getLinks();
|
||||||
for (var i = 0; i < links.length; i++) {
|
for (var i = 0; i < links.length; i++) {
|
||||||
@ -283,8 +284,6 @@ var PageView = function(container, content, id, width, height,
|
|||||||
var width = 0, height = 0, widthScale, heightScale;
|
var width = 0, height = 0, widthScale, heightScale;
|
||||||
var scale = 0;
|
var scale = 0;
|
||||||
switch (dest[1].name) {
|
switch (dest[1].name) {
|
||||||
default:
|
|
||||||
return;
|
|
||||||
case 'XYZ':
|
case 'XYZ':
|
||||||
x = dest[2];
|
x = dest[2];
|
||||||
y = dest[3];
|
y = dest[3];
|
||||||
@ -315,6 +314,8 @@ var PageView = function(container, content, id, width, height,
|
|||||||
height / kCssUnits;
|
height / kCssUnits;
|
||||||
scale = Math.min(widthScale, heightScale);
|
scale = Math.min(widthScale, heightScale);
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var boundingRect = [
|
var boundingRect = [
|
||||||
@ -369,7 +370,7 @@ var PageView = function(container, content, id, width, height,
|
|||||||
stats.begin = Date.now();
|
stats.begin = Date.now();
|
||||||
this.content.startRendering(ctx, this.updateStats);
|
this.content.startRendering(ctx, this.updateStats);
|
||||||
|
|
||||||
setupLinks(canvas, this.content, this.scale);
|
setupLinks(this.content, this.scale);
|
||||||
div.setAttribute('data-loaded', true);
|
div.setAttribute('data-loaded', true);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -39,7 +39,7 @@ function GradientProxy(cmdQueue, x0, y0, x1, y1) {
|
|||||||
cmdQueue.push(['$createLinearGradient', [x0, y0, x1, y1]]);
|
cmdQueue.push(['$createLinearGradient', [x0, y0, x1, y1]]);
|
||||||
this.addColorStop = function(i, rgba) {
|
this.addColorStop = function(i, rgba) {
|
||||||
cmdQueue.push(['$addColorStop', [i, rgba]]);
|
cmdQueue.push(['$addColorStop', [i, rgba]]);
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Really simple PatternProxy.
|
// Really simple PatternProxy.
|
||||||
@ -72,7 +72,7 @@ function CanvasProxy(width, height) {
|
|||||||
throw 'CanvasProxy can only provide a 2d context.';
|
throw 'CanvasProxy can only provide a 2d context.';
|
||||||
}
|
}
|
||||||
return ctx;
|
return ctx;
|
||||||
}
|
};
|
||||||
|
|
||||||
// Expose only the minimum of the canvas object - there is no dom to do
|
// Expose only the minimum of the canvas object - there is no dom to do
|
||||||
// more here.
|
// more here.
|
||||||
@ -127,7 +127,7 @@ function CanvasProxy(width, height) {
|
|||||||
return function() {
|
return function() {
|
||||||
// console.log("funcCall", name)
|
// console.log("funcCall", name)
|
||||||
cmdQueue.push([name, Array.prototype.slice.call(arguments)]);
|
cmdQueue.push([name, Array.prototype.slice.call(arguments)]);
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
var name;
|
var name;
|
||||||
for (var i = 0; i < ctxFunc.length; i++) {
|
for (var i = 0; i < ctxFunc.length; i++) {
|
||||||
@ -139,11 +139,11 @@ function CanvasProxy(width, height) {
|
|||||||
|
|
||||||
ctx.createPattern = function(object, kind) {
|
ctx.createPattern = function(object, kind) {
|
||||||
return new PatternProxy(cmdQueue, object, kind);
|
return new PatternProxy(cmdQueue, object, kind);
|
||||||
}
|
};
|
||||||
|
|
||||||
ctx.createLinearGradient = function(x0, y0, x1, y1) {
|
ctx.createLinearGradient = function(x0, y0, x1, y1) {
|
||||||
return new GradientProxy(cmdQueue, x0, y0, x1, y1);
|
return new GradientProxy(cmdQueue, x0, y0, x1, y1);
|
||||||
}
|
};
|
||||||
|
|
||||||
ctx.getImageData = function(x, y, w, h) {
|
ctx.getImageData = function(x, y, w, h) {
|
||||||
return {
|
return {
|
||||||
@ -151,11 +151,11 @@ function CanvasProxy(width, height) {
|
|||||||
height: h,
|
height: h,
|
||||||
data: Uint8ClampedArray(w * h * 4)
|
data: Uint8ClampedArray(w * h * 4)
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
ctx.putImageData = function(data, x, y, width, height) {
|
ctx.putImageData = function(data, x, y, width, height) {
|
||||||
cmdQueue.push(['$putImageData', [data, x, y, width, height]]);
|
cmdQueue.push(['$putImageData', [data, x, y, width, height]]);
|
||||||
}
|
};
|
||||||
|
|
||||||
ctx.drawImage = function(image, x, y, width, height,
|
ctx.drawImage = function(image, x, y, width, height,
|
||||||
sx, sy, swidth, sheight) {
|
sx, sy, swidth, sheight) {
|
||||||
@ -168,7 +168,7 @@ function CanvasProxy(width, height) {
|
|||||||
} else {
|
} else {
|
||||||
throw 'unkown type to drawImage';
|
throw 'unkown type to drawImage';
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
// Setup property access to `ctx`.
|
// Setup property access to `ctx`.
|
||||||
var ctxProp = {
|
var ctxProp = {
|
||||||
@ -195,14 +195,14 @@ function CanvasProxy(width, height) {
|
|||||||
function buildGetter(name) {
|
function buildGetter(name) {
|
||||||
return function() {
|
return function() {
|
||||||
return ctx['$' + name];
|
return ctx['$' + name];
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildSetter(name) {
|
function buildSetter(name) {
|
||||||
return function(value) {
|
return function(value) {
|
||||||
cmdQueue.push(['$', name, value]);
|
cmdQueue.push(['$', name, value]);
|
||||||
return ctx['$' + name] = value;
|
return (ctx['$' + name] = value);
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setting the value to `stroke|fillStyle` needs special handling, as it
|
// Setting the value to `stroke|fillStyle` needs special handling, as it
|
||||||
@ -215,9 +215,9 @@ function CanvasProxy(width, height) {
|
|||||||
cmdQueue.push(['$' + name + 'Pattern', [value.id]]);
|
cmdQueue.push(['$' + name + 'Pattern', [value.id]]);
|
||||||
} else {
|
} else {
|
||||||
cmdQueue.push(['$', name, value]);
|
cmdQueue.push(['$', name, value]);
|
||||||
return ctx['$' + name] = value;
|
return (ctx['$' + name] = value);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var name in ctxProp) {
|
for (var name in ctxProp) {
|
||||||
|
110
worker/client.js
110
worker/client.js
@ -3,23 +3,26 @@
|
|||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
if (typeof console.time == 'undefined') {
|
var consoleUtils = (function() {
|
||||||
var consoleTimer = {};
|
var consoleTimer = {};
|
||||||
console.time = function(name) {
|
|
||||||
|
var obj = {};
|
||||||
|
obj.time = function(name) {
|
||||||
consoleTimer[name] = Date.now();
|
consoleTimer[name] = Date.now();
|
||||||
};
|
};
|
||||||
|
obj.timeEnd = function(name) {
|
||||||
console.timeEnd = function(name) {
|
|
||||||
var time = consoleTimer[name];
|
var time = consoleTimer[name];
|
||||||
if (time == null) {
|
if (time == null) {
|
||||||
throw 'Unkown timer name ' + name;
|
throw 'Unkown timer name ' + name;
|
||||||
}
|
}
|
||||||
this.log('Timer:', name, Date.now() - time);
|
console.log('Timer:', name, Date.now() - time);
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
return obj;
|
||||||
|
})();
|
||||||
|
|
||||||
function FontWorker() {
|
function FontWorker() {
|
||||||
this.worker = new Worker('worker/font.js');
|
this.worker = new Worker('../worker/font.js');
|
||||||
this.fontsWaiting = 0;
|
this.fontsWaiting = 0;
|
||||||
this.fontsWaitingCallbacks = [];
|
this.fontsWaitingCallbacks = [];
|
||||||
|
|
||||||
@ -58,7 +61,7 @@ FontWorker.prototype = {
|
|||||||
|
|
||||||
'fonts': function(data) {
|
'fonts': function(data) {
|
||||||
// console.log("got processed fonts from worker", Object.keys(data));
|
// console.log("got processed fonts from worker", Object.keys(data));
|
||||||
for (name in data) {
|
for (var name in data) {
|
||||||
// Update the encoding property.
|
// Update the encoding property.
|
||||||
var font = Fonts.lookup(name);
|
var font = Fonts.lookup(name);
|
||||||
font.properties = {
|
font.properties = {
|
||||||
@ -96,7 +99,7 @@ FontWorker.prototype = {
|
|||||||
this.fontsWaiting++;
|
this.fontsWaiting++;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.time('ensureFonts');
|
consoleUtils.time('ensureFonts');
|
||||||
// If there are fonts, that need to get loaded, tell the FontWorker to get
|
// If there are fonts, that need to get loaded, tell the FontWorker to get
|
||||||
// started and push the callback on the waiting-callback-stack.
|
// started and push the callback on the waiting-callback-stack.
|
||||||
if (notLoaded.length != 0) {
|
if (notLoaded.length != 0) {
|
||||||
@ -124,7 +127,7 @@ function WorkerPDFDoc(canvas) {
|
|||||||
|
|
||||||
this.ctx = canvas.getContext('2d');
|
this.ctx = canvas.getContext('2d');
|
||||||
this.canvas = canvas;
|
this.canvas = canvas;
|
||||||
this.worker = new Worker('worker/pdf.js');
|
this.worker = new Worker('../worker/pdf.js');
|
||||||
this.fontWorker = new FontWorker();
|
this.fontWorker = new FontWorker();
|
||||||
this.waitingForFonts = false;
|
this.waitingForFonts = false;
|
||||||
this.waitingForFontsCallback = [];
|
this.waitingForFontsCallback = [];
|
||||||
@ -167,7 +170,8 @@ function WorkerPDFDoc(canvas) {
|
|||||||
},
|
},
|
||||||
|
|
||||||
'$putImageData': function(imageData, x, y) {
|
'$putImageData': function(imageData, x, y) {
|
||||||
var imgData = this.getImageData(0, 0, imageData.width, imageData.height);
|
var imgData = this.getImageData(0, 0,
|
||||||
|
imageData.width, imageData.height);
|
||||||
|
|
||||||
// Store the .data property to avaid property lookups.
|
// Store the .data property to avaid property lookups.
|
||||||
var imageRealData = imageData.data;
|
var imageRealData = imageData.data;
|
||||||
@ -176,7 +180,7 @@ function WorkerPDFDoc(canvas) {
|
|||||||
// Copy over the imageData.
|
// Copy over the imageData.
|
||||||
var len = imageRealData.length;
|
var len = imageRealData.length;
|
||||||
while (len--)
|
while (len--)
|
||||||
imgRealData[len] = imageRealData[len];
|
imgRealData[len] = imageRealData[len];
|
||||||
|
|
||||||
this.putImageData(imgData, x, y);
|
this.putImageData(imgData, x, y);
|
||||||
},
|
},
|
||||||
@ -273,7 +277,7 @@ function WorkerPDFDoc(canvas) {
|
|||||||
},
|
},
|
||||||
|
|
||||||
'pdf_num_pages': function(data) {
|
'pdf_num_pages': function(data) {
|
||||||
this.numPages = parseInt(data);
|
this.numPages = parseInt(data, 10);
|
||||||
if (this.loadCallback) {
|
if (this.loadCallback) {
|
||||||
this.loadCallback();
|
this.loadCallback();
|
||||||
}
|
}
|
||||||
@ -302,8 +306,8 @@ function WorkerPDFDoc(canvas) {
|
|||||||
'setup_page': function(data) {
|
'setup_page': function(data) {
|
||||||
var size = data.split(',');
|
var size = data.split(',');
|
||||||
var canvas = this.canvas, ctx = this.ctx;
|
var canvas = this.canvas, ctx = this.ctx;
|
||||||
canvas.width = parseInt(size[0]);
|
canvas.width = parseInt(size[0], 10);
|
||||||
canvas.height = parseInt(size[1]);
|
canvas.height = parseInt(size[1], 10);
|
||||||
},
|
},
|
||||||
|
|
||||||
'fonts': function(data) {
|
'fonts': function(data) {
|
||||||
@ -339,7 +343,7 @@ function WorkerPDFDoc(canvas) {
|
|||||||
|
|
||||||
var renderData = function() {
|
var renderData = function() {
|
||||||
if (id == 0) {
|
if (id == 0) {
|
||||||
console.time('main canvas rendering');
|
consoleUtils.time('main canvas rendering');
|
||||||
var ctx = this.ctx;
|
var ctx = this.ctx;
|
||||||
ctx.save();
|
ctx.save();
|
||||||
ctx.fillStyle = 'rgb(255, 255, 255)';
|
ctx.fillStyle = 'rgb(255, 255, 255)';
|
||||||
@ -348,8 +352,8 @@ function WorkerPDFDoc(canvas) {
|
|||||||
}
|
}
|
||||||
renderProxyCanvas(canvasList[id], cmdQueue);
|
renderProxyCanvas(canvasList[id], cmdQueue);
|
||||||
if (id == 0) {
|
if (id == 0) {
|
||||||
console.timeEnd('main canvas rendering');
|
consoleUtils.timeEnd('main canvas rendering');
|
||||||
console.timeEnd('>>> total page display time:');
|
consoleUtils.timeEnd('>>> total page display time:');
|
||||||
}
|
}
|
||||||
}.bind(this);
|
}.bind(this);
|
||||||
|
|
||||||
@ -368,50 +372,52 @@ function WorkerPDFDoc(canvas) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Listen to the WebWorker for data and call actionHandler on it.
|
// Listen to the WebWorker for data and call actionHandler on it.
|
||||||
this.worker.onmessage = function(event) {
|
this.worker.addEventListener('message', function(event) {
|
||||||
var data = event.data;
|
var data = event.data;
|
||||||
if (data.action in actionHandler) {
|
if (data.action in actionHandler) {
|
||||||
actionHandler[data.action].call(this, data.data);
|
actionHandler[data.action].call(this, data.data);
|
||||||
} else {
|
} else {
|
||||||
throw 'Unkown action from worker: ' + data.action;
|
throw 'Unkown action from worker: ' + data.action;
|
||||||
}
|
}
|
||||||
}.bind(this);
|
}.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
WorkerPDFDoc.prototype.open = function(url, callback) {
|
WorkerPDFDoc.prototype = {
|
||||||
var req = new XMLHttpRequest();
|
open: function(url, callback) {
|
||||||
req.open('GET', url);
|
var req = new XMLHttpRequest();
|
||||||
req.mozResponseType = req.responseType = 'arraybuffer';
|
req.open('GET', url);
|
||||||
req.expected = (document.URL.indexOf('file:') == 0) ? 0 : 200;
|
req.mozResponseType = req.responseType = 'arraybuffer';
|
||||||
req.onreadystatechange = function() {
|
req.expected = (document.URL.indexOf('file:') == 0) ? 0 : 200;
|
||||||
if (req.readyState == 4 && req.status == req.expected) {
|
req.onreadystatechange = function() {
|
||||||
var data = req.mozResponseArrayBuffer || req.mozResponse ||
|
if (req.readyState == 4 && req.status == req.expected) {
|
||||||
req.responseArrayBuffer || req.response;
|
var data = req.mozResponseArrayBuffer || req.mozResponse ||
|
||||||
|
req.responseArrayBuffer || req.response;
|
||||||
|
|
||||||
this.loadCallback = callback;
|
this.loadCallback = callback;
|
||||||
this.worker.postMessage(data);
|
this.worker.postMessage(data);
|
||||||
this.showPage(this.numPage);
|
this.showPage(this.numPage);
|
||||||
|
}
|
||||||
|
}.bind(this);
|
||||||
|
req.send(null);
|
||||||
|
},
|
||||||
|
|
||||||
|
showPage: function(numPage) {
|
||||||
|
this.numPage = parseInt(numPage, 10);
|
||||||
|
console.log('=== start rendering page ' + numPage + ' ===');
|
||||||
|
consoleUtils.time('>>> total page display time:');
|
||||||
|
this.worker.postMessage(numPage);
|
||||||
|
if (this.onChangePage) {
|
||||||
|
this.onChangePage(numPage);
|
||||||
}
|
}
|
||||||
}.bind(this);
|
},
|
||||||
req.send(null);
|
|
||||||
};
|
|
||||||
|
|
||||||
WorkerPDFDoc.prototype.showPage = function(numPage) {
|
nextPage: function() {
|
||||||
this.numPage = parseInt(numPage);
|
if (this.numPage != this.numPages)
|
||||||
console.log('=== start rendering page ' + numPage + ' ===');
|
this.showPage(++this.numPage);
|
||||||
console.time('>>> total page display time:');
|
},
|
||||||
this.worker.postMessage(numPage);
|
|
||||||
if (this.onChangePage) {
|
prevPage: function() {
|
||||||
this.onChangePage(numPage);
|
if (this.numPage != 1)
|
||||||
|
this.showPage(--this.numPage);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
WorkerPDFDoc.prototype.nextPage = function() {
|
|
||||||
if (this.numPage == this.numPages) return;
|
|
||||||
this.showPage(++this.numPage);
|
|
||||||
};
|
|
||||||
|
|
||||||
WorkerPDFDoc.prototype.prevPage = function() {
|
|
||||||
if (this.numPage == 1) return;
|
|
||||||
this.showPage(--this.numPage);
|
|
||||||
};
|
|
||||||
|
@ -25,3 +25,4 @@ var console = {
|
|||||||
this.log('Timer:', name, Date.now() - time);
|
this.log('Timer:', name, Date.now() - time);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -56,11 +56,12 @@ var actionHandler = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Listen to the MainThread for data and call actionHandler on it.
|
// Listen to the MainThread for data and call actionHandler on it.
|
||||||
this.onmessage = function(event) {
|
addEventListener('message', function(event) {
|
||||||
var data = event.data;
|
var data = event.data;
|
||||||
if (data.action in actionHandler) {
|
if (data.action in actionHandler) {
|
||||||
actionHandler[data.action].call(this, data.data);
|
actionHandler[data.action].call(this, data.data);
|
||||||
} else {
|
} else {
|
||||||
throw 'Unkown action from worker: ' + data.action;
|
throw 'Unkown action from worker: ' + data.action;
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
|
@ -11,8 +11,10 @@ var console = {
|
|||||||
action: 'log',
|
action: 'log',
|
||||||
data: args
|
data: args
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var consoleUtils = {
|
||||||
time: function(name) {
|
time: function(name) {
|
||||||
consoleTimer[name] = Date.now();
|
consoleTimer[name] = Date.now();
|
||||||
},
|
},
|
||||||
@ -22,7 +24,7 @@ var console = {
|
|||||||
if (time == null) {
|
if (time == null) {
|
||||||
throw 'Unkown timer name ' + name;
|
throw 'Unkown timer name ' + name;
|
||||||
}
|
}
|
||||||
this.log('Timer:', name, Date.now() - time);
|
console.log('Timer:', name, Date.now() - time);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -42,7 +44,7 @@ var canvas = new CanvasProxy(1224, 1584);
|
|||||||
|
|
||||||
// Listen for messages from the main thread.
|
// Listen for messages from the main thread.
|
||||||
var pdfDocument = null;
|
var pdfDocument = null;
|
||||||
onmessage = function(event) {
|
addEventListener('message', function(event) {
|
||||||
var data = event.data;
|
var data = event.data;
|
||||||
// If there is no pdfDocument yet, then the sent data is the PDFDocument.
|
// If there is no pdfDocument yet, then the sent data is the PDFDocument.
|
||||||
if (!pdfDocument) {
|
if (!pdfDocument) {
|
||||||
@ -55,10 +57,10 @@ onmessage = function(event) {
|
|||||||
}
|
}
|
||||||
// User requested to render a certain page.
|
// User requested to render a certain page.
|
||||||
else {
|
else {
|
||||||
console.time('compile');
|
consoleUtils.time('compile');
|
||||||
|
|
||||||
// Let's try to render the first page...
|
// Let's try to render the first page...
|
||||||
var page = pdfDocument.getPage(parseInt(data));
|
var page = pdfDocument.getPage(parseInt(data, 10));
|
||||||
|
|
||||||
var pdfToCssUnitsCoef = 96.0 / 72.0;
|
var pdfToCssUnitsCoef = 96.0 / 72.0;
|
||||||
var pageWidth = (page.mediaBox[2] - page.mediaBox[0]) * pdfToCssUnitsCoef;
|
var pageWidth = (page.mediaBox[2] - page.mediaBox[0]) * pdfToCssUnitsCoef;
|
||||||
@ -77,19 +79,19 @@ onmessage = function(event) {
|
|||||||
var fonts = [];
|
var fonts = [];
|
||||||
var gfx = new CanvasGraphics(canvas.getContext('2d'), CanvasProxy);
|
var gfx = new CanvasGraphics(canvas.getContext('2d'), CanvasProxy);
|
||||||
page.compile(gfx, fonts);
|
page.compile(gfx, fonts);
|
||||||
console.timeEnd('compile');
|
consoleUtils.timeEnd('compile');
|
||||||
|
|
||||||
// Send fonts to the main thread.
|
// Send fonts to the main thread.
|
||||||
console.time('fonts');
|
consoleUtils.time('fonts');
|
||||||
postMessage({
|
postMessage({
|
||||||
action: 'fonts',
|
action: 'fonts',
|
||||||
data: fonts
|
data: fonts
|
||||||
});
|
});
|
||||||
console.timeEnd('fonts');
|
consoleUtils.timeEnd('fonts');
|
||||||
|
|
||||||
console.time('display');
|
consoleUtils.time('display');
|
||||||
page.display(gfx);
|
page.display(gfx);
|
||||||
canvas.flush();
|
canvas.flush();
|
||||||
console.timeEnd('display');
|
consoleUtils.timeEnd('display');
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user