Improve text-selection for Type3 fonts with empty /FontBBox-entries (issue 6605)

For Type3 fonts where the /CharProcs-streams of the individual glyph starts with a `d1` operator, we can use that to build a fallback bounding box for the font and thus improve text-selection in some cases.
This commit is contained in:
Jonas Jenwald 2021-05-29 18:06:49 +02:00
parent 6255c2a8f3
commit 20770cb06a
4 changed files with 30 additions and 5 deletions

View File

@ -2115,7 +2115,7 @@ class PartialEvaluator {
if (
font.isType3Font &&
textState.fontSize <= 1 &&
(textState.fontSize <= 1 || font.isCharBBox) &&
!isArrayEqual(textState.fontMatrix, FONT_IDENTITY_MATRIX)
) {
const glyphHeight = font.bbox[3] - font.bbox[1];
@ -3815,7 +3815,7 @@ class PartialEvaluator {
firstChar,
lastChar,
toUnicode,
bbox: descriptor.getArray("FontBBox"),
bbox: descriptor.getArray("FontBBox") || dict.getArray("FontBBox"),
ascent: descriptor.get("Ascent"),
descent: descriptor.get("Descent"),
xHeight: descriptor.get("XHeight"),
@ -3962,6 +3962,9 @@ class TranslatedFont {
const fontResources = this.dict.get("Resources") || resources;
const charProcOperatorList = Object.create(null);
const isEmptyBBox =
!translatedFont.bbox || isArrayEqual(translatedFont.bbox, [0, 0, 0, 0]);
for (const key of charProcs.getKeys()) {
loadCharProcsPromise = loadCharProcsPromise.then(() => {
const glyphStream = charProcs.get(key);
@ -3981,7 +3984,7 @@ class TranslatedFont {
// colour-related parameters) in the graphics state;
// any use of such operators shall be ignored."
if (operatorList.fnArray[0] === OPS.setCharWidthAndBounds) {
this._removeType3ColorOperators(operatorList);
this._removeType3ColorOperators(operatorList, isEmptyBBox);
}
charProcOperatorList[key] = operatorList.getIR();
@ -3996,8 +3999,12 @@ class TranslatedFont {
});
});
}
this.type3Loaded = loadCharProcsPromise.then(function () {
this.type3Loaded = loadCharProcsPromise.then(() => {
translatedFont.charProcOperatorList = charProcOperatorList;
if (this._bbox) {
translatedFont.isCharBBox = true;
translatedFont.bbox = this._bbox;
}
});
return this.type3Loaded;
}
@ -4005,7 +4012,7 @@ class TranslatedFont {
/**
* @private
*/
_removeType3ColorOperators(operatorList) {
_removeType3ColorOperators(operatorList, isEmptyBBox = false) {
if (
typeof PDFJSDev === "undefined" ||
PDFJSDev.test("!PRODUCTION || TESTING")
@ -4015,6 +4022,17 @@ class TranslatedFont {
"Type3 glyph shall start with the d1 operator."
);
}
if (isEmptyBBox) {
if (!this._bbox) {
this._bbox = [Infinity, Infinity, -Infinity, -Infinity];
}
const charBBox = Util.normalizeRect(operatorList.argsArray[0].slice(2));
this._bbox[0] = Math.min(this._bbox[0], charBBox[0]);
this._bbox[1] = Math.min(this._bbox[1], charBBox[1]);
this._bbox[2] = Math.max(this._bbox[2], charBBox[2]);
this._bbox[3] = Math.max(this._bbox[3], charBBox[3]);
}
let i = 1,
ii = operatorList.length;
while (i < ii) {

View File

@ -437,6 +437,7 @@
!quadpoints.pdf
!transparent.pdf
!xobject-image.pdf
!issue6605.pdf
!ccitt_EndOfBlock_false.pdf
!issue9972-1.pdf
!issue9972-2.pdf

BIN
test/pdfs/issue6605.pdf Normal file

Binary file not shown.

View File

@ -4935,6 +4935,12 @@
"type": "eq",
"annotations": true
},
{ "id": "issue6605",
"file": "pdfs/issue6605.pdf",
"md5": "67158a9c6d0e966ece55f7c433e18cc5",
"rounds": 1,
"type": "text"
},
{ "id": "annotation-choice-widget-forms",
"file": "pdfs/annotation-choice-widget.pdf",
"md5": "7dfb0d743a0da0f4a71b209ab43b0be5",