Merge pull request #15082 from calixteman/print_freetext
[Editor] Add support for printing newly added FreeText annotations
This commit is contained in:
commit
c5dc082da4
@ -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 {
|
||||
|
@ -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 () {
|
||||
|
@ -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];
|
||||
|
Loading…
x
Reference in New Issue
Block a user