mirror of
https://github.com/mozilla/pdf.js.git
synced 2025-04-22 16:18:08 +02:00
Merge upstream.
This commit is contained in:
commit
7c8445753d
19 changed files with 567 additions and 99 deletions
|
@ -672,6 +672,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||
ctx.translate(current.x, current.y);
|
||||
|
||||
ctx.scale(textHScale, 1);
|
||||
ctx.lineWidth /= current.textMatrix[0];
|
||||
|
||||
if (textSelection) {
|
||||
this.save();
|
||||
|
@ -708,6 +709,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||
} else {
|
||||
ctx.save();
|
||||
this.applyTextTransforms();
|
||||
ctx.lineWidth /= current.textMatrix[0] * fontMatrix[0];
|
||||
|
||||
if (textSelection)
|
||||
text.geom = this.getTextGeometry();
|
||||
|
||||
|
|
|
@ -225,7 +225,7 @@ var AlternateCS = (function AlternateCSClosure() {
|
|||
return base.getRgbBuffer(baseBuf, 8);
|
||||
},
|
||||
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;
|
||||
},
|
||||
isDefaultDecode: function graycs_isDefaultDecode(decodeMap) {
|
||||
ColorSpace.isDefaultDecode(decodeMap, this.numComps);
|
||||
return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
|
||||
}
|
||||
};
|
||||
return DeviceGrayCS;
|
||||
|
@ -354,7 +354,7 @@ var DeviceRgbCS = (function DeviceRgbCSClosure() {
|
|||
return rgbBuf;
|
||||
},
|
||||
isDefaultDecode: function rgbcs_isDefaultDecode(decodeMap) {
|
||||
ColorSpace.isDefaultDecode(decodeMap, this.numComps);
|
||||
return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
|
||||
}
|
||||
};
|
||||
return DeviceRgbCS;
|
||||
|
@ -441,7 +441,7 @@ var DeviceCmykCS = (function DeviceCmykCSClosure() {
|
|||
return rgbBuf;
|
||||
},
|
||||
isDefaultDecode: function cmykcs_isDefaultDecode(decodeMap) {
|
||||
ColorSpace.isDefaultDecode(decodeMap, this.numComps);
|
||||
return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
179
src/core.js
179
src/core.js
|
@ -274,46 +274,125 @@ var Page = (function PageClosure() {
|
|||
}
|
||||
},
|
||||
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;
|
||||
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 i, n = annotations.length;
|
||||
var links = [];
|
||||
var items = [];
|
||||
for (i = 0; i < n; ++i) {
|
||||
var annotation = xref.fetch(annotations[i]);
|
||||
var annotationRef = annotations[i];
|
||||
var annotation = xref.fetch(annotationRef);
|
||||
if (!isDict(annotation))
|
||||
continue;
|
||||
var subtype = annotation.get('Subtype');
|
||||
if (!isName(subtype) || subtype.name != 'Link')
|
||||
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 link = {};
|
||||
link.x = Math.min(topLeftCorner.x, bottomRightCorner.x);
|
||||
link.y = Math.min(topLeftCorner.y, bottomRightCorner.y);
|
||||
link.width = Math.abs(topLeftCorner.x - bottomRightCorner.x);
|
||||
link.height = Math.abs(topLeftCorner.y - bottomRightCorner.y);
|
||||
var a = this.xref.fetchIfRef(annotation.get('A'));
|
||||
if (a) {
|
||||
switch (a.get('S').name) {
|
||||
case 'URI':
|
||||
link.url = a.get('URI');
|
||||
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);
|
||||
switch (subtype.name) {
|
||||
case 'Link':
|
||||
var a = this.xref.fetchIfRef(annotation.get('A'));
|
||||
if (a) {
|
||||
switch (a.get('S').name) {
|
||||
case 'URI':
|
||||
item.url = a.get('URI');
|
||||
break;
|
||||
case 'GoTo':
|
||||
item.dest = a.get('D');
|
||||
break;
|
||||
default:
|
||||
TODO('other link types');
|
||||
}
|
||||
} else if (annotation.has('Dest')) {
|
||||
// simple destination link
|
||||
var dest = annotation.get('Dest');
|
||||
item.dest = isName(dest) ? dest.name : dest;
|
||||
}
|
||||
break;
|
||||
case 'Widget':
|
||||
var fieldType = getInheritableProperty(annotation, 'FT');
|
||||
if (!isName(fieldType))
|
||||
break;
|
||||
case 'GoTo':
|
||||
link.dest = a.get('D');
|
||||
break;
|
||||
default:
|
||||
TODO('other link types');
|
||||
}
|
||||
} else if (annotation.has('Dest')) {
|
||||
// simple destination link
|
||||
var dest = annotation.get('Dest');
|
||||
link.dest = isName(dest) ? dest.name : dest;
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
links.push(link);
|
||||
items.push(item);
|
||||
}
|
||||
return links;
|
||||
return items;
|
||||
},
|
||||
startRendering: function pageStartRendering(ctx, callback, textLayer) {
|
||||
this.ctx = ctx;
|
||||
|
@ -352,6 +431,7 @@ var PDFDocModel = (function PDFDocModelClosure() {
|
|||
assertWellFormed(stream.length > 0, 'stream must have data');
|
||||
this.stream = stream;
|
||||
this.setup();
|
||||
this.acroForm = this.xref.fetchIfRef(this.catalog.catDict.get('AcroForm'));
|
||||
}
|
||||
|
||||
function find(stream, needle, limit, backwards) {
|
||||
|
@ -499,36 +579,35 @@ var PDFDoc = (function PDFDocClosure() {
|
|||
throw 'No PDFJS.workerSrc specified';
|
||||
}
|
||||
|
||||
var worker;
|
||||
try {
|
||||
worker = new Worker(workerSrc);
|
||||
} catch (e) {
|
||||
// Some versions of FF can't create a worker on localhost, see:
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=683280
|
||||
globalScope.PDFJS.disableWorker = true;
|
||||
this.setupFakeWorker();
|
||||
var worker = new Worker(workerSrc);
|
||||
|
||||
var messageHandler = new MessageHandler('main', worker);
|
||||
// Tell the worker the file it was created from.
|
||||
messageHandler.send('workerSrc', workerSrc);
|
||||
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;
|
||||
}
|
||||
|
||||
var messageHandler = new MessageHandler('main', worker);
|
||||
|
||||
// Tell the worker the file it was created from.
|
||||
messageHandler.send('workerSrc', workerSrc);
|
||||
|
||||
messageHandler.on('test', function pdfDocTest(supportTypedArray) {
|
||||
if (supportTypedArray) {
|
||||
this.worker = worker;
|
||||
this.setupMessageHandler(messageHandler);
|
||||
} else {
|
||||
this.setupFakeWorker();
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
var testObj = new Uint8Array(1);
|
||||
messageHandler.send('test', testObj);
|
||||
} else {
|
||||
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 = {
|
||||
|
|
|
@ -221,13 +221,15 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||
fn = 'paintImageXObject';
|
||||
|
||||
PDFImage.buildImage(function(imageObj) {
|
||||
var drawWidth = imageObj.drawWidth;
|
||||
var drawHeight = imageObj.drawHeight;
|
||||
var imgData = {
|
||||
width: w,
|
||||
height: h,
|
||||
data: new Uint8Array(w * h * 4)
|
||||
width: drawWidth,
|
||||
height: drawHeight,
|
||||
data: new Uint8Array(drawWidth * drawHeight * 4)
|
||||
};
|
||||
var pixels = imgData.data;
|
||||
imageObj.fillRgbaBuffer(pixels);
|
||||
imageObj.fillRgbaBuffer(pixels, drawWidth, drawHeight);
|
||||
handler.send('obj', [objId, 'Image', imgData]);
|
||||
}, handler, xref, resources, image, inline);
|
||||
}
|
||||
|
|
86
src/image.js
86
src/image.js
|
@ -127,7 +127,56 @@ var PDFImage = (function PDFImageClosure() {
|
|||
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 = {
|
||||
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) {
|
||||
var bpc = this.bpc;
|
||||
var needsDecode = this.needsDecode;
|
||||
|
@ -216,22 +265,21 @@ var PDFImage = (function PDFImageClosure() {
|
|||
}
|
||||
return output;
|
||||
},
|
||||
getOpacity: function getOpacity() {
|
||||
getOpacity: function getOpacity(width, height) {
|
||||
var smask = this.smask;
|
||||
var width = this.width;
|
||||
var height = this.height;
|
||||
var buf = new Uint8Array(width * height);
|
||||
var originalWidth = this.width;
|
||||
var originalHeight = this.height;
|
||||
var buf;
|
||||
|
||||
if (smask) {
|
||||
var sw = smask.width;
|
||||
var sh = smask.height;
|
||||
if (sw != this.width || sh != this.height)
|
||||
error('smask dimensions do not match image dimensions: ' + sw +
|
||||
' != ' + this.width + ', ' + sh + ' != ' + this.height);
|
||||
|
||||
buf = new Uint8Array(sw * sh);
|
||||
smask.fillGrayBuffer(buf);
|
||||
return buf;
|
||||
if (sw != width || sh != height)
|
||||
buf = PDFImage.resize(buf, smask.bps, 1, sw, sh, width, height);
|
||||
} else {
|
||||
buf = new Uint8Array(width * height);
|
||||
for (var i = 0, ii = width * height; i < ii; ++i)
|
||||
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 width = this.width;
|
||||
var height = this.height;
|
||||
var originalWidth = this.width;
|
||||
var originalHeight = this.height;
|
||||
var bpc = this.bpc;
|
||||
|
||||
// rows start at byte boundary;
|
||||
var rowBytes = (width * numComps * bpc + 7) >> 3;
|
||||
var imgArray = this.getImageBytes(height * rowBytes);
|
||||
var rowBytes = (originalWidth * numComps * bpc + 7) >> 3;
|
||||
var imgArray = this.getImageBytes(originalHeight * rowBytes);
|
||||
|
||||
var comps = this.colorSpace.getRgbBuffer(
|
||||
this.getComponents(imgArray), bpc);
|
||||
if (originalWidth != width || originalHeight != height)
|
||||
comps = PDFImage.resize(comps, this.bpc, 3, originalWidth,
|
||||
originalHeight, width, height);
|
||||
var compsPos = 0;
|
||||
var opacity = this.getOpacity();
|
||||
var opacity = this.getOpacity(width, height);
|
||||
var opacityPos = 0;
|
||||
var length = width * height * 4;
|
||||
|
||||
|
@ -299,9 +350,10 @@ var PDFImage = (function PDFImageClosure() {
|
|||
|
||||
var comps = this.getComponents(imgArray);
|
||||
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)
|
||||
buffer[i] = comps[i];
|
||||
buffer[i] = (scale * comps[i]) | 0;
|
||||
},
|
||||
getImageBytes: function getImageBytes(length) {
|
||||
this.image.reset();
|
||||
|
|
11
src/obj.js
11
src/obj.js
|
@ -22,6 +22,17 @@ var Cmd = (function CmdClosure() {
|
|||
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;
|
||||
})();
|
||||
|
||||
|
|
|
@ -157,7 +157,7 @@ var Parser = (function ParserClosure() {
|
|||
imageStream = this.filter(imageStream, dict, length);
|
||||
imageStream.parameters = dict;
|
||||
|
||||
this.buf2 = new Cmd('EI');
|
||||
this.buf2 = Cmd.get('EI');
|
||||
this.shift();
|
||||
|
||||
return imageStream;
|
||||
|
@ -496,14 +496,14 @@ var Lexer = (function LexerClosure() {
|
|||
// array punctuation
|
||||
case '[':
|
||||
case ']':
|
||||
return new Cmd(ch);
|
||||
return Cmd.get(ch);
|
||||
// hex string or dict punctuation
|
||||
case '<':
|
||||
ch = stream.lookChar();
|
||||
if (ch == '<') {
|
||||
// dict punctuation
|
||||
stream.skip();
|
||||
return new Cmd('<<');
|
||||
return Cmd.get('<<');
|
||||
}
|
||||
return this.getHexString(ch);
|
||||
// dict punctuation
|
||||
|
@ -511,11 +511,11 @@ var Lexer = (function LexerClosure() {
|
|||
ch = stream.lookChar();
|
||||
if (ch == '>') {
|
||||
stream.skip();
|
||||
return new Cmd('>>');
|
||||
return Cmd.get('>>');
|
||||
}
|
||||
case '{':
|
||||
case '}':
|
||||
return new Cmd(ch);
|
||||
return Cmd.get(ch);
|
||||
// fall through
|
||||
case ')':
|
||||
error('Illegal character: ' + ch);
|
||||
|
@ -538,7 +538,7 @@ var Lexer = (function LexerClosure() {
|
|||
return false;
|
||||
if (str == 'null')
|
||||
return null;
|
||||
return new Cmd(str);
|
||||
return Cmd.get(str);
|
||||
},
|
||||
skipToNextLine: function lexerSkipToNextLine() {
|
||||
var stream = this.stream;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue