Merge upstream.
This commit is contained in:
commit
7c8445753d
1
LICENSE
1
LICENSE
@ -9,6 +9,7 @@
|
|||||||
Yury Delendik
|
Yury Delendik
|
||||||
Kalervo Kujala
|
Kalervo Kujala
|
||||||
Adil Allawi <@ironymark>
|
Adil Allawi <@ironymark>
|
||||||
|
Jakob Miland <saebekassebil@gmail.com>
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
copy of this software and associated documentation files (the "Software"),
|
copy of this software and associated documentation files (the "Software"),
|
||||||
|
141
examples/acroforms/forms.js
Normal file
141
examples/acroforms/forms.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: */
|
||||||
|
|
||||||
|
//
|
||||||
|
// Basic AcroForms input controls rendering
|
||||||
|
//
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var formFields = {};
|
||||||
|
|
||||||
|
function setupForm(div, content, scale) {
|
||||||
|
function bindInputItem(input, item) {
|
||||||
|
if (input.name in formFields) {
|
||||||
|
var value = formFields[input.name];
|
||||||
|
if (input.type == 'checkbox')
|
||||||
|
input.checked = value;
|
||||||
|
else if (!input.type || input.type == 'text')
|
||||||
|
input.value = value;
|
||||||
|
}
|
||||||
|
input.onchange = function pageViewSetupInputOnBlur() {
|
||||||
|
if (input.type == 'checkbox')
|
||||||
|
formFields[input.name] = input.checked;
|
||||||
|
else if (!input.type || input.type == 'text')
|
||||||
|
formFields[input.name] = input.value;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
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';
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
function assignFontStyle(element, item) {
|
||||||
|
var fontStyles = '';
|
||||||
|
if ('fontSize' in item)
|
||||||
|
fontStyles += 'font-size: ' + Math.round(item.fontSize * scale) + 'px;';
|
||||||
|
switch (item.textAlignment) {
|
||||||
|
case 0:
|
||||||
|
fontStyles += 'text-align: left;';
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
fontStyles += 'text-align: center;';
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
fontStyles += 'text-align: right;';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
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';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
|
||||||
|
var pageDisplayWidth = page.width * scale;
|
||||||
|
var pageDisplayHeight = page.height * scale;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
|
||||||
|
// Render PDF page into canvas context
|
||||||
|
page.startRendering(context, callback);
|
||||||
|
|
||||||
|
// Prepare and populate form elements layer
|
||||||
|
var formDiv = document.createElement('div');
|
||||||
|
pageDivHolder.appendChild(formDiv);
|
||||||
|
|
||||||
|
setupForm(formDiv, page, scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFJS.getPdf(pdfWithFormsPath, function getPdfForm(data) {
|
||||||
|
// Instantiate PDFDoc with PDF data
|
||||||
|
var pdf = new PDFJS.PDFDoc(data);
|
||||||
|
|
||||||
|
// Rendering all pages starting from first
|
||||||
|
var viewer = document.getElementById('viewer');
|
||||||
|
var pageNumber = 1;
|
||||||
|
renderPage(viewer, pdf, pageNumber++, function pageRenderingComplete() {
|
||||||
|
if (pageNumber > pdf.numPages)
|
||||||
|
return; // All pages rendered
|
||||||
|
// Continue rendering of the next page
|
||||||
|
renderPage(viewer, pdf, pageNumber++, pageRenderingComplete);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
52
examples/acroforms/index.html
Normal file
52
examples/acroforms/index.html
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<!-- In production, only one script (pdf.js) is necessary -->
|
||||||
|
<!-- 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/canvas.js"></script>
|
||||||
|
<script type="text/javascript" src="../../src/obj.js"></script>
|
||||||
|
<script type="text/javascript" src="../../src/function.js"></script>
|
||||||
|
<script type="text/javascript" src="../../src/charsets.js"></script>
|
||||||
|
<script type="text/javascript" src="../../src/cidmaps.js"></script>
|
||||||
|
<script type="text/javascript" src="../../src/colorspace.js"></script>
|
||||||
|
<script type="text/javascript" src="../../src/crypto.js"></script>
|
||||||
|
<script type="text/javascript" src="../../src/evaluator.js"></script>
|
||||||
|
<script type="text/javascript" src="../../src/fonts.js"></script>
|
||||||
|
<script type="text/javascript" src="../../src/glyphlist.js"></script>
|
||||||
|
<script type="text/javascript" src="../../src/image.js"></script>
|
||||||
|
<script type="text/javascript" src="../../src/metrics.js"></script>
|
||||||
|
<script type="text/javascript" src="../../src/parser.js"></script>
|
||||||
|
<script type="text/javascript" src="../../src/pattern.js"></script>
|
||||||
|
<script type="text/javascript" src="../../src/stream.js"></script>
|
||||||
|
<script type="text/javascript" src="../../src/worker.js"></script>
|
||||||
|
<script type="text/javascript" src="../../external/jpgjs/jpg.js"></script>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
// Specify the main script used to create a new PDF.JS web worker.
|
||||||
|
// In production, change this to point to the combined `pdf.js` file.
|
||||||
|
PDFJS.workerSrc = '../../src/worker_loader.js';
|
||||||
|
|
||||||
|
// Specify the PDF with AcroForm here
|
||||||
|
var pdfWithFormsPath = '../../test/pdfs/f1040.pdf';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.pdfpage { position:relative; top: 0; left: 0; border: solid 1px black; margin: 10px; }
|
||||||
|
.pdfpage > canvas { position: absolute; top: 0; left: 0; }
|
||||||
|
.pdfpage > div { position: absolute; top: 0; left: 0; }
|
||||||
|
.inputControl { background: transparent; border: 0px none; position: absolute; margin: auto; }
|
||||||
|
.inputControl[type='checkbox'] { margin: 0px; }
|
||||||
|
.inputHint { opacity: 0.2; background: #ccc; position: absolute; }
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script type="text/javascript" src="forms.js"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="viewer"></div>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
@ -672,6 +672,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||||||
ctx.translate(current.x, current.y);
|
ctx.translate(current.x, current.y);
|
||||||
|
|
||||||
ctx.scale(textHScale, 1);
|
ctx.scale(textHScale, 1);
|
||||||
|
ctx.lineWidth /= current.textMatrix[0];
|
||||||
|
|
||||||
if (textSelection) {
|
if (textSelection) {
|
||||||
this.save();
|
this.save();
|
||||||
@ -708,6 +709,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||||||
} else {
|
} else {
|
||||||
ctx.save();
|
ctx.save();
|
||||||
this.applyTextTransforms();
|
this.applyTextTransforms();
|
||||||
|
ctx.lineWidth /= current.textMatrix[0] * fontMatrix[0];
|
||||||
|
|
||||||
if (textSelection)
|
if (textSelection)
|
||||||
text.geom = this.getTextGeometry();
|
text.geom = this.getTextGeometry();
|
||||||
|
|
||||||
|
@ -225,7 +225,7 @@ var AlternateCS = (function AlternateCSClosure() {
|
|||||||
return base.getRgbBuffer(baseBuf, 8);
|
return base.getRgbBuffer(baseBuf, 8);
|
||||||
},
|
},
|
||||||
isDefaultDecode: function altcs_isDefaultDecode(decodeMap) {
|
isDefaultDecode: function altcs_isDefaultDecode(decodeMap) {
|
||||||
ColorSpace.isDefaultDecode(decodeMap, this.numComps);
|
return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -327,7 +327,7 @@ var DeviceGrayCS = (function DeviceGrayCSClosure() {
|
|||||||
return rgbBuf;
|
return rgbBuf;
|
||||||
},
|
},
|
||||||
isDefaultDecode: function graycs_isDefaultDecode(decodeMap) {
|
isDefaultDecode: function graycs_isDefaultDecode(decodeMap) {
|
||||||
ColorSpace.isDefaultDecode(decodeMap, this.numComps);
|
return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return DeviceGrayCS;
|
return DeviceGrayCS;
|
||||||
@ -354,7 +354,7 @@ var DeviceRgbCS = (function DeviceRgbCSClosure() {
|
|||||||
return rgbBuf;
|
return rgbBuf;
|
||||||
},
|
},
|
||||||
isDefaultDecode: function rgbcs_isDefaultDecode(decodeMap) {
|
isDefaultDecode: function rgbcs_isDefaultDecode(decodeMap) {
|
||||||
ColorSpace.isDefaultDecode(decodeMap, this.numComps);
|
return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return DeviceRgbCS;
|
return DeviceRgbCS;
|
||||||
@ -441,7 +441,7 @@ var DeviceCmykCS = (function DeviceCmykCSClosure() {
|
|||||||
return rgbBuf;
|
return rgbBuf;
|
||||||
},
|
},
|
||||||
isDefaultDecode: function cmykcs_isDefaultDecode(decodeMap) {
|
isDefaultDecode: function cmykcs_isDefaultDecode(decodeMap) {
|
||||||
ColorSpace.isDefaultDecode(decodeMap, this.numComps);
|
return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
127
src/core.js
127
src/core.js
@ -274,34 +274,59 @@ var Page = (function PageClosure() {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
getLinks: function pageGetLinks() {
|
getLinks: function pageGetLinks() {
|
||||||
|
var links = [];
|
||||||
|
var annotations = pageGetAnnotations();
|
||||||
|
var i, n = annotations.length;
|
||||||
|
for (i = 0; i < n; ++i) {
|
||||||
|
if (annotations[i].type != 'Link')
|
||||||
|
continue;
|
||||||
|
links.push(annotations[i]);
|
||||||
|
}
|
||||||
|
return links;
|
||||||
|
},
|
||||||
|
getAnnotations: function pageGetAnnotations() {
|
||||||
var xref = this.xref;
|
var xref = this.xref;
|
||||||
|
function getInheritableProperty(annotation, name) {
|
||||||
|
var item = annotation;
|
||||||
|
while (item && !item.has(name)) {
|
||||||
|
item = xref.fetchIfRef(item.get('Parent'));
|
||||||
|
}
|
||||||
|
if (!item)
|
||||||
|
return null;
|
||||||
|
return item.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
var annotations = xref.fetchIfRef(this.annotations) || [];
|
var annotations = xref.fetchIfRef(this.annotations) || [];
|
||||||
var i, n = annotations.length;
|
var i, n = annotations.length;
|
||||||
var links = [];
|
var items = [];
|
||||||
for (i = 0; i < n; ++i) {
|
for (i = 0; i < n; ++i) {
|
||||||
var annotation = xref.fetch(annotations[i]);
|
var annotationRef = annotations[i];
|
||||||
|
var annotation = xref.fetch(annotationRef);
|
||||||
if (!isDict(annotation))
|
if (!isDict(annotation))
|
||||||
continue;
|
continue;
|
||||||
var subtype = annotation.get('Subtype');
|
var subtype = annotation.get('Subtype');
|
||||||
if (!isName(subtype) || subtype.name != 'Link')
|
if (!isName(subtype))
|
||||||
continue;
|
continue;
|
||||||
var rect = annotation.get('Rect');
|
var rect = annotation.get('Rect');
|
||||||
var topLeftCorner = this.rotatePoint(rect[0], rect[1]);
|
var topLeftCorner = this.rotatePoint(rect[0], rect[1]);
|
||||||
var bottomRightCorner = this.rotatePoint(rect[2], rect[3]);
|
var bottomRightCorner = this.rotatePoint(rect[2], rect[3]);
|
||||||
|
|
||||||
var link = {};
|
var item = {};
|
||||||
link.x = Math.min(topLeftCorner.x, bottomRightCorner.x);
|
item.type = subtype.name;
|
||||||
link.y = Math.min(topLeftCorner.y, bottomRightCorner.y);
|
item.x = Math.min(topLeftCorner.x, bottomRightCorner.x);
|
||||||
link.width = Math.abs(topLeftCorner.x - bottomRightCorner.x);
|
item.y = Math.min(topLeftCorner.y, bottomRightCorner.y);
|
||||||
link.height = Math.abs(topLeftCorner.y - bottomRightCorner.y);
|
item.width = Math.abs(topLeftCorner.x - bottomRightCorner.x);
|
||||||
|
item.height = Math.abs(topLeftCorner.y - bottomRightCorner.y);
|
||||||
|
switch (subtype.name) {
|
||||||
|
case 'Link':
|
||||||
var a = this.xref.fetchIfRef(annotation.get('A'));
|
var a = this.xref.fetchIfRef(annotation.get('A'));
|
||||||
if (a) {
|
if (a) {
|
||||||
switch (a.get('S').name) {
|
switch (a.get('S').name) {
|
||||||
case 'URI':
|
case 'URI':
|
||||||
link.url = a.get('URI');
|
item.url = a.get('URI');
|
||||||
break;
|
break;
|
||||||
case 'GoTo':
|
case 'GoTo':
|
||||||
link.dest = a.get('D');
|
item.dest = a.get('D');
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
TODO('other link types');
|
TODO('other link types');
|
||||||
@ -309,11 +334,65 @@ var Page = (function PageClosure() {
|
|||||||
} else if (annotation.has('Dest')) {
|
} else if (annotation.has('Dest')) {
|
||||||
// simple destination link
|
// simple destination link
|
||||||
var dest = annotation.get('Dest');
|
var dest = annotation.get('Dest');
|
||||||
link.dest = isName(dest) ? dest.name : dest;
|
item.dest = isName(dest) ? dest.name : dest;
|
||||||
}
|
}
|
||||||
links.push(link);
|
break;
|
||||||
|
case 'Widget':
|
||||||
|
var fieldType = getInheritableProperty(annotation, 'FT');
|
||||||
|
if (!isName(fieldType))
|
||||||
|
break;
|
||||||
|
item.fieldType = fieldType.name;
|
||||||
|
// Building the full field name by collecting the field and
|
||||||
|
// its ancestors 'T' properties and joining them using '.'.
|
||||||
|
var fieldName = [];
|
||||||
|
var namedItem = annotation, ref = annotationRef;
|
||||||
|
while (namedItem) {
|
||||||
|
var parentRef = namedItem.get('Parent');
|
||||||
|
var parent = xref.fetchIfRef(parentRef);
|
||||||
|
var name = namedItem.get('T');
|
||||||
|
if (name)
|
||||||
|
fieldName.unshift(stringToPDFString(name));
|
||||||
|
else {
|
||||||
|
// The field name is absent, that means more than one field
|
||||||
|
// with the same name may exist. Replacing the empty name
|
||||||
|
// with the '`' plus index in the parent's 'Kids' array.
|
||||||
|
// This is not in the PDF spec but necessary to id the
|
||||||
|
// the input controls.
|
||||||
|
var kids = xref.fetchIfRef(parent.get('Kids'));
|
||||||
|
var j, jj;
|
||||||
|
for (j = 0, jj = kids.length; j < jj; j++) {
|
||||||
|
if (kids[j].num == ref.num && kids[j].gen == ref.gen)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return links;
|
fieldName.unshift('`' + j);
|
||||||
|
}
|
||||||
|
namedItem = parent;
|
||||||
|
ref = parentRef;
|
||||||
|
}
|
||||||
|
item.fullName = fieldName.join('.');
|
||||||
|
var alternativeText = stringToPDFString(annotation.get('TU') || '');
|
||||||
|
item.alternativeText = alternativeText;
|
||||||
|
var da = getInheritableProperty(annotation, 'DA') || '';
|
||||||
|
var m = /([\d\.]+)\sTf/.exec(da);
|
||||||
|
if (m)
|
||||||
|
item.fontSize = parseFloat(m[1]);
|
||||||
|
item.textAlignment = getInheritableProperty(annotation, 'Q');
|
||||||
|
item.flags = getInheritableProperty(annotation, 'Ff') || 0;
|
||||||
|
break;
|
||||||
|
case 'Text':
|
||||||
|
var content = annotation.get('Contents');
|
||||||
|
var title = annotation.get('T');
|
||||||
|
item.content = stringToPDFString(content || '');
|
||||||
|
item.title = stringToPDFString(title || '');
|
||||||
|
item.name = annotation.get('Name').name;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
TODO('unimplemented annotation type: ' + subtype.name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
items.push(item);
|
||||||
|
}
|
||||||
|
return items;
|
||||||
},
|
},
|
||||||
startRendering: function pageStartRendering(ctx, callback, textLayer) {
|
startRendering: function pageStartRendering(ctx, callback, textLayer) {
|
||||||
this.ctx = ctx;
|
this.ctx = ctx;
|
||||||
@ -352,6 +431,7 @@ var PDFDocModel = (function PDFDocModelClosure() {
|
|||||||
assertWellFormed(stream.length > 0, 'stream must have data');
|
assertWellFormed(stream.length > 0, 'stream must have data');
|
||||||
this.stream = stream;
|
this.stream = stream;
|
||||||
this.setup();
|
this.setup();
|
||||||
|
this.acroForm = this.xref.fetchIfRef(this.catalog.catDict.get('AcroForm'));
|
||||||
}
|
}
|
||||||
|
|
||||||
function find(stream, needle, limit, backwards) {
|
function find(stream, needle, limit, backwards) {
|
||||||
@ -499,36 +579,35 @@ var PDFDoc = (function PDFDocClosure() {
|
|||||||
throw 'No PDFJS.workerSrc specified';
|
throw 'No PDFJS.workerSrc specified';
|
||||||
}
|
}
|
||||||
|
|
||||||
var worker;
|
|
||||||
try {
|
try {
|
||||||
worker = new Worker(workerSrc);
|
|
||||||
} catch (e) {
|
|
||||||
// Some versions of FF can't create a worker on localhost, see:
|
// Some versions of FF can't create a worker on localhost, see:
|
||||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=683280
|
// https://bugzilla.mozilla.org/show_bug.cgi?id=683280
|
||||||
globalScope.PDFJS.disableWorker = true;
|
var worker = new Worker(workerSrc);
|
||||||
this.setupFakeWorker();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var messageHandler = new MessageHandler('main', worker);
|
var messageHandler = new MessageHandler('main', worker);
|
||||||
|
|
||||||
// Tell the worker the file it was created from.
|
// Tell the worker the file it was created from.
|
||||||
messageHandler.send('workerSrc', workerSrc);
|
messageHandler.send('workerSrc', workerSrc);
|
||||||
|
|
||||||
messageHandler.on('test', function pdfDocTest(supportTypedArray) {
|
messageHandler.on('test', function pdfDocTest(supportTypedArray) {
|
||||||
if (supportTypedArray) {
|
if (supportTypedArray) {
|
||||||
this.worker = worker;
|
this.worker = worker;
|
||||||
this.setupMessageHandler(messageHandler);
|
this.setupMessageHandler(messageHandler);
|
||||||
} else {
|
} else {
|
||||||
|
globalScope.PDFJS.disableWorker = true;
|
||||||
this.setupFakeWorker();
|
this.setupFakeWorker();
|
||||||
}
|
}
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
|
|
||||||
var testObj = new Uint8Array(1);
|
var testObj = new Uint8Array(1);
|
||||||
|
// Some versions of Opera throw a DATA_CLONE_ERR on
|
||||||
|
// serializing the typed array.
|
||||||
messageHandler.send('test', testObj);
|
messageHandler.send('test', testObj);
|
||||||
} else {
|
return;
|
||||||
this.setupFakeWorker();
|
} catch (e) {}
|
||||||
}
|
}
|
||||||
|
// 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 = {
|
PDFDoc.prototype = {
|
||||||
|
@ -221,13 +221,15 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||||||
fn = 'paintImageXObject';
|
fn = 'paintImageXObject';
|
||||||
|
|
||||||
PDFImage.buildImage(function(imageObj) {
|
PDFImage.buildImage(function(imageObj) {
|
||||||
|
var drawWidth = imageObj.drawWidth;
|
||||||
|
var drawHeight = imageObj.drawHeight;
|
||||||
var imgData = {
|
var imgData = {
|
||||||
width: w,
|
width: drawWidth,
|
||||||
height: h,
|
height: drawHeight,
|
||||||
data: new Uint8Array(w * h * 4)
|
data: new Uint8Array(drawWidth * drawHeight * 4)
|
||||||
};
|
};
|
||||||
var pixels = imgData.data;
|
var pixels = imgData.data;
|
||||||
imageObj.fillRgbaBuffer(pixels);
|
imageObj.fillRgbaBuffer(pixels, drawWidth, drawHeight);
|
||||||
handler.send('obj', [objId, 'Image', imgData]);
|
handler.send('obj', [objId, 'Image', imgData]);
|
||||||
}, handler, xref, resources, image, inline);
|
}, handler, xref, resources, image, inline);
|
||||||
}
|
}
|
||||||
|
86
src/image.js
86
src/image.js
@ -127,7 +127,56 @@ var PDFImage = (function PDFImageClosure() {
|
|||||||
smaskPromise.resolve(null);
|
smaskPromise.resolve(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resize an image using the nearest neighbor algorithm. Currently only
|
||||||
|
* supports one and three component images.
|
||||||
|
* @param {TypedArray} pixels The original image with one component.
|
||||||
|
* @param {Number} bpc Number of bits per component.
|
||||||
|
* @param {Number} components Number of color components, 1 or 3 is supported.
|
||||||
|
* @param {Number} w1 Original width.
|
||||||
|
* @param {Number} h1 Original height.
|
||||||
|
* @param {Number} w2 New width.
|
||||||
|
* @param {Number} h2 New height.
|
||||||
|
* @return {TypedArray} Resized image data.
|
||||||
|
*/
|
||||||
|
PDFImage.resize = function resize(pixels, bpc, components, w1, h1, w2, h2) {
|
||||||
|
var length = w2 * h2 * components;
|
||||||
|
var temp = bpc <= 8 ? new Uint8Array(length) :
|
||||||
|
bpc <= 16 ? new Uint16Array(length) : new Uint32Array(length);
|
||||||
|
var xRatio = w1 / w2;
|
||||||
|
var yRatio = h1 / h2;
|
||||||
|
var px, py, newIndex, oldIndex;
|
||||||
|
for (var i = 0; i < h2; i++) {
|
||||||
|
for (var j = 0; j < w2; j++) {
|
||||||
|
px = Math.floor(j * xRatio);
|
||||||
|
py = Math.floor(i * yRatio);
|
||||||
|
newIndex = (i * w2) + j;
|
||||||
|
oldIndex = ((py * w1) + px);
|
||||||
|
if (components === 1) {
|
||||||
|
temp[newIndex] = pixels[oldIndex];
|
||||||
|
} else if (components === 3) {
|
||||||
|
newIndex *= 3;
|
||||||
|
oldIndex *= 3;
|
||||||
|
temp[newIndex] = pixels[oldIndex];
|
||||||
|
temp[newIndex + 1] = pixels[oldIndex + 1];
|
||||||
|
temp[newIndex + 2] = pixels[oldIndex + 2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return temp;
|
||||||
|
};
|
||||||
|
|
||||||
PDFImage.prototype = {
|
PDFImage.prototype = {
|
||||||
|
get drawWidth() {
|
||||||
|
if (!this.smask)
|
||||||
|
return this.width;
|
||||||
|
return Math.max(this.width, this.smask.width);
|
||||||
|
},
|
||||||
|
get drawHeight() {
|
||||||
|
if (!this.smask)
|
||||||
|
return this.height;
|
||||||
|
return Math.max(this.height, this.smask.height);
|
||||||
|
},
|
||||||
getComponents: function getComponents(buffer) {
|
getComponents: function getComponents(buffer) {
|
||||||
var bpc = this.bpc;
|
var bpc = this.bpc;
|
||||||
var needsDecode = this.needsDecode;
|
var needsDecode = this.needsDecode;
|
||||||
@ -216,22 +265,21 @@ var PDFImage = (function PDFImageClosure() {
|
|||||||
}
|
}
|
||||||
return output;
|
return output;
|
||||||
},
|
},
|
||||||
getOpacity: function getOpacity() {
|
getOpacity: function getOpacity(width, height) {
|
||||||
var smask = this.smask;
|
var smask = this.smask;
|
||||||
var width = this.width;
|
var originalWidth = this.width;
|
||||||
var height = this.height;
|
var originalHeight = this.height;
|
||||||
var buf = new Uint8Array(width * height);
|
var buf;
|
||||||
|
|
||||||
if (smask) {
|
if (smask) {
|
||||||
var sw = smask.width;
|
var sw = smask.width;
|
||||||
var sh = smask.height;
|
var sh = smask.height;
|
||||||
if (sw != this.width || sh != this.height)
|
buf = new Uint8Array(sw * sh);
|
||||||
error('smask dimensions do not match image dimensions: ' + sw +
|
|
||||||
' != ' + this.width + ', ' + sh + ' != ' + this.height);
|
|
||||||
|
|
||||||
smask.fillGrayBuffer(buf);
|
smask.fillGrayBuffer(buf);
|
||||||
return buf;
|
if (sw != width || sh != height)
|
||||||
|
buf = PDFImage.resize(buf, smask.bps, 1, sw, sh, width, height);
|
||||||
} else {
|
} else {
|
||||||
|
buf = new Uint8Array(width * height);
|
||||||
for (var i = 0, ii = width * height; i < ii; ++i)
|
for (var i = 0, ii = width * height; i < ii; ++i)
|
||||||
buf[i] = 255;
|
buf[i] = 255;
|
||||||
}
|
}
|
||||||
@ -260,20 +308,23 @@ var PDFImage = (function PDFImageClosure() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
fillRgbaBuffer: function fillRgbaBuffer(buffer) {
|
fillRgbaBuffer: function fillRgbaBuffer(buffer, width, height) {
|
||||||
var numComps = this.numComps;
|
var numComps = this.numComps;
|
||||||
var width = this.width;
|
var originalWidth = this.width;
|
||||||
var height = this.height;
|
var originalHeight = this.height;
|
||||||
var bpc = this.bpc;
|
var bpc = this.bpc;
|
||||||
|
|
||||||
// rows start at byte boundary;
|
// rows start at byte boundary;
|
||||||
var rowBytes = (width * numComps * bpc + 7) >> 3;
|
var rowBytes = (originalWidth * numComps * bpc + 7) >> 3;
|
||||||
var imgArray = this.getImageBytes(height * rowBytes);
|
var imgArray = this.getImageBytes(originalHeight * rowBytes);
|
||||||
|
|
||||||
var comps = this.colorSpace.getRgbBuffer(
|
var comps = this.colorSpace.getRgbBuffer(
|
||||||
this.getComponents(imgArray), bpc);
|
this.getComponents(imgArray), bpc);
|
||||||
|
if (originalWidth != width || originalHeight != height)
|
||||||
|
comps = PDFImage.resize(comps, this.bpc, 3, originalWidth,
|
||||||
|
originalHeight, width, height);
|
||||||
var compsPos = 0;
|
var compsPos = 0;
|
||||||
var opacity = this.getOpacity();
|
var opacity = this.getOpacity(width, height);
|
||||||
var opacityPos = 0;
|
var opacityPos = 0;
|
||||||
var length = width * height * 4;
|
var length = width * height * 4;
|
||||||
|
|
||||||
@ -299,9 +350,10 @@ var PDFImage = (function PDFImageClosure() {
|
|||||||
|
|
||||||
var comps = this.getComponents(imgArray);
|
var comps = this.getComponents(imgArray);
|
||||||
var length = width * height;
|
var length = width * height;
|
||||||
|
// we aren't using a colorspace so we need to scale the value
|
||||||
|
var scale = 255 / ((1 << bpc) - 1);
|
||||||
for (var i = 0; i < length; ++i)
|
for (var i = 0; i < length; ++i)
|
||||||
buffer[i] = comps[i];
|
buffer[i] = (scale * comps[i]) | 0;
|
||||||
},
|
},
|
||||||
getImageBytes: function getImageBytes(length) {
|
getImageBytes: function getImageBytes(length) {
|
||||||
this.image.reset();
|
this.image.reset();
|
||||||
|
11
src/obj.js
11
src/obj.js
@ -22,6 +22,17 @@ var Cmd = (function CmdClosure() {
|
|||||||
Cmd.prototype = {
|
Cmd.prototype = {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
var cmdCache = {};
|
||||||
|
|
||||||
|
Cmd.get = function cmdGet(cmd) {
|
||||||
|
var cmdValue = cmdCache[cmd];
|
||||||
|
if (cmdValue)
|
||||||
|
return cmdValue;
|
||||||
|
|
||||||
|
return cmdCache[cmd] = new Cmd(cmd);
|
||||||
|
};
|
||||||
|
|
||||||
return Cmd;
|
return Cmd;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
@ -157,7 +157,7 @@ var Parser = (function ParserClosure() {
|
|||||||
imageStream = this.filter(imageStream, dict, length);
|
imageStream = this.filter(imageStream, dict, length);
|
||||||
imageStream.parameters = dict;
|
imageStream.parameters = dict;
|
||||||
|
|
||||||
this.buf2 = new Cmd('EI');
|
this.buf2 = Cmd.get('EI');
|
||||||
this.shift();
|
this.shift();
|
||||||
|
|
||||||
return imageStream;
|
return imageStream;
|
||||||
@ -496,14 +496,14 @@ var Lexer = (function LexerClosure() {
|
|||||||
// array punctuation
|
// array punctuation
|
||||||
case '[':
|
case '[':
|
||||||
case ']':
|
case ']':
|
||||||
return new Cmd(ch);
|
return Cmd.get(ch);
|
||||||
// hex string or dict punctuation
|
// hex string or dict punctuation
|
||||||
case '<':
|
case '<':
|
||||||
ch = stream.lookChar();
|
ch = stream.lookChar();
|
||||||
if (ch == '<') {
|
if (ch == '<') {
|
||||||
// dict punctuation
|
// dict punctuation
|
||||||
stream.skip();
|
stream.skip();
|
||||||
return new Cmd('<<');
|
return Cmd.get('<<');
|
||||||
}
|
}
|
||||||
return this.getHexString(ch);
|
return this.getHexString(ch);
|
||||||
// dict punctuation
|
// dict punctuation
|
||||||
@ -511,11 +511,11 @@ var Lexer = (function LexerClosure() {
|
|||||||
ch = stream.lookChar();
|
ch = stream.lookChar();
|
||||||
if (ch == '>') {
|
if (ch == '>') {
|
||||||
stream.skip();
|
stream.skip();
|
||||||
return new Cmd('>>');
|
return Cmd.get('>>');
|
||||||
}
|
}
|
||||||
case '{':
|
case '{':
|
||||||
case '}':
|
case '}':
|
||||||
return new Cmd(ch);
|
return Cmd.get(ch);
|
||||||
// fall through
|
// fall through
|
||||||
case ')':
|
case ')':
|
||||||
error('Illegal character: ' + ch);
|
error('Illegal character: ' + ch);
|
||||||
@ -538,7 +538,7 @@ var Lexer = (function LexerClosure() {
|
|||||||
return false;
|
return false;
|
||||||
if (str == 'null')
|
if (str == 'null')
|
||||||
return null;
|
return null;
|
||||||
return new Cmd(str);
|
return Cmd.get(str);
|
||||||
},
|
},
|
||||||
skipToNextLine: function lexerSkipToNextLine() {
|
skipToNextLine: function lexerSkipToNextLine() {
|
||||||
var stream = this.stream;
|
var stream = this.stream;
|
||||||
|
2
test/pdfs/.gitignore
vendored
2
test/pdfs/.gitignore
vendored
@ -20,5 +20,5 @@
|
|||||||
!scan-bad.pdf
|
!scan-bad.pdf
|
||||||
!freeculture.pdf
|
!freeculture.pdf
|
||||||
!issue918.pdf
|
!issue918.pdf
|
||||||
|
!smaskdim.pdf
|
||||||
!type4psfunc.pdf
|
!type4psfunc.pdf
|
||||||
|
|
||||||
|
BIN
test/pdfs/smaskdim.pdf
Executable file
BIN
test/pdfs/smaskdim.pdf
Executable file
Binary file not shown.
@ -17,12 +17,13 @@
|
|||||||
"rounds": 1,
|
"rounds": 1,
|
||||||
"type": "load"
|
"type": "load"
|
||||||
},
|
},
|
||||||
{ "id": "intelisa-load",
|
{ "id": "intelisa-eq",
|
||||||
"file": "pdfs/intelisa.pdf",
|
"file": "pdfs/intelisa.pdf",
|
||||||
"md5": "f5712097d29287a97f1278839814f682",
|
"md5": "f5712097d29287a97f1278839814f682",
|
||||||
"link": true,
|
"link": true,
|
||||||
|
"pageLimit": 100,
|
||||||
"rounds": 1,
|
"rounds": 1,
|
||||||
"type": "load"
|
"type": "eq"
|
||||||
},
|
},
|
||||||
{ "id": "pdfspec-load",
|
{ "id": "pdfspec-load",
|
||||||
"file": "pdfs/pdf.pdf",
|
"file": "pdfs/pdf.pdf",
|
||||||
@ -361,5 +362,11 @@
|
|||||||
"rounds": 1,
|
"rounds": 1,
|
||||||
"link": true,
|
"link": true,
|
||||||
"type": "eq"
|
"type": "eq"
|
||||||
|
},
|
||||||
|
{ "id": "smaskdim",
|
||||||
|
"file": "pdfs/smaskdim.pdf",
|
||||||
|
"md5": "de80aeca7cbf79940189fd34d59671ee",
|
||||||
|
"rounds": 1,
|
||||||
|
"type": "eq"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -205,3 +205,15 @@
|
|||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
// HTMLElement dataset property
|
||||||
|
(function checkDatasetProperty() {
|
||||||
|
var div = document.createElement('div');
|
||||||
|
if ('dataset' in div)
|
||||||
|
return; // dataset property exists
|
||||||
|
Object.defineProperty(HTMLElement.prototype, 'dataset', {
|
||||||
|
get: function htmlElementDatasetGetter() {
|
||||||
|
// adding dataset field to the actual object
|
||||||
|
return (this.dataset = {});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
3
web/images/check.svg
Normal file
3
web/images/check.svg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg height="40" width="40" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M2.379,14.729 5.208,11.899 12.958,19.648 25.877,6.733 28.707,9.561 12.958,25.308z" fill="#333333"></path>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 188 B |
3
web/images/comment.svg
Normal file
3
web/images/comment.svg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg height="40" width="40" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M16,5.333c-7.732,0-14,4.701-14,10.5c0,1.982,0.741,3.833,2.016,5.414L2,25.667l5.613-1.441c2.339,1.317,5.237,2.107,8.387,2.107c7.732,0,14-4.701,14-10.5C30,10.034,23.732,5.333,16,5.333z" fill="#333333"></path>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 289 B |
@ -247,6 +247,35 @@ canvas {
|
|||||||
line-height:1.3;
|
line-height:1.3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.annotComment > div {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
.annotComment > img {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
.annotComment > img:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.annotComment > div {
|
||||||
|
padding: 0.2em;
|
||||||
|
max-width: 20em;
|
||||||
|
background-color: #F1E47B;
|
||||||
|
box-shadow: 0px 2px 10px #333;
|
||||||
|
-moz-box-shadow: 0px 2px 10px #333;
|
||||||
|
-webkit-box-shadow: 0px 2px 10px #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.annotComment > div > h1 {
|
||||||
|
font-weight: normal;
|
||||||
|
font-size: 1.2em;
|
||||||
|
border-bottom: 1px solid #000000;
|
||||||
|
margin: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
/* TODO: file FF bug to support ::-moz-selection:window-inactive
|
/* TODO: file FF bug to support ::-moz-selection:window-inactive
|
||||||
so we can override the opaque grey background when the window is inactive;
|
so we can override the opaque grey background when the window is inactive;
|
||||||
see https://bugzilla.mozilla.org/show_bug.cgi?id=706209 */
|
see https://bugzilla.mozilla.org/show_bug.cgi?id=706209 */
|
||||||
|
@ -11,7 +11,7 @@ var kCssUnits = 96.0 / 72.0;
|
|||||||
var kScrollbarPadding = 40;
|
var kScrollbarPadding = 40;
|
||||||
var kMinScale = 0.25;
|
var kMinScale = 0.25;
|
||||||
var kMaxScale = 4.0;
|
var kMaxScale = 4.0;
|
||||||
|
var kImageDirectory = './images/';
|
||||||
|
|
||||||
var Cache = function cacheCache(size) {
|
var Cache = function cacheCache(size) {
|
||||||
var data = [];
|
var data = [];
|
||||||
@ -458,7 +458,7 @@ var PageView = function pageView(container, content, id, pageWidth, pageHeight,
|
|||||||
delete this.canvas;
|
delete this.canvas;
|
||||||
};
|
};
|
||||||
|
|
||||||
function setupLinks(content, scale) {
|
function setupAnnotations(content, scale) {
|
||||||
function bindLink(link, dest) {
|
function bindLink(link, dest) {
|
||||||
link.href = PDFView.getDestinationHash(dest);
|
link.href = PDFView.getDestinationHash(dest);
|
||||||
link.onclick = function pageViewSetupLinksOnclick() {
|
link.onclick = function pageViewSetupLinksOnclick() {
|
||||||
@ -467,18 +467,67 @@ var PageView = function pageView(container, content, id, pageWidth, pageHeight,
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
function createElementWithStyle(tagName, item) {
|
||||||
|
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';
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
function createCommentAnnotation(type, item) {
|
||||||
|
var container = document.createElement('section');
|
||||||
|
container.className = 'annotComment';
|
||||||
|
|
||||||
var links = content.getLinks();
|
var image = createElementWithStyle('img', item);
|
||||||
for (var i = 0; i < links.length; i++) {
|
image.src = kImageDirectory + type.toLowerCase() + '.svg';
|
||||||
var link = document.createElement('a');
|
var content = document.createElement('div');
|
||||||
link.style.left = (Math.floor(links[i].x - view.x) * scale) + 'px';
|
content.setAttribute('hidden', true);
|
||||||
link.style.top = (Math.floor(links[i].y - view.y) * scale) + 'px';
|
var title = document.createElement('h1');
|
||||||
link.style.width = Math.ceil(links[i].width * scale) + 'px';
|
var text = document.createElement('p');
|
||||||
link.style.height = Math.ceil(links[i].height * scale) + 'px';
|
var offsetPos = Math.floor(item.x - view.x + item.width);
|
||||||
link.href = links[i].url || '';
|
content.style.left = (offsetPos * scale) + 'px';
|
||||||
if (!links[i].url)
|
content.style.top = (Math.floor(item.y - view.y) * scale) + 'px';
|
||||||
bindLink(link, ('dest' in links[i]) ? links[i].dest : null);
|
title.textContent = item.title;
|
||||||
|
|
||||||
|
if (!item.content) {
|
||||||
|
content.setAttribute('hidden', true);
|
||||||
|
} else {
|
||||||
|
text.innerHTML = item.content.replace('\n', '<br />');
|
||||||
|
image.addEventListener('mouseover', function annotationImageOver() {
|
||||||
|
this.nextSibling.removeAttribute('hidden');
|
||||||
|
}, false);
|
||||||
|
|
||||||
|
image.addEventListener('mouseout', function annotationImageOut() {
|
||||||
|
this.nextSibling.setAttribute('hidden', true);
|
||||||
|
}, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
content.appendChild(title);
|
||||||
|
content.appendChild(text);
|
||||||
|
container.appendChild(image);
|
||||||
|
container.appendChild(content);
|
||||||
|
|
||||||
|
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);
|
div.appendChild(link);
|
||||||
|
break;
|
||||||
|
case 'Text':
|
||||||
|
var comment = createCommentAnnotation(item.name, item);
|
||||||
|
if (comment)
|
||||||
|
div.appendChild(comment);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -598,7 +647,7 @@ var PageView = function pageView(container, content, id, pageWidth, pageHeight,
|
|||||||
}).bind(this), textLayer
|
}).bind(this), textLayer
|
||||||
);
|
);
|
||||||
|
|
||||||
setupLinks(this.content, this.scale);
|
setupAnnotations(this.content, this.scale);
|
||||||
div.setAttribute('data-loaded', true);
|
div.setAttribute('data-loaded', true);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -888,25 +937,49 @@ window.addEventListener('pagechange', function pagechange(evt) {
|
|||||||
}, true);
|
}, true);
|
||||||
|
|
||||||
window.addEventListener('keydown', function keydown(evt) {
|
window.addEventListener('keydown', function keydown(evt) {
|
||||||
|
if (evt.ctrlKey || evt.altKey || evt.shiftKey || evt.metaKey)
|
||||||
|
return;
|
||||||
var curElement = document.activeElement;
|
var curElement = document.activeElement;
|
||||||
|
if (curElement && curElement.tagName == 'INPUT')
|
||||||
|
return;
|
||||||
var controlsElement = document.getElementById('controls');
|
var controlsElement = document.getElementById('controls');
|
||||||
while (curElement) {
|
while (curElement) {
|
||||||
if (curElement === controlsElement)
|
if (curElement === controlsElement)
|
||||||
return; // ignoring if the 'controls' element is focused
|
return; // ignoring if the 'controls' element is focused
|
||||||
curElement = curElement.parentNode;
|
curElement = curElement.parentNode;
|
||||||
}
|
}
|
||||||
|
var handled = false;
|
||||||
switch (evt.keyCode) {
|
switch (evt.keyCode) {
|
||||||
case 61: // FF/Mac '='
|
case 61: // FF/Mac '='
|
||||||
case 107: // FF '+' and '='
|
case 107: // FF '+' and '='
|
||||||
case 187: // Chrome '+'
|
case 187: // Chrome '+'
|
||||||
PDFView.zoomIn();
|
PDFView.zoomIn();
|
||||||
|
handled = true;
|
||||||
break;
|
break;
|
||||||
case 109: // FF '-'
|
case 109: // FF '-'
|
||||||
case 189: // Chrome '-'
|
case 189: // Chrome '-'
|
||||||
PDFView.zoomOut();
|
PDFView.zoomOut();
|
||||||
|
handled = true;
|
||||||
break;
|
break;
|
||||||
case 48: // '0'
|
case 48: // '0'
|
||||||
PDFView.setScale(kDefaultScale, true);
|
PDFView.setScale(kDefaultScale, true);
|
||||||
|
handled = true;
|
||||||
|
break;
|
||||||
|
case 37: // left arrow
|
||||||
|
case 75: // 'k'
|
||||||
|
case 80: // 'p'
|
||||||
|
PDFView.page--;
|
||||||
|
handled = true;
|
||||||
|
break;
|
||||||
|
case 39: // right arrow
|
||||||
|
case 74: // 'j'
|
||||||
|
case 78: // 'n'
|
||||||
|
PDFView.page++;
|
||||||
|
handled = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (handled) {
|
||||||
|
evt.preventDefault();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user