Skip to content

Commit

Permalink
Merge pull request mozilla#13448 from Snuffleupagus/_setDefaultAppear…
Browse files Browse the repository at this point in the history
…ance-alpha

Support strokeAlpha/fillAlpha when creating a fallback appearance stream (issue 6810)
  • Loading branch information
timvandermeij authored May 28, 2021
2 parents 5e5641b + 52c1332 commit a0ce3cb
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 18 deletions.
115 changes: 97 additions & 18 deletions src/core/annotation.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import {
assert,
escapeString,
getModificationDate,
isArrayEqual,
isAscii,
isString,
OPS,
Expand Down Expand Up @@ -1070,6 +1069,8 @@ class MarkupAnnotation extends Annotation {
strokeColor,
fillColor,
blendMode,
strokeAlpha,
fillAlpha,
pointsCallback,
}) {
let minX = Number.MAX_VALUE;
Expand Down Expand Up @@ -1124,6 +1125,12 @@ class MarkupAnnotation extends Annotation {
if (blendMode) {
gsDict.set("BM", Name.get(blendMode));
}
if (typeof strokeAlpha === "number") {
gsDict.set("CA", strokeAlpha);
}
if (typeof fillAlpha === "number") {
gsDict.set("ca", fillAlpha);
}

const stateDict = new Dict(xref);
stateDict.set("GS0", gsDict);
Expand Down Expand Up @@ -2400,24 +2407,42 @@ class LineAnnotation extends MarkupAnnotation {
const strokeColor = this.color
? Array.from(this.color).map(c => c / 255)
: [0, 0, 0];
const strokeAlpha = parameters.dict.get("CA");

const borderWidth = this.borderStyle.width;

// If the /Rect-entry is empty, create a fallback rectangle such that we
// get similar rendering/highlighting behaviour as in Adobe Reader.
if (isArrayEqual(this.rectangle, [0, 0, 0, 0])) {
this.rectangle = [
this.data.lineCoordinates[0] - 2 * borderWidth,
this.data.lineCoordinates[1] - 2 * borderWidth,
this.data.lineCoordinates[2] + 2 * borderWidth,
this.data.lineCoordinates[3] + 2 * borderWidth,
];
// 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");
if (interiorColor) {
interiorColor = getRgbColor(interiorColor);
fillColor = interiorColor
? Array.from(interiorColor).map(c => c / 255)
: null;
}
const fillAlpha = fillColor ? strokeAlpha : null;

const borderWidth = this.borderStyle.width || 1,
borderAdjust = 2 * borderWidth;

// If the /Rect-entry is empty/wrong, create a fallback rectangle so that
// we get similar rendering/highlighting behaviour as in Adobe Reader.
const bbox = [
this.data.lineCoordinates[0] - borderAdjust,
this.data.lineCoordinates[1] - borderAdjust,
this.data.lineCoordinates[2] + borderAdjust,
this.data.lineCoordinates[3] + borderAdjust,
];
if (!Util.intersect(this.rectangle, bbox)) {
this.rectangle = bbox;
}

this._setDefaultAppearance({
xref: parameters.xref,
extra: `${borderWidth} w`,
strokeColor,
fillColor,
strokeAlpha,
fillAlpha,
pointsCallback: (buffer, points) => {
buffer.push(
`${lineCoordinates[0]} ${lineCoordinates[1]} m`,
Expand Down Expand Up @@ -2447,22 +2472,26 @@ class SquareAnnotation extends MarkupAnnotation {
const strokeColor = this.color
? Array.from(this.color).map(c => c / 255)
: [0, 0, 0];
const strokeAlpha = parameters.dict.get("CA");

// The default fill color is transparent.
let fillColor = null;
let interiorColor = parameters.dict.getArray("IC");
let fillColor = null,
interiorColor = parameters.dict.getArray("IC");
if (interiorColor) {
interiorColor = getRgbColor(interiorColor);
fillColor = interiorColor
? Array.from(interiorColor).map(c => c / 255)
: null;
}
const fillAlpha = fillColor ? strokeAlpha : null;

this._setDefaultAppearance({
xref: parameters.xref,
extra: `${this.borderStyle.width} w`,
strokeColor,
fillColor,
strokeAlpha,
fillAlpha,
pointsCallback: (buffer, points) => {
const x = points[2].x + this.borderStyle.width / 2;
const y = points[2].y + this.borderStyle.width / 2;
Expand Down Expand Up @@ -2492,6 +2521,7 @@ class CircleAnnotation extends MarkupAnnotation {
const strokeColor = this.color
? Array.from(this.color).map(c => c / 255)
: [0, 0, 0];
const strokeAlpha = parameters.dict.get("CA");

// The default fill color is transparent.
let fillColor = null;
Expand All @@ -2502,6 +2532,7 @@ class CircleAnnotation extends MarkupAnnotation {
? Array.from(interiorColor).map(c => c / 255)
: null;
}
const fillAlpha = fillColor ? strokeAlpha : null;

// Circles are approximated by Bézier curves with four segments since
// there is no circle primitive in the PDF specification. For the control
Expand All @@ -2513,6 +2544,8 @@ class CircleAnnotation extends MarkupAnnotation {
extra: `${this.borderStyle.width} w`,
strokeColor,
fillColor,
strokeAlpha,
fillAlpha,
pointsCallback: (buffer, points) => {
const x0 = points[0].x + this.borderStyle.width / 2;
const y0 = points[0].y - this.borderStyle.width / 2;
Expand Down Expand Up @@ -2569,13 +2602,29 @@ class PolylineAnnotation extends MarkupAnnotation {
const strokeColor = this.color
? Array.from(this.color).map(c => c / 255)
: [0, 0, 0];

const borderWidth = this.borderStyle.width || 1;
const strokeAlpha = parameters.dict.get("CA");

const borderWidth = this.borderStyle.width || 1,
borderAdjust = 2 * borderWidth;

// If the /Rect-entry is empty/wrong, create a fallback rectangle so that
// we get similar rendering/highlighting behaviour as in Adobe Reader.
const bbox = [Infinity, Infinity, -Infinity, -Infinity];
for (const vertex of this.data.vertices) {
bbox[0] = Math.min(bbox[0], vertex.x - borderAdjust);
bbox[1] = Math.min(bbox[1], vertex.y - borderAdjust);
bbox[2] = Math.max(bbox[2], vertex.x + borderAdjust);
bbox[3] = Math.max(bbox[3], vertex.y + borderAdjust);
}
if (!Util.intersect(this.rectangle, bbox)) {
this.rectangle = bbox;
}

this._setDefaultAppearance({
xref: parameters.xref,
extra: `${borderWidth} w`,
strokeColor,
strokeAlpha,
pointsCallback: (buffer, points) => {
const vertices = this.data.vertices;
for (let i = 0, ii = vertices.length; i < ii; i++) {
Expand Down Expand Up @@ -2639,13 +2688,31 @@ class InkAnnotation extends MarkupAnnotation {
const strokeColor = this.color
? Array.from(this.color).map(c => c / 255)
: [0, 0, 0];

const borderWidth = this.borderStyle.width || 1;
const strokeAlpha = parameters.dict.get("CA");

const borderWidth = this.borderStyle.width || 1,
borderAdjust = 2 * borderWidth;

// If the /Rect-entry is empty/wrong, create a fallback rectangle so that
// we get similar rendering/highlighting behaviour as in Adobe Reader.
const bbox = [Infinity, Infinity, -Infinity, -Infinity];
for (const inkLists of this.data.inkLists) {
for (const vertex of inkLists) {
bbox[0] = Math.min(bbox[0], vertex.x - borderAdjust);
bbox[1] = Math.min(bbox[1], vertex.y - borderAdjust);
bbox[2] = Math.max(bbox[2], vertex.x + borderAdjust);
bbox[3] = Math.max(bbox[3], vertex.y + borderAdjust);
}
}
if (!Util.intersect(this.rectangle, bbox)) {
this.rectangle = bbox;
}

this._setDefaultAppearance({
xref: parameters.xref,
extra: `${borderWidth} w`,
strokeColor,
strokeAlpha,
pointsCallback: (buffer, points) => {
// According to the specification, see "12.5.6.13 Ink Annotations":
// When drawn, the points shall be connected by straight lines or
Expand Down Expand Up @@ -2691,10 +2758,13 @@ class HighlightAnnotation extends MarkupAnnotation {
const fillColor = this.color
? Array.from(this.color).map(c => c / 255)
: [1, 1, 0];
const fillAlpha = parameters.dict.get("CA");

this._setDefaultAppearance({
xref: parameters.xref,
fillColor,
blendMode: "Multiply",
fillAlpha,
pointsCallback: (buffer, points) => {
buffer.push(
`${points[0].x} ${points[0].y} m`,
Expand Down Expand Up @@ -2728,10 +2798,13 @@ class UnderlineAnnotation extends MarkupAnnotation {
const strokeColor = this.color
? Array.from(this.color).map(c => c / 255)
: [0, 0, 0];
const strokeAlpha = parameters.dict.get("CA");

this._setDefaultAppearance({
xref: parameters.xref,
extra: "[] 0 d 1 w",
strokeColor,
strokeAlpha,
pointsCallback: (buffer, points) => {
buffer.push(
`${points[2].x} ${points[2].y} m`,
Expand Down Expand Up @@ -2764,10 +2837,13 @@ class SquigglyAnnotation extends MarkupAnnotation {
const strokeColor = this.color
? Array.from(this.color).map(c => c / 255)
: [0, 0, 0];
const strokeAlpha = parameters.dict.get("CA");

this._setDefaultAppearance({
xref: parameters.xref,
extra: "[] 0 d 1 w",
strokeColor,
strokeAlpha,
pointsCallback: (buffer, points) => {
const dy = (points[0].y - points[2].y) / 6;
let shift = dy;
Expand Down Expand Up @@ -2807,10 +2883,13 @@ class StrikeOutAnnotation extends MarkupAnnotation {
const strokeColor = this.color
? Array.from(this.color).map(c => c / 255)
: [0, 0, 0];
const strokeAlpha = parameters.dict.get("CA");

this._setDefaultAppearance({
xref: parameters.xref,
extra: "[] 0 d 1 w",
strokeColor,
strokeAlpha,
pointsCallback: (buffer, points) => {
buffer.push(
`${(points[0].x + points[2].x) / 2} ` +
Expand Down
1 change: 1 addition & 0 deletions test/pdfs/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@
!bug1068432.pdf
!issue12295.pdf
!bug1146106.pdf
!issue13447.pdf
!bug1245391_reduced.pdf
!bug1252420.pdf
!bug1513120_reduced.pdf
Expand Down
Binary file added test/pdfs/issue13447.pdf
Binary file not shown.
13 changes: 13 additions & 0 deletions test/test_manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,19 @@
"type": "eq",
"about": "Causes cmap to be created with invalid glyph ids."
},
{ "id": "issue13447-eq",
"file": "pdfs/issue13447.pdf",
"md5": "a729709950d69ec1cfc516bf559e995d",
"rounds": 1,
"type": "eq"
},
{ "id": "issue13447-annotations",
"file": "pdfs/issue13447.pdf",
"md5": "a729709950d69ec1cfc516bf559e995d",
"rounds": 1,
"type": "eq",
"annotations": true
},
{ "id": "bug946506",
"file": "pdfs/bug946506.pdf",
"md5": "c28911b5c31bdc337c2ce404c5971cfc",
Expand Down

0 comments on commit a0ce3cb

Please sign in to comment.