Skip to content

Commit

Permalink
Handle canvas styles with alpha in rgba() format
Browse files Browse the repository at this point in the history
The HTML Canvas standard specifies `#rrggbb` and `rgba(r, g, b, a)` as
the only allowed serializations (the latter for alpha < 1) of CSS colors
returned by fill and stroke styles. So far we handled only hex values.

This was put off till now, as PDF.js never seemed to draw with styles
having alpha, even with PDFs having transparent shapes. But the newly
added Ink annotation editor with opacity control does draw with rgba()
styles, finally necessitating this patch.
  • Loading branch information
shivaprsd committed Oct 19, 2022
1 parent 82f0db2 commit b0d6306
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 15 deletions.
13 changes: 7 additions & 6 deletions addon/doq.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,14 +154,15 @@ const DOQReader = {
);
if (isShape && !this.flags.shapesOn || !isColor)
return style;
style = newColor(style);
const bg = isText && this.getCanvasColor(ctx, ...args);
const key = style + (bg ? bg.toHex() : "");
const key = style.hex + (bg ? bg.hex : "");
let newStyle = this.styleCache.get(key);
if (!newStyle) {
newStyle = this.calcStyle(newColor(style), bg);
newStyle = this.calcStyle(style, bg);
this.styleCache.set(key, newStyle);
}
return newStyle;
return newStyle.toHex(style.alpha);
},
getCanvasColor(ctx, text, tx, ty) {
if (!this.canvasData.has(ctx))
Expand All @@ -186,12 +187,12 @@ const DOQReader = {
if (color.chroma > 10) {
const accents = acc.concat(this.readerTone.scheme.colors);
if (accents.length)
style = this.findMatch(accents, e => e.deltaE(color), Math.min).toHex();
style = this.findMatch(accents, e => e.deltaE(color), Math.min);
} else if (textBg && bg.deltaE(textBg) > 2.3) {
style = this.findMatch([bg, fg], diffL, Math.max).toHex();
style = this.findMatch([bg, fg], diffL, Math.max);
} else {
const whiteL = Color.white.lightness;
style = grad(1 - color.lightness / whiteL).toHex();
style = grad(1 - color.lightness / whiteL);
}
return style;
},
Expand Down
38 changes: 29 additions & 9 deletions addon/lib/color.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,24 @@ export class Color {
}
else if (typeof args[0] === "string") {
const str = args[0];
if (str[0] !== "#" || str.length !== 7) {
console.error(`Invalid hex: "${str}"`);
if (str[0] === "#" && str.length === 7) {
this._hex = str;
this._rgb = Color.parseHex(str);
} else if (str.startsWith("rgba(")) {
[this._rgb, this._alpha] = Color.parseRGBA(str);
} else {
console.error(`Unsupported color format: "${str}"`);
return null;
}
this._rgb = Color.parseHex(str);
} else {
this._rgb = [0, 0, 0];
}
}

get hex() {
this._hex = this._hex || this.toHex();
return this._hex;
}
get rgb() {
this._rgb = this._rgb || sRGB.fromLab(this._lab);
return this._rgb;
Expand All @@ -39,6 +47,9 @@ export class Color {
const [L, a, b] = this.lab;
return Math.sqrt(a ** 2 + b ** 2);
}
get alpha() {
return this._alpha ?? 1;
}

deltaE(color) {
return Math.sqrt(this.lab.reduce((a, c, i) => {
Expand Down Expand Up @@ -67,12 +78,10 @@ export class Color {
};
}

toHex() {
const coords = this.rgb.map(c => Math.round(c * 255));
const hex = coords.map(c => {
c = Math.min(Math.max(c, 0), 255);
return c.toString(16).padStart(2, "0");
}).join("");
toHex(alpha = 1) {
let hex = this.rgb.map(Color.compToHex).join("");
if (alpha !== 1)
hex += Color.compToHex(alpha);
return "#" + hex;
}
static parseHex(str) {
Expand All @@ -82,6 +91,17 @@ export class Color {
});
return rgba.slice(0, 3);
}
static parseRGBA(str) {
const rgba = str.slice(5, -1).split(",");
return [
rgba.slice(0, 3).map(c => parseInt(c) / 255), /* [r, g, b] */
parseFloat(rgba.pop()) /* alpha */
];
}
static compToHex(c) {
c = Math.round(Math.min(Math.max(c * 255, 0), 255));
return c.toString(16).padStart(2, "0");
}
}
Color.white = new Color([1, 1, 1]);

Expand Down

0 comments on commit b0d6306

Please sign in to comment.