Merge branch 'master' into new-ui
Conflicts: web/viewer.html web/viewer.js
This commit is contained in:
commit
7e51d2b1f7
37
Makefile
37
Makefile
@ -6,7 +6,7 @@ DEFAULT_TESTS := test_manifest.json
|
||||
DEFAULT_PYTHON := python2.7
|
||||
|
||||
EXTENSION_SRC := ./extensions/
|
||||
EXTENSION_BASE_VERSION := 4bb289ec499013de66eb421737a4dbb4a9273eda
|
||||
EXTENSION_BASE_VERSION := f0f0418a9c6637981fe1182b9212c2d592774c7d
|
||||
FIREFOX_EXTENSION_NAME := pdf.js.xpi
|
||||
FIREFOX_AMO_EXTENSION_NAME := pdf.js.amo.xpi
|
||||
CHROME_EXTENSION_NAME := pdf.js.crx
|
||||
@ -20,6 +20,7 @@ all: bundle
|
||||
PDF_JS_FILES = \
|
||||
core.js \
|
||||
util.js \
|
||||
api.js \
|
||||
canvas.js \
|
||||
obj.js \
|
||||
function.js \
|
||||
@ -74,7 +75,8 @@ bundle: | $(BUILD_DIR)
|
||||
@cd src; \
|
||||
cat $(PDF_JS_FILES) > all_files.tmp; \
|
||||
sed '/PDFJSSCRIPT_INCLUDE_ALL/ r all_files.tmp' pdf.js > ../$(BUILD_TARGET); \
|
||||
sed -i.bak "s/PDFJSSCRIPT_BUNDLE_VER/`git log --format="%h" -n 1`/" ../$(BUILD_TARGET); \
|
||||
cp ../$(BUILD_TARGET) ../$(BUILD_TARGET).bak; \
|
||||
sed "s/PDFJSSCRIPT_BUNDLE_VER/`git log --format="%h" -n 1`/" ../$(BUILD_TARGET).bak > ../$(BUILD_TARGET); \
|
||||
rm -f ../$(BUILD_TARGET).bak; \
|
||||
rm -f *.tmp; \
|
||||
cd ..
|
||||
@ -184,7 +186,7 @@ web: | production extension compiler pages-repo
|
||||
# and deletions.
|
||||
pages-repo: | $(BUILD_DIR)
|
||||
@if [ ! -d "$(GH_PAGES)" ]; then \
|
||||
git clone -b gh-pages $(REPO) $(GH_PAGES); \
|
||||
git clone --depth 1 -b gh-pages $(REPO) $(GH_PAGES); \
|
||||
rm -rf $(GH_PAGES)/*; \
|
||||
fi;
|
||||
@mkdir -p $(GH_PAGES)/web;
|
||||
@ -211,7 +213,7 @@ pages-repo: | $(BUILD_DIR)
|
||||
# copy of the pdf.js source.
|
||||
CONTENT_DIR := content
|
||||
BUILD_NUMBER := `git log --format=oneline $(EXTENSION_BASE_VERSION).. | wc -l | awk '{print $$1}'`
|
||||
PDFJSSCRIPT_VERSION := 0.2.$(BUILD_NUMBER)
|
||||
PDFJSSCRIPT_VERSION := 0.3.$(BUILD_NUMBER)
|
||||
EXTENSION_WEB_FILES = \
|
||||
web/images \
|
||||
web/viewer.css \
|
||||
@ -273,25 +275,34 @@ extension: | production
|
||||
@cp web/viewer-snippet-firefox-extension.html $(FIREFOX_BUILD_CONTENT)/web/
|
||||
# Modify the viewer so it does all the extension only stuff.
|
||||
@cd $(FIREFOX_BUILD_CONTENT)/web; \
|
||||
sed -i.bak '/PDFJSSCRIPT_INCLUDE_BUNDLE/ r ../build/pdf.js' viewer-snippet-firefox-extension.html; \
|
||||
sed -i.bak '/PDFJSSCRIPT_REMOVE_CORE/d' viewer.html; \
|
||||
sed -i.bak '/PDFJSSCRIPT_REMOVE_FIREFOX_EXTENSION/d' viewer.html; \
|
||||
sed -i.bak '/PDFJSSCRIPT_INCLUDE_FIREFOX_EXTENSION/ r viewer-snippet-firefox-extension.html' viewer.html; \
|
||||
cp viewer-snippet-firefox-extension.html viewer-snippet-firefox-extension.html.bak; \
|
||||
sed '/PDFJSSCRIPT_INCLUDE_BUNDLE/ r ../build/pdf.js' viewer-snippet-firefox-extension.html.bak > viewer-snippet-firefox-extension.html; \
|
||||
cp viewer.html viewer.html.bak; \
|
||||
sed '/PDFJSSCRIPT_REMOVE_CORE/d' viewer.html.bak > viewer.html; \
|
||||
cp viewer.html viewer.html.bak; \
|
||||
sed '/PDFJSSCRIPT_REMOVE_FIREFOX_EXTENSION/d' viewer.html.bak > viewer.html; \
|
||||
cp viewer.html viewer.html.bak; \
|
||||
sed '/PDFJSSCRIPT_INCLUDE_FIREFOX_EXTENSION/ r viewer-snippet-firefox-extension.html' viewer.html.bak > viewer.html; \
|
||||
rm -f *.bak;
|
||||
# We don't need pdf.js anymore since its inlined
|
||||
@rm -Rf $(FIREFOX_BUILD_CONTENT)/$(BUILD_DIR)/;
|
||||
# Update the build version number
|
||||
@sed -i.bak "s/PDFJSSCRIPT_VERSION/$(PDFJSSCRIPT_VERSION)/" $(FIREFOX_BUILD_DIR)/install.rdf
|
||||
@sed -i.bak "s/PDFJSSCRIPT_VERSION/$(PDFJSSCRIPT_VERSION)/" $(FIREFOX_BUILD_DIR)/install.rdf.in
|
||||
@sed -i.bak "s/PDFJSSCRIPT_VERSION/$(PDFJSSCRIPT_VERSION)/" $(FIREFOX_BUILD_DIR)/update.rdf
|
||||
@sed -i.bak "s/PDFJSSCRIPT_VERSION/$(PDFJSSCRIPT_VERSION)/" $(FIREFOX_BUILD_DIR)/README.mozilla
|
||||
cp $(FIREFOX_BUILD_DIR)/install.rdf $(FIREFOX_BUILD_DIR)/install.rdf.bak
|
||||
@sed "s/PDFJSSCRIPT_VERSION/$(PDFJSSCRIPT_VERSION)/" $(FIREFOX_BUILD_DIR)/install.rdf.bak > $(FIREFOX_BUILD_DIR)/install.rdf
|
||||
cp $(FIREFOX_BUILD_DIR)/install.rdf.in $(FIREFOX_BUILD_DIR)/install.rdf.in.bak
|
||||
@sed "s/PDFJSSCRIPT_VERSION/$(PDFJSSCRIPT_VERSION)/" $(FIREFOX_BUILD_DIR)/install.rdf.in.bak > $(FIREFOX_BUILD_DIR)/install.rdf.in
|
||||
cp $(FIREFOX_BUILD_DIR)/update.rdf $(FIREFOX_BUILD_DIR)/update.rdf.bak
|
||||
@sed "s/PDFJSSCRIPT_VERSION/$(PDFJSSCRIPT_VERSION)/" $(FIREFOX_BUILD_DIR)/update.rdf.bak > $(FIREFOX_BUILD_DIR)/update.rdf
|
||||
cp $(FIREFOX_BUILD_DIR)/README.mozilla $(FIREFOX_BUILD_DIR)/README.mozilla.bak
|
||||
@sed "s/PDFJSSCRIPT_VERSION/$(PDFJSSCRIPT_VERSION)/" $(FIREFOX_BUILD_DIR)/README.mozilla.bak > $(FIREFOX_BUILD_DIR)/README.mozilla
|
||||
@rm -f $(FIREFOX_BUILD_DIR)/*.bak
|
||||
@find $(FIREFOX_BUILD_DIR) -name ".*" -delete
|
||||
# Create the xpi
|
||||
@cd $(FIREFOX_BUILD_DIR); zip -r $(FIREFOX_EXTENSION_NAME) $(FIREFOX_EXTENSION_FILES)
|
||||
@echo "extension created: " $(FIREFOX_EXTENSION_NAME)
|
||||
# Build the amo extension too (remove the updateUrl)
|
||||
@sed -i.bak "/updateURL/d" $(FIREFOX_BUILD_DIR)/install.rdf
|
||||
cp $(FIREFOX_BUILD_DIR)/install.rdf $(FIREFOX_BUILD_DIR)/install.rdf.bak
|
||||
@sed "/updateURL/d" $(FIREFOX_BUILD_DIR)/install.rdf.bak > $(FIREFOX_BUILD_DIR)/install.rdf
|
||||
@rm -f $(FIREFOX_BUILD_DIR)/*.bak
|
||||
@cd $(FIREFOX_BUILD_DIR); zip -r $(FIREFOX_AMO_EXTENSION_NAME) $(FIREFOX_EXTENSION_FILES)
|
||||
@echo "AMO extension created: " $(FIREFOX_AMO_EXTENSION_NAME)
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
var formFields = {};
|
||||
|
||||
function setupForm(div, content, scale) {
|
||||
function setupForm(div, content, viewport) {
|
||||
function bindInputItem(input, item) {
|
||||
if (input.name in formFields) {
|
||||
var value = formFields[input.name];
|
||||
@ -27,16 +27,20 @@ function setupForm(div, content, scale) {
|
||||
}
|
||||
function createElementWithStyle(tagName, item) {
|
||||
var element = document.createElement(tagName);
|
||||
element.style.left = (item.x * scale) + 'px';
|
||||
element.style.top = (item.y * scale) + 'px';
|
||||
element.style.width = Math.ceil(item.width * scale) + 'px';
|
||||
element.style.height = Math.ceil(item.height * scale) + 'px';
|
||||
var rect = Util.normalizeRect(
|
||||
viewport.convertToViewportRectangle(item.rect));
|
||||
element.style.left = Math.floor(rect[0]) + 'px';
|
||||
element.style.top = Math.floor(rect[1]) + 'px';
|
||||
element.style.width = Math.ceil(rect[2] - rect[0]) + 'px';
|
||||
element.style.height = Math.ceil(rect[3] - rect[1]) + 'px';
|
||||
return element;
|
||||
}
|
||||
function assignFontStyle(element, item) {
|
||||
var fontStyles = '';
|
||||
if ('fontSize' in item)
|
||||
fontStyles += 'font-size: ' + Math.round(item.fontSize * scale) + 'px;';
|
||||
if ('fontSize' in item) {
|
||||
fontStyles += 'font-size: ' + Math.round(item.fontSize *
|
||||
viewport.fontScale) + 'px;';
|
||||
}
|
||||
switch (item.textAlignment) {
|
||||
case 0:
|
||||
fontStyles += 'text-align: left;';
|
||||
@ -51,83 +55,88 @@ function setupForm(div, content, scale) {
|
||||
element.setAttribute('style', element.getAttribute('style') + fontStyles);
|
||||
}
|
||||
|
||||
var items = content.getAnnotations();
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
var item = items[i];
|
||||
switch (item.type) {
|
||||
case 'Widget':
|
||||
if (item.fieldType != 'Tx' && item.fieldType != 'Btn' &&
|
||||
item.fieldType != 'Ch')
|
||||
break;
|
||||
var inputDiv = createElementWithStyle('div', item);
|
||||
inputDiv.className = 'inputHint';
|
||||
div.appendChild(inputDiv);
|
||||
var input;
|
||||
if (item.fieldType == 'Tx') {
|
||||
input = createElementWithStyle('input', item);
|
||||
}
|
||||
if (item.fieldType == 'Btn') {
|
||||
input = createElementWithStyle('input', item);
|
||||
if (item.flags & 32768) {
|
||||
input.type = 'radio';
|
||||
// radio button is not supported
|
||||
} else if (item.flags & 65536) {
|
||||
input.type = 'button';
|
||||
// pushbutton is not supported
|
||||
} else {
|
||||
input.type = 'checkbox';
|
||||
content.getAnnotations().then(function(items) {
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
var item = items[i];
|
||||
switch (item.type) {
|
||||
case 'Widget':
|
||||
if (item.fieldType != 'Tx' && item.fieldType != 'Btn' &&
|
||||
item.fieldType != 'Ch')
|
||||
break;
|
||||
var inputDiv = createElementWithStyle('div', item);
|
||||
inputDiv.className = 'inputHint';
|
||||
div.appendChild(inputDiv);
|
||||
var input;
|
||||
if (item.fieldType == 'Tx') {
|
||||
input = createElementWithStyle('input', item);
|
||||
}
|
||||
}
|
||||
if (item.fieldType == 'Ch') {
|
||||
input = createElementWithStyle('select', item);
|
||||
// select box is not supported
|
||||
}
|
||||
input.className = 'inputControl';
|
||||
input.name = item.fullName;
|
||||
input.title = item.alternativeText;
|
||||
assignFontStyle(input, item);
|
||||
bindInputItem(input, item);
|
||||
div.appendChild(input);
|
||||
break;
|
||||
if (item.fieldType == 'Btn') {
|
||||
input = createElementWithStyle('input', item);
|
||||
if (item.flags & 32768) {
|
||||
input.type = 'radio';
|
||||
// radio button is not supported
|
||||
} else if (item.flags & 65536) {
|
||||
input.type = 'button';
|
||||
// pushbutton is not supported
|
||||
} else {
|
||||
input.type = 'checkbox';
|
||||
}
|
||||
}
|
||||
if (item.fieldType == 'Ch') {
|
||||
input = createElementWithStyle('select', item);
|
||||
// select box is not supported
|
||||
}
|
||||
input.className = 'inputControl';
|
||||
input.name = item.fullName;
|
||||
input.title = item.alternativeText;
|
||||
assignFontStyle(input, item);
|
||||
bindInputItem(input, item);
|
||||
div.appendChild(input);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function renderPage(div, pdf, pageNumber, callback) {
|
||||
var page = pdf.getPage(pageNumber);
|
||||
var scale = 1.5;
|
||||
pdf.getPage(pageNumber).then(function(page) {
|
||||
var scale = 1.5;
|
||||
var viewport = page.getViewport(scale);
|
||||
|
||||
var pageDisplayWidth = page.width * scale;
|
||||
var pageDisplayHeight = page.height * scale;
|
||||
var pageDisplayWidth = viewport.width;
|
||||
var pageDisplayHeight = viewport.height;
|
||||
|
||||
var pageDivHolder = document.createElement('div');
|
||||
pageDivHolder.className = 'pdfpage';
|
||||
pageDivHolder.style.width = pageDisplayWidth + 'px';
|
||||
pageDivHolder.style.height = pageDisplayHeight + 'px';
|
||||
div.appendChild(pageDivHolder);
|
||||
var pageDivHolder = document.createElement('div');
|
||||
pageDivHolder.className = 'pdfpage';
|
||||
pageDivHolder.style.width = pageDisplayWidth + 'px';
|
||||
pageDivHolder.style.height = pageDisplayHeight + 'px';
|
||||
div.appendChild(pageDivHolder);
|
||||
|
||||
// Prepare canvas using PDF page dimensions
|
||||
var canvas = document.createElement('canvas');
|
||||
var context = canvas.getContext('2d');
|
||||
canvas.width = pageDisplayWidth;
|
||||
canvas.height = pageDisplayHeight;
|
||||
pageDivHolder.appendChild(canvas);
|
||||
// Prepare canvas using PDF page dimensions
|
||||
var canvas = document.createElement('canvas');
|
||||
var context = canvas.getContext('2d');
|
||||
canvas.width = pageDisplayWidth;
|
||||
canvas.height = pageDisplayHeight;
|
||||
pageDivHolder.appendChild(canvas);
|
||||
|
||||
|
||||
// Render PDF page into canvas context
|
||||
page.startRendering(context, callback);
|
||||
// Render PDF page into canvas context
|
||||
var renderContext = {
|
||||
canvasContext: context,
|
||||
viewport: viewport
|
||||
};
|
||||
page.render(renderContext).then(callback);
|
||||
|
||||
// Prepare and populate form elements layer
|
||||
var formDiv = document.createElement('div');
|
||||
pageDivHolder.appendChild(formDiv);
|
||||
// Prepare and populate form elements layer
|
||||
var formDiv = document.createElement('div');
|
||||
pageDivHolder.appendChild(formDiv);
|
||||
|
||||
setupForm(formDiv, page, scale);
|
||||
setupForm(formDiv, page, viewport);
|
||||
});
|
||||
}
|
||||
|
||||
PDFJS.getPdf(pdfWithFormsPath, function getPdfForm(data) {
|
||||
// Instantiate PDFDoc with PDF data
|
||||
var pdf = new PDFJS.PDFDoc(data);
|
||||
|
||||
// Fetch the PDF document from the URL using promices
|
||||
PDFJS.getDocument(pdfWithFormsPath).then(function getPdfForm(pdf) {
|
||||
// Rendering all pages starting from first
|
||||
var viewer = document.getElementById('viewer');
|
||||
var pageNumber = 1;
|
||||
|
@ -6,6 +6,7 @@
|
||||
<!-- In production, change the content of PDFJS.workerSrc below -->
|
||||
<script type="text/javascript" src="../../src/core.js"></script>
|
||||
<script type="text/javascript" src="../../src/util.js"></script>
|
||||
<script type="text/javascript" src="../../src/api.js"></script>
|
||||
<script type="text/javascript" src="../../src/canvas.js"></script>
|
||||
<script type="text/javascript" src="../../src/obj.js"></script>
|
||||
<script type="text/javascript" src="../../src/function.js"></script>
|
||||
|
@ -7,25 +7,31 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
PDFJS.getPdf('helloworld.pdf', function getPdfHelloWorld(data) {
|
||||
//
|
||||
// Instantiate PDFDoc with PDF data
|
||||
//
|
||||
var pdf = new PDFJS.PDFDoc(data);
|
||||
var page = pdf.getPage(1);
|
||||
var scale = 1.5;
|
||||
//
|
||||
// Fetch the PDF document from the URL using promices
|
||||
//
|
||||
PDFJS.getDocument('helloworld.pdf').then(function(pdf) {
|
||||
// Using promise to fetch the page
|
||||
pdf.getPage(1).then(function(page) {
|
||||
var scale = 1.5;
|
||||
var viewport = page.getViewport(scale);
|
||||
|
||||
//
|
||||
// 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;
|
||||
//
|
||||
// Prepare canvas using PDF page dimensions
|
||||
//
|
||||
var canvas = document.getElementById('the-canvas');
|
||||
var context = canvas.getContext('2d');
|
||||
canvas.height = viewport.height;
|
||||
canvas.width = viewport.width;
|
||||
|
||||
//
|
||||
// Render PDF page into canvas context
|
||||
//
|
||||
page.startRendering(context);
|
||||
//
|
||||
// Render PDF page into canvas context
|
||||
//
|
||||
var renderContext = {
|
||||
canvasContext: context,
|
||||
viewport: viewport
|
||||
};
|
||||
page.render(renderContext);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
<!-- In production, change the content of PDFJS.workerSrc below -->
|
||||
<script type="text/javascript" src="../../src/core.js"></script>
|
||||
<script type="text/javascript" src="../../src/util.js"></script>
|
||||
<script type="text/javascript" src="../../src/api.js"></script>
|
||||
<script type="text/javascript" src="../../src/canvas.js"></script>
|
||||
<script type="text/javascript" src="../../src/obj.js"></script>
|
||||
<script type="text/javascript" src="../../src/function.js"></script>
|
||||
|
@ -153,7 +153,7 @@ PdfStreamConverter.prototype = {
|
||||
'resource://pdf.js/web/viewer.html', null, null);
|
||||
|
||||
var listener = this.listener;
|
||||
// Proxy all the requst observer calls, when it gets to onStopRequst
|
||||
// Proxy all the request observer calls, when it gets to onStopRequest
|
||||
// we can get the dom window.
|
||||
var proxy = {
|
||||
onStartRequest: function() {
|
||||
|
5
make.js
5
make.js
@ -79,6 +79,7 @@ target.bundle = function() {
|
||||
var SRC_FILES =
|
||||
['core.js',
|
||||
'util.js',
|
||||
'api.js',
|
||||
'canvas.js',
|
||||
'obj.js',
|
||||
'function.js',
|
||||
@ -175,8 +176,8 @@ var EXTENSION_WEB_FILES =
|
||||
'web/viewer.js',
|
||||
'web/viewer.html',
|
||||
'web/viewer-production.html'],
|
||||
EXTENSION_BASE_VERSION = '4bb289ec499013de66eb421737a4dbb4a9273eda',
|
||||
EXTENSION_VERSION_PREFIX = '0.2.',
|
||||
EXTENSION_BASE_VERSION = 'f0f0418a9c6637981fe1182b9212c2d592774c7d',
|
||||
EXTENSION_VERSION_PREFIX = '0.3.',
|
||||
EXTENSION_BUILD_NUMBER,
|
||||
EXTENSION_VERSION;
|
||||
|
||||
|
590
src/api.js
Normal file
590
src/api.js
Normal file
@ -0,0 +1,590 @@
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
|
||||
/**
|
||||
* This is the main entry point for loading a PDF and interacting with it.
|
||||
* NOTE: If a URL is used to fetch the PDF data a standard XMLHttpRequest(XHR)
|
||||
* is used, which means it must follow the same origin rules that any XHR does
|
||||
* e.g. No cross domain requests without CORS.
|
||||
*
|
||||
* @param {string|TypedAray} source Either a url to a PDF is located or a
|
||||
* typed array already populated with data.
|
||||
* @return {Promise} A promise that is resolved with {PDFDocumentProxy} object.
|
||||
*/
|
||||
PDFJS.getDocument = function getDocument(source) {
|
||||
var promise = new PDFJS.Promise();
|
||||
var transport = new WorkerTransport(promise);
|
||||
if (typeof source === 'string') {
|
||||
// fetch url
|
||||
PDFJS.getPdf(
|
||||
{
|
||||
url: source,
|
||||
progress: function getPDFProgress(evt) {
|
||||
if (evt.lengthComputable)
|
||||
promise.progress({
|
||||
loaded: evt.loaded,
|
||||
total: evt.total
|
||||
});
|
||||
},
|
||||
error: function getPDFError(e) {
|
||||
promise.reject('Unexpected server response of ' +
|
||||
e.target.status + '.');
|
||||
}
|
||||
},
|
||||
function getPDFLoad(data) {
|
||||
transport.sendData(data);
|
||||
});
|
||||
} else {
|
||||
// assuming the source is array, instantiating directly from it
|
||||
transport.sendData(source);
|
||||
}
|
||||
return promise;
|
||||
};
|
||||
|
||||
/**
|
||||
* Proxy to a PDFDocument in the worker thread. Also, contains commonly used
|
||||
* properties that can be read synchronously.
|
||||
*/
|
||||
var PDFDocumentProxy = (function() {
|
||||
function PDFDocumentProxy(pdfInfo, transport) {
|
||||
this.pdfInfo = pdfInfo;
|
||||
this.transport = transport;
|
||||
}
|
||||
PDFDocumentProxy.prototype = {
|
||||
/**
|
||||
* @return {number} Total number of pages the PDF contains.
|
||||
*/
|
||||
get numPages() {
|
||||
return this.pdfInfo.numPages;
|
||||
},
|
||||
/**
|
||||
* @return {string} A unique ID to identify a PDF. Not guaranteed to be
|
||||
* unique.
|
||||
*/
|
||||
get fingerprint() {
|
||||
return this.pdfInfo.fingerprint;
|
||||
},
|
||||
/**
|
||||
* @param {number} The page number to get. The first page is 1.
|
||||
* @return {Promise} A promise that is resolved with a {PDFPageProxy}
|
||||
* object.
|
||||
*/
|
||||
getPage: function(number) {
|
||||
return this.transport.getPage(number);
|
||||
},
|
||||
/**
|
||||
* @return {Promise} A promise that is resolved with a lookup table for
|
||||
* mapping named destinations to reference numbers.
|
||||
*/
|
||||
getDestinations: function() {
|
||||
var promise = new PDFJS.Promise();
|
||||
var destinations = this.pdfInfo.destinations;
|
||||
promise.resolve(destinations);
|
||||
return promise;
|
||||
},
|
||||
/**
|
||||
* @return {Promise} A promise that is resolved with an {array} that is a
|
||||
* tree outline (if it has one) of the PDF. The tree is in the format of:
|
||||
* [
|
||||
* {
|
||||
* title: string,
|
||||
* bold: boolean,
|
||||
* italic: boolean,
|
||||
* color: rgb array,
|
||||
* dest: dest obj,
|
||||
* items: array of more items like this
|
||||
* },
|
||||
* ...
|
||||
* ].
|
||||
*/
|
||||
getOutline: function() {
|
||||
var promise = new PDFJS.Promise();
|
||||
var outline = this.pdfInfo.outline;
|
||||
promise.resolve(outline);
|
||||
return promise;
|
||||
},
|
||||
/**
|
||||
* @return {Promise} A promise that is resolved with an {object} that has
|
||||
* info and metadata properties. Info is an {object} filled with anything
|
||||
* available in the information dictionary and similarly metadata is a
|
||||
* {Metadata} object with information from the metadata section of the PDF.
|
||||
*/
|
||||
getMetadata: function() {
|
||||
var promise = new PDFJS.Promise();
|
||||
var info = this.pdfInfo.info;
|
||||
var metadata = this.pdfInfo.metadata;
|
||||
promise.resolve({
|
||||
info: info,
|
||||
metadata: metadata ? new PDFJS.Metadata(metadata) : null
|
||||
});
|
||||
return promise;
|
||||
},
|
||||
destroy: function() {
|
||||
this.transport.destroy();
|
||||
}
|
||||
};
|
||||
return PDFDocumentProxy;
|
||||
})();
|
||||
|
||||
var PDFPageProxy = (function PDFPageProxyClosure() {
|
||||
function PDFPageProxy(pageInfo, transport) {
|
||||
this.pageInfo = pageInfo;
|
||||
this.transport = transport;
|
||||
this.stats = new StatTimer();
|
||||
this.stats.enabled = !!globalScope.PDFJS.enableStats;
|
||||
this.objs = transport.objs;
|
||||
this.renderInProgress = false;
|
||||
}
|
||||
PDFPageProxy.prototype = {
|
||||
/**
|
||||
* @return {number} Page number of the page. First page is 1.
|
||||
*/
|
||||
get pageNumber() {
|
||||
return this.pageInfo.pageIndex + 1;
|
||||
},
|
||||
/**
|
||||
* @return {number} The number of degrees the page is rotated clockwise.
|
||||
*/
|
||||
get rotate() {
|
||||
return this.pageInfo.rotate;
|
||||
},
|
||||
/**
|
||||
* @return {object} The reference that points to this page. It has 'num' and
|
||||
* 'gen' properties.
|
||||
*/
|
||||
get ref() {
|
||||
return this.pageInfo.ref;
|
||||
},
|
||||
/**
|
||||
* @return {array} An array of the visible portion of the PDF page in the
|
||||
* user space units - [x1, y1, x2, y2].
|
||||
*/
|
||||
get view() {
|
||||
return this.pageInfo.view;
|
||||
},
|
||||
/**
|
||||
* @param {number} scale The desired scale of the viewport.
|
||||
* @param {number} rotate Degrees to rotate the viewport. If omitted this
|
||||
* defaults to the page rotation.
|
||||
* @return {PageViewport} Contains 'width' and 'height' properties along
|
||||
* with transforms required for rendering.
|
||||
*/
|
||||
getViewport: function(scale, rotate) {
|
||||
if (arguments.length < 2)
|
||||
rotate = this.rotate;
|
||||
return new PDFJS.PageViewport(this.view, scale, rotate, 0, 0);
|
||||
},
|
||||
/**
|
||||
* @return {Promise} A promise that is resolved with an {array} of the
|
||||
* annotation objects.
|
||||
*/
|
||||
getAnnotations: function() {
|
||||
if (this.annotationsPromise)
|
||||
return this.annotationsPromise;
|
||||
|
||||
var promise = new PDFJS.Promise();
|
||||
this.annotationsPromise = promise;
|
||||
this.transport.getAnnotations(this.pageInfo.pageIndex);
|
||||
return promise;
|
||||
},
|
||||
/**
|
||||
* Begins the process of rendering a page to the desired context.
|
||||
* @param {object} params A parameter object that supports:
|
||||
* {
|
||||
* canvasContext(required): A 2D context of a DOM Canvas object.,
|
||||
* textLayer(optional): An object that has beginLayout, endLayout, and
|
||||
* appendText functions.
|
||||
* }.
|
||||
* @return {Promise} A promise that is resolved when the page finishes
|
||||
* rendering.
|
||||
*/
|
||||
render: function(params) {
|
||||
this.renderInProgress = true;
|
||||
|
||||
var promise = new Promise();
|
||||
var stats = this.stats;
|
||||
stats.time('Overall');
|
||||
// If there is no displayReadyPromise yet, then the operatorList was never
|
||||
// requested before. Make the request and create the promise.
|
||||
if (!this.displayReadyPromise) {
|
||||
this.displayReadyPromise = new Promise();
|
||||
this.destroyed = false;
|
||||
|
||||
this.stats.time('Page Request');
|
||||
this.transport.messageHandler.send('RenderPageRequest', {
|
||||
pageIndex: this.pageNumber - 1
|
||||
});
|
||||
}
|
||||
|
||||
var self = this;
|
||||
function complete(error) {
|
||||
self.renderInProgress = false;
|
||||
if (self.destroyed) {
|
||||
delete self.operatorList;
|
||||
delete self.displayReadyPromise;
|
||||
}
|
||||
|
||||
if (error)
|
||||
promise.reject(error);
|
||||
else
|
||||
promise.resolve();
|
||||
};
|
||||
|
||||
// Once the operatorList and fonts are loaded, do the actual rendering.
|
||||
this.displayReadyPromise.then(
|
||||
function pageDisplayReadyPromise() {
|
||||
if (self.destroyed) {
|
||||
complete();
|
||||
return;
|
||||
}
|
||||
|
||||
var gfx = new CanvasGraphics(params.canvasContext,
|
||||
this.objs, params.textLayer);
|
||||
try {
|
||||
this.display(gfx, params.viewport, complete);
|
||||
} catch (e) {
|
||||
complete(e);
|
||||
}
|
||||
}.bind(this),
|
||||
function pageDisplayReadPromiseError(reason) {
|
||||
complete(reason);
|
||||
}
|
||||
);
|
||||
|
||||
return promise;
|
||||
},
|
||||
/**
|
||||
* For internal use only.
|
||||
*/
|
||||
startRenderingFromOperatorList:
|
||||
function PDFPageWrapper_startRenderingFromOperatorList(operatorList,
|
||||
fonts) {
|
||||
var self = this;
|
||||
this.operatorList = operatorList;
|
||||
|
||||
var displayContinuation = function pageDisplayContinuation() {
|
||||
// Always defer call to display() to work around bug in
|
||||
// Firefox error reporting from XHR callbacks.
|
||||
setTimeout(function pageSetTimeout() {
|
||||
self.displayReadyPromise.resolve();
|
||||
});
|
||||
};
|
||||
|
||||
this.ensureFonts(fonts,
|
||||
function pageStartRenderingFromOperatorListEnsureFonts() {
|
||||
displayContinuation();
|
||||
}
|
||||
);
|
||||
},
|
||||
/**
|
||||
* For internal use only.
|
||||
*/
|
||||
ensureFonts: function PDFPageWrapper_ensureFonts(fonts, callback) {
|
||||
this.stats.time('Font Loading');
|
||||
// Convert the font names to the corresponding font obj.
|
||||
for (var i = 0, ii = fonts.length; i < ii; i++) {
|
||||
fonts[i] = this.objs.objs[fonts[i]].data;
|
||||
}
|
||||
|
||||
// Load all the fonts
|
||||
FontLoader.bind(
|
||||
fonts,
|
||||
function pageEnsureFontsFontObjs(fontObjs) {
|
||||
this.stats.timeEnd('Font Loading');
|
||||
|
||||
callback.call(this);
|
||||
}.bind(this)
|
||||
);
|
||||
},
|
||||
/**
|
||||
* For internal use only.
|
||||
*/
|
||||
display: function PDFPageWrapper_display(gfx, viewport, callback) {
|
||||
var stats = this.stats;
|
||||
stats.time('Rendering');
|
||||
|
||||
gfx.beginDrawing(viewport);
|
||||
|
||||
var startIdx = 0;
|
||||
var length = this.operatorList.fnArray.length;
|
||||
var operatorList = this.operatorList;
|
||||
var stepper = null;
|
||||
if (PDFJS.pdfBug && StepperManager.enabled) {
|
||||
stepper = StepperManager.create(this.pageNumber - 1);
|
||||
stepper.init(operatorList);
|
||||
stepper.nextBreakPoint = stepper.getNextBreakPoint();
|
||||
}
|
||||
|
||||
var self = this;
|
||||
function next() {
|
||||
startIdx =
|
||||
gfx.executeOperatorList(operatorList, startIdx, next, stepper);
|
||||
if (startIdx == length) {
|
||||
gfx.endDrawing();
|
||||
stats.timeEnd('Rendering');
|
||||
stats.timeEnd('Overall');
|
||||
if (callback) callback();
|
||||
}
|
||||
}
|
||||
next();
|
||||
},
|
||||
/**
|
||||
* Stub for future feature.
|
||||
*/
|
||||
getTextContent: function() {
|
||||
var promise = new PDFJS.Promise();
|
||||
var textContent = 'page text'; // not implemented
|
||||
promise.resolve(textContent);
|
||||
return promise;
|
||||
},
|
||||
/**
|
||||
* Stub for future feature.
|
||||
*/
|
||||
getOperationList: function() {
|
||||
var promise = new PDFJS.Promise();
|
||||
var operationList = { // not implemented
|
||||
dependencyFontsID: null,
|
||||
operatorList: null
|
||||
};
|
||||
promise.resolve(operationList);
|
||||
return promise;
|
||||
},
|
||||
/**
|
||||
* Destroys resources allocated by the page.
|
||||
*/
|
||||
destroy: function() {
|
||||
this.destroyed = true;
|
||||
|
||||
if (!this.renderInProgress) {
|
||||
delete this.operatorList;
|
||||
delete this.displayReadyPromise;
|
||||
}
|
||||
}
|
||||
};
|
||||
return PDFPageProxy;
|
||||
})();
|
||||
/**
|
||||
* For internal use only.
|
||||
*/
|
||||
var WorkerTransport = (function WorkerTransportClosure() {
|
||||
function WorkerTransport(promise) {
|
||||
this.workerReadyPromise = promise;
|
||||
this.objs = new PDFObjects();
|
||||
|
||||
this.pageCache = [];
|
||||
this.pagePromises = [];
|
||||
this.fontsLoading = {};
|
||||
|
||||
// If worker support isn't disabled explicit and the browser has worker
|
||||
// support, create a new web worker and test if it/the browser fullfills
|
||||
// all requirements to run parts of pdf.js in a web worker.
|
||||
// Right now, the requirement is, that an Uint8Array is still an Uint8Array
|
||||
// as it arrives on the worker. Chrome added this with version 15.
|
||||
if (!globalScope.PDFJS.disableWorker && typeof Worker !== 'undefined') {
|
||||
var workerSrc = PDFJS.workerSrc;
|
||||
if (typeof workerSrc === 'undefined') {
|
||||
error('No PDFJS.workerSrc specified');
|
||||
}
|
||||
|
||||
try {
|
||||
var worker;
|
||||
if (PDFJS.isFirefoxExtension) {
|
||||
// The firefox extension can't load the worker from the resource://
|
||||
// url so we have to inline the script and then use the blob loader.
|
||||
var bb = new MozBlobBuilder();
|
||||
bb.append(document.querySelector('#PDFJS_SCRIPT_TAG').textContent);
|
||||
var blobUrl = window.URL.createObjectURL(bb.getBlob());
|
||||
worker = new Worker(blobUrl);
|
||||
} else {
|
||||
// Some versions of FF can't create a worker on localhost, see:
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=683280
|
||||
worker = new Worker(workerSrc);
|
||||
}
|
||||
|
||||
var messageHandler = new MessageHandler('main', worker);
|
||||
this.messageHandler = messageHandler;
|
||||
|
||||
messageHandler.on('test', function transportTest(supportTypedArray) {
|
||||
if (supportTypedArray) {
|
||||
this.worker = worker;
|
||||
this.setupMessageHandler(messageHandler);
|
||||
} else {
|
||||
globalScope.PDFJS.disableWorker = true;
|
||||
this.setupFakeWorker();
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
var testObj = new Uint8Array(1);
|
||||
// Some versions of Opera throw a DATA_CLONE_ERR on
|
||||
// serializing the typed array.
|
||||
messageHandler.send('test', testObj);
|
||||
return;
|
||||
} catch (e) {
|
||||
warn('The worker has been disabled.');
|
||||
}
|
||||
}
|
||||
// Either workers are disabled, not supported or have thrown an exception.
|
||||
// Thus, we fallback to a faked worker.
|
||||
globalScope.PDFJS.disableWorker = true;
|
||||
this.setupFakeWorker();
|
||||
}
|
||||
WorkerTransport.prototype = {
|
||||
destroy: function WorkerTransport_destroy() {
|
||||
if (this.worker)
|
||||
this.worker.terminate();
|
||||
|
||||
this.pageCache = [];
|
||||
this.pagePromises = [];
|
||||
},
|
||||
setupFakeWorker: function WorkerTransport_setupFakeWorker() {
|
||||
// If we don't use a worker, just post/sendMessage to the main thread.
|
||||
var fakeWorker = {
|
||||
postMessage: function WorkerTransport_postMessage(obj) {
|
||||
fakeWorker.onmessage({data: obj});
|
||||
},
|
||||
terminate: function WorkerTransport_terminate() {}
|
||||
};
|
||||
|
||||
var messageHandler = new MessageHandler('main', fakeWorker);
|
||||
this.setupMessageHandler(messageHandler);
|
||||
|
||||
// If the main thread is our worker, setup the handling for the messages
|
||||
// the main thread sends to it self.
|
||||
WorkerMessageHandler.setup(messageHandler);
|
||||
},
|
||||
|
||||
setupMessageHandler:
|
||||
function WorkerTransport_setupMessageHandler(messageHandler) {
|
||||
this.messageHandler = messageHandler;
|
||||
|
||||
messageHandler.on('GetDoc', function transportDoc(data) {
|
||||
var pdfInfo = data.pdfInfo;
|
||||
var pdfDocument = new PDFDocumentProxy(pdfInfo, this);
|
||||
this.pdfDocument = pdfDocument;
|
||||
this.workerReadyPromise.resolve(pdfDocument);
|
||||
}, this);
|
||||
|
||||
messageHandler.on('GetPage', function transportPage(data) {
|
||||
var pageInfo = data.pageInfo;
|
||||
var page = new PDFPageProxy(pageInfo, this);
|
||||
this.pageCache[pageInfo.pageIndex] = page;
|
||||
var promise = this.pagePromises[pageInfo.pageIndex];
|
||||
promise.resolve(page);
|
||||
}, this);
|
||||
|
||||
messageHandler.on('GetAnnotations', function transportAnnotations(data) {
|
||||
var annotations = data.annotations;
|
||||
var promise = this.pageCache[data.pageIndex].annotationsPromise;
|
||||
promise.resolve(annotations);
|
||||
}, this);
|
||||
|
||||
messageHandler.on('RenderPage', function transportRender(data) {
|
||||
var page = this.pageCache[data.pageIndex];
|
||||
var depFonts = data.depFonts;
|
||||
|
||||
page.stats.timeEnd('Page Request');
|
||||
page.startRenderingFromOperatorList(data.operatorList, depFonts);
|
||||
}, this);
|
||||
|
||||
messageHandler.on('obj', function transportObj(data) {
|
||||
var id = data[0];
|
||||
var type = data[1];
|
||||
if (this.objs.hasData(id))
|
||||
return;
|
||||
|
||||
switch (type) {
|
||||
case 'JpegStream':
|
||||
var imageData = data[2];
|
||||
loadJpegStream(id, imageData, this.objs);
|
||||
break;
|
||||
case 'Image':
|
||||
var imageData = data[2];
|
||||
this.objs.resolve(id, imageData);
|
||||
break;
|
||||
case 'Font':
|
||||
var name = data[2];
|
||||
var file = data[3];
|
||||
var properties = data[4];
|
||||
|
||||
if (file) {
|
||||
// Rewrap the ArrayBuffer in a stream.
|
||||
var fontFileDict = new Dict();
|
||||
file = new Stream(file, 0, file.length, fontFileDict);
|
||||
}
|
||||
|
||||
// At this point, only the font object is created but the font is
|
||||
// not yet attached to the DOM. This is done in `FontLoader.bind`.
|
||||
var font = new Font(name, file, properties);
|
||||
this.objs.resolve(id, font);
|
||||
break;
|
||||
default:
|
||||
error('Got unkown object type ' + type);
|
||||
}
|
||||
}, this);
|
||||
|
||||
messageHandler.on('PageError', function transportError(data) {
|
||||
var page = this.pageCache[data.pageNum - 1];
|
||||
if (page.displayReadyPromise)
|
||||
page.displayReadyPromise.reject(data.error);
|
||||
else
|
||||
error(data.error);
|
||||
}, this);
|
||||
|
||||
messageHandler.on('JpegDecode', function(data, promise) {
|
||||
var imageData = data[0];
|
||||
var components = data[1];
|
||||
if (components != 3 && components != 1)
|
||||
error('Only 3 component or 1 component can be returned');
|
||||
|
||||
var img = new Image();
|
||||
img.onload = (function messageHandler_onloadClosure() {
|
||||
var width = img.width;
|
||||
var height = img.height;
|
||||
var size = width * height;
|
||||
var rgbaLength = size * 4;
|
||||
var buf = new Uint8Array(size * components);
|
||||
var tmpCanvas = createScratchCanvas(width, height);
|
||||
var tmpCtx = tmpCanvas.getContext('2d');
|
||||
tmpCtx.drawImage(img, 0, 0);
|
||||
var data = tmpCtx.getImageData(0, 0, width, height).data;
|
||||
|
||||
if (components == 3) {
|
||||
for (var i = 0, j = 0; i < rgbaLength; i += 4, j += 3) {
|
||||
buf[j] = data[i];
|
||||
buf[j + 1] = data[i + 1];
|
||||
buf[j + 2] = data[i + 2];
|
||||
}
|
||||
} else if (components == 1) {
|
||||
for (var i = 0, j = 0; i < rgbaLength; i += 4, j++) {
|
||||
buf[j] = data[i];
|
||||
}
|
||||
}
|
||||
promise.resolve({ data: buf, width: width, height: height});
|
||||
}).bind(this);
|
||||
var src = 'data:image/jpeg;base64,' + window.btoa(imageData);
|
||||
img.src = src;
|
||||
});
|
||||
},
|
||||
|
||||
sendData: function WorkerTransport_sendData(data) {
|
||||
this.messageHandler.send('GetDocRequest', data);
|
||||
},
|
||||
|
||||
getPage: function WorkerTransport_getPage(pageNumber, promise) {
|
||||
var pageIndex = pageNumber - 1;
|
||||
if (pageIndex in this.pagePromises)
|
||||
return this.pagePromises[pageIndex];
|
||||
var promise = new PDFJS.Promise('Page ' + pageNumber);
|
||||
this.pagePromises[pageIndex] = promise;
|
||||
this.messageHandler.send('GetPageRequest', { pageIndex: pageIndex });
|
||||
return promise;
|
||||
},
|
||||
|
||||
getAnnotations: function WorkerTransport_getAnnotations(pageIndex) {
|
||||
this.messageHandler.send('GetAnnotationsRequest',
|
||||
{ pageIndex: pageIndex });
|
||||
}
|
||||
};
|
||||
return WorkerTransport;
|
||||
|
||||
})();
|
@ -241,27 +241,10 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
||||
'shadingFill': true
|
||||
},
|
||||
|
||||
beginDrawing: function CanvasGraphics_beginDrawing(mediaBox) {
|
||||
var cw = this.ctx.canvas.width, ch = this.ctx.canvas.height;
|
||||
beginDrawing: function CanvasGraphics_beginDrawing(viewport) {
|
||||
var transform = viewport.transform;
|
||||
this.ctx.save();
|
||||
switch (mediaBox.rotate) {
|
||||
case 0:
|
||||
this.ctx.transform(1, 0, 0, -1, 0, ch);
|
||||
break;
|
||||
case 90:
|
||||
this.ctx.transform(0, 1, 1, 0, 0, 0);
|
||||
break;
|
||||
case 180:
|
||||
this.ctx.transform(-1, 0, 0, 1, cw, 0);
|
||||
break;
|
||||
case 270:
|
||||
this.ctx.transform(0, -1, -1, 0, cw, ch);
|
||||
break;
|
||||
}
|
||||
// Scale so that canvas units are the same as PDF user space units
|
||||
this.ctx.scale(cw / mediaBox.width, ch / mediaBox.height);
|
||||
// Move the media left-top corner to the (0,0) canvas position
|
||||
this.ctx.translate(-mediaBox.x, -mediaBox.y);
|
||||
this.ctx.transform.apply(this.ctx, transform);
|
||||
|
||||
if (this.textLayer)
|
||||
this.textLayer.beginLayout();
|
||||
|
466
src/core.js
466
src/core.js
@ -63,8 +63,6 @@ var Page = (function PageClosure() {
|
||||
function Page(xref, pageNumber, pageDict, ref) {
|
||||
this.pageNumber = pageNumber;
|
||||
this.pageDict = pageDict;
|
||||
this.stats = new StatTimer();
|
||||
this.stats.enabled = !!globalScope.PDFJS.enableStats;
|
||||
this.xref = xref;
|
||||
this.ref = ref;
|
||||
|
||||
@ -100,18 +98,10 @@ var Page = (function PageClosure() {
|
||||
return shadow(this, 'mediaBox', obj);
|
||||
},
|
||||
get view() {
|
||||
var cropBox = this.inheritPageProp('CropBox');
|
||||
var view = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: this.width,
|
||||
height: this.height
|
||||
};
|
||||
if (!isArray(cropBox) || cropBox.length !== 4)
|
||||
return shadow(this, 'view', view);
|
||||
|
||||
var mediaBox = this.mediaBox;
|
||||
var offsetX = mediaBox[0], offsetY = mediaBox[1];
|
||||
var cropBox = this.inheritPageProp('CropBox');
|
||||
if (!isArray(cropBox) || cropBox.length !== 4)
|
||||
return shadow(this, 'view', mediaBox);
|
||||
|
||||
// From the spec, 6th ed., p.963:
|
||||
// "The crop, bleed, trim, and art boxes should not ordinarily
|
||||
@ -119,42 +109,13 @@ var Page = (function PageClosure() {
|
||||
// effectively reduced to their intersection with the media box."
|
||||
cropBox = Util.intersect(cropBox, mediaBox);
|
||||
if (!cropBox)
|
||||
return shadow(this, 'view', view);
|
||||
return shadow(this, 'view', mediaBox);
|
||||
|
||||
var tl = this.rotatePoint(cropBox[0] - offsetX, cropBox[1] - offsetY);
|
||||
var br = this.rotatePoint(cropBox[2] - offsetX, cropBox[3] - offsetY);
|
||||
view.x = Math.min(tl.x, br.x);
|
||||
view.y = Math.min(tl.y, br.y);
|
||||
view.width = Math.abs(tl.x - br.x);
|
||||
view.height = Math.abs(tl.y - br.y);
|
||||
|
||||
return shadow(this, 'view', view);
|
||||
return shadow(this, 'view', cropBox);
|
||||
},
|
||||
get annotations() {
|
||||
return shadow(this, 'annotations', this.inheritPageProp('Annots'));
|
||||
},
|
||||
get width() {
|
||||
var mediaBox = this.mediaBox;
|
||||
var rotate = this.rotate;
|
||||
var width;
|
||||
if (rotate == 0 || rotate == 180) {
|
||||
width = (mediaBox[2] - mediaBox[0]);
|
||||
} else {
|
||||
width = (mediaBox[3] - mediaBox[1]);
|
||||
}
|
||||
return shadow(this, 'width', width);
|
||||
},
|
||||
get height() {
|
||||
var mediaBox = this.mediaBox;
|
||||
var rotate = this.rotate;
|
||||
var height;
|
||||
if (rotate == 0 || rotate == 180) {
|
||||
height = (mediaBox[3] - mediaBox[1]);
|
||||
} else {
|
||||
height = (mediaBox[2] - mediaBox[0]);
|
||||
}
|
||||
return shadow(this, 'height', height);
|
||||
},
|
||||
get rotate() {
|
||||
var rotate = this.inheritPageProp('Rotate') || 0;
|
||||
// Normalize rotation so it's a multiple of 90 and between 0 and 270
|
||||
@ -170,43 +131,19 @@ var Page = (function PageClosure() {
|
||||
return shadow(this, 'rotate', rotate);
|
||||
},
|
||||
|
||||
startRenderingFromOperatorList:
|
||||
function Page_startRenderingFromOperatorList(operatorList, fonts) {
|
||||
var self = this;
|
||||
this.operatorList = operatorList;
|
||||
|
||||
var displayContinuation = function pageDisplayContinuation() {
|
||||
// Always defer call to display() to work around bug in
|
||||
// Firefox error reporting from XHR callbacks.
|
||||
setTimeout(function pageSetTimeout() {
|
||||
self.displayReadyPromise.resolve();
|
||||
});
|
||||
};
|
||||
|
||||
this.ensureFonts(fonts,
|
||||
function pageStartRenderingFromOperatorListEnsureFonts() {
|
||||
displayContinuation();
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
getOperatorList: function Page_getOperatorList(handler, dependency) {
|
||||
if (this.operatorList) {
|
||||
// content was compiled
|
||||
return this.operatorList;
|
||||
}
|
||||
|
||||
this.stats.time('Build IR Queue');
|
||||
|
||||
var xref = this.xref;
|
||||
var content = this.content;
|
||||
var resources = this.resources;
|
||||
if (isArray(content)) {
|
||||
// fetching items
|
||||
var streams = [];
|
||||
var i, n = content.length;
|
||||
for (i = 0; i < n; ++i)
|
||||
content[i] = xref.fetchIfRef(content[i]);
|
||||
content = new StreamsSequenceStream(content);
|
||||
streams.push(xref.fetchIfRef(content[i]));
|
||||
content = new StreamsSequenceStream(streams);
|
||||
} else if (isStream(content)) {
|
||||
content.reset();
|
||||
} else if (!content) {
|
||||
// replacing non-existent page content with empty one
|
||||
content = new Stream(new Uint8Array(0));
|
||||
@ -215,82 +152,9 @@ var Page = (function PageClosure() {
|
||||
var pe = this.pe = new PartialEvaluator(
|
||||
xref, handler, 'p' + this.pageNumber + '_');
|
||||
|
||||
this.operatorList = pe.getOperatorList(content, resources, dependency);
|
||||
this.stats.timeEnd('Build IR Queue');
|
||||
return this.operatorList;
|
||||
return pe.getOperatorList(content, resources, dependency);
|
||||
},
|
||||
|
||||
ensureFonts: function Page_ensureFonts(fonts, callback) {
|
||||
this.stats.time('Font Loading');
|
||||
// Convert the font names to the corresponding font obj.
|
||||
for (var i = 0, ii = fonts.length; i < ii; i++) {
|
||||
fonts[i] = this.objs.objs[fonts[i]].data;
|
||||
}
|
||||
|
||||
// Load all the fonts
|
||||
FontLoader.bind(
|
||||
fonts,
|
||||
function pageEnsureFontsFontObjs(fontObjs) {
|
||||
this.stats.timeEnd('Font Loading');
|
||||
|
||||
callback.call(this);
|
||||
}.bind(this)
|
||||
);
|
||||
},
|
||||
|
||||
display: function Page_display(gfx, callback) {
|
||||
var stats = this.stats;
|
||||
stats.time('Rendering');
|
||||
var xref = this.xref;
|
||||
var resources = this.resources;
|
||||
var mediaBox = this.mediaBox;
|
||||
assertWellFormed(isDict(resources), 'invalid page resources');
|
||||
|
||||
gfx.xref = xref;
|
||||
gfx.res = resources;
|
||||
gfx.beginDrawing({ x: mediaBox[0], y: mediaBox[1],
|
||||
width: this.width,
|
||||
height: this.height,
|
||||
rotate: this.rotate });
|
||||
|
||||
var startIdx = 0;
|
||||
var length = this.operatorList.fnArray.length;
|
||||
var operatorList = this.operatorList;
|
||||
var stepper = null;
|
||||
if (PDFJS.pdfBug && StepperManager.enabled) {
|
||||
stepper = StepperManager.create(this.pageNumber);
|
||||
stepper.init(operatorList);
|
||||
stepper.nextBreakPoint = stepper.getNextBreakPoint();
|
||||
}
|
||||
|
||||
var self = this;
|
||||
function next() {
|
||||
startIdx =
|
||||
gfx.executeOperatorList(operatorList, startIdx, next, stepper);
|
||||
if (startIdx == length) {
|
||||
gfx.endDrawing();
|
||||
stats.timeEnd('Rendering');
|
||||
stats.timeEnd('Overall');
|
||||
if (callback) callback();
|
||||
}
|
||||
}
|
||||
next();
|
||||
},
|
||||
rotatePoint: function Page_rotatePoint(x, y, reverse) {
|
||||
var rotate = reverse ? (360 - this.rotate) : this.rotate;
|
||||
switch (rotate) {
|
||||
case 180:
|
||||
return {x: this.width - x, y: y};
|
||||
case 90:
|
||||
return {x: this.width - y, y: this.height - x};
|
||||
case 270:
|
||||
return {x: y, y: x};
|
||||
case 360:
|
||||
case 0:
|
||||
default:
|
||||
return {x: x, y: this.height - y};
|
||||
}
|
||||
},
|
||||
getLinks: function Page_getLinks() {
|
||||
var links = [];
|
||||
var annotations = pageGetAnnotations();
|
||||
@ -342,15 +206,10 @@ var Page = (function PageClosure() {
|
||||
if (!isName(subtype))
|
||||
continue;
|
||||
var rect = annotation.get('Rect');
|
||||
var topLeftCorner = this.rotatePoint(rect[0], rect[1]);
|
||||
var bottomRightCorner = this.rotatePoint(rect[2], rect[3]);
|
||||
|
||||
var item = {};
|
||||
item.type = subtype.name;
|
||||
item.x = Math.min(topLeftCorner.x, bottomRightCorner.x);
|
||||
item.y = Math.min(topLeftCorner.y, bottomRightCorner.y);
|
||||
item.width = Math.abs(topLeftCorner.x - bottomRightCorner.x);
|
||||
item.height = Math.abs(topLeftCorner.y - bottomRightCorner.y);
|
||||
item.rect = rect;
|
||||
switch (subtype.name) {
|
||||
case 'Link':
|
||||
var a = annotation.get('A');
|
||||
@ -424,7 +283,8 @@ var Page = (function PageClosure() {
|
||||
var title = annotation.get('T');
|
||||
item.content = stringToPDFString(content || '');
|
||||
item.title = stringToPDFString(title || '');
|
||||
item.name = annotation.get('Name').name;
|
||||
item.name = !annotation.has('Name') ? 'Note' :
|
||||
annotation.get('Name').name;
|
||||
break;
|
||||
default:
|
||||
TODO('unimplemented annotation type: ' + subtype.name);
|
||||
@ -433,37 +293,6 @@ var Page = (function PageClosure() {
|
||||
items.push(item);
|
||||
}
|
||||
return items;
|
||||
},
|
||||
startRendering: function Page_startRendering(ctx, callback, textLayer) {
|
||||
var stats = this.stats;
|
||||
stats.time('Overall');
|
||||
// If there is no displayReadyPromise yet, then the operatorList was never
|
||||
// requested before. Make the request and create the promise.
|
||||
if (!this.displayReadyPromise) {
|
||||
this.pdf.startRendering(this);
|
||||
this.displayReadyPromise = new Promise();
|
||||
}
|
||||
|
||||
// Once the operatorList and fonts are loaded, do the actual rendering.
|
||||
this.displayReadyPromise.then(
|
||||
function pageDisplayReadyPromise() {
|
||||
var gfx = new CanvasGraphics(ctx, this.objs, textLayer);
|
||||
try {
|
||||
this.display(gfx, callback);
|
||||
} catch (e) {
|
||||
if (callback)
|
||||
callback(e);
|
||||
else
|
||||
error(e);
|
||||
}
|
||||
}.bind(this),
|
||||
function pageDisplayReadPromiseError(reason) {
|
||||
if (callback)
|
||||
callback(reason);
|
||||
else
|
||||
error(reason);
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@ -471,20 +300,20 @@ var Page = (function PageClosure() {
|
||||
})();
|
||||
|
||||
/**
|
||||
* The `PDFDocModel` holds all the data of the PDF file. Compared to the
|
||||
* The `PDFDocument` holds all the data of the PDF file. Compared to the
|
||||
* `PDFDoc`, this one doesn't have any job management code.
|
||||
* Right now there exists one PDFDocModel on the main thread + one object
|
||||
* Right now there exists one PDFDocument on the main thread + one object
|
||||
* for each worker. If there is no worker support enabled, there are two
|
||||
* `PDFDocModel` objects on the main thread created.
|
||||
* `PDFDocument` objects on the main thread created.
|
||||
*/
|
||||
var PDFDocModel = (function PDFDocModelClosure() {
|
||||
function PDFDocModel(arg, callback) {
|
||||
var PDFDocument = (function PDFDocumentClosure() {
|
||||
function PDFDocument(arg, callback) {
|
||||
if (isStream(arg))
|
||||
init.call(this, arg);
|
||||
else if (isArrayBuffer(arg))
|
||||
init.call(this, new Stream(arg));
|
||||
else
|
||||
error('PDFDocModel: Unknown argument type');
|
||||
error('PDFDocument: Unknown argument type');
|
||||
}
|
||||
|
||||
function init(stream) {
|
||||
@ -510,7 +339,7 @@ var PDFDocModel = (function PDFDocModelClosure() {
|
||||
return true; /* found */
|
||||
}
|
||||
|
||||
PDFDocModel.prototype = {
|
||||
PDFDocument.prototype = {
|
||||
get linearization() {
|
||||
var length = this.stream.length;
|
||||
var linearization = false;
|
||||
@ -571,7 +400,7 @@ var PDFDocModel = (function PDFDocModelClosure() {
|
||||
},
|
||||
// Find the header, remove leading garbage and setup the stream
|
||||
// starting from the header.
|
||||
checkHeader: function PDFDocModel_checkHeader() {
|
||||
checkHeader: function PDFDocument_checkHeader() {
|
||||
var stream = this.stream;
|
||||
stream.reset();
|
||||
if (find(stream, '%PDF-', 1024)) {
|
||||
@ -581,7 +410,7 @@ var PDFDocModel = (function PDFDocModelClosure() {
|
||||
}
|
||||
// May not be a PDF file, continue anyway.
|
||||
},
|
||||
setup: function PDFDocModel_setup(ownerPassword, userPassword) {
|
||||
setup: function PDFDocument_setup(ownerPassword, userPassword) {
|
||||
this.checkHeader();
|
||||
var xref = new XRef(this.stream,
|
||||
this.startXRef,
|
||||
@ -595,7 +424,7 @@ var PDFDocModel = (function PDFDocModelClosure() {
|
||||
// shadow the prototype getter
|
||||
return shadow(this, 'numPages', num);
|
||||
},
|
||||
getDocumentInfo: function PDFDocModel_getDocumentInfo() {
|
||||
getDocumentInfo: function PDFDocument_getDocumentInfo() {
|
||||
var info;
|
||||
if (this.xref.trailer.has('Info')) {
|
||||
var infoDict = this.xref.trailer.get('Info');
|
||||
@ -609,7 +438,7 @@ var PDFDocModel = (function PDFDocModelClosure() {
|
||||
|
||||
return shadow(this, 'getDocumentInfo', info);
|
||||
},
|
||||
getFingerprint: function PDFDocModel_getFingerprint() {
|
||||
getFingerprint: function PDFDocument_getFingerprint() {
|
||||
var xref = this.xref, fileID;
|
||||
if (xref.trailer.has('ID')) {
|
||||
fileID = '';
|
||||
@ -630,251 +459,10 @@ var PDFDocModel = (function PDFDocModelClosure() {
|
||||
|
||||
return shadow(this, 'getFingerprint', fileID);
|
||||
},
|
||||
getPage: function PDFDocModel_getPage(n) {
|
||||
getPage: function PDFDocument_getPage(n) {
|
||||
return this.catalog.getPage(n);
|
||||
}
|
||||
};
|
||||
|
||||
return PDFDocModel;
|
||||
return PDFDocument;
|
||||
})();
|
||||
|
||||
var PDFDoc = (function PDFDocClosure() {
|
||||
function PDFDoc(arg, callback) {
|
||||
var stream = null;
|
||||
var data = null;
|
||||
|
||||
if (isStream(arg)) {
|
||||
stream = arg;
|
||||
data = arg.bytes;
|
||||
} else if (isArrayBuffer(arg)) {
|
||||
stream = new Stream(arg);
|
||||
data = arg;
|
||||
} else {
|
||||
error('PDFDoc: Unknown argument type');
|
||||
}
|
||||
|
||||
this.data = data;
|
||||
this.stream = stream;
|
||||
this.pdfModel = new PDFDocModel(stream);
|
||||
this.fingerprint = this.pdfModel.getFingerprint();
|
||||
this.info = this.pdfModel.getDocumentInfo();
|
||||
this.catalog = this.pdfModel.catalog;
|
||||
this.objs = new PDFObjects();
|
||||
|
||||
this.pageCache = [];
|
||||
this.fontsLoading = {};
|
||||
this.workerReadyPromise = new Promise('workerReady');
|
||||
|
||||
// If worker support isn't disabled explicit and the browser has worker
|
||||
// support, create a new web worker and test if it/the browser fullfills
|
||||
// all requirements to run parts of pdf.js in a web worker.
|
||||
// Right now, the requirement is, that an Uint8Array is still an Uint8Array
|
||||
// as it arrives on the worker. Chrome added this with version 15.
|
||||
if (!globalScope.PDFJS.disableWorker && typeof Worker !== 'undefined') {
|
||||
var workerSrc = PDFJS.workerSrc;
|
||||
if (typeof workerSrc === 'undefined') {
|
||||
error('No PDFJS.workerSrc specified');
|
||||
}
|
||||
|
||||
try {
|
||||
var worker;
|
||||
if (PDFJS.isFirefoxExtension) {
|
||||
// The firefox extension can't load the worker from the resource://
|
||||
// url so we have to inline the script and then use the blob loader.
|
||||
var bb = new MozBlobBuilder();
|
||||
bb.append(document.querySelector('#PDFJS_SCRIPT_TAG').textContent);
|
||||
var blobUrl = window.URL.createObjectURL(bb.getBlob());
|
||||
worker = new Worker(blobUrl);
|
||||
} else {
|
||||
// Some versions of FF can't create a worker on localhost, see:
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=683280
|
||||
worker = new Worker(workerSrc);
|
||||
}
|
||||
|
||||
var messageHandler = new MessageHandler('main', worker);
|
||||
|
||||
messageHandler.on('test', function pdfDocTest(supportTypedArray) {
|
||||
if (supportTypedArray) {
|
||||
this.worker = worker;
|
||||
this.setupMessageHandler(messageHandler);
|
||||
} else {
|
||||
globalScope.PDFJS.disableWorker = true;
|
||||
this.setupFakeWorker();
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
var testObj = new Uint8Array(1);
|
||||
// Some versions of Opera throw a DATA_CLONE_ERR on
|
||||
// serializing the typed array.
|
||||
messageHandler.send('test', testObj);
|
||||
return;
|
||||
} catch (e) {
|
||||
warn('The worker has been disabled.');
|
||||
}
|
||||
}
|
||||
// Either workers are disabled, not supported or have thrown an exception.
|
||||
// Thus, we fallback to a faked worker.
|
||||
globalScope.PDFJS.disableWorker = true;
|
||||
this.setupFakeWorker();
|
||||
}
|
||||
|
||||
PDFDoc.prototype = {
|
||||
setupFakeWorker: function PDFDoc_setupFakeWorker() {
|
||||
// If we don't use a worker, just post/sendMessage to the main thread.
|
||||
var fakeWorker = {
|
||||
postMessage: function PDFDoc_postMessage(obj) {
|
||||
fakeWorker.onmessage({data: obj});
|
||||
},
|
||||
terminate: function PDFDoc_terminate() {}
|
||||
};
|
||||
|
||||
var messageHandler = new MessageHandler('main', fakeWorker);
|
||||
this.setupMessageHandler(messageHandler);
|
||||
|
||||
// If the main thread is our worker, setup the handling for the messages
|
||||
// the main thread sends to it self.
|
||||
WorkerMessageHandler.setup(messageHandler);
|
||||
},
|
||||
|
||||
|
||||
setupMessageHandler: function PDFDoc_setupMessageHandler(messageHandler) {
|
||||
this.messageHandler = messageHandler;
|
||||
|
||||
messageHandler.on('page', function pdfDocPage(data) {
|
||||
var pageNum = data.pageNum;
|
||||
var page = this.pageCache[pageNum];
|
||||
var depFonts = data.depFonts;
|
||||
|
||||
page.stats.timeEnd('Page Request');
|
||||
page.startRenderingFromOperatorList(data.operatorList, depFonts);
|
||||
}, this);
|
||||
|
||||
messageHandler.on('obj', function pdfDocObj(data) {
|
||||
var id = data[0];
|
||||
var type = data[1];
|
||||
|
||||
switch (type) {
|
||||
case 'JpegStream':
|
||||
var imageData = data[2];
|
||||
loadJpegStream(id, imageData, this.objs);
|
||||
break;
|
||||
case 'Image':
|
||||
var imageData = data[2];
|
||||
this.objs.resolve(id, imageData);
|
||||
break;
|
||||
case 'Font':
|
||||
var name = data[2];
|
||||
var file = data[3];
|
||||
var properties = data[4];
|
||||
|
||||
if (file) {
|
||||
// Rewrap the ArrayBuffer in a stream.
|
||||
var fontFileDict = new Dict();
|
||||
file = new Stream(file, 0, file.length, fontFileDict);
|
||||
}
|
||||
|
||||
// At this point, only the font object is created but the font is
|
||||
// not yet attached to the DOM. This is done in `FontLoader.bind`.
|
||||
var font = new Font(name, file, properties);
|
||||
this.objs.resolve(id, font);
|
||||
break;
|
||||
default:
|
||||
error('Got unkown object type ' + type);
|
||||
}
|
||||
}, this);
|
||||
|
||||
messageHandler.on('page_error', function pdfDocError(data) {
|
||||
var page = this.pageCache[data.pageNum];
|
||||
if (page.displayReadyPromise)
|
||||
page.displayReadyPromise.reject(data.error);
|
||||
else
|
||||
error(data.error);
|
||||
}, this);
|
||||
|
||||
messageHandler.on('jpeg_decode', function(data, promise) {
|
||||
var imageData = data[0];
|
||||
var components = data[1];
|
||||
if (components != 3 && components != 1)
|
||||
error('Only 3 component or 1 component can be returned');
|
||||
|
||||
var img = new Image();
|
||||
img.onload = (function messageHandler_onloadClosure() {
|
||||
var width = img.width;
|
||||
var height = img.height;
|
||||
var size = width * height;
|
||||
var rgbaLength = size * 4;
|
||||
var buf = new Uint8Array(size * components);
|
||||
var tmpCanvas = createScratchCanvas(width, height);
|
||||
var tmpCtx = tmpCanvas.getContext('2d');
|
||||
tmpCtx.drawImage(img, 0, 0);
|
||||
var data = tmpCtx.getImageData(0, 0, width, height).data;
|
||||
|
||||
if (components == 3) {
|
||||
for (var i = 0, j = 0; i < rgbaLength; i += 4, j += 3) {
|
||||
buf[j] = data[i];
|
||||
buf[j + 1] = data[i + 1];
|
||||
buf[j + 2] = data[i + 2];
|
||||
}
|
||||
} else if (components == 1) {
|
||||
for (var i = 0, j = 0; i < rgbaLength; i += 4, j++) {
|
||||
buf[j] = data[i];
|
||||
}
|
||||
}
|
||||
promise.resolve({ data: buf, width: width, height: height});
|
||||
}).bind(this);
|
||||
var src = 'data:image/jpeg;base64,' + window.btoa(imageData);
|
||||
img.src = src;
|
||||
});
|
||||
|
||||
setTimeout(function pdfDocFontReadySetTimeout() {
|
||||
messageHandler.send('doc', this.data);
|
||||
this.workerReadyPromise.resolve(true);
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
get numPages() {
|
||||
return this.pdfModel.numPages;
|
||||
},
|
||||
|
||||
startRendering: function PDFDoc_startRendering(page) {
|
||||
// The worker might not be ready to receive the page request yet.
|
||||
this.workerReadyPromise.then(function pdfDocStartRenderingThen() {
|
||||
page.stats.time('Page Request');
|
||||
this.messageHandler.send('page_request', page.pageNumber + 1);
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
getPage: function PDFDoc_getPage(n) {
|
||||
if (this.pageCache[n])
|
||||
return this.pageCache[n];
|
||||
|
||||
var page = this.pdfModel.getPage(n);
|
||||
// Add a reference to the objects such that Page can forward the reference
|
||||
// to the CanvasGraphics and so on.
|
||||
page.objs = this.objs;
|
||||
page.pdf = this;
|
||||
return (this.pageCache[n] = page);
|
||||
},
|
||||
|
||||
destroy: function PDFDoc_destroy() {
|
||||
if (this.worker)
|
||||
this.worker.terminate();
|
||||
|
||||
if (this.fontWorker)
|
||||
this.fontWorker.terminate();
|
||||
|
||||
for (var n in this.pageCache)
|
||||
delete this.pageCache[n];
|
||||
|
||||
delete this.data;
|
||||
delete this.stream;
|
||||
delete this.pdf;
|
||||
delete this.catalog;
|
||||
}
|
||||
};
|
||||
|
||||
return PDFDoc;
|
||||
})();
|
||||
|
||||
globalScope.PDFJS.PDFDoc = PDFDoc;
|
||||
|
||||
|
@ -153,13 +153,14 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
||||
|
||||
font = xref.fetchIfRef(font) || fontRes.get(fontName);
|
||||
assertWellFormed(isDict(font));
|
||||
++self.objIdCounter;
|
||||
if (!font.translated) {
|
||||
font.translated = self.translateFont(font, xref, resources,
|
||||
dependency);
|
||||
if (font.translated) {
|
||||
// keep track of each font we translated so the caller can
|
||||
// load them asynchronously before calling display on a page
|
||||
loadedName = 'font_' + uniquePrefix + (++self.objIdCounter);
|
||||
loadedName = 'font_' + uniquePrefix + self.objIdCounter;
|
||||
font.translated.properties.loadedName = loadedName;
|
||||
font.loadedName = loadedName;
|
||||
|
||||
@ -466,7 +467,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
||||
args = [];
|
||||
} else if (obj != null) {
|
||||
assertWellFormed(args.length <= 33, 'Too many arguments');
|
||||
args.push(obj);
|
||||
args.push(obj instanceof Dict ? obj.getAll() : obj);
|
||||
}
|
||||
}
|
||||
|
||||
@ -862,7 +863,6 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
||||
properties.coded = true;
|
||||
var charProcs = dict.get('CharProcs').getAll();
|
||||
var fontResources = dict.get('Resources') || resources;
|
||||
properties.resources = fontResources;
|
||||
properties.charProcOperatorList = {};
|
||||
for (var key in charProcs) {
|
||||
var glyphStream = charProcs[key];
|
||||
|
53
src/fonts.js
53
src/fonts.js
@ -766,7 +766,6 @@ var Font = (function FontClosure() {
|
||||
this.name = name;
|
||||
this.coded = properties.coded;
|
||||
this.charProcOperatorList = properties.charProcOperatorList;
|
||||
this.resources = properties.resources;
|
||||
this.sizes = [];
|
||||
|
||||
var names = name.split('+');
|
||||
@ -1727,6 +1726,16 @@ var Font = (function FontClosure() {
|
||||
properties.glyphNames = glyphNames;
|
||||
}
|
||||
|
||||
function isOS2Valid(os2Table) {
|
||||
var data = os2Table.data;
|
||||
// usWinAscent == 0 makes font unreadable by windows
|
||||
var usWinAscent = (data[74] << 8) | data[75];
|
||||
if (usWinAscent == 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check that required tables are present
|
||||
var requiredTables = ['OS/2', 'cmap', 'head', 'hhea',
|
||||
'hmtx', 'maxp', 'name', 'post'];
|
||||
@ -1734,7 +1743,7 @@ var Font = (function FontClosure() {
|
||||
var header = readOpenTypeHeader(font);
|
||||
var numTables = header.numTables;
|
||||
|
||||
var cmap, post, maxp, hhea, hmtx, vhea, vmtx, head, loca, glyf;
|
||||
var cmap, post, maxp, hhea, hmtx, vhea, vmtx, head, loca, glyf, os2;
|
||||
var tables = [];
|
||||
for (var i = 0; i < numTables; i++) {
|
||||
var table = readTableEntry(font);
|
||||
@ -1752,6 +1761,8 @@ var Font = (function FontClosure() {
|
||||
hmtx = table;
|
||||
else if (table.tag == 'head')
|
||||
head = table;
|
||||
else if (table.tag == 'OS/2')
|
||||
os2 = table;
|
||||
|
||||
requiredTables.splice(index, 1);
|
||||
} else {
|
||||
@ -1767,7 +1778,7 @@ var Font = (function FontClosure() {
|
||||
tables.push(table);
|
||||
}
|
||||
|
||||
var numTables = header.numTables + requiredTables.length;
|
||||
var numTables = tables.length + requiredTables.length;
|
||||
|
||||
// header and new offsets. Table entry information is appended to the
|
||||
// end of file. The virtualOffset represents where to put the actual
|
||||
@ -1781,21 +1792,10 @@ var Font = (function FontClosure() {
|
||||
// of missing tables
|
||||
createOpenTypeHeader(header.version, ttf, numTables);
|
||||
|
||||
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({
|
||||
tag: 'OS/2',
|
||||
data: stringToArray(createOS2Table(properties, null, override))
|
||||
});
|
||||
// Invalid OS/2 can break the font for the Windows
|
||||
if (os2 && !isOS2Valid(os2)) {
|
||||
tables.splice(tables.indexOf(os2), 1);
|
||||
os2 = null;
|
||||
}
|
||||
|
||||
// Ensure the [h/v]mtx tables contains the advance width and
|
||||
@ -2076,6 +2076,23 @@ var Font = (function FontClosure() {
|
||||
}
|
||||
this.unicodeIsEnabled = unicodeIsEnabled;
|
||||
|
||||
if (!os2) {
|
||||
// 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({
|
||||
tag: 'OS/2',
|
||||
data: stringToArray(createOS2Table(properties, glyphs, override))
|
||||
});
|
||||
}
|
||||
|
||||
// Rewrite the 'post' table if needed
|
||||
if (requiredTables.indexOf('post') != -1) {
|
||||
tables.push({
|
||||
|
@ -15,7 +15,7 @@ var PDFImage = (function PDFImageClosure() {
|
||||
var colorSpace = dict.get('ColorSpace', 'CS');
|
||||
colorSpace = ColorSpace.parse(colorSpace, xref, res);
|
||||
var numComps = colorSpace.numComps;
|
||||
handler.send('jpeg_decode', [image.getIR(), numComps], function(message) {
|
||||
handler.send('JpegDecode', [image.getIR(), numComps], function(message) {
|
||||
var data = message.data;
|
||||
var stream = new Stream(data, 0, data.length, image.dict);
|
||||
promise.resolve(stream);
|
||||
|
64
src/obj.js
64
src/obj.js
@ -37,51 +37,55 @@ var Dict = (function DictClosure() {
|
||||
// xref is optional
|
||||
function Dict(xref) {
|
||||
// Map should only be used internally, use functions below to access.
|
||||
this.map = Object.create(null);
|
||||
this.xref = xref;
|
||||
}
|
||||
var map = Object.create(null);
|
||||
|
||||
this.assignXref = function Dict_assingXref(newXref) {
|
||||
xref = newXref;
|
||||
};
|
||||
|
||||
Dict.prototype = {
|
||||
// automatically dereferences Ref objects
|
||||
get: function Dict_get(key1, key2, key3) {
|
||||
this.get = function Dict_get(key1, key2, key3) {
|
||||
var value;
|
||||
var xref = this.xref;
|
||||
if (typeof (value = this.map[key1]) != 'undefined' || key1 in this.map ||
|
||||
if (typeof (value = map[key1]) != 'undefined' || key1 in map ||
|
||||
typeof key2 == 'undefined') {
|
||||
return xref ? this.xref.fetchIfRef(value) : value;
|
||||
return xref ? xref.fetchIfRef(value) : value;
|
||||
}
|
||||
if (typeof (value = this.map[key2]) != 'undefined' || key2 in this.map ||
|
||||
if (typeof (value = map[key2]) != 'undefined' || key2 in map ||
|
||||
typeof key3 == 'undefined') {
|
||||
return xref ? this.xref.fetchIfRef(value) : value;
|
||||
return xref ? xref.fetchIfRef(value) : value;
|
||||
}
|
||||
value = this.map[key3] || null;
|
||||
return xref ? this.xref.fetchIfRef(value) : value;
|
||||
},
|
||||
value = map[key3] || null;
|
||||
return xref ? xref.fetchIfRef(value) : value;
|
||||
};
|
||||
|
||||
// no dereferencing
|
||||
getRaw: function Dict_getRaw(key) {
|
||||
return this.map[key];
|
||||
},
|
||||
this.getRaw = function Dict_getRaw(key) {
|
||||
return map[key];
|
||||
};
|
||||
|
||||
// creates new map and dereferences all Refs
|
||||
getAll: function Dict_getAll() {
|
||||
this.getAll = function Dict_getAll() {
|
||||
var all = {};
|
||||
for (var key in this.map)
|
||||
all[key] = this.get(key);
|
||||
for (var key in map) {
|
||||
var obj = this.get(key);
|
||||
all[key] = obj instanceof Dict ? obj.getAll() : obj;
|
||||
}
|
||||
return all;
|
||||
},
|
||||
};
|
||||
|
||||
set: function Dict_set(key, value) {
|
||||
this.map[key] = value;
|
||||
},
|
||||
this.set = function Dict_set(key, value) {
|
||||
map[key] = value;
|
||||
};
|
||||
|
||||
has: function Dict_has(key) {
|
||||
return key in this.map;
|
||||
},
|
||||
this.has = function Dict_has(key) {
|
||||
return key in map;
|
||||
};
|
||||
|
||||
forEach: function Dict_forEach(callback) {
|
||||
for (var key in this.map) {
|
||||
this.forEach = function Dict_forEach(callback) {
|
||||
for (var key in map) {
|
||||
callback(key, this.get(key));
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
return Dict;
|
||||
@ -299,7 +303,7 @@ var XRef = (function XRefClosure() {
|
||||
this.entries = [];
|
||||
this.xrefstms = {};
|
||||
var trailerDict = this.readXRef(startXRef);
|
||||
trailerDict.xref = this;
|
||||
trailerDict.assignXref(this);
|
||||
this.trailer = trailerDict;
|
||||
// prepare the XRef cache
|
||||
this.cache = [];
|
||||
|
@ -249,9 +249,12 @@ var Parser = (function ParserClosure() {
|
||||
if (name == 'CCITTFaxDecode' || name == 'CCF') {
|
||||
return new CCITTFaxStream(stream, params);
|
||||
}
|
||||
if (name == 'RunLengthDecode') {
|
||||
if (name == 'RunLengthDecode' || name == 'RL') {
|
||||
return new RunLengthStream(stream);
|
||||
}
|
||||
if (name == 'JBIG2Decode') {
|
||||
error('JBIG2 image format is not currently supprted.');
|
||||
}
|
||||
warn('filter "' + name + '" not supported yet');
|
||||
return stream;
|
||||
}
|
||||
|
108
src/util.js
108
src/util.js
@ -76,7 +76,7 @@ function stringToBytes(str) {
|
||||
|
||||
var IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0];
|
||||
|
||||
var Util = (function UtilClosure() {
|
||||
var Util = PDFJS.Util = (function UtilClosure() {
|
||||
function Util() {}
|
||||
|
||||
Util.makeCssRgb = function Util_makeCssRgb(r, g, b) {
|
||||
@ -97,6 +97,19 @@ var Util = (function UtilClosure() {
|
||||
return [xt, yt];
|
||||
};
|
||||
|
||||
Util.applyInverseTransform = function Util_applyTransform(p, m) {
|
||||
var d = m[0] * m[3] - m[1] * m[2];
|
||||
var xt = (p[0] * m[3] - p[1] * m[2] + m[2] * m[5] - m[4] * m[3]) / d;
|
||||
var yt = (-p[0] * m[1] + p[1] * m[0] + m[4] * m[1] - m[5] * m[0]) / d;
|
||||
return [xt, yt];
|
||||
};
|
||||
|
||||
Util.inverseTransform = function Util_inverseTransform(m) {
|
||||
var d = m[0] * m[3] - m[1] * m[2];
|
||||
return [m[3] / d, -m[1] / d, -m[2] / d, m[0] / d,
|
||||
(m[2] * m[5] - m[4] * m[3]) / d, (m[4] * m[1] - m[5] * m[0]) / d];
|
||||
};
|
||||
|
||||
// Apply a generic 3d matrix M on a 3-vector v:
|
||||
// | a b c | | X |
|
||||
// | d e f | x | Y |
|
||||
@ -165,7 +178,7 @@ var Util = (function UtilClosure() {
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
Util.sign = function Util_sign(num) {
|
||||
return num < 0 ? -1 : 1;
|
||||
@ -174,6 +187,80 @@ var Util = (function UtilClosure() {
|
||||
return Util;
|
||||
})();
|
||||
|
||||
var PageViewport = PDFJS.PageViewport = (function PageViewportClosure() {
|
||||
function PageViewport(viewBox, scale, rotate, offsetX, offsetY) {
|
||||
// creating transform to convert pdf coordinate system to the normal
|
||||
// canvas like coordinates taking in account scale and rotation
|
||||
var centerX = (viewBox[2] + viewBox[0]) / 2;
|
||||
var centerY = (viewBox[3] + viewBox[1]) / 2;
|
||||
var rotateA, rotateB, rotateC, rotateD;
|
||||
switch (rotate) {
|
||||
case -180:
|
||||
case 180:
|
||||
rotateA = -1; rotateB = 0; rotateC = 0; rotateD = 1;
|
||||
break;
|
||||
case -270:
|
||||
case 90:
|
||||
rotateA = 0; rotateB = 1; rotateC = 1; rotateD = 0;
|
||||
break;
|
||||
case -90:
|
||||
case 270:
|
||||
rotateA = 0; rotateB = -1; rotateC = -1; rotateD = 0;
|
||||
break;
|
||||
case 360:
|
||||
case 0:
|
||||
default:
|
||||
rotateA = 1; rotateB = 0; rotateC = 0; rotateD = -1;
|
||||
break;
|
||||
}
|
||||
var offsetCanvasX, offsetCanvasY;
|
||||
var width, height;
|
||||
if (rotateA == 0) {
|
||||
offsetCanvasX = Math.abs(centerY - viewBox[1]) * scale + offsetX;
|
||||
offsetCanvasY = Math.abs(centerX - viewBox[0]) * scale + offsetY;
|
||||
width = Math.abs(viewBox[3] - viewBox[1]) * scale;
|
||||
height = Math.abs(viewBox[2] - viewBox[0]) * scale;
|
||||
} else {
|
||||
offsetCanvasX = Math.abs(centerX - viewBox[0]) * scale + offsetX;
|
||||
offsetCanvasY = Math.abs(centerY - viewBox[1]) * scale + offsetY;
|
||||
width = Math.abs(viewBox[2] - viewBox[0]) * scale;
|
||||
height = Math.abs(viewBox[3] - viewBox[1]) * scale;
|
||||
}
|
||||
// creating transform for the following operations:
|
||||
// translate(-centerX, -centerY), rotate and flip vertically,
|
||||
// scale, and translate(offsetCanvasX, offsetCanvasY)
|
||||
this.transform = [
|
||||
rotateA * scale,
|
||||
rotateB * scale,
|
||||
rotateC * scale,
|
||||
rotateD * scale,
|
||||
offsetCanvasX - rotateA * scale * centerX - rotateC * scale * centerY,
|
||||
offsetCanvasY - rotateB * scale * centerX - rotateD * scale * centerY
|
||||
];
|
||||
|
||||
this.offsetX = offsetX;
|
||||
this.offsetY = offsetY;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.fontScale = scale;
|
||||
}
|
||||
PageViewport.prototype = {
|
||||
convertToViewportPoint: function PageViewport_convertToViewportPoint(x, y) {
|
||||
return Util.applyTransform([x, y], this.transform);
|
||||
},
|
||||
convertToViewportRectangle:
|
||||
function PageViewport_convertToViewportRectangle(rect) {
|
||||
var tl = Util.applyTransform([rect[0], rect[1]], this.transform);
|
||||
var br = Util.applyTransform([rect[2], rect[3]], this.transform);
|
||||
return [tl[0], tl[1], br[0], br[1]];
|
||||
},
|
||||
convertToPdfPoint: function PageViewport_convertToPdfPoint(x, y) {
|
||||
return Util.applyInverseTransform([x, y], this.transform);
|
||||
}
|
||||
};
|
||||
return PageViewport;
|
||||
})();
|
||||
|
||||
var PDFStringTranslateTable = [
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0x2D8, 0x2C7, 0x2C6, 0x2D9, 0x2DD, 0x2DB, 0x2DA, 0x2DC, 0, 0, 0, 0, 0, 0, 0,
|
||||
@ -275,7 +362,7 @@ function isPDFFunction(v) {
|
||||
* can be set. If any of these happens twice or the data is required before
|
||||
* it was set, an exception is throw.
|
||||
*/
|
||||
var Promise = (function PromiseClosure() {
|
||||
var Promise = PDFJS.Promise = (function PromiseClosure() {
|
||||
var EMPTY_PROMISE = {};
|
||||
|
||||
/**
|
||||
@ -297,6 +384,7 @@ var Promise = (function PromiseClosure() {
|
||||
}
|
||||
this.callbacks = [];
|
||||
this.errbacks = [];
|
||||
this.progressbacks = [];
|
||||
};
|
||||
/**
|
||||
* Builds a promise that is resolved when all the passed in promises are
|
||||
@ -312,7 +400,7 @@ var Promise = (function PromiseClosure() {
|
||||
deferred.resolve(results);
|
||||
return deferred;
|
||||
}
|
||||
for (var i = 0; i < unresolved; ++i) {
|
||||
for (var i = 0, ii = promises.length; i < ii; ++i) {
|
||||
var promise = promises[i];
|
||||
promise.then((function(i) {
|
||||
return function(value) {
|
||||
@ -376,6 +464,13 @@ var Promise = (function PromiseClosure() {
|
||||
}
|
||||
},
|
||||
|
||||
progress: function Promise_progress(data) {
|
||||
var callbacks = this.progressbacks;
|
||||
for (var i = 0, ii = callbacks.length; i < ii; i++) {
|
||||
callbacks[i].call(null, data);
|
||||
}
|
||||
},
|
||||
|
||||
reject: function Promise_reject(reason) {
|
||||
if (this.isRejected) {
|
||||
error('A Promise can be rejected only once ' + this.name);
|
||||
@ -393,7 +488,7 @@ var Promise = (function PromiseClosure() {
|
||||
}
|
||||
},
|
||||
|
||||
then: function Promise_then(callback, errback) {
|
||||
then: function Promise_then(callback, errback, progressback) {
|
||||
if (!callback) {
|
||||
error('Requiring callback' + this.name);
|
||||
}
|
||||
@ -410,6 +505,9 @@ var Promise = (function PromiseClosure() {
|
||||
if (errback)
|
||||
this.errbacks.push(errback);
|
||||
}
|
||||
|
||||
if (progressback)
|
||||
this.progressbacks.push(progressback);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -85,14 +85,43 @@ var WorkerMessageHandler = {
|
||||
handler.send('test', data instanceof Uint8Array);
|
||||
});
|
||||
|
||||
handler.on('doc', function wphSetupDoc(data) {
|
||||
handler.on('GetDocRequest', function wphSetupDoc(data) {
|
||||
// Create only the model of the PDFDoc, which is enough for
|
||||
// processing the content of the pdf.
|
||||
pdfModel = new PDFDocModel(new Stream(data));
|
||||
pdfModel = new PDFDocument(new Stream(data));
|
||||
var doc = {
|
||||
numPages: pdfModel.numPages,
|
||||
fingerprint: pdfModel.getFingerprint(),
|
||||
destinations: pdfModel.catalog.destinations,
|
||||
outline: pdfModel.catalog.documentOutline,
|
||||
info: pdfModel.getDocumentInfo(),
|
||||
metadata: pdfModel.catalog.metadata
|
||||
};
|
||||
handler.send('GetDoc', {pdfInfo: doc});
|
||||
});
|
||||
|
||||
handler.on('page_request', function wphSetupPageRequest(pageNum) {
|
||||
pageNum = parseInt(pageNum);
|
||||
handler.on('GetPageRequest', function wphSetupGetPage(data) {
|
||||
var pageNumber = data.pageIndex + 1;
|
||||
var pdfPage = pdfModel.getPage(pageNumber);
|
||||
var page = {
|
||||
pageIndex: data.pageIndex,
|
||||
rotate: pdfPage.rotate,
|
||||
ref: pdfPage.ref,
|
||||
view: pdfPage.view
|
||||
};
|
||||
handler.send('GetPage', {pageInfo: page});
|
||||
});
|
||||
|
||||
handler.on('GetAnnotationsRequest', function wphSetupGetAnnotations(data) {
|
||||
var pdfPage = pdfModel.getPage(data.pageIndex + 1);
|
||||
handler.send('GetAnnotations', {
|
||||
pageIndex: data.pageIndex,
|
||||
annotations: pdfPage.getAnnotations()
|
||||
});
|
||||
});
|
||||
|
||||
handler.on('RenderPageRequest', function wphSetupRenderPage(data) {
|
||||
var pageNum = data.pageIndex + 1;
|
||||
|
||||
|
||||
// The following code does quite the same as
|
||||
@ -130,7 +159,7 @@ var WorkerMessageHandler = {
|
||||
};
|
||||
}
|
||||
|
||||
handler.send('page_error', {
|
||||
handler.send('PageError', {
|
||||
pageNum: pageNum,
|
||||
error: e
|
||||
});
|
||||
@ -148,9 +177,8 @@ var WorkerMessageHandler = {
|
||||
fonts[dep] = true;
|
||||
}
|
||||
}
|
||||
|
||||
handler.send('page', {
|
||||
pageNum: pageNum,
|
||||
handler.send('RenderPage', {
|
||||
pageIndex: data.pageIndex,
|
||||
operatorList: operatorList,
|
||||
depFonts: Object.keys(fonts)
|
||||
});
|
||||
|
@ -10,7 +10,7 @@
|
||||
// Disable worker support for running test as
|
||||
// https://github.com/mozilla/pdf.js/pull/764#issuecomment-2638944
|
||||
// "firefox-bin: Fatal IO error 12 (Cannot allocate memory) on X server :1."
|
||||
PDFJS.disableWorker = true;
|
||||
// PDFJS.disableWorker = true;
|
||||
|
||||
var appPath, browser, canvas, currentTaskIdx, manifest, stdout;
|
||||
var inFlightRequests = 0;
|
||||
@ -100,13 +100,24 @@ function nextTask() {
|
||||
|
||||
getPdf(task.file, function nextTaskGetPdf(data) {
|
||||
var failure;
|
||||
function continuation() {
|
||||
task.pageNum = task.firstPage || 1;
|
||||
nextPage(task, failure);
|
||||
}
|
||||
try {
|
||||
task.pdfDoc = new PDFJS.PDFDoc(data);
|
||||
var promise = PDFJS.getDocument(data);
|
||||
promise.then(function(doc) {
|
||||
task.pdfDoc = doc;
|
||||
continuation();
|
||||
}, function(e) {
|
||||
failure = 'load PDF doc : ' + e;
|
||||
continuation();
|
||||
});
|
||||
return;
|
||||
} catch (e) {
|
||||
failure = 'load PDF doc : ' + exceptionToString(e);
|
||||
}
|
||||
task.pageNum = task.firstPage || 1;
|
||||
nextPage(task, failure);
|
||||
continuation();
|
||||
});
|
||||
}
|
||||
|
||||
@ -163,45 +174,45 @@ function nextPage(task, loadError) {
|
||||
log(' loading page ' + task.pageNum + '/' + task.pdfDoc.numPages +
|
||||
'... ');
|
||||
var ctx = canvas.getContext('2d');
|
||||
page = task.pdfDoc.getPage(task.pageNum);
|
||||
task.pdfDoc.getPage(task.pageNum).then(function(page) {
|
||||
var pdfToCssUnitsCoef = 96.0 / 72.0;
|
||||
var viewport = page.getViewport(pdfToCssUnitsCoef);
|
||||
canvas.width = viewport.width;
|
||||
canvas.height = viewport.height;
|
||||
clear(ctx);
|
||||
|
||||
var pdfToCssUnitsCoef = 96.0 / 72.0;
|
||||
// using mediaBox for the canvas size
|
||||
var pageWidth = page.width;
|
||||
var pageHeight = page.height;
|
||||
canvas.width = pageWidth * pdfToCssUnitsCoef;
|
||||
canvas.height = pageHeight * pdfToCssUnitsCoef;
|
||||
clear(ctx);
|
||||
|
||||
// using the text layer builder that does nothing to test
|
||||
// text layer creation operations
|
||||
var textLayerBuilder = {
|
||||
beginLayout: function nullTextLayerBuilderBeginLayout() {},
|
||||
endLayout: function nullTextLayerBuilderEndLayout() {},
|
||||
appendText: function nullTextLayerBuilderAppendText(text, fontName,
|
||||
fontSize) {}
|
||||
};
|
||||
|
||||
page.startRendering(
|
||||
ctx,
|
||||
function nextPageStartRendering(error) {
|
||||
var failureMessage = false;
|
||||
if (error)
|
||||
failureMessage = 'render : ' + error.message;
|
||||
snapshotCurrentPage(task, failureMessage);
|
||||
// using the text layer builder that does nothing to test
|
||||
// text layer creation operations
|
||||
var textLayerBuilder = {
|
||||
beginLayout: function nullTextLayerBuilderBeginLayout() {},
|
||||
endLayout: function nullTextLayerBuilderEndLayout() {},
|
||||
appendText: function nullTextLayerBuilderAppendText(text, fontName,
|
||||
fontSize) {}
|
||||
};
|
||||
var renderContext = {
|
||||
canvasContext: ctx,
|
||||
textLayer: textLayerBuilder,
|
||||
viewport: viewport
|
||||
};
|
||||
var completeRender = (function(error) {
|
||||
page.destroy();
|
||||
snapshotCurrentPage(task, error);
|
||||
});
|
||||
page.render(renderContext).then(function() {
|
||||
completeRender(false);
|
||||
},
|
||||
textLayerBuilder
|
||||
);
|
||||
function(error) {
|
||||
completeRender('render : ' + error);
|
||||
});
|
||||
},
|
||||
function(error) {
|
||||
snapshotCurrentPage(task, 'render : ' + error);
|
||||
});
|
||||
} catch (e) {
|
||||
failure = 'page setup : ' + exceptionToString(e);
|
||||
snapshotCurrentPage(task, failure);
|
||||
}
|
||||
}
|
||||
|
||||
if (failure) {
|
||||
// Skip right to snapshotting if there was a failure, since the
|
||||
// fonts might be in an inconsistent state.
|
||||
snapshotCurrentPage(task, failure);
|
||||
}
|
||||
}
|
||||
|
||||
function snapshotCurrentPage(task, failure) {
|
||||
|
3
test/pdfs/.gitignore
vendored
3
test/pdfs/.gitignore
vendored
@ -31,4 +31,5 @@
|
||||
!issue1002.pdf
|
||||
!issue925.pdf
|
||||
!gradientfill.pdf
|
||||
|
||||
!basicapi.pdf
|
||||
!mixedfonts.pdf
|
||||
|
BIN
test/pdfs/basicapi.pdf
Normal file
BIN
test/pdfs/basicapi.pdf
Normal file
Binary file not shown.
BIN
test/pdfs/mixedfonts.pdf
Normal file
BIN
test/pdfs/mixedfonts.pdf
Normal file
Binary file not shown.
26
test/test.py
26
test/test.py
@ -16,6 +16,7 @@ BROWSERLOG_FILE = 'browser.log'
|
||||
REFDIR = 'ref'
|
||||
TMPDIR = 'tmp'
|
||||
VERBOSE = False
|
||||
BROWSER_TIMEOUT = 60
|
||||
|
||||
SERVER_HOST = "localhost"
|
||||
|
||||
@ -74,7 +75,7 @@ class State:
|
||||
browsers = [ ]
|
||||
manifest = { }
|
||||
taskResults = { }
|
||||
remaining = 0
|
||||
remaining = { }
|
||||
results = { }
|
||||
done = False
|
||||
numErrors = 0
|
||||
@ -83,6 +84,7 @@ class State:
|
||||
numFBFFailures = 0
|
||||
numLoadFailures = 0
|
||||
eqLog = None
|
||||
lastPost = { }
|
||||
|
||||
class Result:
|
||||
def __init__(self, snapshot, failure, page):
|
||||
@ -180,6 +182,7 @@ class PDFTestHandler(BaseHTTPRequestHandler):
|
||||
|
||||
result = json.loads(self.rfile.read(numBytes))
|
||||
browser, id, failure, round, page, snapshot = result['browser'], result['id'], result['failure'], result['round'], result['page'], result['snapshot']
|
||||
State.lastPost[browser] = int(time.time())
|
||||
taskResults = State.taskResults[browser][id]
|
||||
taskResults[round].append(Result(snapshot, failure, page))
|
||||
|
||||
@ -199,9 +202,16 @@ class PDFTestHandler(BaseHTTPRequestHandler):
|
||||
self.server.masterMode)
|
||||
# Please oh please GC this ...
|
||||
del State.taskResults[browser][id]
|
||||
State.remaining -= 1
|
||||
State.remaining[browser] -= 1
|
||||
|
||||
State.done = (0 == State.remaining)
|
||||
checkIfDone()
|
||||
|
||||
def checkIfDone():
|
||||
State.done = True
|
||||
for key in State.remaining:
|
||||
if State.remaining[key] != 0:
|
||||
State.done = False
|
||||
return
|
||||
|
||||
# Applescript hack to quit Chrome on Mac
|
||||
def tellAppToQuit(path, query):
|
||||
@ -376,6 +386,8 @@ def setUp(options):
|
||||
|
||||
for b in testBrowsers:
|
||||
State.taskResults[b.name] = { }
|
||||
State.remaining[b.name] = len(manifestList)
|
||||
State.lastPost[b.name] = int(time.time())
|
||||
for item in manifestList:
|
||||
id, rounds = item['id'], int(item['rounds'])
|
||||
State.manifest[id] = item
|
||||
@ -384,8 +396,6 @@ def setUp(options):
|
||||
taskResults.append([ ])
|
||||
State.taskResults[b.name][id] = taskResults
|
||||
|
||||
State.remaining = len(testBrowsers) * len(manifestList)
|
||||
|
||||
return testBrowsers
|
||||
|
||||
def startBrowsers(browsers, options):
|
||||
@ -568,6 +578,12 @@ def runTests(options, browsers):
|
||||
try:
|
||||
startBrowsers(browsers, options)
|
||||
while not State.done:
|
||||
for b in State.lastPost:
|
||||
if State.remaining[b] > 0 and int(time.time()) - State.lastPost[b] > BROWSER_TIMEOUT:
|
||||
print 'TEST-UNEXPECTED-FAIL | test failed', b, "has not responded in", BROWSER_TIMEOUT, "s"
|
||||
State.numErrors += State.remaining[b]
|
||||
State.remaining[b] = 0
|
||||
checkIfDone()
|
||||
time.sleep(1)
|
||||
processResults()
|
||||
finally:
|
||||
|
@ -19,7 +19,7 @@
|
||||
},
|
||||
{ "id": "intelisa-eq",
|
||||
"file": "pdfs/intelisa.pdf",
|
||||
"md5": "83032ccbfdc5a66269b1403971110abe",
|
||||
"md5": "c1444b7ccd935c0577d094297e1a6448",
|
||||
"link": true,
|
||||
"pageLimit": 100,
|
||||
"rounds": 1,
|
||||
@ -29,12 +29,13 @@
|
||||
"file": "pdfs/pdf.pdf",
|
||||
"md5": "dbdb23c939d2be09b43126c3c56060c7",
|
||||
"link": true,
|
||||
"pageLimit": 500,
|
||||
"rounds": 1,
|
||||
"type": "load"
|
||||
},
|
||||
{ "id": "shavian-load",
|
||||
"file": "pdfs/shavian.pdf",
|
||||
"md5": "4fabf0a03e82693007435020bc446f9b",
|
||||
"md5": "79253352f48b55b7fa28a2586875d8b7",
|
||||
"link": true,
|
||||
"rounds": 1,
|
||||
"type": "load"
|
||||
@ -241,10 +242,10 @@
|
||||
"skipPages": [ 16 ],
|
||||
"type": "load"
|
||||
},
|
||||
{ "id": "tcpdf_033",
|
||||
"file": "pdfs/tcpdf_033.pdf",
|
||||
"md5": "861294df58d185aae80919173f2732ff",
|
||||
"link": true,
|
||||
{ "id": "mixedfonts",
|
||||
"file": "pdfs/mixedfonts.pdf",
|
||||
"md5": "a582b83fa1b3a25a6f13803a367c71ec",
|
||||
"link": false,
|
||||
"rounds": 1,
|
||||
"type": "eq"
|
||||
},
|
||||
|
@ -5,6 +5,7 @@
|
||||
<style type="text/css"></style>
|
||||
<script type="text/javascript" src="/src/core.js"></script>
|
||||
<script type="text/javascript" src="/src/util.js"></script>
|
||||
<script type="text/javascript" src="/src/api.js"></script>
|
||||
<script type="text/javascript" src="/src/canvas.js"></script>
|
||||
<script type="text/javascript" src="/src/obj.js"></script>
|
||||
<script type="text/javascript" src="/src/function.js"></script>
|
||||
|
109
test/unit/api_spec.js
Normal file
109
test/unit/api_spec.js
Normal file
@ -0,0 +1,109 @@
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
|
||||
'use strict';
|
||||
|
||||
describe('api', function() {
|
||||
// TODO run with worker enabled
|
||||
PDFJS.disableWorker = true;
|
||||
var basicApiUrl = '/basicapi.pdf';
|
||||
function waitsForPromise(promise) {
|
||||
waitsFor(function() {
|
||||
return promise.isResolved || promise.isRejected;
|
||||
}, 250);
|
||||
}
|
||||
function expectAfterPromise(promise, successCallback) {
|
||||
waitsForPromise(promise);
|
||||
runs(function() {
|
||||
promise.then(successCallback,
|
||||
function(error, e) {
|
||||
// Shouldn't get here.
|
||||
expect(false).toEqual(true);
|
||||
});
|
||||
});
|
||||
}
|
||||
describe('PDFJS', function() {
|
||||
describe('getDocument', function() {
|
||||
it('creates pdf doc from URL', function() {
|
||||
console.log('what is');
|
||||
debugger;
|
||||
var promise = PDFJS.getDocument(basicApiUrl);
|
||||
expectAfterPromise(promise, function(data) {
|
||||
expect(true).toEqual(true);
|
||||
});
|
||||
});
|
||||
/*
|
||||
it('creates pdf doc from typed array', function() {
|
||||
// TODO
|
||||
});
|
||||
*/
|
||||
});
|
||||
});
|
||||
describe('PDFDocument', function() {
|
||||
var promise = PDFJS.getDocument(basicApiUrl);
|
||||
waitsForPromise(promise);
|
||||
var doc;
|
||||
runs(function() {
|
||||
promise.then(function(data) { doc = data; });
|
||||
});
|
||||
it('gets number of pages', function() {
|
||||
expect(doc.numPages).toEqual(3);
|
||||
});
|
||||
it('gets fingerprint', function() {
|
||||
expect(typeof doc.fingerprint).toEqual('string');
|
||||
});
|
||||
it('gets page', function() {
|
||||
var promise = doc.getPage(1);
|
||||
expectAfterPromise(promise, function(data) {
|
||||
expect(true).toEqual(true);
|
||||
});
|
||||
});
|
||||
it('gets destinations', function() {
|
||||
var promise = doc.getDestinations();
|
||||
expectAfterPromise(promise, function(data) {
|
||||
// TODO this seems to be broken for the test pdf
|
||||
});
|
||||
});
|
||||
it('gets outline', function() {
|
||||
var promise = doc.getOutline();
|
||||
expectAfterPromise(promise, function(outline) {
|
||||
// Two top level entries.
|
||||
expect(outline.length).toEqual(2);
|
||||
// Make sure some basic attributes are set.
|
||||
expect(outline[1].title).toEqual('Chapter 1');
|
||||
expect(outline[1].items.length).toEqual(1);
|
||||
expect(outline[1].items[0].title).toEqual('Paragraph 1.1');
|
||||
});
|
||||
});
|
||||
it('gets metadata', function() {
|
||||
var promise = doc.getMetadata();
|
||||
expectAfterPromise(promise, function(metadata) {
|
||||
expect(metadata.info['Title']).toEqual('Basic API Test');
|
||||
expect(metadata.metadata.get('dc:title')).toEqual('Basic API Test');
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('Page', function() {
|
||||
var promise = new Promise();
|
||||
PDFJS.getDocument(basicApiUrl).then(function(doc) {
|
||||
doc.getPage(1).then(function(data) {
|
||||
promise.resolve(data);
|
||||
});
|
||||
});
|
||||
waitsForPromise(promise);
|
||||
var page;
|
||||
runs(function() {
|
||||
promise.then(function(data) {
|
||||
page = data;
|
||||
});
|
||||
});
|
||||
it('gets ref', function() {
|
||||
expect(page.ref).toEqual({num: 15, gen: 0});
|
||||
});
|
||||
// TODO rotate
|
||||
// TODO viewport
|
||||
// TODO annotaions
|
||||
// TOOD text content
|
||||
// TODO operation list
|
||||
});
|
||||
});
|
@ -1,32 +1,39 @@
|
||||
server: http://localhost:4224
|
||||
|
||||
load:
|
||||
- ../../external/jasmine/jasmine.js
|
||||
- ../../external/jasmineAdapter/JasmineAdapter.js
|
||||
- ../../src/obj.js
|
||||
- ../../src/core.js
|
||||
- ../../src/util.js
|
||||
- ../../src/canvas.js
|
||||
- ../../src/obj.js
|
||||
- ../../src/function.js
|
||||
- ../../src/charsets.js
|
||||
- ../../src/cidmaps.js
|
||||
- ../../src/colorspace.js
|
||||
- ../../src/crypto.js
|
||||
- ../../src/evaluator.js
|
||||
- ../../src/fonts.js
|
||||
- ../../src/glyphlist.js
|
||||
- ../../src/image.js
|
||||
- ../../src/metrics.js
|
||||
- ../../src/parser.js
|
||||
- ../../src/pattern.js
|
||||
- ../../src/stream.js
|
||||
- ../../src/worker.js
|
||||
- ../../src/bidi.js
|
||||
- ../../external/jpgjs/jpg.js
|
||||
- ../unit/obj_spec.js
|
||||
- ../unit/font_spec.js
|
||||
- ../unit/function_spec.js
|
||||
- ../unit/crypto_spec.js
|
||||
- ../unit/stream_spec.js
|
||||
basepath: ..
|
||||
|
||||
load:
|
||||
- ../external/jasmine/jasmine.js
|
||||
- ../external/jasmineAdapter/JasmineAdapter.js
|
||||
- ../src/obj.js
|
||||
- ../src/core.js
|
||||
- ../src/util.js
|
||||
- ../src/api.js
|
||||
- ../src/canvas.js
|
||||
- ../src/obj.js
|
||||
- ../src/function.js
|
||||
- ../src/charsets.js
|
||||
- ../src/cidmaps.js
|
||||
- ../src/colorspace.js
|
||||
- ../src/crypto.js
|
||||
- ../src/evaluator.js
|
||||
- ../src/fonts.js
|
||||
- ../src/glyphlist.js
|
||||
- ../src/image.js
|
||||
- ../src/metrics.js
|
||||
- ../src/parser.js
|
||||
- ../src/pattern.js
|
||||
- ../src/stream.js
|
||||
- ../src/worker.js
|
||||
- ../src/bidi.js
|
||||
- ../src/metadata.js
|
||||
- ../external/jpgjs/jpg.js
|
||||
- unit/obj_spec.js
|
||||
- unit/font_spec.js
|
||||
- unit/function_spec.js
|
||||
- unit/crypto_spec.js
|
||||
- unit/stream_spec.js
|
||||
- unit/api_spec.js
|
||||
|
||||
gateway:
|
||||
- {matcher: "*.pdf", server: "http://localhost:8888/test/pdfs/"}
|
||||
|
@ -234,3 +234,21 @@
|
||||
console = {log: function() {}};
|
||||
}
|
||||
})();
|
||||
|
||||
// Check onclick compatibility in Opera
|
||||
(function checkOnClickCompatibility() {
|
||||
// workaround for reported Opera bug DSK-354448:
|
||||
// onclick fires on disabled buttons with opaque content
|
||||
function ignoreIfTargetDisabled(event) {
|
||||
if (isDisabled(event.target)) {
|
||||
event.stopPropagation();
|
||||
}
|
||||
}
|
||||
function isDisabled(node) {
|
||||
return node.disabled || (node.parentNode && isDisabled(node.parentNode));
|
||||
}
|
||||
if (navigator.userAgent.indexOf('Opera') != -1) {
|
||||
// use browser detection since we cannot feature-check this bug
|
||||
document.addEventListener('click', ignoreIfTargetDisabled, true);
|
||||
}
|
||||
})();
|
||||
|
@ -163,29 +163,29 @@ var StepperManager = (function StepperManagerClosure() {
|
||||
enabled: false,
|
||||
active: false,
|
||||
// Stepper specific functions.
|
||||
create: function create(pageNumber) {
|
||||
create: function create(pageIndex) {
|
||||
var debug = document.createElement('div');
|
||||
debug.id = 'stepper' + pageNumber;
|
||||
debug.id = 'stepper' + pageIndex;
|
||||
debug.setAttribute('hidden', true);
|
||||
debug.className = 'stepper';
|
||||
stepperDiv.appendChild(debug);
|
||||
var b = document.createElement('option');
|
||||
b.textContent = 'Page ' + (pageNumber + 1);
|
||||
b.value = pageNumber;
|
||||
b.textContent = 'Page ' + (pageIndex + 1);
|
||||
b.value = pageIndex;
|
||||
stepperChooser.appendChild(b);
|
||||
var initBreakPoints = breakPoints[pageNumber] || [];
|
||||
var stepper = new Stepper(debug, pageNumber, initBreakPoints);
|
||||
var initBreakPoints = breakPoints[pageIndex] || [];
|
||||
var stepper = new Stepper(debug, pageIndex, initBreakPoints);
|
||||
steppers.push(stepper);
|
||||
if (steppers.length === 1)
|
||||
this.selectStepper(pageNumber, false);
|
||||
this.selectStepper(pageIndex, false);
|
||||
return stepper;
|
||||
},
|
||||
selectStepper: function selectStepper(pageNumber, selectPanel) {
|
||||
selectStepper: function selectStepper(pageIndex, selectPanel) {
|
||||
if (selectPanel)
|
||||
this.manager.selectPanel(1);
|
||||
for (var i = 0; i < steppers.length; ++i) {
|
||||
var stepper = steppers[i];
|
||||
if (stepper.pageNumber == pageNumber)
|
||||
if (stepper.pageIndex == pageIndex)
|
||||
stepper.panel.removeAttribute('hidden');
|
||||
else
|
||||
stepper.panel.setAttribute('hidden', true);
|
||||
@ -193,11 +193,11 @@ var StepperManager = (function StepperManagerClosure() {
|
||||
var options = stepperChooser.options;
|
||||
for (var i = 0; i < options.length; ++i) {
|
||||
var option = options[i];
|
||||
option.selected = option.value == pageNumber;
|
||||
option.selected = option.value == pageIndex;
|
||||
}
|
||||
},
|
||||
saveBreakPoints: function saveBreakPoints(pageNumber, bps) {
|
||||
breakPoints[pageNumber] = bps;
|
||||
saveBreakPoints: function saveBreakPoints(pageIndex, bps) {
|
||||
breakPoints[pageIndex] = bps;
|
||||
sessionStorage.setItem('pdfjsBreakPoints', JSON.stringify(breakPoints));
|
||||
}
|
||||
};
|
||||
@ -205,12 +205,12 @@ var StepperManager = (function StepperManagerClosure() {
|
||||
|
||||
// The stepper for each page's IRQueue.
|
||||
var Stepper = (function StepperClosure() {
|
||||
function Stepper(panel, pageNumber, initialBreakPoints) {
|
||||
function Stepper(panel, pageIndex, initialBreakPoints) {
|
||||
this.panel = panel;
|
||||
this.len;
|
||||
this.breakPoint = 0;
|
||||
this.nextBreakPoint = null;
|
||||
this.pageNumber = pageNumber;
|
||||
this.pageIndex = pageIndex;
|
||||
this.breakPoints = initialBreakPoints;
|
||||
this.currentIdx = -1;
|
||||
}
|
||||
@ -256,7 +256,7 @@ var Stepper = (function StepperClosure() {
|
||||
self.breakPoints.push(x);
|
||||
else
|
||||
self.breakPoints.splice(self.breakPoints.indexOf(x), 1);
|
||||
StepperManager.saveBreakPoints(self.pageNumber, self.breakPoints);
|
||||
StepperManager.saveBreakPoints(self.pageIndex, self.breakPoints);
|
||||
}
|
||||
})(i);
|
||||
|
||||
@ -278,7 +278,7 @@ var Stepper = (function StepperClosure() {
|
||||
return null;
|
||||
},
|
||||
breakIt: function breakIt(idx, callback) {
|
||||
StepperManager.selectStepper(this.pageNumber, true);
|
||||
StepperManager.selectStepper(this.pageIndex, true);
|
||||
var self = this;
|
||||
var dom = document;
|
||||
self.currentIdx = idx;
|
||||
|
46
web/images/text.svg
Normal file
46
web/images/text.svg
Normal file
@ -0,0 +1,46 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
height="40"
|
||||
width="40"
|
||||
id="svg2995"
|
||||
version="1.1">
|
||||
|
||||
<rect
|
||||
style="fill:#f1e47b;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-opacity:1"
|
||||
id="rect3009"
|
||||
width="30.169491"
|
||||
height="24.576269"
|
||||
x="4.237288"
|
||||
y="6.7796612" />
|
||||
<rect
|
||||
style="fill:#000000;fill-opacity:1;stroke:none"
|
||||
id="rect3781"
|
||||
width="23.38983"
|
||||
height="1.1864407"
|
||||
x="7.6271186"
|
||||
y="11.389831" />
|
||||
<rect
|
||||
style="fill:#000000;fill-opacity:1;stroke:none"
|
||||
id="rect3781-1"
|
||||
width="23.38983"
|
||||
height="0.67796612"
|
||||
x="7.6271191"
|
||||
y="21.61017" />
|
||||
<rect
|
||||
style="fill:#000000;fill-opacity:1;stroke:none"
|
||||
id="rect3781-7"
|
||||
width="23.38983"
|
||||
height="0.67796612"
|
||||
x="7.4576273"
|
||||
y="26.152542" />
|
||||
<rect
|
||||
style="fill:#000000;fill-opacity:1;stroke:none"
|
||||
id="rect3781-1-4"
|
||||
width="23.38983"
|
||||
height="0.67796612"
|
||||
x="7.6271186"
|
||||
y="17.033899" />
|
||||
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
@ -1,6 +1,6 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>PDF viewer</title>
|
||||
<title>PDF.js viewer</title>
|
||||
<!-- PDFJSSCRIPT_INCLUDE_FIREFOX_EXTENSION -->
|
||||
|
||||
<link rel="stylesheet" href="viewer.css"/>
|
||||
@ -10,6 +10,7 @@
|
||||
<!-- PDFJSSCRIPT_INCLUDE_BUILD -->
|
||||
<script type="text/javascript" src="../src/core.js"></script> <!-- PDFJSSCRIPT_REMOVE_CORE -->
|
||||
<script type="text/javascript" src="../src/util.js"></script> <!-- PDFJSSCRIPT_REMOVE_CORE -->
|
||||
<script type="text/javascript" src="../src/api.js"></script> <!-- PDFJSSCRIPT_REMOVE_CORE -->
|
||||
<script type="text/javascript" src="../src/metadata.js"></script> <!-- PDFJSSCRIPT_REMOVE_CORE -->
|
||||
<script type="text/javascript" src="../src/canvas.js"></script> <!-- PDFJSSCRIPT_REMOVE_CORE -->
|
||||
<script type="text/javascript" src="../src/obj.js"></script> <!-- PDFJSSCRIPT_REMOVE_CORE -->
|
||||
@ -34,9 +35,8 @@
|
||||
<script type="text/javascript" src="debugger.js"></script>
|
||||
<script type="text/javascript" src="viewer.js"></script>
|
||||
</head>
|
||||
|
||||
|
||||
<body>
|
||||
|
||||
<div id="outerContainer">
|
||||
|
||||
<div class="toolbar">
|
||||
|
364
web/viewer.js
364
web/viewer.js
@ -32,7 +32,7 @@ var Cache = function cacheCache(size) {
|
||||
data.splice(i);
|
||||
data.push(view);
|
||||
if (data.length > size)
|
||||
data.shift().update();
|
||||
data.shift().destroy();
|
||||
};
|
||||
};
|
||||
|
||||
@ -247,9 +247,9 @@ var PDFView = {
|
||||
|
||||
var currentPage = this.pages[this.page - 1];
|
||||
var pageWidthScale = (window.innerWidth - kScrollbarPadding) /
|
||||
currentPage.width / kCssUnits;
|
||||
currentPage.width * currentPage.scale / kCssUnits;
|
||||
var pageHeightScale = (window.innerHeight - kScrollbarPadding) /
|
||||
currentPage.height / kCssUnits;
|
||||
currentPage.height * currentPage.scale / kCssUnits;
|
||||
if ('page-width' == value)
|
||||
this.setScale(pageWidthScale, resetAutoSettings);
|
||||
if ('page-height' == value)
|
||||
@ -318,27 +318,25 @@ var PDFView = {
|
||||
}
|
||||
|
||||
var self = this;
|
||||
PDFJS.getPdf(
|
||||
{
|
||||
url: url,
|
||||
progress: function getPdfProgress(evt) {
|
||||
if (evt.lengthComputable)
|
||||
self.progress(evt.loaded / evt.total);
|
||||
},
|
||||
error: function getPdfError(e) {
|
||||
var loadingIndicator = document.getElementById('loading');
|
||||
loadingIndicator.textContent = 'Error';
|
||||
var moreInfo = {
|
||||
message: 'Unexpected server response of ' + e.target.status + '.'
|
||||
};
|
||||
self.error('An error occurred while loading the PDF.', moreInfo);
|
||||
}
|
||||
},
|
||||
function getPdfLoad(data) {
|
||||
self.loading = true;
|
||||
self.load(data, scale);
|
||||
self.loading = true;
|
||||
PDFJS.getDocument(url).then(
|
||||
function getDocumentCallback(pdfDocument) {
|
||||
self.load(pdfDocument, scale);
|
||||
self.loading = false;
|
||||
});
|
||||
},
|
||||
function getDocumentError(message, exception) {
|
||||
var loadingIndicator = document.getElementById('loading');
|
||||
loadingIndicator.textContent = 'Error';
|
||||
var moreInfo = {
|
||||
message: message
|
||||
};
|
||||
self.error('An error occurred while loading the PDF.', moreInfo);
|
||||
self.loading = false;
|
||||
},
|
||||
function getDocumentProgress(progressData) {
|
||||
self.progress(progressData.loaded / progressData.total);
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
download: function pdfViewDownload() {
|
||||
@ -360,6 +358,8 @@ var PDFView = {
|
||||
var destRef = dest[0];
|
||||
var pageNumber = destRef instanceof Object ?
|
||||
this.pagesRefMap[destRef.num + ' ' + destRef.gen + ' R'] : (destRef + 1);
|
||||
if (pageNumber > this.pages.length)
|
||||
pageNumber = this.pages.length;
|
||||
if (pageNumber) {
|
||||
this.page = pageNumber;
|
||||
var currentPage = this.pages[pageNumber - 1];
|
||||
@ -461,7 +461,7 @@ var PDFView = {
|
||||
PDFView.loadingBar.percent = percent;
|
||||
},
|
||||
|
||||
load: function pdfViewLoad(data, scale) {
|
||||
load: function pdfViewLoad(pdfDocument, scale) {
|
||||
function bindOnAfterDraw(pageView, thumbnailView) {
|
||||
// when page is painted, using the image as thumbnail base
|
||||
pageView.onAfterDraw = function pdfViewLoadOnAfterDraw() {
|
||||
@ -489,14 +489,8 @@ var PDFView = {
|
||||
while (container.hasChildNodes())
|
||||
container.removeChild(container.lastChild);
|
||||
|
||||
var pdf;
|
||||
try {
|
||||
pdf = new PDFJS.PDFDoc(data);
|
||||
} catch (e) {
|
||||
this.error('An error occurred while reading the PDF.', e);
|
||||
}
|
||||
var pagesCount = pdf.numPages;
|
||||
var id = pdf.fingerprint;
|
||||
var pagesCount = pdfDocument.numPages;
|
||||
var id = pdfDocument.fingerprint;
|
||||
var storedHash = null;
|
||||
document.getElementById('numPages').textContent = '/ ' + pagesCount;
|
||||
document.getElementById('pageNumber').max = pagesCount;
|
||||
@ -514,30 +508,68 @@ var PDFView = {
|
||||
var pages = this.pages = [];
|
||||
var pagesRefMap = {};
|
||||
var thumbnails = this.thumbnails = [];
|
||||
for (var i = 1; i <= pagesCount; i++) {
|
||||
var page = pdf.getPage(i);
|
||||
var pageView = new PageView(container, page, i, page.width, page.height,
|
||||
page.stats, this.navigateTo.bind(this));
|
||||
var thumbnailView = new ThumbnailView(thumbsView, page, i,
|
||||
page.width / page.height);
|
||||
bindOnAfterDraw(pageView, thumbnailView);
|
||||
var pagePromises = [];
|
||||
for (var i = 1; i <= pagesCount; i++)
|
||||
pagePromises.push(pdfDocument.getPage(i));
|
||||
var self = this;
|
||||
var pagesPromise = PDFJS.Promise.all(pagePromises);
|
||||
pagesPromise.then(function(promisedPages) {
|
||||
for (var i = 1; i <= pagesCount; i++) {
|
||||
var page = promisedPages[i - 1];
|
||||
var pageView = new PageView(container, page, i, scale,
|
||||
page.stats, self.navigateTo.bind(self));
|
||||
var thumbnailView = new ThumbnailView(thumbsView, page, i);
|
||||
bindOnAfterDraw(pageView, thumbnailView);
|
||||
|
||||
pages.push(pageView);
|
||||
thumbnails.push(thumbnailView);
|
||||
var pageRef = page.ref;
|
||||
pagesRefMap[pageRef.num + ' ' + pageRef.gen + ' R'] = i;
|
||||
}
|
||||
pages.push(pageView);
|
||||
thumbnails.push(thumbnailView);
|
||||
var pageRef = page.ref;
|
||||
pagesRefMap[pageRef.num + ' ' + pageRef.gen + ' R'] = i;
|
||||
}
|
||||
|
||||
this.pagesRefMap = pagesRefMap;
|
||||
this.destinations = pdf.catalog.destinations;
|
||||
self.pagesRefMap = pagesRefMap;
|
||||
});
|
||||
|
||||
if (pdf.catalog.documentOutline) {
|
||||
this.outline = new DocumentOutlineView(pdf.catalog.documentOutline);
|
||||
var outlineSwitchButton = document.getElementById('viewOutline');
|
||||
outlineSwitchButton.removeAttribute('disabled');
|
||||
this.switchSidebarView('outline');
|
||||
}
|
||||
var destinationsPromise = pdfDocument.getDestinations();
|
||||
destinationsPromise.then(function(destinations) {
|
||||
self.destinations = destinations;
|
||||
});
|
||||
|
||||
// outline and initial view depends on destinations and pagesRefMap
|
||||
PDFJS.Promise.all([pagesPromise, destinationsPromise]).then(function() {
|
||||
pdfDocument.getOutline().then(function(outline) {
|
||||
if (!outline)
|
||||
return;
|
||||
|
||||
self.outline = new DocumentOutlineView(outline);
|
||||
var outlineSwitchButton = document.getElementById('viewOutline');
|
||||
outlineSwitchButton.removeAttribute('disabled');
|
||||
self.switchSidebarView('outline');
|
||||
});
|
||||
|
||||
self.setInitialView(storedHash, scale);
|
||||
});
|
||||
|
||||
pdfDocument.getMetadata().then(function(data) {
|
||||
var info = data.info, metadata = data.metadata;
|
||||
self.documentInfo = info;
|
||||
self.metadata = metadata;
|
||||
|
||||
var pdfTitle;
|
||||
if (metadata) {
|
||||
if (metadata.has('dc:title'))
|
||||
pdfTitle = metadata.get('dc:title');
|
||||
}
|
||||
|
||||
if (!pdfTitle && info && info['Title'])
|
||||
pdfTitle = info['Title'];
|
||||
|
||||
if (pdfTitle)
|
||||
document.title = pdfTitle + ' - ' + document.title;
|
||||
});
|
||||
},
|
||||
|
||||
setInitialView: function pdfViewSetInitialView(storedHash, scale) {
|
||||
// Reset the current scale, as otherwise the page's scale might not get
|
||||
// updated if the zoom level stayed the same.
|
||||
this.currentScale = 0;
|
||||
@ -558,24 +590,6 @@ var PDFView = {
|
||||
// Setting the default one.
|
||||
this.parseScale(kDefaultScale, true);
|
||||
}
|
||||
|
||||
this.metadata = null;
|
||||
var metadata = pdf.catalog.metadata;
|
||||
var info = this.documentInfo = pdf.info;
|
||||
var pdfTitle;
|
||||
|
||||
if (metadata) {
|
||||
this.metadata = metadata = new PDFJS.Metadata(metadata);
|
||||
|
||||
if (metadata.has('dc:title'))
|
||||
pdfTitle = metadata.get('dc:title');
|
||||
}
|
||||
|
||||
if (!pdfTitle && info && info['Title'])
|
||||
pdfTitle = info['Title'];
|
||||
|
||||
if (pdfTitle)
|
||||
document.title = pdfTitle + ' - ' + document.title;
|
||||
},
|
||||
|
||||
setHash: function pdfViewSetHash(hash) {
|
||||
@ -649,7 +663,7 @@ var PDFView = {
|
||||
var windowTop = window.pageYOffset;
|
||||
for (var i = 1; i <= pages.length; ++i) {
|
||||
var page = pages[i - 1];
|
||||
var pageHeight = page.height * page.scale + kBottomMargin;
|
||||
var pageHeight = page.height + kBottomMargin;
|
||||
if (currentHeight + pageHeight > windowTop)
|
||||
break;
|
||||
|
||||
@ -673,8 +687,8 @@ var PDFView = {
|
||||
|
||||
var view = document.getElementById('thumbnailView');
|
||||
var currentHeight = kBottomMargin;
|
||||
var top = view.scrollTop;
|
||||
|
||||
|
||||
var top = view.scrollTop;
|
||||
for (var i = 1; i <= thumbs.length; ++i) {
|
||||
var thumb = thumbs[i - 1];
|
||||
var thumbHeight = thumb.height * thumb.scaleY + kBottomMargin;
|
||||
@ -685,7 +699,6 @@ var PDFView = {
|
||||
}
|
||||
|
||||
var bottom = top + view.clientHeight;
|
||||
|
||||
for (; i <= thumbs.length && currentHeight < bottom; ++i) {
|
||||
var singleThumb = thumbs[i - 1];
|
||||
visibleThumbs.push({ id: singleThumb.id, y: currentHeight,
|
||||
@ -710,16 +723,13 @@ var PDFView = {
|
||||
}
|
||||
};
|
||||
|
||||
var PageView = function pageView(container, content, id, pageWidth, pageHeight,
|
||||
var PageView = function pageView(container, pdfPage, id, scale,
|
||||
stats, navigateTo) {
|
||||
this.id = id;
|
||||
this.content = content;
|
||||
this.pdfPage = pdfPage;
|
||||
|
||||
var view = this.content.view;
|
||||
this.x = view.x;
|
||||
this.y = view.y;
|
||||
this.width = view.width;
|
||||
this.height = view.height;
|
||||
this.scale = scale || 1.0;
|
||||
this.viewport = this.pdfPage.getViewport(this.scale);
|
||||
|
||||
var anchor = document.createElement('a');
|
||||
anchor.name = '' + this.id;
|
||||
@ -731,10 +741,18 @@ var PageView = function pageView(container, content, id, pageWidth, pageHeight,
|
||||
container.appendChild(anchor);
|
||||
container.appendChild(div);
|
||||
|
||||
this.destroy = function pageViewDestroy() {
|
||||
this.update();
|
||||
this.pdfPage.destroy();
|
||||
};
|
||||
|
||||
this.update = function pageViewUpdate(scale) {
|
||||
this.scale = scale || this.scale;
|
||||
div.style.width = (this.width * this.scale) + 'px';
|
||||
div.style.height = (this.height * this.scale) + 'px';
|
||||
var viewport = this.pdfPage.getViewport(this.scale);
|
||||
|
||||
this.viewport = viewport;
|
||||
div.style.width = viewport.width + 'px';
|
||||
div.style.height = viewport.height + 'px';
|
||||
|
||||
while (div.hasChildNodes())
|
||||
div.removeChild(div.lastChild);
|
||||
@ -747,7 +765,21 @@ var PageView = function pageView(container, content, id, pageWidth, pageHeight,
|
||||
div.appendChild(this.loadingIconDiv);
|
||||
};
|
||||
|
||||
function setupAnnotations(content, scale) {
|
||||
Object.defineProperty(this, 'width', {
|
||||
get: function PageView_getWidth() {
|
||||
return this.viewport.width;
|
||||
},
|
||||
enumerable: true
|
||||
});
|
||||
|
||||
Object.defineProperty(this, 'height', {
|
||||
get: function PageView_getHeight() {
|
||||
return this.viewport.height;
|
||||
},
|
||||
enumerable: true
|
||||
});
|
||||
|
||||
function setupAnnotations(pdfPage, viewport) {
|
||||
function bindLink(link, dest) {
|
||||
link.href = PDFView.getDestinationHash(dest);
|
||||
link.onclick = function pageViewSetupLinksOnclick() {
|
||||
@ -757,11 +789,13 @@ var PageView = function pageView(container, content, id, pageWidth, pageHeight,
|
||||
};
|
||||
}
|
||||
function createElementWithStyle(tagName, item) {
|
||||
var rect = viewport.convertToViewportRectangle(item.rect);
|
||||
rect = PDFJS.Util.normalizeRect(rect);
|
||||
var element = document.createElement(tagName);
|
||||
element.style.left = (Math.floor(item.x - view.x) * scale) + 'px';
|
||||
element.style.top = (Math.floor(item.y - view.y) * scale) + 'px';
|
||||
element.style.width = Math.ceil(item.width * scale) + 'px';
|
||||
element.style.height = Math.ceil(item.height * scale) + 'px';
|
||||
element.style.left = Math.floor(rect[0]) + 'px';
|
||||
element.style.top = Math.floor(rect[1]) + 'px';
|
||||
element.style.width = Math.ceil(rect[2] - rect[0]) + 'px';
|
||||
element.style.height = Math.ceil(rect[3] - rect[1]) + 'px';
|
||||
return element;
|
||||
}
|
||||
function createCommentAnnotation(type, item) {
|
||||
@ -769,17 +803,20 @@ var PageView = function pageView(container, content, id, pageWidth, pageHeight,
|
||||
container.className = 'annotComment';
|
||||
|
||||
var image = createElementWithStyle('img', item);
|
||||
var type = item.type;
|
||||
var rect = viewport.convertToViewportRectangle(item.rect);
|
||||
rect = PDFJS.Util.normalizeRect(rect);
|
||||
image.src = kImageDirectory + type.toLowerCase() + '.svg';
|
||||
image.alt = '[' + type + ' Annotation]';
|
||||
var content = document.createElement('div');
|
||||
content.setAttribute('hidden', true);
|
||||
var title = document.createElement('h1');
|
||||
var text = document.createElement('p');
|
||||
var offsetPos = Math.floor(item.x - view.x + item.width);
|
||||
content.style.left = (offsetPos * scale) + 'px';
|
||||
content.style.top = (Math.floor(item.y - view.y) * scale) + 'px';
|
||||
content.style.left = Math.floor(rect[2]) + 'px';
|
||||
content.style.top = Math.floor(rect[1]) + 'px';
|
||||
title.textContent = item.title;
|
||||
|
||||
if (!item.content) {
|
||||
if (!item.content && !item.title) {
|
||||
content.setAttribute('hidden', true);
|
||||
} else {
|
||||
var e = document.createElement('span');
|
||||
@ -792,11 +829,11 @@ var PageView = function pageView(container, content, id, pageWidth, pageHeight,
|
||||
}
|
||||
text.appendChild(e);
|
||||
image.addEventListener('mouseover', function annotationImageOver() {
|
||||
this.nextSibling.removeAttribute('hidden');
|
||||
content.removeAttribute('hidden');
|
||||
}, false);
|
||||
|
||||
image.addEventListener('mouseout', function annotationImageOut() {
|
||||
this.nextSibling.setAttribute('hidden', true);
|
||||
content.setAttribute('hidden', true);
|
||||
}, false);
|
||||
}
|
||||
|
||||
@ -808,29 +845,29 @@ var PageView = function pageView(container, content, id, pageWidth, pageHeight,
|
||||
return container;
|
||||
}
|
||||
|
||||
var items = content.getAnnotations();
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
var item = items[i];
|
||||
switch (item.type) {
|
||||
case 'Link':
|
||||
var link = createElementWithStyle('a', item);
|
||||
link.href = item.url || '';
|
||||
if (!item.url)
|
||||
bindLink(link, ('dest' in item) ? item.dest : null);
|
||||
div.appendChild(link);
|
||||
break;
|
||||
case 'Text':
|
||||
var comment = createCommentAnnotation(item.name, item);
|
||||
if (comment)
|
||||
div.appendChild(comment);
|
||||
break;
|
||||
pdfPage.getAnnotations().then(function(items) {
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
var item = items[i];
|
||||
switch (item.type) {
|
||||
case 'Link':
|
||||
var link = createElementWithStyle('a', item);
|
||||
link.href = item.url || '';
|
||||
if (!item.url)
|
||||
bindLink(link, ('dest' in item) ? item.dest : null);
|
||||
div.appendChild(link);
|
||||
break;
|
||||
case 'Text':
|
||||
var comment = createCommentAnnotation(item.name, item);
|
||||
if (comment)
|
||||
div.appendChild(comment);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.getPagePoint = function pageViewGetPagePoint(x, y) {
|
||||
var scale = PDFView.currentScale;
|
||||
return this.content.rotatePoint(x / scale, y / scale);
|
||||
return this.viewport.convertToPdfPoint(x, y);
|
||||
};
|
||||
|
||||
this.scrollIntoView = function pageViewScrollIntoView(dest) {
|
||||
@ -878,8 +915,8 @@ var PageView = function pageView(container, content, id, pageWidth, pageHeight,
|
||||
}
|
||||
|
||||
var boundingRect = [
|
||||
this.content.rotatePoint(x, y),
|
||||
this.content.rotatePoint(x + width, y + height)
|
||||
this.viewport.convertToViewportPoint(x, y),
|
||||
this.viewport.convertToViewportPoint(x + width, y + height)
|
||||
];
|
||||
|
||||
if (scale && scale !== PDFView.currentScale)
|
||||
@ -890,18 +927,18 @@ var PageView = function pageView(container, content, id, pageWidth, pageHeight,
|
||||
setTimeout(function pageViewScrollIntoViewRelayout() {
|
||||
// letting page to re-layout before scrolling
|
||||
var scale = PDFView.currentScale;
|
||||
var x = Math.min(boundingRect[0].x, boundingRect[1].x);
|
||||
var y = Math.min(boundingRect[0].y, boundingRect[1].y);
|
||||
var width = Math.abs(boundingRect[0].x - boundingRect[1].x);
|
||||
var height = Math.abs(boundingRect[0].y - boundingRect[1].y);
|
||||
var x = Math.min(boundingRect[0][0], boundingRect[1][0]);
|
||||
var y = Math.min(boundingRect[0][1], boundingRect[1][1]);
|
||||
var width = Math.abs(boundingRect[0][0] - boundingRect[1][0]);
|
||||
var height = Math.abs(boundingRect[0][1] - boundingRect[1][1]);
|
||||
|
||||
// using temporary div to scroll it into view
|
||||
var tempDiv = document.createElement('div');
|
||||
tempDiv.style.position = 'absolute';
|
||||
tempDiv.style.left = Math.floor(x * scale) + 'px';
|
||||
tempDiv.style.top = Math.floor(y * scale) + 'px';
|
||||
tempDiv.style.width = Math.ceil(width * scale) + 'px';
|
||||
tempDiv.style.height = Math.ceil(height * scale) + 'px';
|
||||
tempDiv.style.left = Math.floor(x) + 'px';
|
||||
tempDiv.style.top = Math.floor(y) + 'px';
|
||||
tempDiv.style.width = Math.ceil(width) + 'px';
|
||||
tempDiv.style.height = Math.ceil(height) + 'px';
|
||||
div.appendChild(tempDiv);
|
||||
tempDiv.scrollIntoView(true);
|
||||
div.removeChild(tempDiv);
|
||||
@ -933,21 +970,20 @@ var PageView = function pageView(container, content, id, pageWidth, pageHeight,
|
||||
}
|
||||
var textLayer = textLayerDiv ? new TextLayerBuilder(textLayerDiv) : null;
|
||||
|
||||
var scale = this.scale;
|
||||
canvas.width = pageWidth * scale;
|
||||
canvas.height = pageHeight * scale;
|
||||
var scale = this.scale, viewport = this.viewport;
|
||||
canvas.width = viewport.width;
|
||||
canvas.height = viewport.height;
|
||||
|
||||
var ctx = canvas.getContext('2d');
|
||||
ctx.save();
|
||||
ctx.fillStyle = 'rgb(255, 255, 255)';
|
||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||
ctx.restore();
|
||||
ctx.translate(-this.x * scale, -this.y * scale);
|
||||
|
||||
// Rendering area
|
||||
|
||||
var self = this;
|
||||
this.content.startRendering(ctx, function pageViewDrawCallback(error) {
|
||||
function pageViewDrawCallback(error) {
|
||||
if (self.loadingIconDiv) {
|
||||
div.removeChild(self.loadingIconDiv);
|
||||
delete self.loadingIconDiv;
|
||||
@ -956,16 +992,30 @@ var PageView = function pageView(container, content, id, pageWidth, pageHeight,
|
||||
if (error)
|
||||
PDFView.error('An error occurred while rendering the page.', error);
|
||||
|
||||
self.stats = content.stats;
|
||||
self.stats = pdfPage.stats;
|
||||
self.updateStats();
|
||||
if (self.onAfterDraw)
|
||||
self.onAfterDraw();
|
||||
|
||||
cache.push(self);
|
||||
callback();
|
||||
}, textLayer);
|
||||
}
|
||||
|
||||
setupAnnotations(this.content, this.scale);
|
||||
var renderContext = {
|
||||
canvasContext: ctx,
|
||||
viewport: this.viewport,
|
||||
textLayer: textLayer
|
||||
};
|
||||
this.pdfPage.render(renderContext).then(
|
||||
function pdfPageRenderCallback() {
|
||||
pageViewDrawCallback(null);
|
||||
},
|
||||
function pdfPageRenderError(error) {
|
||||
pageViewDrawCallback(error);
|
||||
}
|
||||
);
|
||||
|
||||
setupAnnotations(this.pdfPage, this.viewport);
|
||||
div.setAttribute('data-loaded', true);
|
||||
};
|
||||
|
||||
@ -977,7 +1027,7 @@ var PageView = function pageView(container, content, id, pageWidth, pageHeight,
|
||||
};
|
||||
};
|
||||
|
||||
var ThumbnailView = function thumbnailView(container, page, id, pageRatio) {
|
||||
var ThumbnailView = function thumbnailView(container, pdfPage, id) {
|
||||
var anchor = document.createElement('a');
|
||||
anchor.href = PDFView.getAnchorUrl('#page=' + id);
|
||||
anchor.onclick = function stopNivigation() {
|
||||
@ -985,15 +1035,16 @@ var ThumbnailView = function thumbnailView(container, page, id, pageRatio) {
|
||||
return false;
|
||||
};
|
||||
|
||||
var view = page.view;
|
||||
this.width = view.width;
|
||||
this.height = view.height;
|
||||
var viewport = pdfPage.getViewport(1);
|
||||
var pageWidth = viewport.width;
|
||||
var pageHeight = viewport.height;
|
||||
var pageRatio = pageWidth / pageHeight;
|
||||
this.id = id;
|
||||
|
||||
var canvasWidth = 98;
|
||||
var canvasHeight = canvasWidth / this.width * this.height;
|
||||
var scaleX = this.scaleX = (canvasWidth / this.width);
|
||||
var scaleY = this.scaleY = (canvasHeight / this.height);
|
||||
var scaleX = this.scaleX = (canvasWidth / pageWidth);
|
||||
var scaleY = this.scaleY = (canvasHeight / pageHeight);
|
||||
|
||||
var div = document.createElement('div');
|
||||
div.id = 'thumbnailContainer' + id;
|
||||
@ -1014,7 +1065,7 @@ var ThumbnailView = function thumbnailView(container, page, id, pageRatio) {
|
||||
canvas.className = 'thumbnailImage';
|
||||
|
||||
div.setAttribute('data-loaded', true);
|
||||
|
||||
|
||||
var ring = document.createElement('div');
|
||||
ring.className = 'thumbnailSelectionRing';
|
||||
ring.appendChild(canvas);
|
||||
@ -1023,11 +1074,8 @@ var ThumbnailView = function thumbnailView(container, page, id, pageRatio) {
|
||||
var ctx = canvas.getContext('2d');
|
||||
ctx.save();
|
||||
ctx.fillStyle = 'rgb(255, 255, 255)';
|
||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||
ctx.fillRect(0, 0, canvasWidth, canvasHeight);
|
||||
ctx.restore();
|
||||
|
||||
var view = page.view;
|
||||
ctx.translate(-view.x * scaleX, -view.y * scaleY);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
@ -1042,10 +1090,19 @@ var ThumbnailView = function thumbnailView(container, page, id, pageRatio) {
|
||||
}
|
||||
|
||||
var ctx = getPageDrawContext();
|
||||
page.startRendering(ctx, function thumbnailViewDrawStartRendering() {
|
||||
callback();
|
||||
});
|
||||
|
||||
var drawViewport = pdfPage.getViewport(scaleX);
|
||||
var renderContext = {
|
||||
canvasContext: ctx,
|
||||
viewport: drawViewport
|
||||
};
|
||||
pdfPage.render(renderContext).then(
|
||||
function pdfPageRenderCallback() {
|
||||
callback();
|
||||
},
|
||||
function pdfPageRenderError(error) {
|
||||
callback();
|
||||
}
|
||||
);
|
||||
this.hasImage = true;
|
||||
};
|
||||
|
||||
@ -1235,7 +1292,6 @@ window.addEventListener('load', function webViewerLoad(evt) {
|
||||
|
||||
var file = PDFJS.isFirefoxExtension ?
|
||||
window.location.toString() : params.file || kDefaultURL;
|
||||
PDFView.open(file, 0);
|
||||
|
||||
if (PDFJS.isFirefoxExtension || !window.File || !window.FileReader ||
|
||||
!window.FileList || !window.Blob) {
|
||||
@ -1273,6 +1329,8 @@ window.addEventListener('load', function webViewerLoad(evt) {
|
||||
document.getElementById('sidebarContainer').classList.toggle('hidden');
|
||||
updateThumbViewArea();
|
||||
});
|
||||
|
||||
PDFView.open(file, 0);
|
||||
}, true);
|
||||
|
||||
/**
|
||||
@ -1336,14 +1394,14 @@ function updateViewarea() {
|
||||
var currentPage = PDFView.pages[pageNumber - 1];
|
||||
var topLeft = currentPage.getPagePoint(window.pageXOffset,
|
||||
window.pageYOffset - firstPage.y - kViewerTopMargin);
|
||||
pdfOpenParams += ',' + Math.round(topLeft.x) + ',' + Math.round(topLeft.y);
|
||||
pdfOpenParams += ',' + Math.round(topLeft[0]) + ',' + Math.round(topLeft[1]);
|
||||
|
||||
var store = PDFView.store;
|
||||
store.set('exists', true);
|
||||
store.set('page', pageNumber);
|
||||
store.set('zoom', normalizedScaleValue);
|
||||
store.set('scrollLeft', Math.round(topLeft.x));
|
||||
store.set('scrollTop', Math.round(topLeft.y));
|
||||
store.set('scrollLeft', Math.round(topLeft[0]));
|
||||
store.set('scrollTop', Math.round(topLeft[1]));
|
||||
var href = PDFView.getAnchorUrl(pdfOpenParams);
|
||||
document.getElementById('viewBookmark').href = href;
|
||||
}
|
||||
@ -1397,7 +1455,11 @@ window.addEventListener('change', function webViewerChange(evt) {
|
||||
|
||||
for (var i = 0; i < data.length; i++)
|
||||
uint8Array[i] = data.charCodeAt(i);
|
||||
PDFView.load(uint8Array);
|
||||
|
||||
// TODO using blob instead?
|
||||
PDFJS.getDocument(uint8Array).then(function(pdfDocument) {
|
||||
PDFView.load(pdfDocument);
|
||||
});
|
||||
};
|
||||
|
||||
// Read as a binary string since "readAsArrayBuffer" is not yet
|
||||
|
Loading…
Reference in New Issue
Block a user