Add few methods to the Dict class in order to simplify the code when writing an annotation
This commit is contained in:
parent
729f2bb148
commit
63b37b4371
@ -361,10 +361,10 @@ class AnnotationFactory {
|
||||
case AnnotationEditorType.FREETEXT:
|
||||
if (!baseFontRef) {
|
||||
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"));
|
||||
baseFont.setIfName("BaseFont", "Helvetica");
|
||||
baseFont.setIfName("Type", "Font");
|
||||
baseFont.setIfName("Subtype", "Type1");
|
||||
baseFont.setIfName("Encoding", "WinAnsiEncoding");
|
||||
baseFontRef = xref.getNewTemporaryRef();
|
||||
changes.put(baseFontRef, {
|
||||
data: baseFont,
|
||||
@ -571,8 +571,8 @@ function getRgbColor(color, defaultColor = new Uint8ClampedArray(3)) {
|
||||
}
|
||||
}
|
||||
|
||||
function getPdfColorArray(color) {
|
||||
return Array.from(color, c => c / 255);
|
||||
function getPdfColorArray(color, defaultValue = null) {
|
||||
return (color && Array.from(color, c => c / 255)) || defaultValue;
|
||||
}
|
||||
|
||||
function getQuadPoints(dict, rect) {
|
||||
@ -1741,7 +1741,7 @@ class MarkupAnnotation extends Annotation {
|
||||
|
||||
const formDict = new Dict(xref);
|
||||
const appearanceStreamDict = new Dict(xref);
|
||||
appearanceStreamDict.set("Subtype", Name.get("Form"));
|
||||
appearanceStreamDict.setIfName("Subtype", "Form");
|
||||
|
||||
const appearanceStream = new StringStream(buffer.join(" "));
|
||||
appearanceStream.dict = appearanceStreamDict;
|
||||
@ -1749,14 +1749,10 @@ class MarkupAnnotation extends Annotation {
|
||||
|
||||
const gsDict = new Dict(xref);
|
||||
if (blendMode) {
|
||||
gsDict.set("BM", Name.get(blendMode));
|
||||
}
|
||||
if (typeof strokeAlpha === "number") {
|
||||
gsDict.set("CA", strokeAlpha);
|
||||
}
|
||||
if (typeof fillAlpha === "number") {
|
||||
gsDict.set("ca", fillAlpha);
|
||||
gsDict.setIfName("BM", blendMode);
|
||||
}
|
||||
gsDict.setIfNumber("CA", strokeAlpha);
|
||||
gsDict.setIfNumber("ca", fillAlpha);
|
||||
|
||||
const stateDict = new Dict(xref);
|
||||
stateDict.set("GS0", gsDict);
|
||||
@ -2107,12 +2103,8 @@ class WidgetAnnotation extends Annotation {
|
||||
if (rotation) {
|
||||
mk.set("R", rotation);
|
||||
}
|
||||
if (this.borderColor) {
|
||||
mk.set("BC", getPdfColorArray(this.borderColor));
|
||||
}
|
||||
if (this.backgroundColor) {
|
||||
mk.set("BG", getPdfColorArray(this.backgroundColor));
|
||||
}
|
||||
mk.setIfArray("BC", getPdfColorArray(this.borderColor));
|
||||
mk.setIfArray("BG", getPdfColorArray(this.backgroundColor));
|
||||
return mk.size > 0 ? mk : null;
|
||||
}
|
||||
|
||||
@ -2248,7 +2240,7 @@ class WidgetAnnotation extends Annotation {
|
||||
const resources = this._getSaveFieldResources(xref);
|
||||
const appearanceStream = new StringStream(appearance);
|
||||
const appearanceDict = (appearanceStream.dict = new Dict(xref));
|
||||
appearanceDict.set("Subtype", Name.get("Form"));
|
||||
appearanceDict.setIfName("Subtype", "Form");
|
||||
appearanceDict.set("Resources", resources);
|
||||
const bbox =
|
||||
rotation % 180 === 0
|
||||
@ -3272,8 +3264,8 @@ class ButtonWidgetAnnotation extends WidgetAnnotation {
|
||||
|
||||
const appearanceStreamDict = new Dict(params.xref);
|
||||
appearanceStreamDict.set("FormType", 1);
|
||||
appearanceStreamDict.set("Subtype", Name.get("Form"));
|
||||
appearanceStreamDict.set("Type", Name.get("XObject"));
|
||||
appearanceStreamDict.setIfName("Subtype", "Form");
|
||||
appearanceStreamDict.setIfName("Type", "XObject");
|
||||
appearanceStreamDict.set("BBox", bbox);
|
||||
appearanceStreamDict.set("Matrix", [1, 0, 0, 1, 0, 0]);
|
||||
appearanceStreamDict.set("Length", appearance.length);
|
||||
@ -3460,10 +3452,10 @@ class ButtonWidgetAnnotation extends WidgetAnnotation {
|
||||
|
||||
get fallbackFontDict() {
|
||||
const dict = new Dict();
|
||||
dict.set("BaseFont", Name.get("ZapfDingbats"));
|
||||
dict.set("Type", Name.get("FallbackType"));
|
||||
dict.set("Subtype", Name.get("FallbackType"));
|
||||
dict.set("Encoding", Name.get("ZapfDingbatsEncoding"));
|
||||
dict.setIfName("BaseFont", "ZapfDingbats");
|
||||
dict.setIfName("Type", "FallbackType");
|
||||
dict.setIfName("Subtype", "FallbackType");
|
||||
dict.setIfName("Encoding", "ZapfDingbatsEncoding");
|
||||
|
||||
return shadow(this, "fallbackFontDict", dict);
|
||||
}
|
||||
@ -3958,8 +3950,8 @@ class FreeTextAnnotation extends MarkupAnnotation {
|
||||
const { color, fontSize, oldAnnotation, rect, rotation, user, value } =
|
||||
annotation;
|
||||
const freetext = oldAnnotation || new Dict(xref);
|
||||
freetext.set("Type", Name.get("Annot"));
|
||||
freetext.set("Subtype", Name.get("FreeText"));
|
||||
freetext.setIfNotExists("Type", Name.get("Annot"));
|
||||
freetext.setIfNotExists("Subtype", Name.get("FreeText"));
|
||||
if (oldAnnotation) {
|
||||
freetext.set("M", `D:${getModificationDate()}`);
|
||||
// TODO: We should try to generate a new RC from the content we've.
|
||||
@ -3968,27 +3960,19 @@ class FreeTextAnnotation extends MarkupAnnotation {
|
||||
} else {
|
||||
freetext.set("CreationDate", `D:${getModificationDate()}`);
|
||||
}
|
||||
freetext.set("Rect", rect);
|
||||
freetext.setIfArray("Rect", rect);
|
||||
const da = `/Helv ${fontSize} Tf ${getPdfColor(color, /* isFill */ true)}`;
|
||||
freetext.set("DA", da);
|
||||
freetext.set("Contents", stringToAsciiOrUTF16BE(value));
|
||||
freetext.set("F", 4);
|
||||
freetext.set("Border", [0, 0, 0]);
|
||||
freetext.set("Rotate", rotation);
|
||||
|
||||
if (user) {
|
||||
freetext.set("T", stringToAsciiOrUTF16BE(user));
|
||||
}
|
||||
freetext.setIfDefined("Contents", stringToAsciiOrUTF16BE(value));
|
||||
freetext.setIfNotExists("F", 4);
|
||||
freetext.setIfNotExists("Border", [0, 0, 0]);
|
||||
freetext.setIfNumber("Rotate", rotation);
|
||||
freetext.setIfDefined("T", stringToAsciiOrUTF16BE(user));
|
||||
|
||||
if (apRef || ap) {
|
||||
const n = new Dict(xref);
|
||||
freetext.set("AP", n);
|
||||
|
||||
if (apRef) {
|
||||
n.set("N", apRef);
|
||||
} else {
|
||||
n.set("N", ap);
|
||||
}
|
||||
n.set("N", apRef || ap);
|
||||
}
|
||||
|
||||
return freetext;
|
||||
@ -3997,6 +3981,9 @@ class FreeTextAnnotation extends MarkupAnnotation {
|
||||
static async createNewAppearanceStream(annotation, xref, params) {
|
||||
const { baseFontRef, evaluator, task } = params;
|
||||
const { color, fontSize, rect, rotation, value } = annotation;
|
||||
if (!color) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const resources = new Dict(xref);
|
||||
const font = new Dict(xref);
|
||||
@ -4005,10 +3992,10 @@ class FreeTextAnnotation extends MarkupAnnotation {
|
||||
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"));
|
||||
baseFont.setIfName("BaseFont", "Helvetica");
|
||||
baseFont.setIfName("Type", "Font");
|
||||
baseFont.setIfName("Subtype", "Type1");
|
||||
baseFont.setIfName("Encoding", "WinAnsiEncoding");
|
||||
font.set("Helv", baseFont);
|
||||
}
|
||||
resources.set("Font", font);
|
||||
@ -4110,8 +4097,8 @@ class FreeTextAnnotation extends MarkupAnnotation {
|
||||
|
||||
const appearanceStreamDict = new Dict(xref);
|
||||
appearanceStreamDict.set("FormType", 1);
|
||||
appearanceStreamDict.set("Subtype", Name.get("Form"));
|
||||
appearanceStreamDict.set("Type", Name.get("XObject"));
|
||||
appearanceStreamDict.setIfName("Subtype", "Form");
|
||||
appearanceStreamDict.setIfName("Type", "XObject");
|
||||
appearanceStreamDict.set("BBox", rect);
|
||||
appearanceStreamDict.set("Resources", resources);
|
||||
appearanceStreamDict.set("Matrix", [1, 0, 0, 1, -rect[0], -rect[1]]);
|
||||
@ -4142,13 +4129,13 @@ class LineAnnotation extends MarkupAnnotation {
|
||||
|
||||
if (!this.appearance) {
|
||||
// The default stroke color is black.
|
||||
const strokeColor = this.color ? getPdfColorArray(this.color) : [0, 0, 0];
|
||||
const strokeColor = getPdfColorArray(this.color, [0, 0, 0]);
|
||||
const strokeAlpha = dict.get("CA");
|
||||
|
||||
const interiorColor = getRgbColor(dict.getArray("IC"), null);
|
||||
// The default fill color is transparent. Setting the fill colour is
|
||||
// necessary if/when we want to add support for non-default line endings.
|
||||
const fillColor = interiorColor ? getPdfColorArray(interiorColor) : null;
|
||||
const fillColor = getPdfColorArray(interiorColor);
|
||||
const fillAlpha = fillColor ? strokeAlpha : null;
|
||||
|
||||
const borderWidth = this.borderStyle.width || 1,
|
||||
@ -4202,12 +4189,12 @@ class SquareAnnotation extends MarkupAnnotation {
|
||||
|
||||
if (!this.appearance) {
|
||||
// The default stroke color is black.
|
||||
const strokeColor = this.color ? getPdfColorArray(this.color) : [0, 0, 0];
|
||||
const strokeColor = getPdfColorArray(this.color, [0, 0, 0]);
|
||||
const strokeAlpha = dict.get("CA");
|
||||
|
||||
const interiorColor = getRgbColor(dict.getArray("IC"), null);
|
||||
// The default fill color is transparent.
|
||||
const fillColor = interiorColor ? getPdfColorArray(interiorColor) : null;
|
||||
const fillColor = getPdfColorArray(interiorColor);
|
||||
const fillAlpha = fillColor ? strokeAlpha : null;
|
||||
|
||||
if (this.borderStyle.width === 0 && !fillColor) {
|
||||
@ -4249,12 +4236,12 @@ class CircleAnnotation extends MarkupAnnotation {
|
||||
|
||||
if (!this.appearance) {
|
||||
// The default stroke color is black.
|
||||
const strokeColor = this.color ? getPdfColorArray(this.color) : [0, 0, 0];
|
||||
const strokeColor = getPdfColorArray(this.color, [0, 0, 0]);
|
||||
const strokeAlpha = dict.get("CA");
|
||||
|
||||
const interiorColor = getRgbColor(dict.getArray("IC"), null);
|
||||
// The default fill color is transparent.
|
||||
const fillColor = interiorColor ? getPdfColorArray(interiorColor) : null;
|
||||
const fillColor = getPdfColorArray(interiorColor);
|
||||
const fillAlpha = fillColor ? strokeAlpha : null;
|
||||
|
||||
if (this.borderStyle.width === 0 && !fillColor) {
|
||||
@ -4334,7 +4321,7 @@ class PolylineAnnotation extends MarkupAnnotation {
|
||||
|
||||
if (!this.appearance) {
|
||||
// The default stroke color is black.
|
||||
const strokeColor = this.color ? getPdfColorArray(this.color) : [0, 0, 0];
|
||||
const strokeColor = getPdfColorArray(this.color, [0, 0, 0]);
|
||||
const strokeAlpha = dict.get("CA");
|
||||
|
||||
const borderWidth = this.borderStyle.width || 1,
|
||||
@ -4433,7 +4420,7 @@ class InkAnnotation extends MarkupAnnotation {
|
||||
|
||||
if (!this.appearance) {
|
||||
// The default stroke color is black.
|
||||
const strokeColor = this.color ? getPdfColorArray(this.color) : [0, 0, 0];
|
||||
const strokeColor = getPdfColorArray(this.color, [0, 0, 0]);
|
||||
const strokeAlpha = dict.get("CA");
|
||||
|
||||
const borderWidth = this.borderStyle.width || 1,
|
||||
@ -4494,44 +4481,40 @@ class InkAnnotation extends MarkupAnnotation {
|
||||
user,
|
||||
} = annotation;
|
||||
const ink = oldAnnotation || new Dict(xref);
|
||||
ink.set("Type", Name.get("Annot"));
|
||||
ink.set("Subtype", Name.get("Ink"));
|
||||
ink.setIfNotExists("Type", Name.get("Annot"));
|
||||
ink.setIfNotExists("Subtype", Name.get("Ink"));
|
||||
ink.set(oldAnnotation ? "M" : "CreationDate", `D:${getModificationDate()}`);
|
||||
ink.set("Rect", rect);
|
||||
ink.set("InkList", outlines?.points || paths.points);
|
||||
ink.set("F", 4);
|
||||
ink.set("Rotate", rotation);
|
||||
|
||||
if (user) {
|
||||
ink.set("T", stringToAsciiOrUTF16BE(user));
|
||||
}
|
||||
ink.setIfArray("Rect", rect);
|
||||
ink.setIfArray("InkList", outlines?.points || paths?.points);
|
||||
ink.setIfNotExists("F", 4);
|
||||
ink.setIfNumber("Rotate", rotation);
|
||||
ink.setIfDefined("T", stringToAsciiOrUTF16BE(user));
|
||||
|
||||
if (outlines) {
|
||||
// Free highlight.
|
||||
// There's nothing about this in the spec, but it's used when highlighting
|
||||
// in Edge's viewer. Acrobat takes into account this parameter to indicate
|
||||
// that the Ink is used for highlighting.
|
||||
ink.set("IT", Name.get("InkHighlight"));
|
||||
ink.setIfName("IT", "InkHighlight");
|
||||
}
|
||||
|
||||
// Line thickness.
|
||||
const bs = new Dict(xref);
|
||||
ink.set("BS", bs);
|
||||
bs.set("W", thickness);
|
||||
if (thickness > 0) {
|
||||
const bs = new Dict(xref);
|
||||
ink.set("BS", bs);
|
||||
bs.set("W", thickness);
|
||||
}
|
||||
|
||||
// Color.
|
||||
ink.set("C", getPdfColorArray(color));
|
||||
ink.setIfArray("C", getPdfColorArray(color));
|
||||
|
||||
// Opacity.
|
||||
ink.set("CA", opacity);
|
||||
ink.setIfNumber("CA", opacity);
|
||||
|
||||
const n = new Dict(xref);
|
||||
ink.set("AP", n);
|
||||
|
||||
if (apRef) {
|
||||
n.set("N", apRef);
|
||||
} else {
|
||||
n.set("N", ap);
|
||||
if (ap || apRef) {
|
||||
const n = new Dict(xref);
|
||||
ink.set("AP", n);
|
||||
n.set("N", apRef || ap);
|
||||
}
|
||||
|
||||
return ink;
|
||||
@ -4546,6 +4529,9 @@ class InkAnnotation extends MarkupAnnotation {
|
||||
);
|
||||
}
|
||||
const { color, rect, paths, thickness, opacity } = annotation;
|
||||
if (!color) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const appearanceBuffer = [
|
||||
`${thickness} w 1 J 1 j`,
|
||||
@ -4586,8 +4572,8 @@ class InkAnnotation extends MarkupAnnotation {
|
||||
|
||||
const appearanceStreamDict = new Dict(xref);
|
||||
appearanceStreamDict.set("FormType", 1);
|
||||
appearanceStreamDict.set("Subtype", Name.get("Form"));
|
||||
appearanceStreamDict.set("Type", Name.get("XObject"));
|
||||
appearanceStreamDict.setIfName("Subtype", "Form");
|
||||
appearanceStreamDict.setIfName("Type", "XObject");
|
||||
appearanceStreamDict.set("BBox", rect);
|
||||
appearanceStreamDict.set("Length", appearance.length);
|
||||
|
||||
@ -4596,7 +4582,7 @@ class InkAnnotation extends MarkupAnnotation {
|
||||
const extGState = new Dict(xref);
|
||||
const r0 = new Dict(xref);
|
||||
r0.set("CA", opacity);
|
||||
r0.set("Type", Name.get("ExtGState"));
|
||||
r0.setIfName("Type", "ExtGState");
|
||||
extGState.set("R0", r0);
|
||||
resources.set("ExtGState", extGState);
|
||||
appearanceStreamDict.set("Resources", resources);
|
||||
@ -4615,6 +4601,9 @@ class InkAnnotation extends MarkupAnnotation {
|
||||
outlines: { outline },
|
||||
opacity,
|
||||
} = annotation;
|
||||
if (!color) {
|
||||
return null;
|
||||
}
|
||||
const appearanceBuffer = [
|
||||
`${getPdfColor(color, /* isFill */ true)}`,
|
||||
"/R0 gs",
|
||||
@ -4642,8 +4631,8 @@ class InkAnnotation extends MarkupAnnotation {
|
||||
|
||||
const appearanceStreamDict = new Dict(xref);
|
||||
appearanceStreamDict.set("FormType", 1);
|
||||
appearanceStreamDict.set("Subtype", Name.get("Form"));
|
||||
appearanceStreamDict.set("Type", Name.get("XObject"));
|
||||
appearanceStreamDict.setIfName("Subtype", "Form");
|
||||
appearanceStreamDict.setIfName("Type", "XObject");
|
||||
appearanceStreamDict.set("BBox", rect);
|
||||
appearanceStreamDict.set("Length", appearance.length);
|
||||
|
||||
@ -4653,11 +4642,11 @@ class InkAnnotation extends MarkupAnnotation {
|
||||
appearanceStreamDict.set("Resources", resources);
|
||||
const r0 = new Dict(xref);
|
||||
extGState.set("R0", r0);
|
||||
r0.set("BM", Name.get("Multiply"));
|
||||
r0.setIfName("BM", "Multiply");
|
||||
|
||||
if (opacity !== 1) {
|
||||
r0.set("ca", opacity);
|
||||
r0.set("Type", Name.get("ExtGState"));
|
||||
r0.setIfName("Type", "ExtGState");
|
||||
}
|
||||
|
||||
const ap = new StringStream(appearance);
|
||||
@ -4691,7 +4680,7 @@ class HighlightAnnotation extends MarkupAnnotation {
|
||||
warn("HighlightAnnotation - ignoring built-in appearance stream.");
|
||||
}
|
||||
// Default color is yellow in Acrobat Reader
|
||||
const fillColor = this.color ? getPdfColorArray(this.color) : [1, 1, 0];
|
||||
const fillColor = getPdfColorArray(this.color, [1, 1, 0]);
|
||||
const fillAlpha = dict.get("CA");
|
||||
|
||||
this._setDefaultAppearance({
|
||||
@ -4723,29 +4712,19 @@ class HighlightAnnotation extends MarkupAnnotation {
|
||||
static createNewDict(annotation, xref, { apRef, ap }) {
|
||||
const { color, oldAnnotation, opacity, rect, rotation, user, quadPoints } =
|
||||
annotation;
|
||||
const date = `D:${getModificationDate()}`;
|
||||
const highlight = oldAnnotation || new Dict(xref);
|
||||
highlight.set("Type", Name.get("Annot"));
|
||||
highlight.set("Subtype", Name.get("Highlight"));
|
||||
highlight.set(
|
||||
oldAnnotation ? "M" : "CreationDate",
|
||||
`D:${getModificationDate()}`
|
||||
);
|
||||
highlight.set("CreationDate", `D:${getModificationDate()}`);
|
||||
highlight.set("Rect", rect);
|
||||
highlight.set("F", 4);
|
||||
highlight.set("Border", [0, 0, 0]);
|
||||
highlight.set("Rotate", rotation);
|
||||
highlight.set("QuadPoints", quadPoints);
|
||||
|
||||
// Color.
|
||||
highlight.set("C", getPdfColorArray(color));
|
||||
|
||||
// Opacity.
|
||||
highlight.set("CA", opacity);
|
||||
|
||||
if (user) {
|
||||
highlight.set("T", stringToAsciiOrUTF16BE(user));
|
||||
}
|
||||
highlight.setIfNotExists("Type", Name.get("Annot"));
|
||||
highlight.setIfNotExists("Subtype", Name.get("Highlight"));
|
||||
highlight.set(oldAnnotation ? "M" : "CreationDate", date);
|
||||
highlight.setIfArray("Rect", rect);
|
||||
highlight.setIfNotExists("F", 4);
|
||||
highlight.setIfNotExists("Border", [0, 0, 0]);
|
||||
highlight.setIfNumber("Rotate", rotation);
|
||||
highlight.setIfArray("QuadPoints", quadPoints);
|
||||
highlight.setIfArray("C", getPdfColorArray(color));
|
||||
highlight.setIfNumber("CA", opacity);
|
||||
highlight.setIfDefined("T", stringToAsciiOrUTF16BE(user));
|
||||
|
||||
if (apRef || ap) {
|
||||
const n = new Dict(xref);
|
||||
@ -4758,6 +4737,9 @@ class HighlightAnnotation extends MarkupAnnotation {
|
||||
|
||||
static async createNewAppearanceStream(annotation, xref, params) {
|
||||
const { color, rect, outlines, opacity } = annotation;
|
||||
if (!color) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const appearanceBuffer = [
|
||||
`${getPdfColor(color, /* isFill */ true)}`,
|
||||
@ -4783,8 +4765,8 @@ class HighlightAnnotation extends MarkupAnnotation {
|
||||
|
||||
const appearanceStreamDict = new Dict(xref);
|
||||
appearanceStreamDict.set("FormType", 1);
|
||||
appearanceStreamDict.set("Subtype", Name.get("Form"));
|
||||
appearanceStreamDict.set("Type", Name.get("XObject"));
|
||||
appearanceStreamDict.setIfName("Subtype", "Form");
|
||||
appearanceStreamDict.setIfName("Type", "XObject");
|
||||
appearanceStreamDict.set("BBox", rect);
|
||||
appearanceStreamDict.set("Length", appearance.length);
|
||||
|
||||
@ -4794,11 +4776,11 @@ class HighlightAnnotation extends MarkupAnnotation {
|
||||
appearanceStreamDict.set("Resources", resources);
|
||||
const r0 = new Dict(xref);
|
||||
extGState.set("R0", r0);
|
||||
r0.set("BM", Name.get("Multiply"));
|
||||
r0.setIfName("BM", "Multiply");
|
||||
|
||||
if (opacity !== 1) {
|
||||
r0.set("ca", opacity);
|
||||
r0.set("Type", Name.get("ExtGState"));
|
||||
r0.setIfName("Type", "ExtGState");
|
||||
}
|
||||
|
||||
const ap = new StringStream(appearance);
|
||||
@ -4819,9 +4801,7 @@ class UnderlineAnnotation extends MarkupAnnotation {
|
||||
if (quadPoints) {
|
||||
if (!this.appearance) {
|
||||
// Default color is black
|
||||
const strokeColor = this.color
|
||||
? getPdfColorArray(this.color)
|
||||
: [0, 0, 0];
|
||||
const strokeColor = getPdfColorArray(this.color, [0, 0, 0]);
|
||||
const strokeAlpha = dict.get("CA");
|
||||
|
||||
// The values 0.571 and 1.3 below corresponds to what Acrobat is doing.
|
||||
@ -4861,9 +4841,7 @@ class SquigglyAnnotation extends MarkupAnnotation {
|
||||
if (quadPoints) {
|
||||
if (!this.appearance) {
|
||||
// Default color is black
|
||||
const strokeColor = this.color
|
||||
? getPdfColorArray(this.color)
|
||||
: [0, 0, 0];
|
||||
const strokeColor = getPdfColorArray(this.color, [0, 0, 0]);
|
||||
const strokeAlpha = dict.get("CA");
|
||||
|
||||
this._setDefaultAppearance({
|
||||
@ -4909,9 +4887,7 @@ class StrikeOutAnnotation extends MarkupAnnotation {
|
||||
if (quadPoints) {
|
||||
if (!this.appearance) {
|
||||
// Default color is black
|
||||
const strokeColor = this.color
|
||||
? getPdfColorArray(this.color)
|
||||
: [0, 0, 0];
|
||||
const strokeColor = getPdfColorArray(this.color, [0, 0, 0]);
|
||||
const strokeAlpha = dict.get("CA");
|
||||
|
||||
this._setDefaultAppearance({
|
||||
@ -5010,8 +4986,8 @@ class StampAnnotation extends MarkupAnnotation {
|
||||
image.set("Type", xobjectName);
|
||||
image.set("Subtype", imageName);
|
||||
image.set("BitsPerComponent", 8);
|
||||
image.set("ColorSpace", Name.get("DeviceRGB"));
|
||||
image.set("Filter", Name.get("DCTDecode"));
|
||||
image.setIfName("ColorSpace", "DeviceRGB");
|
||||
image.setIfName("Filter", "DCTDecode");
|
||||
image.set("BBox", [0, 0, width, height]);
|
||||
image.set("Width", width);
|
||||
image.set("Height", height);
|
||||
@ -5033,7 +5009,7 @@ class StampAnnotation extends MarkupAnnotation {
|
||||
smask.set("Type", xobjectName);
|
||||
smask.set("Subtype", imageName);
|
||||
smask.set("BitsPerComponent", 8);
|
||||
smask.set("ColorSpace", Name.get("DeviceGray"));
|
||||
smask.setIfName("ColorSpace", "DeviceGray");
|
||||
smask.set("Width", width);
|
||||
smask.set("Height", height);
|
||||
|
||||
@ -5051,31 +5027,21 @@ class StampAnnotation extends MarkupAnnotation {
|
||||
|
||||
static createNewDict(annotation, xref, { apRef, ap }) {
|
||||
const { oldAnnotation, rect, rotation, user } = annotation;
|
||||
const date = `D:${getModificationDate(annotation.date)}`;
|
||||
const stamp = oldAnnotation || new Dict(xref);
|
||||
stamp.set("Type", Name.get("Annot"));
|
||||
stamp.set("Subtype", Name.get("Stamp"));
|
||||
stamp.set(
|
||||
oldAnnotation ? "M" : "CreationDate",
|
||||
`D:${getModificationDate()}`
|
||||
);
|
||||
stamp.set("Rect", rect);
|
||||
stamp.set("F", 4);
|
||||
stamp.set("Border", [0, 0, 0]);
|
||||
stamp.set("Rotate", rotation);
|
||||
|
||||
if (user) {
|
||||
stamp.set("T", stringToAsciiOrUTF16BE(user));
|
||||
}
|
||||
stamp.setIfNotExists("Type", Name.get("Annot"));
|
||||
stamp.setIfNotExists("Subtype", Name.get("Stamp"));
|
||||
stamp.set(oldAnnotation ? "M" : "CreationDate", date);
|
||||
stamp.setIfArray("Rect", rect);
|
||||
stamp.setIfNotExists("F", 4);
|
||||
stamp.setIfNotExists("Border", [0, 0, 0]);
|
||||
stamp.setIfNumber("Rotate", rotation);
|
||||
stamp.setIfDefined("T", stringToAsciiOrUTF16BE(user));
|
||||
|
||||
if (apRef || ap) {
|
||||
const n = new Dict(xref);
|
||||
stamp.set("AP", n);
|
||||
|
||||
if (apRef) {
|
||||
n.set("N", apRef);
|
||||
} else {
|
||||
n.set("N", ap);
|
||||
}
|
||||
n.set("N", apRef || ap);
|
||||
}
|
||||
|
||||
return stamp;
|
||||
@ -5083,6 +5049,9 @@ class StampAnnotation extends MarkupAnnotation {
|
||||
|
||||
static async #createNewAppearanceStreamForDrawing(annotation, xref) {
|
||||
const { areContours, color, rect, lines, thickness } = annotation;
|
||||
if (!color) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const appearanceBuffer = [
|
||||
`${thickness} w 1 J 1 j`,
|
||||
@ -5117,8 +5086,8 @@ class StampAnnotation extends MarkupAnnotation {
|
||||
|
||||
const appearanceStreamDict = new Dict(xref);
|
||||
appearanceStreamDict.set("FormType", 1);
|
||||
appearanceStreamDict.set("Subtype", Name.get("Form"));
|
||||
appearanceStreamDict.set("Type", Name.get("XObject"));
|
||||
appearanceStreamDict.setIfName("Subtype", "Form");
|
||||
appearanceStreamDict.setIfName("Type", "XObject");
|
||||
appearanceStreamDict.set("BBox", rect);
|
||||
appearanceStreamDict.set("Length", appearance.length);
|
||||
|
||||
@ -5147,8 +5116,8 @@ class StampAnnotation extends MarkupAnnotation {
|
||||
|
||||
const appearanceStreamDict = new Dict(xref);
|
||||
appearanceStreamDict.set("FormType", 1);
|
||||
appearanceStreamDict.set("Subtype", Name.get("Form"));
|
||||
appearanceStreamDict.set("Type", Name.get("XObject"));
|
||||
appearanceStreamDict.setIfName("Subtype", "Form");
|
||||
appearanceStreamDict.setIfName("Type", "XObject");
|
||||
appearanceStreamDict.set("BBox", [0, 0, width, height]);
|
||||
appearanceStreamDict.set("Resources", resources);
|
||||
|
||||
|
||||
@ -679,12 +679,19 @@ function getNewAnnotationsMap(annotationStorage) {
|
||||
return newAnnotationsByPage.size > 0 ? newAnnotationsByPage : null;
|
||||
}
|
||||
|
||||
// If the string is null or undefined then it is returned as is.
|
||||
function stringToAsciiOrUTF16BE(str) {
|
||||
if (str === null || str === undefined) {
|
||||
return str;
|
||||
}
|
||||
return isAscii(str) ? str : stringToUTF16String(str, /* bigEndian = */ true);
|
||||
}
|
||||
|
||||
function isAscii(str) {
|
||||
return /^[\x00-\x7F]*$/.test(str);
|
||||
if (typeof str !== "string") {
|
||||
return false;
|
||||
}
|
||||
return !str || /^[\x00-\x7F]*$/.test(str);
|
||||
}
|
||||
|
||||
function stringToUTF16HexString(str) {
|
||||
|
||||
@ -267,11 +267,11 @@ class FakeUnicodeFont {
|
||||
get fontDescriptorRef() {
|
||||
if (!FakeUnicodeFont._fontDescriptorRef) {
|
||||
const fontDescriptor = new Dict(this.xref);
|
||||
fontDescriptor.set("Type", Name.get("FontDescriptor"));
|
||||
fontDescriptor.setIfName("Type", "FontDescriptor");
|
||||
fontDescriptor.set("FontName", this.fontName);
|
||||
fontDescriptor.set("FontFamily", "MyriadPro Regular");
|
||||
fontDescriptor.set("FontBBox", [0, 0, 0, 0]);
|
||||
fontDescriptor.set("FontStretch", Name.get("Normal"));
|
||||
fontDescriptor.setIfName("FontStretch", "Normal");
|
||||
fontDescriptor.set("FontWeight", 400);
|
||||
fontDescriptor.set("ItalicAngle", 0);
|
||||
|
||||
@ -285,9 +285,9 @@ class FakeUnicodeFont {
|
||||
get descendantFontRef() {
|
||||
const descendantFont = new Dict(this.xref);
|
||||
descendantFont.set("BaseFont", this.fontName);
|
||||
descendantFont.set("Type", Name.get("Font"));
|
||||
descendantFont.set("Subtype", Name.get("CIDFontType0"));
|
||||
descendantFont.set("CIDToGIDMap", Name.get("Identity"));
|
||||
descendantFont.setIfName("Type", "Font");
|
||||
descendantFont.setIfName("Subtype", "CIDFontType0");
|
||||
descendantFont.setIfName("CIDToGIDMap", "Identity");
|
||||
descendantFont.set("FirstChar", this.firstChar);
|
||||
descendantFont.set("LastChar", this.lastChar);
|
||||
descendantFont.set("FontDescriptor", this.fontDescriptorRef);
|
||||
@ -330,11 +330,11 @@ class FakeUnicodeFont {
|
||||
get baseFontRef() {
|
||||
const baseFont = new Dict(this.xref);
|
||||
baseFont.set("BaseFont", this.fontName);
|
||||
baseFont.set("Type", Name.get("Font"));
|
||||
baseFont.set("Subtype", Name.get("Type0"));
|
||||
baseFont.set("Encoding", Name.get("Identity-H"));
|
||||
baseFont.setIfName("Type", "Font");
|
||||
baseFont.setIfName("Subtype", "Type0");
|
||||
baseFont.setIfName("Encoding", "Identity-H");
|
||||
baseFont.set("DescendantFonts", [this.descendantFontRef]);
|
||||
baseFont.set("ToUnicode", Name.get("Identity-H"));
|
||||
baseFont.setIfName("ToUnicode", "Identity-H");
|
||||
|
||||
return this.xref.getNewPersistentRef(baseFont);
|
||||
}
|
||||
@ -463,7 +463,7 @@ class FakeUnicodeFont {
|
||||
const r0 = new Dict(this.xref);
|
||||
r0.set("ca", strokeAlpha);
|
||||
r0.set("CA", strokeAlpha);
|
||||
r0.set("Type", Name.get("ExtGState"));
|
||||
r0.setIfName("Type", "ExtGState");
|
||||
extGState.set("R0", r0);
|
||||
resources.set("ExtGState", extGState);
|
||||
}
|
||||
@ -476,8 +476,8 @@ class FakeUnicodeFont {
|
||||
const appearance = buffer.join("\n");
|
||||
|
||||
const appearanceStreamDict = new Dict(this.xref);
|
||||
appearanceStreamDict.set("Subtype", Name.get("Form"));
|
||||
appearanceStreamDict.set("Type", Name.get("XObject"));
|
||||
appearanceStreamDict.setIfName("Subtype", "Form");
|
||||
appearanceStreamDict.setIfName("Type", "XObject");
|
||||
appearanceStreamDict.set("BBox", [0, 0, w, h]);
|
||||
appearanceStreamDict.set("Length", appearance.length);
|
||||
appearanceStreamDict.set("Resources", resources);
|
||||
|
||||
@ -199,6 +199,38 @@ class Dict {
|
||||
this._map.set(key, value);
|
||||
}
|
||||
|
||||
setIfNotExists(key, value) {
|
||||
if (!this.has(key)) {
|
||||
this.set(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
setIfNumber(key, value) {
|
||||
if (typeof value === "number") {
|
||||
this.set(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
setIfArray(key, value) {
|
||||
if (Array.isArray(value) || ArrayBuffer.isView(value)) {
|
||||
this.set(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
setIfDefined(key, value) {
|
||||
if (value !== undefined && value !== null) {
|
||||
this.set(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
setIfName(key, value) {
|
||||
if (typeof value === "string") {
|
||||
this.set(key, Name.get(value));
|
||||
} else if (value instanceof Name) {
|
||||
this.set(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
has(key) {
|
||||
return this._map.has(key);
|
||||
}
|
||||
|
||||
@ -271,7 +271,7 @@ function updateXFA({ xfaData, xfaDatasetsRef, changes, xref }) {
|
||||
}
|
||||
const xfaDataStream = new StringStream(xfaData);
|
||||
xfaDataStream.dict = new Dict(xref);
|
||||
xfaDataStream.dict.set("Type", Name.get("EmbeddedFile"));
|
||||
xfaDataStream.dict.setIfName("Type", "EmbeddedFile");
|
||||
|
||||
changes.put(xfaDatasetsRef, {
|
||||
data: xfaDataStream,
|
||||
@ -382,7 +382,7 @@ function getTrailerDict(xrefInfo, changes, useXrefStream) {
|
||||
if (useXrefStream) {
|
||||
changes.put(refForXrefTable, { data: "" });
|
||||
newXref.set("Size", refForXrefTable.num + 1);
|
||||
newXref.set("Type", Name.get("XRef"));
|
||||
newXref.setIfName("Type", "XRef");
|
||||
} else {
|
||||
newXref.set("Size", refForXrefTable.num);
|
||||
}
|
||||
|
||||
@ -431,6 +431,10 @@ describe("core_utils", function () {
|
||||
expect(isAscii("hello world in Japanese is こんにちは世界の")).toEqual(
|
||||
false
|
||||
);
|
||||
expect(isAscii("")).toEqual(true);
|
||||
expect(isAscii(123)).toEqual(false);
|
||||
expect(isAscii(null)).toEqual(false);
|
||||
expect(isAscii(undefined)).toEqual(false);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@ -380,6 +380,50 @@ describe("primitives", function () {
|
||||
"Global font three",
|
||||
]);
|
||||
});
|
||||
|
||||
it("should set the values if they're as expected", function () {
|
||||
const dict = new Dict();
|
||||
dict.set("key", "value");
|
||||
|
||||
dict.setIfNotExists("key", "new value");
|
||||
expect(dict.get("key")).toEqual("value");
|
||||
|
||||
dict.setIfNotExists("key1", "value");
|
||||
expect(dict.get("key1")).toEqual("value");
|
||||
|
||||
dict.setIfNumber("a", 123);
|
||||
expect(dict.get("a")).toEqual(123);
|
||||
|
||||
dict.setIfNumber("b", "not a number");
|
||||
expect(dict.has("b")).toBeFalse();
|
||||
|
||||
dict.setIfArray("c", [1, 2, 3]);
|
||||
expect(dict.get("c")).toEqual([1, 2, 3]);
|
||||
|
||||
dict.setIfArray("d", new Uint8Array([4, 5, 6]));
|
||||
expect(dict.get("d")).toEqual(new Uint8Array([4, 5, 6]));
|
||||
|
||||
dict.setIfArray("e", "not an array");
|
||||
expect(dict.has("e")).toBeFalse();
|
||||
|
||||
dict.setIfDefined("f", "defined");
|
||||
expect(dict.get("f")).toEqual("defined");
|
||||
|
||||
dict.setIfDefined("g", undefined);
|
||||
expect(dict.has("g")).toBeFalse();
|
||||
|
||||
dict.setIfDefined("h", null);
|
||||
expect(dict.has("h")).toBeFalse();
|
||||
|
||||
dict.setIfName("i", Name.get("name"));
|
||||
expect(dict.get("i")).toEqual(Name.get("name"));
|
||||
|
||||
dict.setIfName("j", "name");
|
||||
expect(dict.get("j")).toEqual(Name.get("name"));
|
||||
|
||||
dict.setIfName("k", 1234);
|
||||
expect(dict.has("k")).toBeFalse();
|
||||
});
|
||||
});
|
||||
|
||||
describe("Ref", function () {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user