|
|
|
@ -19,8 +19,9 @@ import {
@@ -19,8 +19,9 @@ import {
|
|
|
|
|
import { getOutputScale, NullL10n } from './ui_utils'; |
|
|
|
|
import { RenderingStates } from './pdf_rendering_queue'; |
|
|
|
|
|
|
|
|
|
var THUMBNAIL_WIDTH = 98; // px
|
|
|
|
|
var THUMBNAIL_CANVAS_BORDER_WIDTH = 1; // px
|
|
|
|
|
const MAX_NUM_SCALING_STEPS = 3; |
|
|
|
|
const THUMBNAIL_CANVAS_BORDER_WIDTH = 1; // px
|
|
|
|
|
const THUMBNAIL_WIDTH = 98; // px
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* @typedef {Object} PDFThumbnailViewOptions |
|
|
|
@ -31,7 +32,7 @@ var THUMBNAIL_CANVAS_BORDER_WIDTH = 1; // px
@@ -31,7 +32,7 @@ var THUMBNAIL_CANVAS_BORDER_WIDTH = 1; // px
|
|
|
|
|
* @property {PDFRenderingQueue} renderingQueue - The rendering queue object. |
|
|
|
|
* @property {boolean} disableCanvasToImageConversion - (optional) Don't convert |
|
|
|
|
* the canvas thumbnails to images. This prevents `toDataURL` calls, |
|
|
|
|
* but increases the overall memory usage. The default value is false. |
|
|
|
|
* but increases the overall memory usage. The default value is `false`. |
|
|
|
|
* @property {IL10n} l10n - Localization service. |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
@ -77,23 +78,14 @@ const TempImageFactory = (function TempImageFactoryClosure() {
@@ -77,23 +78,14 @@ const TempImageFactory = (function TempImageFactoryClosure() {
|
|
|
|
|
})(); |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* @class |
|
|
|
|
* @implements {IRenderableView} |
|
|
|
|
*/ |
|
|
|
|
var PDFThumbnailView = (function PDFThumbnailViewClosure() { |
|
|
|
|
class PDFThumbnailView { |
|
|
|
|
/** |
|
|
|
|
* @constructs PDFThumbnailView |
|
|
|
|
* @param {PDFThumbnailViewOptions} options |
|
|
|
|
*/ |
|
|
|
|
function PDFThumbnailView(options) { |
|
|
|
|
var container = options.container; |
|
|
|
|
var id = options.id; |
|
|
|
|
var defaultViewport = options.defaultViewport; |
|
|
|
|
var linkService = options.linkService; |
|
|
|
|
var renderingQueue = options.renderingQueue; |
|
|
|
|
var disableCanvasToImageConversion = |
|
|
|
|
options.disableCanvasToImageConversion || false; |
|
|
|
|
|
|
|
|
|
constructor({ container, id, defaultViewport, linkService, renderingQueue, |
|
|
|
|
disableCanvasToImageConversion = false, l10n = NullL10n, }) { |
|
|
|
|
this.id = id; |
|
|
|
|
this.renderingId = 'thumbnail' + id; |
|
|
|
|
this.pageLabel = null; |
|
|
|
@ -119,21 +111,21 @@ var PDFThumbnailView = (function PDFThumbnailViewClosure() {
@@ -119,21 +111,21 @@ var PDFThumbnailView = (function PDFThumbnailViewClosure() {
|
|
|
|
|
this.canvasHeight = (this.canvasWidth / this.pageRatio) | 0; |
|
|
|
|
this.scale = this.canvasWidth / this.pageWidth; |
|
|
|
|
|
|
|
|
|
this.l10n = options.l10n || NullL10n; |
|
|
|
|
this.l10n = l10n; |
|
|
|
|
|
|
|
|
|
var anchor = document.createElement('a'); |
|
|
|
|
let anchor = document.createElement('a'); |
|
|
|
|
anchor.href = linkService.getAnchorUrl('#page=' + id); |
|
|
|
|
this.l10n.get('thumb_page_title', { page: id, }, 'Page {{page}}'). |
|
|
|
|
then((msg) => { |
|
|
|
|
anchor.title = msg; |
|
|
|
|
}); |
|
|
|
|
anchor.onclick = function stopNavigation() { |
|
|
|
|
anchor.onclick = function() { |
|
|
|
|
linkService.page = id; |
|
|
|
|
return false; |
|
|
|
|
}; |
|
|
|
|
this.anchor = anchor; |
|
|
|
|
|
|
|
|
|
var div = document.createElement('div'); |
|
|
|
|
let div = document.createElement('div'); |
|
|
|
|
div.className = 'thumbnail'; |
|
|
|
|
div.setAttribute('data-page-number', this.id); |
|
|
|
|
this.div = div; |
|
|
|
@ -144,9 +136,9 @@ var PDFThumbnailView = (function PDFThumbnailViewClosure() {
@@ -144,9 +136,9 @@ var PDFThumbnailView = (function PDFThumbnailViewClosure() {
|
|
|
|
|
div.classList.add('selected'); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var ring = document.createElement('div'); |
|
|
|
|
let ring = document.createElement('div'); |
|
|
|
|
ring.className = 'thumbnailSelectionRing'; |
|
|
|
|
var borderAdjustment = 2 * THUMBNAIL_CANVAS_BORDER_WIDTH; |
|
|
|
|
let borderAdjustment = 2 * THUMBNAIL_CANVAS_BORDER_WIDTH; |
|
|
|
|
ring.style.width = this.canvasWidth + borderAdjustment + 'px'; |
|
|
|
|
ring.style.height = this.canvasHeight + borderAdjustment + 'px'; |
|
|
|
|
this.ring = ring; |
|
|
|
@ -156,296 +148,288 @@ var PDFThumbnailView = (function PDFThumbnailViewClosure() {
@@ -156,296 +148,288 @@ var PDFThumbnailView = (function PDFThumbnailViewClosure() {
|
|
|
|
|
container.appendChild(anchor); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
PDFThumbnailView.prototype = { |
|
|
|
|
setPdfPage: function PDFThumbnailView_setPdfPage(pdfPage) { |
|
|
|
|
this.pdfPage = pdfPage; |
|
|
|
|
this.pdfPageRotate = pdfPage.rotate; |
|
|
|
|
var totalRotation = (this.rotation + this.pdfPageRotate) % 360; |
|
|
|
|
this.viewport = pdfPage.getViewport(1, totalRotation); |
|
|
|
|
this.reset(); |
|
|
|
|
}, |
|
|
|
|
setPdfPage(pdfPage) { |
|
|
|
|
this.pdfPage = pdfPage; |
|
|
|
|
this.pdfPageRotate = pdfPage.rotate; |
|
|
|
|
let totalRotation = (this.rotation + this.pdfPageRotate) % 360; |
|
|
|
|
this.viewport = pdfPage.getViewport(1, totalRotation); |
|
|
|
|
this.reset(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
reset: function PDFThumbnailView_reset() { |
|
|
|
|
this.cancelRendering(); |
|
|
|
|
reset() { |
|
|
|
|
this.cancelRendering(); |
|
|
|
|
|
|
|
|
|
this.pageWidth = this.viewport.width; |
|
|
|
|
this.pageHeight = this.viewport.height; |
|
|
|
|
this.pageRatio = this.pageWidth / this.pageHeight; |
|
|
|
|
this.pageWidth = this.viewport.width; |
|
|
|
|
this.pageHeight = this.viewport.height; |
|
|
|
|
this.pageRatio = this.pageWidth / this.pageHeight; |
|
|
|
|
|
|
|
|
|
this.canvasHeight = (this.canvasWidth / this.pageRatio) | 0; |
|
|
|
|
this.scale = (this.canvasWidth / this.pageWidth); |
|
|
|
|
this.canvasHeight = (this.canvasWidth / this.pageRatio) | 0; |
|
|
|
|
this.scale = (this.canvasWidth / this.pageWidth); |
|
|
|
|
|
|
|
|
|
this.div.removeAttribute('data-loaded'); |
|
|
|
|
var ring = this.ring; |
|
|
|
|
var childNodes = ring.childNodes; |
|
|
|
|
for (var i = childNodes.length - 1; i >= 0; i--) { |
|
|
|
|
ring.removeChild(childNodes[i]); |
|
|
|
|
} |
|
|
|
|
var borderAdjustment = 2 * THUMBNAIL_CANVAS_BORDER_WIDTH; |
|
|
|
|
ring.style.width = this.canvasWidth + borderAdjustment + 'px'; |
|
|
|
|
ring.style.height = this.canvasHeight + borderAdjustment + 'px'; |
|
|
|
|
this.div.removeAttribute('data-loaded'); |
|
|
|
|
let ring = this.ring; |
|
|
|
|
let childNodes = ring.childNodes; |
|
|
|
|
for (let i = childNodes.length - 1; i >= 0; i--) { |
|
|
|
|
ring.removeChild(childNodes[i]); |
|
|
|
|
} |
|
|
|
|
let borderAdjustment = 2 * THUMBNAIL_CANVAS_BORDER_WIDTH; |
|
|
|
|
ring.style.width = this.canvasWidth + borderAdjustment + 'px'; |
|
|
|
|
ring.style.height = this.canvasHeight + borderAdjustment + 'px'; |
|
|
|
|
|
|
|
|
|
if (this.canvas) { |
|
|
|
|
// Zeroing the width and height causes Firefox to release graphics
|
|
|
|
|
// resources immediately, which can greatly reduce memory consumption.
|
|
|
|
|
this.canvas.width = 0; |
|
|
|
|
this.canvas.height = 0; |
|
|
|
|
delete this.canvas; |
|
|
|
|
} |
|
|
|
|
if (this.image) { |
|
|
|
|
this.image.removeAttribute('src'); |
|
|
|
|
delete this.image; |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
if (this.canvas) { |
|
|
|
|
// Zeroing the width and height causes Firefox to release graphics
|
|
|
|
|
// resources immediately, which can greatly reduce memory consumption.
|
|
|
|
|
this.canvas.width = 0; |
|
|
|
|
this.canvas.height = 0; |
|
|
|
|
delete this.canvas; |
|
|
|
|
} |
|
|
|
|
if (this.image) { |
|
|
|
|
this.image.removeAttribute('src'); |
|
|
|
|
delete this.image; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
update: function PDFThumbnailView_update(rotation) { |
|
|
|
|
if (typeof rotation !== 'undefined') { |
|
|
|
|
this.rotation = rotation; |
|
|
|
|
} |
|
|
|
|
var totalRotation = (this.rotation + this.pdfPageRotate) % 360; |
|
|
|
|
this.viewport = this.viewport.clone({ |
|
|
|
|
scale: 1, |
|
|
|
|
rotation: totalRotation, |
|
|
|
|
}); |
|
|
|
|
this.reset(); |
|
|
|
|
}, |
|
|
|
|
update(rotation) { |
|
|
|
|
if (typeof rotation !== 'undefined') { |
|
|
|
|
this.rotation = rotation; |
|
|
|
|
} |
|
|
|
|
let totalRotation = (this.rotation + this.pdfPageRotate) % 360; |
|
|
|
|
this.viewport = this.viewport.clone({ |
|
|
|
|
scale: 1, |
|
|
|
|
rotation: totalRotation, |
|
|
|
|
}); |
|
|
|
|
this.reset(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
cancelRendering: function PDFThumbnailView_cancelRendering() { |
|
|
|
|
if (this.renderTask) { |
|
|
|
|
this.renderTask.cancel(); |
|
|
|
|
this.renderTask = null; |
|
|
|
|
} |
|
|
|
|
this.renderingState = RenderingStates.INITIAL; |
|
|
|
|
this.resume = null; |
|
|
|
|
}, |
|
|
|
|
cancelRendering() { |
|
|
|
|
if (this.renderTask) { |
|
|
|
|
this.renderTask.cancel(); |
|
|
|
|
this.renderTask = null; |
|
|
|
|
} |
|
|
|
|
this.renderingState = RenderingStates.INITIAL; |
|
|
|
|
this.resume = null; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* @private |
|
|
|
|
*/ |
|
|
|
|
_getPageDrawContext: |
|
|
|
|
function PDFThumbnailView_getPageDrawContext(noCtxScale) { |
|
|
|
|
var canvas = document.createElement('canvas'); |
|
|
|
|
// Keep the no-thumbnail outline visible, i.e. `data-loaded === false`,
|
|
|
|
|
// until rendering/image conversion is complete, to avoid display issues.
|
|
|
|
|
this.canvas = canvas; |
|
|
|
|
/** |
|
|
|
|
* @private |
|
|
|
|
*/ |
|
|
|
|
_getPageDrawContext(noCtxScale = false) { |
|
|
|
|
let canvas = document.createElement('canvas'); |
|
|
|
|
// Keep the no-thumbnail outline visible, i.e. `data-loaded === false`,
|
|
|
|
|
// until rendering/image conversion is complete, to avoid display issues.
|
|
|
|
|
this.canvas = canvas; |
|
|
|
|
|
|
|
|
|
if (typeof PDFJSDev === 'undefined' || |
|
|
|
|
PDFJSDev.test('MOZCENTRAL || FIREFOX || GENERIC')) { |
|
|
|
|
canvas.mozOpaque = true; |
|
|
|
|
} |
|
|
|
|
let ctx = canvas.getContext('2d', { alpha: false, }); |
|
|
|
|
let outputScale = getOutputScale(ctx); |
|
|
|
|
|
|
|
|
|
if (typeof PDFJSDev === 'undefined' || |
|
|
|
|
PDFJSDev.test('MOZCENTRAL || FIREFOX || GENERIC')) { |
|
|
|
|
canvas.mozOpaque = true; |
|
|
|
|
} |
|
|
|
|
var ctx = canvas.getContext('2d', { alpha: false, }); |
|
|
|
|
var outputScale = getOutputScale(ctx); |
|
|
|
|
canvas.width = (this.canvasWidth * outputScale.sx) | 0; |
|
|
|
|
canvas.height = (this.canvasHeight * outputScale.sy) | 0; |
|
|
|
|
canvas.style.width = this.canvasWidth + 'px'; |
|
|
|
|
canvas.style.height = this.canvasHeight + 'px'; |
|
|
|
|
|
|
|
|
|
canvas.width = (this.canvasWidth * outputScale.sx) | 0; |
|
|
|
|
canvas.height = (this.canvasHeight * outputScale.sy) | 0; |
|
|
|
|
canvas.style.width = this.canvasWidth + 'px'; |
|
|
|
|
canvas.style.height = this.canvasHeight + 'px'; |
|
|
|
|
if (!noCtxScale && outputScale.scaled) { |
|
|
|
|
ctx.scale(outputScale.sx, outputScale.sy); |
|
|
|
|
} |
|
|
|
|
return ctx; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!noCtxScale && outputScale.scaled) { |
|
|
|
|
ctx.scale(outputScale.sx, outputScale.sy); |
|
|
|
|
} |
|
|
|
|
return ctx; |
|
|
|
|
}, |
|
|
|
|
/** |
|
|
|
|
* @private |
|
|
|
|
*/ |
|
|
|
|
_convertCanvasToImage() { |
|
|
|
|
if (!this.canvas) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
if (this.renderingState !== RenderingStates.FINISHED) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
let id = this.renderingId; |
|
|
|
|
let className = 'thumbnailImage'; |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* @private |
|
|
|
|
*/ |
|
|
|
|
_convertCanvasToImage: function PDFThumbnailView_convertCanvasToImage() { |
|
|
|
|
if (!this.canvas) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
if (this.renderingState !== RenderingStates.FINISHED) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
var id = this.renderingId; |
|
|
|
|
var className = 'thumbnailImage'; |
|
|
|
|
|
|
|
|
|
if (this.disableCanvasToImageConversion) { |
|
|
|
|
this.canvas.id = id; |
|
|
|
|
this.canvas.className = className; |
|
|
|
|
this.l10n.get('thumb_page_canvas', { page: this.pageId, }, |
|
|
|
|
'Thumbnail of Page {{page}}').then((msg) => { |
|
|
|
|
this.canvas.setAttribute('aria-label', msg); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
this.div.setAttribute('data-loaded', true); |
|
|
|
|
this.ring.appendChild(this.canvas); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
var image = document.createElement('img'); |
|
|
|
|
image.id = id; |
|
|
|
|
image.className = className; |
|
|
|
|
if (this.disableCanvasToImageConversion) { |
|
|
|
|
this.canvas.id = id; |
|
|
|
|
this.canvas.className = className; |
|
|
|
|
this.l10n.get('thumb_page_canvas', { page: this.pageId, }, |
|
|
|
|
'Thumbnail of Page {{page}}'). |
|
|
|
|
then((msg) => { |
|
|
|
|
image.setAttribute('aria-label', msg); |
|
|
|
|
'Thumbnail of Page {{page}}').then((msg) => { |
|
|
|
|
this.canvas.setAttribute('aria-label', msg); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
image.style.width = this.canvasWidth + 'px'; |
|
|
|
|
image.style.height = this.canvasHeight + 'px'; |
|
|
|
|
|
|
|
|
|
image.src = this.canvas.toDataURL(); |
|
|
|
|
this.image = image; |
|
|
|
|
|
|
|
|
|
this.div.setAttribute('data-loaded', true); |
|
|
|
|
this.ring.appendChild(image); |
|
|
|
|
this.ring.appendChild(this.canvas); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
let image = document.createElement('img'); |
|
|
|
|
image.id = id; |
|
|
|
|
image.className = className; |
|
|
|
|
this.l10n.get('thumb_page_canvas', { page: this.pageId, }, |
|
|
|
|
'Thumbnail of Page {{page}}'). |
|
|
|
|
then((msg) => { |
|
|
|
|
image.setAttribute('aria-label', msg); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
// Zeroing the width and height causes Firefox to release graphics
|
|
|
|
|
// resources immediately, which can greatly reduce memory consumption.
|
|
|
|
|
this.canvas.width = 0; |
|
|
|
|
this.canvas.height = 0; |
|
|
|
|
delete this.canvas; |
|
|
|
|
}, |
|
|
|
|
image.style.width = this.canvasWidth + 'px'; |
|
|
|
|
image.style.height = this.canvasHeight + 'px'; |
|
|
|
|
|
|
|
|
|
draw() { |
|
|
|
|
if (this.renderingState !== RenderingStates.INITIAL) { |
|
|
|
|
console.error('Must be in new state before drawing'); |
|
|
|
|
return Promise.resolve(undefined); |
|
|
|
|
} |
|
|
|
|
image.src = this.canvas.toDataURL(); |
|
|
|
|
this.image = image; |
|
|
|
|
|
|
|
|
|
this.renderingState = RenderingStates.RUNNING; |
|
|
|
|
|
|
|
|
|
let renderCapability = createPromiseCapability(); |
|
|
|
|
|
|
|
|
|
let finishRenderTask = (error) => { |
|
|
|
|
// The renderTask may have been replaced by a new one, so only remove
|
|
|
|
|
// the reference to the renderTask if it matches the one that is
|
|
|
|
|
// triggering this callback.
|
|
|
|
|
if (renderTask === this.renderTask) { |
|
|
|
|
this.renderTask = null; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (((typeof PDFJSDev === 'undefined' || |
|
|
|
|
!PDFJSDev.test('PDFJS_NEXT')) && error === 'cancelled') || |
|
|
|
|
error instanceof RenderingCancelledException) { |
|
|
|
|
renderCapability.resolve(undefined); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
this.renderingState = RenderingStates.FINISHED; |
|
|
|
|
this._convertCanvasToImage(); |
|
|
|
|
|
|
|
|
|
if (!error) { |
|
|
|
|
renderCapability.resolve(undefined); |
|
|
|
|
} else { |
|
|
|
|
renderCapability.reject(error); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
let ctx = this._getPageDrawContext(); |
|
|
|
|
let drawViewport = this.viewport.clone({ scale: this.scale, }); |
|
|
|
|
let renderContinueCallback = (cont) => { |
|
|
|
|
if (!this.renderingQueue.isHighestPriority(this)) { |
|
|
|
|
this.renderingState = RenderingStates.PAUSED; |
|
|
|
|
this.resume = () => { |
|
|
|
|
this.renderingState = RenderingStates.RUNNING; |
|
|
|
|
cont(); |
|
|
|
|
}; |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
cont(); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
let renderContext = { |
|
|
|
|
canvasContext: ctx, |
|
|
|
|
viewport: drawViewport, |
|
|
|
|
}; |
|
|
|
|
let renderTask = this.renderTask = this.pdfPage.render(renderContext); |
|
|
|
|
renderTask.onContinue = renderContinueCallback; |
|
|
|
|
|
|
|
|
|
renderTask.promise.then(function() { |
|
|
|
|
finishRenderTask(null); |
|
|
|
|
}, function(error) { |
|
|
|
|
finishRenderTask(error); |
|
|
|
|
}); |
|
|
|
|
return renderCapability.promise; |
|
|
|
|
}, |
|
|
|
|
this.div.setAttribute('data-loaded', true); |
|
|
|
|
this.ring.appendChild(image); |
|
|
|
|
|
|
|
|
|
setImage: function PDFThumbnailView_setImage(pageView) { |
|
|
|
|
if (this.renderingState !== RenderingStates.INITIAL) { |
|
|
|
|
return; |
|
|
|
|
// Zeroing the width and height causes Firefox to release graphics
|
|
|
|
|
// resources immediately, which can greatly reduce memory consumption.
|
|
|
|
|
this.canvas.width = 0; |
|
|
|
|
this.canvas.height = 0; |
|
|
|
|
delete this.canvas; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
draw() { |
|
|
|
|
if (this.renderingState !== RenderingStates.INITIAL) { |
|
|
|
|
console.error('Must be in new state before drawing'); |
|
|
|
|
return Promise.resolve(undefined); |
|
|
|
|
} |
|
|
|
|
this.renderingState = RenderingStates.RUNNING; |
|
|
|
|
|
|
|
|
|
let renderCapability = createPromiseCapability(); |
|
|
|
|
let finishRenderTask = (error) => { |
|
|
|
|
// The renderTask may have been replaced by a new one, so only remove
|
|
|
|
|
// the reference to the renderTask if it matches the one that is
|
|
|
|
|
// triggering this callback.
|
|
|
|
|
if (renderTask === this.renderTask) { |
|
|
|
|
this.renderTask = null; |
|
|
|
|
} |
|
|
|
|
var img = pageView.canvas; |
|
|
|
|
if (!img) { |
|
|
|
|
|
|
|
|
|
if (((typeof PDFJSDev === 'undefined' || |
|
|
|
|
!PDFJSDev.test('PDFJS_NEXT')) && error === 'cancelled') || |
|
|
|
|
error instanceof RenderingCancelledException) { |
|
|
|
|
renderCapability.resolve(undefined); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
if (!this.pdfPage) { |
|
|
|
|
this.setPdfPage(pageView.pdfPage); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
this.renderingState = RenderingStates.FINISHED; |
|
|
|
|
this._convertCanvasToImage(); |
|
|
|
|
|
|
|
|
|
var ctx = this._getPageDrawContext(true); |
|
|
|
|
var canvas = ctx.canvas; |
|
|
|
|
if (!error) { |
|
|
|
|
renderCapability.resolve(undefined); |
|
|
|
|
} else { |
|
|
|
|
renderCapability.reject(error); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
if (img.width <= 2 * canvas.width) { |
|
|
|
|
ctx.drawImage(img, 0, 0, img.width, img.height, |
|
|
|
|
0, 0, canvas.width, canvas.height); |
|
|
|
|
this._convertCanvasToImage(); |
|
|
|
|
let ctx = this._getPageDrawContext(); |
|
|
|
|
let drawViewport = this.viewport.clone({ scale: this.scale, }); |
|
|
|
|
let renderContinueCallback = (cont) => { |
|
|
|
|
if (!this.renderingQueue.isHighestPriority(this)) { |
|
|
|
|
this.renderingState = RenderingStates.PAUSED; |
|
|
|
|
this.resume = () => { |
|
|
|
|
this.renderingState = RenderingStates.RUNNING; |
|
|
|
|
cont(); |
|
|
|
|
}; |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
// drawImage does an awful job of rescaling the image, doing it gradually.
|
|
|
|
|
var MAX_NUM_SCALING_STEPS = 3; |
|
|
|
|
var reducedWidth = canvas.width << MAX_NUM_SCALING_STEPS; |
|
|
|
|
var reducedHeight = canvas.height << MAX_NUM_SCALING_STEPS; |
|
|
|
|
var reducedImage = TempImageFactory.getCanvas(reducedWidth, |
|
|
|
|
reducedHeight); |
|
|
|
|
var reducedImageCtx = reducedImage.getContext('2d'); |
|
|
|
|
|
|
|
|
|
while (reducedWidth > img.width || reducedHeight > img.height) { |
|
|
|
|
reducedWidth >>= 1; |
|
|
|
|
reducedHeight >>= 1; |
|
|
|
|
} |
|
|
|
|
reducedImageCtx.drawImage(img, 0, 0, img.width, img.height, |
|
|
|
|
0, 0, reducedWidth, reducedHeight); |
|
|
|
|
while (reducedWidth > 2 * canvas.width) { |
|
|
|
|
reducedImageCtx.drawImage(reducedImage, |
|
|
|
|
0, 0, reducedWidth, reducedHeight, |
|
|
|
|
0, 0, reducedWidth >> 1, reducedHeight >> 1); |
|
|
|
|
reducedWidth >>= 1; |
|
|
|
|
reducedHeight >>= 1; |
|
|
|
|
} |
|
|
|
|
ctx.drawImage(reducedImage, 0, 0, reducedWidth, reducedHeight, |
|
|
|
|
cont(); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
let renderContext = { |
|
|
|
|
canvasContext: ctx, |
|
|
|
|
viewport: drawViewport, |
|
|
|
|
}; |
|
|
|
|
let renderTask = this.renderTask = this.pdfPage.render(renderContext); |
|
|
|
|
renderTask.onContinue = renderContinueCallback; |
|
|
|
|
|
|
|
|
|
renderTask.promise.then(function() { |
|
|
|
|
finishRenderTask(null); |
|
|
|
|
}, function(error) { |
|
|
|
|
finishRenderTask(error); |
|
|
|
|
}); |
|
|
|
|
return renderCapability.promise; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
setImage(pageView) { |
|
|
|
|
if (this.renderingState !== RenderingStates.INITIAL) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
let img = pageView.canvas; |
|
|
|
|
if (!img) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
if (!this.pdfPage) { |
|
|
|
|
this.setPdfPage(pageView.pdfPage); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
this.renderingState = RenderingStates.FINISHED; |
|
|
|
|
|
|
|
|
|
let ctx = this._getPageDrawContext(true); |
|
|
|
|
let canvas = ctx.canvas; |
|
|
|
|
if (img.width <= 2 * canvas.width) { |
|
|
|
|
ctx.drawImage(img, 0, 0, img.width, img.height, |
|
|
|
|
0, 0, canvas.width, canvas.height); |
|
|
|
|
this._convertCanvasToImage(); |
|
|
|
|
}, |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
get pageId() { |
|
|
|
|
return (this.pageLabel !== null ? this.pageLabel : this.id); |
|
|
|
|
}, |
|
|
|
|
// drawImage does an awful job of rescaling the image, doing it gradually.
|
|
|
|
|
let reducedWidth = canvas.width << MAX_NUM_SCALING_STEPS; |
|
|
|
|
let reducedHeight = canvas.height << MAX_NUM_SCALING_STEPS; |
|
|
|
|
let reducedImage = TempImageFactory.getCanvas(reducedWidth, |
|
|
|
|
reducedHeight); |
|
|
|
|
let reducedImageCtx = reducedImage.getContext('2d'); |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* @param {string|null} label |
|
|
|
|
*/ |
|
|
|
|
setPageLabel: function PDFThumbnailView_setPageLabel(label) { |
|
|
|
|
this.pageLabel = (typeof label === 'string' ? label : null); |
|
|
|
|
while (reducedWidth > img.width || reducedHeight > img.height) { |
|
|
|
|
reducedWidth >>= 1; |
|
|
|
|
reducedHeight >>= 1; |
|
|
|
|
} |
|
|
|
|
reducedImageCtx.drawImage(img, 0, 0, img.width, img.height, |
|
|
|
|
0, 0, reducedWidth, reducedHeight); |
|
|
|
|
while (reducedWidth > 2 * canvas.width) { |
|
|
|
|
reducedImageCtx.drawImage(reducedImage, |
|
|
|
|
0, 0, reducedWidth, reducedHeight, |
|
|
|
|
0, 0, reducedWidth >> 1, reducedHeight >> 1); |
|
|
|
|
reducedWidth >>= 1; |
|
|
|
|
reducedHeight >>= 1; |
|
|
|
|
} |
|
|
|
|
ctx.drawImage(reducedImage, 0, 0, reducedWidth, reducedHeight, |
|
|
|
|
0, 0, canvas.width, canvas.height); |
|
|
|
|
this._convertCanvasToImage(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
this.l10n.get('thumb_page_title', { page: this.pageId, }, |
|
|
|
|
'Page {{page}}').then((msg) => { |
|
|
|
|
this.anchor.title = msg; |
|
|
|
|
}); |
|
|
|
|
get pageId() { |
|
|
|
|
return (this.pageLabel !== null ? this.pageLabel : this.id); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (this.renderingState !== RenderingStates.FINISHED) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
/** |
|
|
|
|
* @param {string|null} label |
|
|
|
|
*/ |
|
|
|
|
setPageLabel(label) { |
|
|
|
|
this.pageLabel = (typeof label === 'string' ? label : null); |
|
|
|
|
|
|
|
|
|
this.l10n.get('thumb_page_canvas', { page: this.pageId, }, |
|
|
|
|
'Thumbnail of Page {{page}}').then((ariaLabel) => { |
|
|
|
|
if (this.image) { |
|
|
|
|
this.image.setAttribute('aria-label', ariaLabel); |
|
|
|
|
} else if (this.disableCanvasToImageConversion && this.canvas) { |
|
|
|
|
this.canvas.setAttribute('aria-label', ariaLabel); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
}, |
|
|
|
|
}; |
|
|
|
|
this.l10n.get('thumb_page_title', { page: this.pageId, }, |
|
|
|
|
'Page {{page}}').then((msg) => { |
|
|
|
|
this.anchor.title = msg; |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
PDFThumbnailView.cleanup = function() { |
|
|
|
|
TempImageFactory.destroyCanvas(); |
|
|
|
|
}; |
|
|
|
|
if (this.renderingState !== RenderingStates.FINISHED) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return PDFThumbnailView; |
|
|
|
|
})(); |
|
|
|
|
this.l10n.get('thumb_page_canvas', { page: this.pageId, }, |
|
|
|
|
'Thumbnail of Page {{page}}').then((ariaLabel) => { |
|
|
|
|
if (this.image) { |
|
|
|
|
this.image.setAttribute('aria-label', ariaLabel); |
|
|
|
|
} else if (this.disableCanvasToImageConversion && this.canvas) { |
|
|
|
|
this.canvas.setAttribute('aria-label', ariaLabel); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static cleanup() { |
|
|
|
|
TempImageFactory.destroyCanvas(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
export { |
|
|
|
|
PDFThumbnailView, |
|
|
|
|