Merge pull request #2127 from jviereck/text-algo-3
Use the text extracted in the getTextContent function for the divs of the textLayer.
This commit is contained in:
commit
e98eba1b11
22
src/bidi.js
22
src/bidi.js
@ -138,11 +138,16 @@ var bidi = PDFJS.bidi = (function bidiClosure() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function bidi(text, startLevel) {
|
function BidiResult(str, isLTR) {
|
||||||
var str = text.str;
|
this.str = str;
|
||||||
|
this.ltr = isLTR;
|
||||||
|
}
|
||||||
|
|
||||||
|
function bidi(str, startLevel) {
|
||||||
|
var isLTR = true;
|
||||||
var strLength = str.length;
|
var strLength = str.length;
|
||||||
if (strLength == 0)
|
if (strLength == 0)
|
||||||
return str;
|
return new BidiResult(str, ltr);
|
||||||
|
|
||||||
// get types, fill arrays
|
// get types, fill arrays
|
||||||
|
|
||||||
@ -176,16 +181,16 @@ var bidi = PDFJS.bidi = (function bidiClosure() {
|
|||||||
// if less than 30% chars are rtl then string is primarily ltr
|
// if less than 30% chars are rtl then string is primarily ltr
|
||||||
// if more than 30% chars are rtl then string is primarily rtl
|
// if more than 30% chars are rtl then string is primarily rtl
|
||||||
if (numBidi == 0) {
|
if (numBidi == 0) {
|
||||||
text.direction = 'ltr';
|
isLTR = true;
|
||||||
return str;
|
return new BidiResult(str, isLTR);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (startLevel == -1) {
|
if (startLevel == -1) {
|
||||||
if ((strLength / numBidi) < 0.3) {
|
if ((strLength / numBidi) < 0.3) {
|
||||||
text.direction = 'ltr';
|
isLTR = true;
|
||||||
startLevel = 0;
|
startLevel = 0;
|
||||||
} else {
|
} else {
|
||||||
text.direction = 'rtl';
|
isLTR = false;
|
||||||
startLevel = 1;
|
startLevel = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -438,7 +443,8 @@ var bidi = PDFJS.bidi = (function bidiClosure() {
|
|||||||
if (ch != '<' && ch != '>')
|
if (ch != '<' && ch != '>')
|
||||||
result += ch;
|
result += ch;
|
||||||
}
|
}
|
||||||
return result;
|
|
||||||
|
return new BidiResult(result, isLTR);
|
||||||
}
|
}
|
||||||
|
|
||||||
return bidi;
|
return bidi;
|
||||||
|
@ -677,9 +677,10 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||||||
var textHScale2 = textHScale * fontMatrix[0];
|
var textHScale2 = textHScale * fontMatrix[0];
|
||||||
var glyphsLength = glyphs.length;
|
var glyphsLength = glyphs.length;
|
||||||
var textLayer = this.textLayer;
|
var textLayer = this.textLayer;
|
||||||
var text = {str: '', length: 0, canvasWidth: 0, geom: {}};
|
var geom;
|
||||||
var textSelection = textLayer && !skipTextSelection ? true : false;
|
var textSelection = textLayer && !skipTextSelection ? true : false;
|
||||||
var textRenderingMode = current.textRenderingMode;
|
var textRenderingMode = current.textRenderingMode;
|
||||||
|
var canvasWidth = 0.0;
|
||||||
|
|
||||||
// Type3 fonts - each glyph is a "mini-PDF"
|
// Type3 fonts - each glyph is a "mini-PDF"
|
||||||
if (font.coded) {
|
if (font.coded) {
|
||||||
@ -692,7 +693,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||||||
if (textSelection) {
|
if (textSelection) {
|
||||||
this.save();
|
this.save();
|
||||||
ctx.scale(1, -1);
|
ctx.scale(1, -1);
|
||||||
text.geom = this.getTextGeometry();
|
geom = this.getTextGeometry();
|
||||||
this.restore();
|
this.restore();
|
||||||
}
|
}
|
||||||
for (var i = 0; i < glyphsLength; ++i) {
|
for (var i = 0; i < glyphsLength; ++i) {
|
||||||
@ -718,9 +719,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||||||
ctx.translate(width, 0);
|
ctx.translate(width, 0);
|
||||||
current.x += width * textHScale;
|
current.x += width * textHScale;
|
||||||
|
|
||||||
text.str += glyph.unicode;
|
canvasWidth += width;
|
||||||
text.length++;
|
|
||||||
text.canvasWidth += width;
|
|
||||||
}
|
}
|
||||||
ctx.restore();
|
ctx.restore();
|
||||||
} else {
|
} else {
|
||||||
@ -735,7 +734,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||||||
lineWidth /= scale;
|
lineWidth /= scale;
|
||||||
|
|
||||||
if (textSelection)
|
if (textSelection)
|
||||||
text.geom = this.getTextGeometry();
|
geom = this.getTextGeometry();
|
||||||
|
|
||||||
if (fontSizeScale != 1.0) {
|
if (fontSizeScale != 1.0) {
|
||||||
ctx.scale(fontSizeScale, fontSizeScale);
|
ctx.scale(fontSizeScale, fontSizeScale);
|
||||||
@ -784,17 +783,19 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||||||
var glyphUnicode = glyph.unicode === ' ' ? '\u00A0' : glyph.unicode;
|
var glyphUnicode = glyph.unicode === ' ' ? '\u00A0' : glyph.unicode;
|
||||||
if (glyphUnicode in NormalizedUnicodes)
|
if (glyphUnicode in NormalizedUnicodes)
|
||||||
glyphUnicode = NormalizedUnicodes[glyphUnicode];
|
glyphUnicode = NormalizedUnicodes[glyphUnicode];
|
||||||
text.str += reverseIfRtl(glyphUnicode);
|
|
||||||
text.canvasWidth += charWidth;
|
canvasWidth += charWidth;
|
||||||
}
|
}
|
||||||
current.x += x * textHScale2;
|
current.x += x * textHScale2;
|
||||||
ctx.restore();
|
ctx.restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (textSelection)
|
if (textSelection) {
|
||||||
this.textLayer.appendText(text, font.fallbackName, fontSize);
|
geom.canvasWidth = canvasWidth;
|
||||||
|
this.textLayer.appendText(font.fallbackName, fontSize, geom);
|
||||||
|
}
|
||||||
|
|
||||||
return text;
|
return canvasWidth;
|
||||||
},
|
},
|
||||||
showSpacedText: function CanvasGraphics_showSpacedText(arr) {
|
showSpacedText: function CanvasGraphics_showSpacedText(arr) {
|
||||||
var ctx = this.ctx;
|
var ctx = this.ctx;
|
||||||
@ -806,7 +807,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||||||
textHScale *= (current.fontMatrix || IDENTITY_MATRIX)[0];
|
textHScale *= (current.fontMatrix || IDENTITY_MATRIX)[0];
|
||||||
var arrLength = arr.length;
|
var arrLength = arr.length;
|
||||||
var textLayer = this.textLayer;
|
var textLayer = this.textLayer;
|
||||||
var text = {str: '', length: 0, canvasWidth: 0, geom: {}};
|
var geom;
|
||||||
|
var canvasWidth = 0.0;
|
||||||
var textSelection = textLayer ? true : false;
|
var textSelection = textLayer ? true : false;
|
||||||
|
|
||||||
if (textSelection) {
|
if (textSelection) {
|
||||||
@ -819,7 +821,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||||||
ctx.scale(textHScale, 1);
|
ctx.scale(textHScale, 1);
|
||||||
} else
|
} else
|
||||||
this.applyTextTransforms();
|
this.applyTextTransforms();
|
||||||
text.geom = this.getTextGeometry();
|
geom = this.getTextGeometry();
|
||||||
ctx.restore();
|
ctx.restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -829,34 +831,22 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||||||
var spacingLength = -e * 0.001 * fontSize * textHScale;
|
var spacingLength = -e * 0.001 * fontSize * textHScale;
|
||||||
current.x += spacingLength;
|
current.x += spacingLength;
|
||||||
|
|
||||||
if (textSelection) {
|
if (textSelection)
|
||||||
// Emulate precise spacing via HTML spaces
|
canvasWidth += spacingLength;
|
||||||
text.canvasWidth += spacingLength;
|
|
||||||
if (e < 0 && text.geom.spaceWidth > 0) { // avoid div by zero
|
|
||||||
var numFakeSpaces = Math.round(-e / text.geom.spaceWidth);
|
|
||||||
if (numFakeSpaces > 0) {
|
|
||||||
text.str += '\u00A0';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (isString(e)) {
|
} else if (isString(e)) {
|
||||||
var shownText = this.showText(e, true);
|
var shownCanvasWidth = this.showText(e, true);
|
||||||
|
|
||||||
if (textSelection) {
|
if (textSelection)
|
||||||
if (shownText.str === ' ') {
|
canvasWidth += shownCanvasWidth;
|
||||||
text.str += '\u00A0';
|
|
||||||
} else {
|
|
||||||
text.str += shownText.str;
|
|
||||||
}
|
|
||||||
text.canvasWidth += shownText.canvasWidth;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
error('TJ array element ' + e + ' is not string or num');
|
error('TJ array element ' + e + ' is not string or num');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (textSelection)
|
if (textSelection) {
|
||||||
this.textLayer.appendText(text, font.fallbackName, fontSize);
|
geom.canvasWidth = canvasWidth;
|
||||||
|
this.textLayer.appendText(font.fallbackName, fontSize, geom);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
nextLineShowText: function CanvasGraphics_nextLineShowText(text) {
|
nextLineShowText: function CanvasGraphics_nextLineShowText(text) {
|
||||||
this.nextLine();
|
this.nextLine();
|
||||||
|
117
src/evaluator.js
117
src/evaluator.js
@ -164,6 +164,21 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||||||
translated = { error: e };
|
translated = { error: e };
|
||||||
}
|
}
|
||||||
font.translated = translated;
|
font.translated = translated;
|
||||||
|
|
||||||
|
var data = translated;
|
||||||
|
if (data.loadCharProcs) {
|
||||||
|
delete data.loadCharProcs;
|
||||||
|
|
||||||
|
var charProcs = font.get('CharProcs').getAll();
|
||||||
|
var fontResources = font.get('Resources') || resources;
|
||||||
|
var charProcOperatorList = {};
|
||||||
|
for (var key in charProcs) {
|
||||||
|
var glyphStream = charProcs[key];
|
||||||
|
charProcOperatorList[key] =
|
||||||
|
this.getOperatorList(glyphStream, fontResources, dependency);
|
||||||
|
}
|
||||||
|
data.charProcOperatorList = charProcOperatorList;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return font;
|
return font;
|
||||||
},
|
},
|
||||||
@ -195,19 +210,6 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||||||
var loadedName = font.loadedName;
|
var loadedName = font.loadedName;
|
||||||
if (!font.sent) {
|
if (!font.sent) {
|
||||||
var data = font.translated;
|
var data = font.translated;
|
||||||
if (data.loadCharProcs) {
|
|
||||||
delete data.loadCharProcs;
|
|
||||||
|
|
||||||
var charProcs = font.get('CharProcs').getAll();
|
|
||||||
var fontResources = font.get('Resources') || resources;
|
|
||||||
var charProcOperatorList = {};
|
|
||||||
for (var key in charProcs) {
|
|
||||||
var glyphStream = charProcs[key];
|
|
||||||
charProcOperatorList[key] =
|
|
||||||
self.getOperatorList(glyphStream, fontResources, dependency);
|
|
||||||
}
|
|
||||||
data.charProcOperatorList = charProcOperatorList;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data instanceof Font)
|
if (data instanceof Font)
|
||||||
data = data.exportData();
|
data = data.exportData();
|
||||||
@ -505,7 +507,18 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||||||
return queue;
|
return queue;
|
||||||
},
|
},
|
||||||
|
|
||||||
getTextContent: function partialEvaluatorGetIRQueue(stream, resources) {
|
getTextContent: function partialEvaluatorGetIRQueue(
|
||||||
|
stream, resources, state) {
|
||||||
|
var bidiTexts;
|
||||||
|
|
||||||
|
if (!state) {
|
||||||
|
bidiTexts = [];
|
||||||
|
state = {
|
||||||
|
bidiTexts: bidiTexts
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
bidiTexts = state.bidiTexts;
|
||||||
|
}
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
var xref = this.xref;
|
var xref = this.xref;
|
||||||
@ -515,18 +528,20 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
resources = xref.fetchIfRef(resources) || new Dict();
|
resources = xref.fetchIfRef(resources) || new Dict();
|
||||||
|
// The xobj is parsed iff it's needed, e.g. if there is a `DO` cmd.
|
||||||
|
var xobjs = null;
|
||||||
|
|
||||||
var parser = new Parser(new Lexer(stream), false);
|
var parser = new Parser(new Lexer(stream), false);
|
||||||
var res = resources;
|
var res = resources;
|
||||||
var args = [], obj;
|
var args = [], obj;
|
||||||
|
|
||||||
var text = '';
|
|
||||||
var chunk = '';
|
var chunk = '';
|
||||||
var font = null;
|
var font = null;
|
||||||
while (!isEOF(obj = parser.getObj())) {
|
while (!isEOF(obj = parser.getObj())) {
|
||||||
if (isCmd(obj)) {
|
if (isCmd(obj)) {
|
||||||
var cmd = obj.cmd;
|
var cmd = obj.cmd;
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
|
// TODO: Add support for SAVE/RESTORE and XFORM here.
|
||||||
case 'Tf':
|
case 'Tf':
|
||||||
font = handleSetFont(args[0].name).translated;
|
font = handleSetFont(args[0].name).translated;
|
||||||
break;
|
break;
|
||||||
@ -535,25 +550,81 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||||||
for (var j = 0, jj = items.length; j < jj; j++) {
|
for (var j = 0, jj = items.length; j < jj; j++) {
|
||||||
if (typeof items[j] === 'string') {
|
if (typeof items[j] === 'string') {
|
||||||
chunk += fontCharsToUnicode(items[j], font);
|
chunk += fontCharsToUnicode(items[j], font);
|
||||||
} else if (items[j] < 0) {
|
} else if (items[j] < 0 && font.spaceWidth > 0) {
|
||||||
// making all negative offsets a space - better to have
|
var numFakeSpaces = Math.round(-items[j] / font.spaceWidth);
|
||||||
// a space in incorrect place than not have them at all
|
if (numFakeSpaces > 0) {
|
||||||
chunk += ' ';
|
chunk += ' ';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 'Tj':
|
case 'Tj':
|
||||||
chunk += fontCharsToUnicode(args[0], font);
|
chunk += fontCharsToUnicode(args[0], font);
|
||||||
break;
|
break;
|
||||||
case "'":
|
case "'":
|
||||||
chunk += fontCharsToUnicode(args[0], font) + ' ';
|
// For search, adding a extra white space for line breaks would be
|
||||||
|
// better here, but that causes too much spaces in the
|
||||||
|
// text-selection divs.
|
||||||
|
chunk += fontCharsToUnicode(args[0], font);
|
||||||
break;
|
break;
|
||||||
case '"':
|
case '"':
|
||||||
chunk += fontCharsToUnicode(args[2], font) + ' ';
|
// Note comment in "'"
|
||||||
|
chunk += fontCharsToUnicode(args[2], font);
|
||||||
|
break;
|
||||||
|
case 'Do':
|
||||||
|
// Set the chunk such that the following if won't add something
|
||||||
|
// to the state.
|
||||||
|
chunk = '';
|
||||||
|
|
||||||
|
if (args[0].code) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!xobjs) {
|
||||||
|
xobjs = resources.get('XObject') || new Dict();
|
||||||
|
}
|
||||||
|
|
||||||
|
var name = args[0].name;
|
||||||
|
var xobj = xobjs.get(name);
|
||||||
|
if (!xobj)
|
||||||
|
break;
|
||||||
|
assertWellFormed(isStream(xobj), 'XObject should be a stream');
|
||||||
|
|
||||||
|
var type = xobj.dict.get('Subtype');
|
||||||
|
assertWellFormed(
|
||||||
|
isName(type),
|
||||||
|
'XObject should have a Name subtype'
|
||||||
|
);
|
||||||
|
|
||||||
|
if ('Form' !== type.name)
|
||||||
|
break;
|
||||||
|
|
||||||
|
state = this.getTextContent(
|
||||||
|
xobj,
|
||||||
|
xobj.dict.get('Resources') || resources,
|
||||||
|
state
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case 'gs':
|
||||||
|
var dictName = args[0];
|
||||||
|
var extGState = resources.get('ExtGState');
|
||||||
|
|
||||||
|
if (!isDict(extGState) || !extGState.has(dictName.name))
|
||||||
|
break;
|
||||||
|
|
||||||
|
var gsState = extGState.get(dictName.name);
|
||||||
|
|
||||||
|
for (var i = 0; i < gsState.length; i++) {
|
||||||
|
if (gsState[i] === 'Font') {
|
||||||
|
font = handleSetFont(args[0].name).translated;
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
} // switch
|
} // switch
|
||||||
|
|
||||||
if (chunk !== '') {
|
if (chunk !== '') {
|
||||||
text += chunk;
|
bidiTexts.push(PDFJS.bidi(chunk, -1));
|
||||||
|
|
||||||
chunk = '';
|
chunk = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -562,9 +633,9 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||||||
assertWellFormed(args.length <= 33, 'Too many arguments');
|
assertWellFormed(args.length <= 33, 'Too many arguments');
|
||||||
args.push(obj);
|
args.push(obj);
|
||||||
}
|
}
|
||||||
}
|
} // while
|
||||||
|
|
||||||
return text;
|
return state;
|
||||||
},
|
},
|
||||||
|
|
||||||
extractDataStructures: function
|
extractDataStructures: function
|
||||||
|
@ -3886,6 +3886,10 @@ var Font = (function FontClosure() {
|
|||||||
},
|
},
|
||||||
|
|
||||||
get spaceWidth() {
|
get spaceWidth() {
|
||||||
|
if ('_shadowWidth' in this) {
|
||||||
|
return this._shadowWidth;
|
||||||
|
}
|
||||||
|
|
||||||
// trying to estimate space character width
|
// trying to estimate space character width
|
||||||
var possibleSpaceReplacements = ['space', 'minus', 'one', 'i'];
|
var possibleSpaceReplacements = ['space', 'minus', 'one', 'i'];
|
||||||
var width;
|
var width;
|
||||||
@ -3913,7 +3917,10 @@ var Font = (function FontClosure() {
|
|||||||
break; // the non-zero width found
|
break; // the non-zero width found
|
||||||
}
|
}
|
||||||
width = (width || this.defaultWidth) * this.widthMultiplier;
|
width = (width || this.defaultWidth) * this.widthMultiplier;
|
||||||
return shadow(this, 'spaceWidth', width);
|
// Do not shadow the property here. See discussion:
|
||||||
|
// https://github.com/mozilla/pdf.js/pull/2127#discussion_r1662280
|
||||||
|
this._shadowWidth = width;
|
||||||
|
return width;
|
||||||
},
|
},
|
||||||
|
|
||||||
charToGlyph: function Font_charToGlyph(charcode) {
|
charToGlyph: function Font_charToGlyph(charcode) {
|
||||||
|
@ -159,6 +159,7 @@ NullTextLayerBuilder.prototype = {
|
|||||||
function SimpleTextLayerBuilder(ctx, viewport) {
|
function SimpleTextLayerBuilder(ctx, viewport) {
|
||||||
this.ctx = ctx;
|
this.ctx = ctx;
|
||||||
this.viewport = viewport;
|
this.viewport = viewport;
|
||||||
|
this.textCounter = 0;
|
||||||
}
|
}
|
||||||
SimpleTextLayerBuilder.prototype = {
|
SimpleTextLayerBuilder.prototype = {
|
||||||
beginLayout: function SimpleTextLayerBuilder_BeginLayout() {
|
beginLayout: function SimpleTextLayerBuilder_BeginLayout() {
|
||||||
@ -167,27 +168,31 @@ SimpleTextLayerBuilder.prototype = {
|
|||||||
endLayout: function SimpleTextLayerBuilder_EndLayout() {
|
endLayout: function SimpleTextLayerBuilder_EndLayout() {
|
||||||
this.ctx.restore();
|
this.ctx.restore();
|
||||||
},
|
},
|
||||||
appendText: function SimpleTextLayerBuilder_AppendText(text, fontName,
|
appendText: function SimpleTextLayerBuilder_AppendText(fontName, fontSize,
|
||||||
fontSize) {
|
geom) {
|
||||||
var ctx = this.ctx, viewport = this.viewport;
|
var ctx = this.ctx, viewport = this.viewport;
|
||||||
// vScale and hScale already contain the scaling to pixel units
|
// vScale and hScale already contain the scaling to pixel units
|
||||||
var fontHeight = fontSize * text.geom.vScale;
|
var fontHeight = fontSize * geom.vScale;
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.strokeStyle = 'red';
|
ctx.strokeStyle = 'red';
|
||||||
ctx.fillStyle = 'yellow';
|
ctx.fillStyle = 'yellow';
|
||||||
ctx.rect(text.geom.x, text.geom.y - fontHeight,
|
ctx.rect(geom.x, geom.y - fontHeight,
|
||||||
text.canvasWidth * text.geom.hScale, fontHeight);
|
geom.canvasWidth * geom.hScale, fontHeight);
|
||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
ctx.fill();
|
ctx.fill();
|
||||||
|
|
||||||
var textContent = bidi(text, -1);
|
var textContent = this.textContent.bidiTexts[this.textCounter].str;
|
||||||
ctx.font = fontHeight + 'px ' + fontName;
|
ctx.font = fontHeight + 'px ' + fontName;
|
||||||
ctx.fillStyle = 'black';
|
ctx.fillStyle = 'black';
|
||||||
ctx.fillText(textContent, text.geom.x, text.geom.y);
|
ctx.fillText(textContent, geom.x, geom.y);
|
||||||
|
|
||||||
|
this.textCounter++;
|
||||||
|
},
|
||||||
|
setTextContent: function SimpleTextLayerBuilder_SetTextContent(textContent) {
|
||||||
|
this.textContent = textContent;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
function nextPage(task, loadError) {
|
function nextPage(task, loadError) {
|
||||||
var failure = loadError || '';
|
var failure = loadError || '';
|
||||||
|
|
||||||
@ -245,6 +250,10 @@ function nextPage(task, loadError) {
|
|||||||
drawContext = dummyCanvas.getContext('2d');
|
drawContext = dummyCanvas.getContext('2d');
|
||||||
// ... text builder will draw its content on the test canvas
|
// ... text builder will draw its content on the test canvas
|
||||||
textLayerBuilder = new SimpleTextLayerBuilder(ctx, viewport);
|
textLayerBuilder = new SimpleTextLayerBuilder(ctx, viewport);
|
||||||
|
|
||||||
|
page.getTextContent().then(function(textContent) {
|
||||||
|
textLayerBuilder.setTextContent(textContent);
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
drawContext = ctx;
|
drawContext = ctx;
|
||||||
textLayerBuilder = new NullTextLayerBuilder();
|
textLayerBuilder = new NullTextLayerBuilder();
|
||||||
|
@ -1066,6 +1066,7 @@ canvas {
|
|||||||
color: transparent;
|
color: transparent;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
line-height:1.3;
|
line-height:1.3;
|
||||||
|
white-space:pre;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: file FF bug to support ::-moz-selection:window-inactive
|
/* TODO: file FF bug to support ::-moz-selection:window-inactive
|
||||||
|
@ -1040,7 +1040,7 @@ var PDFView = {
|
|||||||
function extractPageText(pageIndex) {
|
function extractPageText(pageIndex) {
|
||||||
self.pages[pageIndex].pdfPage.getTextContent().then(
|
self.pages[pageIndex].pdfPage.getTextContent().then(
|
||||||
function textContentResolved(textContent) {
|
function textContentResolved(textContent) {
|
||||||
self.pageText[pageIndex] = textContent;
|
self.pageText[pageIndex] = textContent.join('');
|
||||||
self.search();
|
self.search();
|
||||||
if ((pageIndex + 1) < self.pages.length)
|
if ((pageIndex + 1) < self.pages.length)
|
||||||
extractPageText(pageIndex + 1);
|
extractPageText(pageIndex + 1);
|
||||||
@ -1228,6 +1228,8 @@ var PageView = function pageView(container, pdfPage, id, scale,
|
|||||||
this.renderingState = RenderingStates.INITIAL;
|
this.renderingState = RenderingStates.INITIAL;
|
||||||
this.resume = null;
|
this.resume = null;
|
||||||
|
|
||||||
|
this.textContent = null;
|
||||||
|
|
||||||
var anchor = document.createElement('a');
|
var anchor = document.createElement('a');
|
||||||
anchor.name = '' + this.id;
|
anchor.name = '' + this.id;
|
||||||
|
|
||||||
@ -1448,6 +1450,13 @@ var PageView = function pageView(container, pdfPage, id, scale,
|
|||||||
}, 0);
|
}, 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.getTextContent = function pageviewGetTextContent() {
|
||||||
|
if (!this.textContent) {
|
||||||
|
this.textContent = this.pdfPage.getTextContent();
|
||||||
|
}
|
||||||
|
return this.textContent;
|
||||||
|
};
|
||||||
|
|
||||||
this.draw = function pageviewDraw(callback) {
|
this.draw = function pageviewDraw(callback) {
|
||||||
if (this.renderingState !== RenderingStates.INITIAL)
|
if (this.renderingState !== RenderingStates.INITIAL)
|
||||||
error('Must be in new state before drawing');
|
error('Must be in new state before drawing');
|
||||||
@ -1528,6 +1537,14 @@ var PageView = function pageView(container, pdfPage, id, scale,
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (textLayer) {
|
||||||
|
this.getTextContent().then(
|
||||||
|
function textContentResolved(textContent) {
|
||||||
|
textLayer.setTextContent(textContent);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
setupAnnotations(this.pdfPage, this.viewport);
|
setupAnnotations(this.pdfPage, this.viewport);
|
||||||
div.setAttribute('data-loaded', true);
|
div.setAttribute('data-loaded', true);
|
||||||
};
|
};
|
||||||
@ -1820,12 +1837,19 @@ var CustomStyle = (function CustomStyleClosure() {
|
|||||||
var TextLayerBuilder = function textLayerBuilder(textLayerDiv) {
|
var TextLayerBuilder = function textLayerBuilder(textLayerDiv) {
|
||||||
var textLayerFrag = document.createDocumentFragment();
|
var textLayerFrag = document.createDocumentFragment();
|
||||||
this.textLayerDiv = textLayerDiv;
|
this.textLayerDiv = textLayerDiv;
|
||||||
|
this.layoutDone = false;
|
||||||
|
this.divContentDone = false;
|
||||||
|
|
||||||
this.beginLayout = function textLayerBuilderBeginLayout() {
|
this.beginLayout = function textLayerBuilderBeginLayout() {
|
||||||
this.textDivs = [];
|
this.textDivs = [];
|
||||||
this.textLayerQueue = [];
|
this.textLayerQueue = [];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.endLayout = function textLayerBuilderEndLayout() {
|
||||||
|
this.layoutDone = true;
|
||||||
|
this.insertDivContent();
|
||||||
|
},
|
||||||
|
|
||||||
this.renderLayer = function textLayerBuilderRenderLayer() {
|
this.renderLayer = function textLayerBuilderRenderLayer() {
|
||||||
var self = this;
|
var self = this;
|
||||||
var textDivs = this.textDivs;
|
var textDivs = this.textDivs;
|
||||||
@ -1857,7 +1881,7 @@ var TextLayerBuilder = function textLayerBuilder(textLayerDiv) {
|
|||||||
textLayerDiv.appendChild(textLayerFrag);
|
textLayerDiv.appendChild(textLayerFrag);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.endLayout = function textLayerBuilderEndLayout() {
|
this.setupRenderLayoutTimer = function textLayerSetupRenderLayoutTimer() {
|
||||||
// Schedule renderLayout() if user has been scrolling, otherwise
|
// Schedule renderLayout() if user has been scrolling, otherwise
|
||||||
// run it right away
|
// run it right away
|
||||||
var kRenderDelay = 200; // in ms
|
var kRenderDelay = 200; // in ms
|
||||||
@ -1870,27 +1894,56 @@ var TextLayerBuilder = function textLayerBuilder(textLayerDiv) {
|
|||||||
if (this.renderTimer)
|
if (this.renderTimer)
|
||||||
clearTimeout(this.renderTimer);
|
clearTimeout(this.renderTimer);
|
||||||
this.renderTimer = setTimeout(function() {
|
this.renderTimer = setTimeout(function() {
|
||||||
self.endLayout();
|
self.setupRenderLayoutTimer();
|
||||||
}, kRenderDelay);
|
}, kRenderDelay);
|
||||||
}
|
}
|
||||||
}; // endLayout
|
};
|
||||||
|
|
||||||
this.appendText = function textLayerBuilderAppendText(text,
|
this.appendText = function textLayerBuilderAppendText(fontName, fontSize,
|
||||||
fontName, fontSize) {
|
geom) {
|
||||||
var textDiv = document.createElement('div');
|
var textDiv = document.createElement('div');
|
||||||
|
|
||||||
// vScale and hScale already contain the scaling to pixel units
|
// vScale and hScale already contain the scaling to pixel units
|
||||||
var fontHeight = fontSize * text.geom.vScale;
|
var fontHeight = fontSize * geom.vScale;
|
||||||
textDiv.dataset.canvasWidth = text.canvasWidth * text.geom.hScale;
|
textDiv.dataset.canvasWidth = geom.canvasWidth * geom.hScale;
|
||||||
|
textDiv.dataset.fontName = fontName;
|
||||||
|
|
||||||
textDiv.style.fontSize = fontHeight + 'px';
|
textDiv.style.fontSize = fontHeight + 'px';
|
||||||
textDiv.style.fontFamily = fontName;
|
textDiv.style.fontFamily = fontName;
|
||||||
textDiv.style.left = text.geom.x + 'px';
|
textDiv.style.left = geom.x + 'px';
|
||||||
textDiv.style.top = (text.geom.y - fontHeight) + 'px';
|
textDiv.style.top = (geom.y - fontHeight) + 'px';
|
||||||
textDiv.textContent = PDFJS.bidi(text, -1);
|
|
||||||
textDiv.dir = text.direction;
|
// The content of the div is set in the `setTextContent` function.
|
||||||
|
|
||||||
this.textDivs.push(textDiv);
|
this.textDivs.push(textDiv);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.insertDivContent = function textLayerUpdateTextContent() {
|
||||||
|
// Only set the content of the divs once layout has finished, the content
|
||||||
|
// for the divs is available and content is not yet set on the divs.
|
||||||
|
if (!this.layoutDone || this.divContentDone || !this.textContent)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.divContentDone = true;
|
||||||
|
|
||||||
|
var textDivs = this.textDivs;
|
||||||
|
var bidiTexts = this.textContent.bidiTexts;
|
||||||
|
|
||||||
|
for (var i = 0; i < bidiTexts.length; i++) {
|
||||||
|
var bidiText = bidiTexts[i];
|
||||||
|
var textDiv = textDivs[i];
|
||||||
|
|
||||||
|
textDiv.textContent = bidiText.str;
|
||||||
|
textDiv.dir = bidiText.ltr ? 'ltr' : 'rtl';
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setupRenderLayoutTimer();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.setTextContent = function textLayerBuilderSetTextContent(textContent) {
|
||||||
|
this.textContent = textContent;
|
||||||
|
this.insertDivContent();
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', function webViewerLoad(evt) {
|
document.addEventListener('DOMContentLoaded', function webViewerLoad(evt) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user