Initial API implementation
This commit is contained in:
parent
d8235925ac
commit
737ed84174
141
src/api.js
Normal file
141
src/api.js
Normal file
@ -0,0 +1,141 @@
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
|
||||
(function pdfApiWrapper() {
|
||||
function PdfPageWrapper(page) {
|
||||
this.page = page;
|
||||
}
|
||||
PdfPageWrapper.prototype = {
|
||||
get width() {
|
||||
return this.page.width;
|
||||
},
|
||||
get height() {
|
||||
return this.page.height;
|
||||
},
|
||||
get stats() {
|
||||
return this.page.stats;
|
||||
},
|
||||
get ref() {
|
||||
return this.page.ref;
|
||||
},
|
||||
get view() {
|
||||
return this.page.view;
|
||||
},
|
||||
rotatePoint: function(x, y) {
|
||||
return this.page.rotatePoint(x, y);
|
||||
},
|
||||
getAnnotations: function() {
|
||||
var promise = new PDFJS.Promise();
|
||||
var annotations = this.page.getAnnotations();
|
||||
promise.resolve(annotations);
|
||||
return promise;
|
||||
},
|
||||
render: function(renderContext) {
|
||||
var promise = new PDFJS.Promise();
|
||||
this.page.startRendering(renderContext.canvasContext,
|
||||
function complete(error) {
|
||||
if (error)
|
||||
promise.reject(error);
|
||||
else
|
||||
promise.resolve();
|
||||
},
|
||||
renderContext.textLayer);
|
||||
return promise;
|
||||
},
|
||||
getTextContent: function() {
|
||||
var promise = new PDFJS.Promise();
|
||||
var textContent = 'page text'; // not implemented
|
||||
promise.resolve(textContent);
|
||||
return promise;
|
||||
},
|
||||
getOperationList: function() {
|
||||
var promise = new PDFJS.Promise();
|
||||
var operationList = { // not implemented
|
||||
dependencyFontsID: null,
|
||||
operatorList: null
|
||||
};
|
||||
promise.resolve(operationList);
|
||||
return promise;
|
||||
}
|
||||
};
|
||||
|
||||
function PdfDocumentWrapper(pdf) {
|
||||
this.pdf = pdf;
|
||||
}
|
||||
PdfDocumentWrapper.prototype = {
|
||||
get numPages() {
|
||||
return this.pdf.numPages;
|
||||
},
|
||||
get fingerprint() {
|
||||
return this.pdf.fingerPrint;
|
||||
},
|
||||
getPage: function(number) {
|
||||
var promise = new PDFJS.Promise();
|
||||
var page = this.pdf.getPage(number);
|
||||
promise.resolve(new PdfPageWrapper(page));
|
||||
return promise;
|
||||
},
|
||||
getDestinations: function() {
|
||||
var promise = new PDFJS.Promise();
|
||||
var destinations = this.pdf.catalog.destinations;
|
||||
promise.resolve(destinations);
|
||||
return promise;
|
||||
},
|
||||
getOutline: function() {
|
||||
var promise = new PDFJS.Promise();
|
||||
var outline = this.pdf.catalog.documentOutline;
|
||||
promise.resolve(outline);
|
||||
return promise;
|
||||
},
|
||||
getMetadata: function() {
|
||||
var promise = new PDFJS.Promise();
|
||||
var info = this.pdf.info;
|
||||
var metadata = this.pdf.catalog.metadata;
|
||||
promise.resolve(info, metadata ? new PDFJS.Metadata(metadata) : null);
|
||||
return promise;
|
||||
}
|
||||
};
|
||||
|
||||
PDFJS.getDocument = function getDocument(source) {
|
||||
var promise = new PDFJS.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) {
|
||||
var pdf = null;
|
||||
try {
|
||||
pdf = new PDFJS.PDFDoc(data);
|
||||
} catch (e) {
|
||||
promise.reject('An error occurred while reading the PDF.', e);
|
||||
}
|
||||
if (pdf)
|
||||
promise.resolve(new PdfDocumentWrapper(pdf));
|
||||
});
|
||||
} else {
|
||||
// assuming the source is array, instantiating directly from it
|
||||
var pdf = null;
|
||||
try {
|
||||
pdf = new PDFJS.PDFDoc(source);
|
||||
} catch (e) {
|
||||
promise.reject('An error occurred while reading the PDF.', e);
|
||||
}
|
||||
if (pdf)
|
||||
promise.resolve(new PdfDocumentWrapper(pdf));
|
||||
}
|
||||
return promise;
|
||||
};
|
||||
})();
|
17
src/util.js
17
src/util.js
@ -275,7 +275,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 +297,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 +313,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 +377,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 +401,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 +418,9 @@ var Promise = (function PromiseClosure() {
|
||||
if (errback)
|
||||
this.errbacks.push(errback);
|
||||
}
|
||||
|
||||
if (progressback)
|
||||
this.progressbacks.push(progressback);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -11,6 +11,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 -->
|
||||
|
220
web/viewer.js
220
web/viewer.js
@ -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() {
|
||||
@ -461,7 +459,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 +487,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 +506,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(sidebar, 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, page.width, page.height,
|
||||
page.stats, self.navigateTo.bind(self));
|
||||
var thumbnailView = new ThumbnailView(sidebar, page, i,
|
||||
page.width / page.height);
|
||||
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('outlineSwitch');
|
||||
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('outlineSwitch');
|
||||
outlineSwitchButton.removeAttribute('disabled');
|
||||
self.switchSidebarView('outline');
|
||||
});
|
||||
|
||||
self.setInitialView(storedHash, scale);
|
||||
});
|
||||
|
||||
pdfDocument.getMetadata().then(function(info, 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 +588,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) {
|
||||
@ -711,12 +723,12 @@ var PDFView = {
|
||||
}
|
||||
};
|
||||
|
||||
var PageView = function pageView(container, content, id, pageWidth, pageHeight,
|
||||
var PageView = function pageView(container, pdfPage, id, pageWidth, pageHeight,
|
||||
stats, navigateTo) {
|
||||
this.id = id;
|
||||
this.content = content;
|
||||
this.pdfPage = pdfPage;
|
||||
|
||||
var view = this.content.view;
|
||||
var view = pdfPage.view;
|
||||
this.x = view.x;
|
||||
this.y = view.y;
|
||||
this.width = view.width;
|
||||
@ -748,7 +760,7 @@ var PageView = function pageView(container, content, id, pageWidth, pageHeight,
|
||||
div.appendChild(this.loadingIconDiv);
|
||||
};
|
||||
|
||||
function setupAnnotations(content, scale) {
|
||||
function setupAnnotations(pdfPage, scale) {
|
||||
function bindLink(link, dest) {
|
||||
link.href = PDFView.getDestinationHash(dest);
|
||||
link.onclick = function pageViewSetupLinksOnclick() {
|
||||
@ -809,29 +821,30 @@ 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.pdfPage.rotatePoint(x / scale, y / scale);
|
||||
};
|
||||
|
||||
this.scrollIntoView = function pageViewScrollIntoView(dest) {
|
||||
@ -879,8 +892,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.pdfPage.rotatePoint(x, y),
|
||||
this.pdfPage.rotatePoint(x + width, y + height)
|
||||
];
|
||||
|
||||
if (scale && scale !== PDFView.currentScale)
|
||||
@ -948,7 +961,7 @@ var PageView = function pageView(container, content, id, pageWidth, pageHeight,
|
||||
// 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;
|
||||
@ -964,9 +977,22 @@ var PageView = function pageView(container, content, id, pageWidth, pageHeight,
|
||||
|
||||
cache.push(self);
|
||||
callback();
|
||||
}, textLayer);
|
||||
}
|
||||
|
||||
setupAnnotations(this.content, this.scale);
|
||||
var renderContext = {
|
||||
canvasContext: ctx,
|
||||
textLayer: textLayer
|
||||
};
|
||||
this.pdfPage.render(renderContext).then(
|
||||
function pdfPageRenderCallback() {
|
||||
pageViewDrawCallback(null);
|
||||
},
|
||||
function pdfPageRenderError(error) {
|
||||
pageViewDrawCallback(error);
|
||||
}
|
||||
);
|
||||
|
||||
setupAnnotations(this.pdfPage, this.scale);
|
||||
div.setAttribute('data-loaded', true);
|
||||
};
|
||||
|
||||
@ -1397,7 +1423,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…
x
Reference in New Issue
Block a user