Skip to content

Commit

Permalink
[api-minor] Include line endings in Line/Polyline Annotation-data (is…
Browse files Browse the repository at this point in the history
…sue 14896)

Please refer to:
 - https://web.archive.org/web/20220309040754if_/https://www.adobe.com/content/dam/acom/en/devnet/pdf/pdfs/PDF32000_2008.pdf#G11.2109792
 - https://web.archive.org/web/20220309040754if_/https://www.adobe.com/content/dam/acom/en/devnet/pdf/pdfs/PDF32000_2008.pdf#G11.2096489
 - https://web.archive.org/web/20220309040754if_/https://www.adobe.com/content/dam/acom/en/devnet/pdf/pdfs/PDF32000_2008.pdf#G11.2096447

Note that we still won't attempt to use the /LE-data when creating fallback appearance streams, as mentioned in PR 13448, since custom line endings aren't common enough to warrant the added complexity.
Finally, note that according to the PDF specification we should *potentially* also take the line endings into account for FreeText Annotations. However, in that case their use is conditional on other parameters that we currently don't support.
  • Loading branch information
Snuffleupagus committed May 10, 2022
1 parent 38c8235 commit 6a682b7
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 5 deletions.
55 changes: 50 additions & 5 deletions src/core/annotation.js
Original file line number Diff line number Diff line change
Expand Up @@ -613,6 +613,40 @@ class Annotation {
this.color = getRgbColor(color);
}

/**
* Set the line endings; should only be used for specific annotation types.
* @param {Array} lineEndings - The line endings array.
*/
setLineEndings(lineEndings) {
this.lineEndings = ["None", "None"]; // The default values.

if (Array.isArray(lineEndings) && lineEndings.length === 2) {
for (let i = 0, ii = lineEndings.length; i < ii; i++) {
const obj = lineEndings[i];

if (obj instanceof Name) {
switch (obj.name) {
case "None":
break;
case "Square":
case "Circle":
case "Diamond":
case "OpenArrow":
case "ClosedArrow":
case "Butt":
case "ROpenArrow":
case "RClosedArrow":
case "Slash":
this.lineEndings[i] = obj.name;
break;
default:
warn(`Ignoring invalid lineEnding: ${obj}`);
}
}
}
}
}

/**
* Set the color for background and border if any.
* The default values are transparent.
Expand Down Expand Up @@ -2803,22 +2837,26 @@ class LineAnnotation extends MarkupAnnotation {
constructor(parameters) {
super(parameters);

const { dict } = parameters;
this.data.annotationType = AnnotationType.LINE;

const lineCoordinates = parameters.dict.getArray("L");
const lineCoordinates = dict.getArray("L");
this.data.lineCoordinates = Util.normalizeRect(lineCoordinates);

this.setLineEndings(dict.getArray("LE"));
this.data.lineEndings = this.lineEndings;

if (!this.appearance) {
// The default stroke color is black.
const strokeColor = this.color
? Array.from(this.color).map(c => c / 255)
: [0, 0, 0];
const strokeAlpha = parameters.dict.get("CA");
const strokeAlpha = dict.get("CA");

// The default fill color is transparent. Setting the fill colour is
// necessary if/when we want to add support for non-default line endings.
let fillColor = null,
interiorColor = parameters.dict.getArray("IC");
interiorColor = dict.getArray("IC");
if (interiorColor) {
interiorColor = getRgbColor(interiorColor, null);
fillColor = interiorColor
Expand Down Expand Up @@ -2996,13 +3034,20 @@ class PolylineAnnotation extends MarkupAnnotation {
constructor(parameters) {
super(parameters);

const { dict } = parameters;
this.data.annotationType = AnnotationType.POLYLINE;
this.data.vertices = [];

if (!(this instanceof PolygonAnnotation)) {
// Only meaningful for polyline annotations.
this.setLineEndings(dict.getArray("LE"));
this.data.lineEndings = this.lineEndings;
}

// The vertices array is an array of numbers representing the alternating
// horizontal and vertical coordinates, respectively, of each vertex.
// Convert this to an array of objects with x and y coordinates.
const rawVertices = parameters.dict.getArray("Vertices");
const rawVertices = dict.getArray("Vertices");
if (!Array.isArray(rawVertices)) {
return;
}
Expand All @@ -3018,7 +3063,7 @@ class PolylineAnnotation extends MarkupAnnotation {
const strokeColor = this.color
? Array.from(this.color).map(c => c / 255)
: [0, 0, 0];
const strokeAlpha = parameters.dict.get("CA");
const strokeAlpha = dict.get("CA");

const borderWidth = this.borderStyle.width || 1,
borderAdjust = 2 * borderWidth;
Expand Down
23 changes: 23 additions & 0 deletions test/unit/annotation_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3618,6 +3618,7 @@ describe("annotation", function () {
lineDict.set("Type", Name.get("Annot"));
lineDict.set("Subtype", Name.get("Line"));
lineDict.set("L", [1, 2, 3, 4]);
lineDict.set("LE", ["Square", "Circle"]);

const lineRef = Ref.get(122, 0);
const xref = new XRefMock([{ ref: lineRef, data: lineDict }]);
Expand All @@ -3630,6 +3631,28 @@ describe("annotation", function () {
);
expect(data.annotationType).toEqual(AnnotationType.LINE);
expect(data.lineCoordinates).toEqual([1, 2, 3, 4]);
expect(data.lineEndings).toEqual(["None", "None"]);
});

it("should set the line endings", async function () {
const lineDict = new Dict();
lineDict.set("Type", Name.get("Annot"));
lineDict.set("Subtype", Name.get("Line"));
lineDict.set("L", [1, 2, 3, 4]);
lineDict.set("LE", [Name.get("Square"), Name.get("Circle")]);

const lineRef = Ref.get(122, 0);
const xref = new XRefMock([{ ref: lineRef, data: lineDict }]);

const { data } = await AnnotationFactory.create(
xref,
lineRef,
pdfManagerMock,
idFactoryMock
);
expect(data.annotationType).toEqual(AnnotationType.LINE);
expect(data.lineCoordinates).toEqual([1, 2, 3, 4]);
expect(data.lineEndings).toEqual(["Square", "Circle"]);
});
});

Expand Down

0 comments on commit 6a682b7

Please sign in to comment.