Merge pull request #15082 from calixteman/print_freetext

[Editor] Add support for printing newly added FreeText annotations
This commit is contained in:
calixteman 2022-06-22 16:19:42 +02:00 committed by GitHub
commit c5dc082da4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 125 additions and 79 deletions

View File

@ -265,12 +265,10 @@ class AnnotationFactory {
promises.push(
FreeTextAnnotation.createNewAnnotation(
xref,
evaluator,
task,
annotation,
baseFontRef,
results,
dependencies
dependencies,
{ evaluator, task, baseFontRef }
)
);
break;
@ -278,8 +276,6 @@ class AnnotationFactory {
promises.push(
InkAnnotation.createNewAnnotation(
xref,
evaluator,
task,
annotation,
results,
dependencies
@ -306,11 +302,18 @@ class AnnotationFactory {
for (const annotation of annotations) {
switch (annotation.annotationType) {
case AnnotationEditorType.FREETEXT:
promises.push(
FreeTextAnnotation.createNewPrintAnnotation(xref, annotation, {
evaluator,
task,
})
);
break;
case AnnotationEditorType.INK:
promises.push(
InkAnnotation.createNewPrintAnnotation(annotation, xref)
InkAnnotation.createNewPrintAnnotation(xref, annotation)
);
break;
}
}
@ -1356,6 +1359,44 @@ class MarkupAnnotation extends Annotation {
// so `this.appearance` is not pushed yet in the `Annotation` constructor.
this._streams.push(this.appearance, appearanceStream);
}
static async createNewAnnotation(
xref,
annotation,
results,
dependencies,
params
) {
const annotationRef = xref.getNewRef();
const apRef = xref.getNewRef();
const annotationDict = this.createNewDict(annotation, xref, { apRef });
const ap = await this.createNewAppearanceStream(annotation, xref, params);
const buffer = [];
let transform = xref.encrypt
? xref.encrypt.createCipherTransform(apRef.num, apRef.gen)
: null;
writeObject(apRef, ap, buffer, transform);
dependencies.push({ ref: apRef, data: buffer.join("") });
buffer.length = 0;
transform = xref.encrypt
? xref.encrypt.createCipherTransform(annotationRef.num, annotationRef.gen)
: null;
writeObject(annotationRef, annotationDict, buffer, transform);
results.push({ ref: annotationRef, data: buffer.join("") });
}
static async createNewPrintAnnotation(xref, annotation, params) {
const ap = await this.createNewAppearanceStream(annotation, xref, params);
const annotationDict = this.createNewDict(annotation, xref, { ap });
return new this.prototype.constructor({
dict: annotationDict,
xref,
});
}
}
class WidgetAnnotation extends Annotation {
@ -3157,17 +3198,8 @@ class FreeTextAnnotation extends MarkupAnnotation {
this.data.annotationType = AnnotationType.FREETEXT;
}
static async createNewAnnotation(
xref,
evaluator,
task,
annotation,
baseFontRef,
results,
dependencies
) {
static createNewDict(annotation, xref, { apRef, ap }) {
const { color, fontSize, rect, user, value } = annotation;
const freetextRef = xref.getNewRef();
const freetext = new Dict(xref);
freetext.set("Type", Name.get("Annot"));
freetext.set("Subtype", Name.get("FreeText"));
@ -3184,9 +3216,35 @@ class FreeTextAnnotation extends MarkupAnnotation {
freetext.set("T", stringToUTF8String(user));
}
const n = new Dict(xref);
freetext.set("AP", n);
if (apRef) {
n.set("N", apRef);
} else {
n.set("N", ap);
}
return freetext;
}
static async createNewAppearanceStream(annotation, xref, params) {
const { baseFontRef, evaluator, task } = params;
const { color, fontSize, rect, value } = annotation;
const resources = new Dict(xref);
const font = new Dict(xref);
font.set("Helv", baseFontRef);
if (baseFontRef) {
font.set("Helv", baseFontRef);
} else {
const baseFont = new Dict(xref);
baseFont.set("BaseFont", Name.get("Helvetica"));
baseFont.set("Type", Name.get("Font"));
baseFont.set("Subtype", Name.get("Type1"));
baseFont.set("Encoding", Name.get("WinAnsiEncoding"));
font.set("Helv", baseFont);
}
resources.set("Font", font);
const helv = await WidgetAnnotation._getFontData(
@ -3260,25 +3318,7 @@ class FreeTextAnnotation extends MarkupAnnotation {
const ap = new StringStream(appearance);
ap.dict = appearanceStreamDict;
buffer.length = 0;
const apRef = xref.getNewRef();
let transform = xref.encrypt
? xref.encrypt.createCipherTransform(apRef.num, apRef.gen)
: null;
writeObject(apRef, ap, buffer, transform);
dependencies.push({ ref: apRef, data: buffer.join("") });
const n = new Dict(xref);
n.set("N", apRef);
freetext.set("AP", n);
buffer.length = 0;
transform = xref.encrypt
? xref.encrypt.createCipherTransform(freetextRef.num, freetextRef.gen)
: null;
writeObject(freetextRef, freetext, buffer, transform);
results.push({ ref: freetextRef, data: buffer.join("") });
return ap;
}
}
@ -3642,7 +3682,7 @@ class InkAnnotation extends MarkupAnnotation {
}
}
static createInkDict(annotation, xref, { apRef, ap }) {
static createNewDict(annotation, xref, { apRef, ap }) {
const ink = new Dict(xref);
ink.set("Type", Name.get("Annot"));
ink.set("Subtype", Name.get("Ink"));
@ -3668,7 +3708,7 @@ class InkAnnotation extends MarkupAnnotation {
return ink;
}
static createNewAppearanceStream(annotation, xref) {
static async createNewAppearanceStream(annotation, xref, params) {
const [x1, y1, x2, y2] = annotation.rect;
const w = x2 - x1;
const h = y2 - y1;
@ -3707,45 +3747,6 @@ class InkAnnotation extends MarkupAnnotation {
return ap;
}
static async createNewAnnotation(
xref,
evaluator,
task,
annotation,
results,
others
) {
const inkRef = xref.getNewRef();
const apRef = xref.getNewRef();
const ink = this.createInkDict(annotation, xref, { apRef });
const ap = this.createNewAppearanceStream(annotation, xref);
const buffer = [];
let transform = xref.encrypt
? xref.encrypt.createCipherTransform(apRef.num, apRef.gen)
: null;
writeObject(apRef, ap, buffer, transform);
others.push({ ref: apRef, data: buffer.join("") });
buffer.length = 0;
transform = xref.encrypt
? xref.encrypt.createCipherTransform(inkRef.num, inkRef.gen)
: null;
writeObject(inkRef, ink, buffer, transform);
results.push({ ref: inkRef, data: buffer.join("") });
}
static async createNewPrintAnnotation(annotation, xref) {
const ap = this.createNewAppearanceStream(annotation, xref);
const ink = this.createInkDict(annotation, xref, { ap });
return new InkAnnotation({
dict: ink,
xref,
});
}
}
class HighlightAnnotation extends MarkupAnnotation {

View File

@ -4069,6 +4069,50 @@ describe("annotation", function () {
"endobj\n"
);
});
it("should render an added FreeText annotation for printing", async function () {
partialEvaluator.xref = new XRefMock();
const task = new WorkerTask("test FreeText printing");
const freetextAnnotation = (
await AnnotationFactory.printNewAnnotations(partialEvaluator, task, [
{
annotationType: AnnotationEditorType.FREETEXT,
rect: [12, 34, 56, 78],
fontSize: 10,
color: [0, 0, 0],
value: "A",
},
])
)[0];
const operatorList = await freetextAnnotation.getOperatorList(
partialEvaluator,
task,
RenderingIntentFlag.PRINT,
false,
null
);
expect(operatorList.fnArray.length).toEqual(16);
expect(operatorList.fnArray).toEqual([
OPS.beginAnnotation,
OPS.save,
OPS.constructPath,
OPS.clip,
OPS.endPath,
OPS.beginText,
OPS.setTextMatrix,
OPS.setCharSpacing,
OPS.setFillRGBColor,
OPS.dependency,
OPS.setFont,
OPS.moveText,
OPS.showText,
OPS.endText,
OPS.restore,
OPS.endAnnotation,
]);
});
});
describe("InkAnnotation", function () {

View File

@ -13,12 +13,12 @@
* limitations under the License.
*/
import { NullStream, StringStream } from "../../src/core/stream.js";
import { Page, PDFDocument } from "../../src/core/document.js";
import { assert } from "../../src/shared/util.js";
import { DocStats } from "../../src/core/core_utils.js";
import { isNodeJS } from "../../src/shared/is_node.js";
import { Ref } from "../../src/core/primitives.js";
import { StringStream } from "../../src/core/stream.js";
const TEST_PDFS_PATH = isNodeJS ? "./test/pdfs/" : "../pdfs/";
@ -79,6 +79,7 @@ class XRefMock {
this._map = Object.create(null);
this.stats = new DocStats({ send: () => {} });
this._newRefNum = null;
this.stream = new NullStream();
for (const key in array) {
const obj = array[key];