Update the StringStream constructor to accept an optional dictionary argument

There's currently some amount of `StringStream` usage where the `dict`-parameter is manually assigned, and by updating the signature of the constructor this can be avoided.
This commit is contained in:
Jonas Jenwald 2026-05-31 10:59:55 +02:00
parent 327822c21f
commit 06439a95c3
9 changed files with 90 additions and 93 deletions

View File

@ -1232,8 +1232,7 @@ class Annotation {
separateCanvas: false,
};
}
appearance = new StringStream("");
appearance.dict = new Dict();
appearance = new StringStream("", new Dict());
}
const appearanceDict = appearance.dict;
@ -1782,8 +1781,10 @@ class MarkupAnnotation extends Annotation {
const appearanceStreamDict = new Dict(xref);
appearanceStreamDict.setIfName("Subtype", "Form");
const appearanceStream = new StringStream(buffer.join(" "));
appearanceStream.dict = appearanceStreamDict;
const appearanceStream = new StringStream(
buffer.join(" "),
appearanceStreamDict
);
formDict.set("Fm0", appearanceStream);
const gsDict = new Dict(xref);
@ -1804,8 +1805,7 @@ class MarkupAnnotation extends Annotation {
appearanceDict.set("Resources", resources);
appearanceDict.set("BBox", bbox);
this.appearance = new StringStream("/GS0 gs /Fm0 Do");
this.appearance.dict = appearanceDict;
this.appearance = new StringStream("/GS0 gs /Fm0 Do", appearanceDict);
// This method is only called if there is no appearance for the annotation,
// so `this.appearance` is not pushed yet in the `Annotation` constructor.
@ -2292,9 +2292,8 @@ class WidgetAnnotation extends Annotation {
dict.set("AP", AP);
AP.set("N", newRef);
const resources = this._getSaveFieldResources(xref);
const appearanceStream = new StringStream(appearance);
const appearanceDict = (appearanceStream.dict = new Dict(xref));
const resources = this._getSaveFieldResources(xref),
appearanceDict = new Dict(xref);
appearanceDict.setIfName("Subtype", "Form");
appearanceDict.set("Resources", resources);
const bbox =
@ -2303,6 +2302,8 @@ class WidgetAnnotation extends Annotation {
: [0, 0, this.height, this.width];
appearanceDict.set("BBox", bbox);
const appearanceStream = new StringStream(appearance, appearanceDict);
const rotationMatrix = this.getRotationMatrix(annotationStorage);
if (rotationMatrix !== IDENTITY_MATRIX) {
// The matrix isn't the identity one.
@ -3402,8 +3403,7 @@ class ButtonWidgetAnnotation extends WidgetAnnotation {
appearanceStreamDict.set("Resources", resources);
this.checkedAppearance = new StringStream(appearance);
this.checkedAppearance.dict = appearanceStreamDict;
this.checkedAppearance = new StringStream(appearance, appearanceStreamDict);
this._streams.push(this.checkedAppearance);
}
@ -4253,10 +4253,7 @@ class FreeTextAnnotation extends MarkupAnnotation {
appearanceStreamDict.set("Resources", resources);
appearanceStreamDict.set("Matrix", [1, 0, 0, 1, -rect[0], -rect[1]]);
const ap = new StringStream(appearance);
ap.dict = appearanceStreamDict;
return ap;
return new StringStream(appearance, appearanceStreamDict);
}
}
@ -4745,10 +4742,7 @@ class InkAnnotation extends MarkupAnnotation {
appearanceStreamDict.set("Resources", resources);
}
const ap = new StringStream(appearance);
ap.dict = appearanceStreamDict;
return ap;
return new StringStream(appearance, appearanceStreamDict);
}
static async createNewAppearanceStreamForHighlight(annotation, xref, params) {
@ -4806,10 +4800,7 @@ class InkAnnotation extends MarkupAnnotation {
r0.setIfName("Type", "ExtGState");
}
const ap = new StringStream(appearance);
ap.dict = appearanceStreamDict;
return ap;
return new StringStream(appearance, appearanceStreamDict);
}
}
@ -4949,10 +4940,7 @@ class HighlightAnnotation extends MarkupAnnotation {
r0.setIfName("Type", "ExtGState");
}
const ap = new StringStream(appearance);
ap.dict = appearanceStreamDict;
return ap;
return new StringStream(appearance, appearanceStreamDict);
}
}
@ -5179,10 +5167,7 @@ class StampAnnotation extends MarkupAnnotation {
appearanceStreamDict.set("BBox", rect);
appearanceStreamDict.set("Length", appearance.length);
const ap = new StringStream(appearance);
ap.dict = appearanceStreamDict;
return ap;
return new StringStream(appearance, appearanceStreamDict);
}
static async createNewAppearanceStream(annotation, xref, params) {
@ -5214,10 +5199,7 @@ class StampAnnotation extends MarkupAnnotation {
appearanceStreamDict.set("Matrix", matrix);
}
const ap = new StringStream(appearance);
ap.dict = appearanceStreamDict;
return ap;
return new StringStream(appearance, appearanceStreamDict);
}
}

View File

@ -479,10 +479,7 @@ class FakeUnicodeFont {
appearanceStreamDict.set("Matrix", matrix);
}
const ap = new StringStream(appearance);
ap.dict = appearanceStreamDict;
return ap;
return new StringStream(appearance, appearanceStreamDict);
}
}

View File

@ -30,12 +30,12 @@ import {
import { Dict, isName, Name, Ref, RefSet, RefSetCache } from "../primitives.js";
import { incrementalUpdate, writeValue } from "../writer.js";
import { NameTree, NumberTree } from "../name_number_tree.js";
import { Stream, StringStream } from "../stream.js";
import { stringToAsciiOrUTF16BE, stringToPDFString } from "../string_utils.js";
import { AnnotationFactory } from "../annotation.js";
import { BaseStream } from "../base_stream.js";
import { createImage } from "./pdf_images.js";
import { LETTER_SIZE_MEDIABOX } from "../document.js";
import { StringStream } from "../stream.js";
import { stringToBytes } from "../../shared/util.js";
const MAX_LEAVES_PER_PAGES_NODE = 16;
@ -2374,12 +2374,9 @@ class PDFEditor {
const content =
`q ${numberToString(drawW)} 0 0 ${numberToString(drawH)} ` +
`${numberToString(tx)} ${numberToString(ty)} cm /Im0 Do Q`;
const contentsDict = new Dict(this.xrefWrapper);
const contentsStream = new Stream(
stringToBytes(content),
0,
0,
contentsDict
const contentsStream = new StringStream(
content,
new Dict(this.xrefWrapper)
);
const contentsRef = this.newRef;
this.xref[contentsRef.num] = contentsStream;
@ -2805,11 +2802,11 @@ class PDFEditor {
offset += obj.length + 1;
}
streamBuffer[0] = objOffsets.join("\n");
const objStream = new StringStream(streamBuffer.join("\n"));
const objStreamDict = (objStream.dict = new Dict());
objStreamDict.setIfName("Type", "ObjStm");
objStreamDict.set("N", objRefs.length);
objStreamDict.set("First", streamBuffer[0].length + 1);
const dict = new Dict();
dict.setIfName("Type", "ObjStm");
dict.set("N", objRefs.length);
dict.set("First", streamBuffer[0].length + 1);
const objStream = new StringStream(streamBuffer.join("\n"), dict);
changes.put(objStreamRef, { data: objStream });
}

View File

@ -95,8 +95,8 @@ class Stream extends BaseStream {
}
class StringStream extends Stream {
constructor(str) {
super(stringToBytes(str));
constructor(str, dict = null) {
super(stringToBytes(str), NaN, NaN, dict);
}
}

View File

@ -288,8 +288,7 @@ function updateXFA({ xfaData, xfaDatasetsRef, changes, xref }) {
const datasets = xref.fetchIfRef(xfaDatasetsRef);
xfaData = writeXFADataForAcroform(datasets.getString(), changes);
}
const xfaDataStream = new StringStream(xfaData);
xfaDataStream.dict = new Dict(xref);
const xfaDataStream = new StringStream(xfaData, new Dict(xref));
xfaDataStream.dict.setIfName("Type", "EmbeddedFile");
changes.put(xfaDatasetsRef, {

View File

@ -1737,8 +1737,10 @@ describe("annotation", function () {
const appearanceStatesDict = new Dict();
const normalAppearanceDict = new Dict();
const normalAppearanceStream = new StringStream("0.1 0.2 0.3 rg");
normalAppearanceStream.dict = normalAppearanceDict;
const normalAppearanceStream = new StringStream(
"0.1 0.2 0.3 rg",
normalAppearanceDict
);
appearanceStatesDict.set("N", normalAppearanceStream);
textWidgetDict.set("AP", appearanceStatesDict);
@ -2549,11 +2551,12 @@ describe("annotation", function () {
const checkedAppearanceDict = new Dict();
const uncheckedAppearanceDict = new Dict();
const checkedStream = new StringStream("/ 12 Tf (4) Tj");
checkedStream.dict = checkedAppearanceDict;
const checkedStream = new StringStream(
"/ 12 Tf (4) Tj",
checkedAppearanceDict
);
const uncheckedStream = new StringStream("");
uncheckedStream.dict = uncheckedAppearanceDict;
const uncheckedStream = new StringStream("", uncheckedAppearanceDict);
checkedAppearanceDict.set("BBox", [0, 0, 8, 8]);
checkedAppearanceDict.set("FormType", 1);
@ -2609,11 +2612,15 @@ describe("annotation", function () {
const checkedAppearanceDict = new Dict();
const uncheckedAppearanceDict = new Dict();
const checkedStream = new StringStream("0.1 0.2 0.3 rg");
checkedStream.dict = checkedAppearanceDict;
const checkedStream = new StringStream(
"0.1 0.2 0.3 rg",
checkedAppearanceDict
);
const uncheckedStream = new StringStream("0.3 0.2 0.1 rg");
uncheckedStream.dict = uncheckedAppearanceDict;
const uncheckedStream = new StringStream(
"0.3 0.2 0.1 rg",
uncheckedAppearanceDict
);
checkedAppearanceDict.set("BBox", [0, 0, 8, 8]);
checkedAppearanceDict.set("FormType", 1);
@ -2690,11 +2697,15 @@ describe("annotation", function () {
const checkedAppearanceDict = new Dict();
const uncheckedAppearanceDict = new Dict();
const checkedStream = new StringStream("0.1 0.2 0.3 rg");
checkedStream.dict = checkedAppearanceDict;
const checkedStream = new StringStream(
"0.1 0.2 0.3 rg",
checkedAppearanceDict
);
const uncheckedStream = new StringStream("0.3 0.2 0.1 rg");
uncheckedStream.dict = uncheckedAppearanceDict;
const uncheckedStream = new StringStream(
"0.3 0.2 0.1 rg",
uncheckedAppearanceDict
);
checkedAppearanceDict.set("BBox", [0, 0, 8, 8]);
checkedAppearanceDict.set("FormType", 1);
@ -2752,11 +2763,15 @@ describe("annotation", function () {
const checkedAppearanceDict = new Dict();
const uncheckedAppearanceDict = new Dict();
const checkedStream = new StringStream("0.1 0.2 0.3 rg");
checkedStream.dict = checkedAppearanceDict;
const checkedStream = new StringStream(
"0.1 0.2 0.3 rg",
checkedAppearanceDict
);
const uncheckedStream = new StringStream("0.3 0.2 0.1 rg");
uncheckedStream.dict = uncheckedAppearanceDict;
const uncheckedStream = new StringStream(
"0.3 0.2 0.1 rg",
uncheckedAppearanceDict
);
checkedAppearanceDict.set("BBox", [0, 0, 8, 8]);
checkedAppearanceDict.set("FormType", 1);
@ -2995,11 +3010,15 @@ describe("annotation", function () {
const checkedAppearanceDict = new Dict();
const uncheckedAppearanceDict = new Dict();
const checkedStream = new StringStream("0.1 0.2 0.3 rg");
checkedStream.dict = checkedAppearanceDict;
const checkedStream = new StringStream(
"0.1 0.2 0.3 rg",
checkedAppearanceDict
);
const uncheckedStream = new StringStream("0.3 0.2 0.1 rg");
uncheckedStream.dict = uncheckedAppearanceDict;
const uncheckedStream = new StringStream(
"0.3 0.2 0.1 rg",
uncheckedAppearanceDict
);
checkedAppearanceDict.set("BBox", [0, 0, 8, 8]);
checkedAppearanceDict.set("FormType", 1);
@ -3077,11 +3096,15 @@ describe("annotation", function () {
const checkedAppearanceDict = new Dict();
const uncheckedAppearanceDict = new Dict();
const checkedStream = new StringStream("0.1 0.2 0.3 rg");
checkedStream.dict = checkedAppearanceDict;
const checkedStream = new StringStream(
"0.1 0.2 0.3 rg",
checkedAppearanceDict
);
const uncheckedStream = new StringStream("0.3 0.2 0.1 rg");
uncheckedStream.dict = uncheckedAppearanceDict;
const uncheckedStream = new StringStream(
"0.3 0.2 0.1 rg",
uncheckedAppearanceDict
);
checkedAppearanceDict.set("BBox", [0, 0, 8, 8]);
checkedAppearanceDict.set("FormType", 1);

View File

@ -841,14 +841,13 @@ describe("colorspace", function () {
fnDict.set("Range", [0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0]);
fnDict.set("Length", 58);
let fn = new StringStream(
const fn = new StringStream(
"{ dup 0.84 mul " +
"exch 0.00 exch " +
"dup 0.44 mul " +
"exch 0.21 mul }"
"exch 0.21 mul }",
fnDict
);
fn = new Stream(fn.bytes, 0, 58, fnDict);
const fnRef = Ref.get(10, 0);
const cs = [

View File

@ -19,8 +19,8 @@ import {
parseDefaultAppearance,
} from "../../src/core/default_appearance.js";
import { Dict, Name } from "../../src/core/primitives.js";
import { NullStream, StringStream } from "../../src/core/stream.js";
import { GlobalColorSpaceCache } from "../../src/core/image_utils.js";
import { StringStream } from "../../src/core/stream.js";
import { XRefMock } from "./test_utils.js";
describe("Default appearance", function () {
@ -132,8 +132,7 @@ describe("Default appearance", function () {
indexedDict.set("N", 3);
indexedDict.set("Length", 0);
const indexedStream = new NullStream();
indexedStream.dict = indexedDict;
const indexedStream = new StringStream("", indexedDict);
const colorSpaceDict = new Dict(xref);
colorSpaceDict.set("Cs1", [Name.get("ICCBased"), indexedStream]);
@ -144,13 +143,15 @@ describe("Default appearance", function () {
const appearanceDict = new Dict(xref);
appearanceDict.set("Resources", resourcesDict);
const appearance = new StringStream(`
const appearance = new StringStream(
`
q Q q 2.128482 2.128482 247.84 26 re W n /Cs1 cs 0.52799 0.3071 0.99498 sc
q 1 0 0 -1 -108.3364 459.8485 cm BT 22.00539 0 0 -22.00539 110.5449 452.72
Tm /TT1 1 Tf [ (H) -0.2 (e) -0.2 (l) -0.2 (l) -0.2 (o) -0.2 ( ) 0.2 (W) 17.7
(o) -0.2 (rl) -0.2 (d) -0.2 ( ) 0.2 (f) 0.2 (ro) -0.2 (m ) 0.2 (Pre) -0.2
(vi) -0.2 (e) -0.2 (w) ] TJ ET Q Q`);
appearance.dict = appearanceDict;
(vi) -0.2 (e) -0.2 (w) ] TJ ET Q Q`,
appearanceDict
);
const result = {
fontSize: 22.00539,

View File

@ -157,8 +157,7 @@ describe("Writer", function () {
const gdict = new Dict(null);
gdict.set("H", 123.00001);
const string = "a stream";
const stream = new StringStream(string);
stream.dict = new Dict(null);
const stream = new StringStream(string, new Dict());
stream.dict.set("Length", string.length);
gdict.set("I", stream);