[Editor] Use the color of the annotation for the background of the comment button
This commit is contained in:
parent
c8d49db624
commit
ca280399c2
@ -38,6 +38,7 @@ import {
|
||||
warn,
|
||||
} from "../shared/util.js";
|
||||
import {
|
||||
applyOpacity,
|
||||
changeLightness,
|
||||
PDFDateString,
|
||||
setLayerDimensions,
|
||||
@ -232,15 +233,8 @@ class AnnotationElement {
|
||||
if (!this.data.color) {
|
||||
return null;
|
||||
}
|
||||
const [r, g, b] = this.data.color;
|
||||
const opacity = this.data.opacity ?? 1;
|
||||
const oppositeOpacity = 255 * (1 - opacity);
|
||||
|
||||
return changeLightness(
|
||||
Math.min(r + oppositeOpacity, 255),
|
||||
Math.min(g + oppositeOpacity, 255),
|
||||
Math.min(b + oppositeOpacity, 255)
|
||||
);
|
||||
const [r, g, b] = applyOpacity(...this.data.color, this.data.opacity);
|
||||
return changeLightness(r, g, b);
|
||||
}
|
||||
|
||||
_normalizePoint(point) {
|
||||
|
||||
@ -770,7 +770,24 @@ const SupportedImageMimeTypes = [
|
||||
"image/x-icon",
|
||||
];
|
||||
|
||||
function changeLightness(r, g, b, lumCallback = l => (1 + Math.sqrt(l)) / 2) {
|
||||
class ColorScheme {
|
||||
static get isDarkMode() {
|
||||
return shadow(
|
||||
this,
|
||||
"isDarkMode",
|
||||
!!window?.matchMedia?.("(prefers-color-scheme: dark)").matches
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function changeLightness(
|
||||
r,
|
||||
g,
|
||||
b,
|
||||
lumCallback = ColorScheme.isDarkMode
|
||||
? l => (1 - Math.sqrt(1 - l)) / 2
|
||||
: l => (1 + Math.sqrt(l)) / 2
|
||||
) {
|
||||
r /= 255;
|
||||
g /= 255;
|
||||
b /= 255;
|
||||
@ -803,8 +820,19 @@ function changeLightness(r, g, b, lumCallback = l => (1 + Math.sqrt(l)) / 2) {
|
||||
return `hsl(${h}, ${s}%, ${newL}%)`;
|
||||
}
|
||||
|
||||
function applyOpacity(r, g, b, opacity) {
|
||||
opacity = Math.min(Math.max(opacity ?? 1, 0), 1);
|
||||
const white = 255 * (1 - opacity);
|
||||
r = Math.round(r * opacity + white);
|
||||
g = Math.round(g * opacity + white);
|
||||
b = Math.round(b * opacity + white);
|
||||
return [r, g, b];
|
||||
}
|
||||
|
||||
export {
|
||||
applyOpacity,
|
||||
changeLightness,
|
||||
ColorScheme,
|
||||
deprecated,
|
||||
fetchData,
|
||||
getColorValues,
|
||||
|
||||
@ -58,6 +58,10 @@ class Comment {
|
||||
: position[0])
|
||||
}% - var(--comment-button-dim))`;
|
||||
style.top = `calc(${100 * position[1]}% - var(--comment-button-dim))`;
|
||||
const color = this.#editor.commentButtonColor;
|
||||
if (color) {
|
||||
style.backgroundColor = color;
|
||||
}
|
||||
}
|
||||
|
||||
return this.#render(button);
|
||||
|
||||
@ -22,13 +22,18 @@ import {
|
||||
ColorManager,
|
||||
KeyboardManager,
|
||||
} from "./tools.js";
|
||||
import {
|
||||
applyOpacity,
|
||||
changeLightness,
|
||||
noContextMenu,
|
||||
stopEvent,
|
||||
} from "../display_utils.js";
|
||||
import {
|
||||
FeatureTest,
|
||||
MathClamp,
|
||||
shadow,
|
||||
unreachable,
|
||||
} from "../../shared/util.js";
|
||||
import { noContextMenu, stopEvent } from "../display_utils.js";
|
||||
import { AltText } from "./alt_text.js";
|
||||
import { Comment } from "./comment.js";
|
||||
import { EditorToolbar } from "./toolbar.js";
|
||||
@ -1857,6 +1862,17 @@ class AnnotationEditor {
|
||||
return this._uiManager.direction === "ltr" ? [1, 0] : [0, 0];
|
||||
}
|
||||
|
||||
get commentButtonColor() {
|
||||
if (!this.color) {
|
||||
return null;
|
||||
}
|
||||
let [r, g, b] = AnnotationEditor._colorManager.convert(
|
||||
this._uiManager.getNonHCMColor(this.color)
|
||||
);
|
||||
[r, g, b] = applyOpacity(r, g, b, this.opacity);
|
||||
return changeLightness(r, g, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* onkeydown callback.
|
||||
* @param {KeyboardEvent} event
|
||||
|
||||
@ -35,8 +35,6 @@ const EOL_PATTERN = /\r\n?|\n/g;
|
||||
* Basic text editor in order to create a FreeTex annotation.
|
||||
*/
|
||||
class FreeTextEditor extends AnnotationEditor {
|
||||
#color;
|
||||
|
||||
#content = "";
|
||||
|
||||
#editorDivId = `${this.id}-editor`;
|
||||
@ -129,7 +127,7 @@ class FreeTextEditor extends AnnotationEditor {
|
||||
|
||||
constructor(params) {
|
||||
super({ ...params, name: "freeTextEditor" });
|
||||
this.#color =
|
||||
this.color =
|
||||
params.color ||
|
||||
FreeTextEditor._defaultColor ||
|
||||
AnnotationEditor._defaultLineColor;
|
||||
@ -201,7 +199,7 @@ class FreeTextEditor extends AnnotationEditor {
|
||||
get propertiesToUpdate() {
|
||||
return [
|
||||
[AnnotationEditorParamsType.FREETEXT_SIZE, this.#fontSize],
|
||||
[AnnotationEditorParamsType.FREETEXT_COLOR, this.#color],
|
||||
[AnnotationEditorParamsType.FREETEXT_COLOR, this.color],
|
||||
];
|
||||
}
|
||||
|
||||
@ -215,10 +213,6 @@ class FreeTextEditor extends AnnotationEditor {
|
||||
return AnnotationEditorParamsType.FREETEXT_COLOR;
|
||||
}
|
||||
|
||||
get colorValue() {
|
||||
return this.#color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the font size and make this action as undoable.
|
||||
* @param {number} fontSize
|
||||
@ -248,10 +242,10 @@ class FreeTextEditor extends AnnotationEditor {
|
||||
*/
|
||||
#updateColor(color) {
|
||||
const setColor = col => {
|
||||
this.#color = this.editorDiv.style.color = col;
|
||||
this.color = this.editorDiv.style.color = col;
|
||||
this._colorPicker?.update(col);
|
||||
};
|
||||
const savedColor = this.#color;
|
||||
const savedColor = this.color;
|
||||
this.addCommands({
|
||||
cmd: setColor.bind(this, color),
|
||||
undo: setColor.bind(this, savedColor),
|
||||
@ -581,7 +575,7 @@ class FreeTextEditor extends AnnotationEditor {
|
||||
|
||||
const { style } = this.editorDiv;
|
||||
style.fontSize = `calc(${this.#fontSize}px * var(--total-scale-factor))`;
|
||||
style.color = this.#color;
|
||||
style.color = this.color;
|
||||
|
||||
this.div.append(this.editorDiv);
|
||||
|
||||
@ -819,7 +813,7 @@ class FreeTextEditor extends AnnotationEditor {
|
||||
}
|
||||
const editor = await super.deserialize(data, parent, uiManager);
|
||||
editor.#fontSize = data.fontSize;
|
||||
editor.#color = Util.makeHexColor(...data.color);
|
||||
editor.color = Util.makeHexColor(...data.color);
|
||||
editor.#content = FreeTextEditor.#deserializeContent(data.value);
|
||||
editor._initialData = initialData;
|
||||
if (data.comment) {
|
||||
@ -841,9 +835,7 @@ class FreeTextEditor extends AnnotationEditor {
|
||||
|
||||
const rect = this.getPDFRect();
|
||||
const color = AnnotationEditor._colorManager.convert(
|
||||
this.isAttachedToDOM
|
||||
? getComputedStyle(this.editorDiv).color
|
||||
: this.#color
|
||||
this.isAttachedToDOM ? getComputedStyle(this.editorDiv).color : this.color
|
||||
);
|
||||
|
||||
const serialized = {
|
||||
@ -895,7 +887,7 @@ class FreeTextEditor extends AnnotationEditor {
|
||||
}
|
||||
const { style } = content;
|
||||
style.fontSize = `calc(${this.#fontSize}px * var(--total-scale-factor))`;
|
||||
style.color = this.#color;
|
||||
style.color = this.color;
|
||||
|
||||
content.replaceChildren();
|
||||
for (const line of this.#content.split("\n")) {
|
||||
|
||||
@ -64,8 +64,6 @@ class HighlightEditor extends AnnotationEditor {
|
||||
|
||||
#lastPoint = null;
|
||||
|
||||
#opacity;
|
||||
|
||||
#outlineId = null;
|
||||
|
||||
#text = "";
|
||||
@ -108,7 +106,7 @@ class HighlightEditor extends AnnotationEditor {
|
||||
super({ ...params, name: "highlightEditor" });
|
||||
this.color = params.color || HighlightEditor._defaultColor;
|
||||
this.#thickness = params.thickness || HighlightEditor._defaultThickness;
|
||||
this.#opacity = params.opacity || HighlightEditor._defaultOpacity;
|
||||
this.opacity = params.opacity || HighlightEditor._defaultOpacity;
|
||||
this.#boxes = params.boxes || null;
|
||||
this.#methodOfCreation = params.methodOfCreation || "";
|
||||
this.#text = params.text || "";
|
||||
@ -361,7 +359,7 @@ class HighlightEditor extends AnnotationEditor {
|
||||
#updateColor(color) {
|
||||
const setColorAndOpacity = (col, opa) => {
|
||||
this.color = col;
|
||||
this.#opacity = opa;
|
||||
this.opacity = opa;
|
||||
this.parent?.drawLayer.updateProperties(this.#id, {
|
||||
root: {
|
||||
fill: col,
|
||||
@ -371,7 +369,7 @@ class HighlightEditor extends AnnotationEditor {
|
||||
this.#colorPicker?.updateColor(col);
|
||||
};
|
||||
const savedColor = this.color;
|
||||
const savedOpacity = this.#opacity;
|
||||
const savedOpacity = this.opacity;
|
||||
this.addCommands({
|
||||
cmd: setColorAndOpacity.bind(
|
||||
this,
|
||||
@ -549,7 +547,7 @@ class HighlightEditor extends AnnotationEditor {
|
||||
root: {
|
||||
viewBox: "0 0 1 1",
|
||||
fill: this.color,
|
||||
"fill-opacity": this.#opacity,
|
||||
"fill-opacity": this.opacity,
|
||||
},
|
||||
rootClass: {
|
||||
highlight: true,
|
||||
@ -951,7 +949,7 @@ class HighlightEditor extends AnnotationEditor {
|
||||
const editor = await super.deserialize(data, parent, uiManager);
|
||||
|
||||
editor.color = Util.makeHexColor(...color);
|
||||
editor.#opacity = opacity || 1;
|
||||
editor.opacity = opacity || 1;
|
||||
if (inkLists) {
|
||||
editor.#thickness = data.thickness;
|
||||
}
|
||||
@ -1046,7 +1044,7 @@ class HighlightEditor extends AnnotationEditor {
|
||||
const serialized = {
|
||||
annotationType: AnnotationEditorType.HIGHLIGHT,
|
||||
color,
|
||||
opacity: this.#opacity,
|
||||
opacity: this.opacity,
|
||||
thickness: this.#thickness,
|
||||
quadPoints: this.#serializeBoxes(),
|
||||
outlines: this.#serializeOutlines(rect),
|
||||
|
||||
@ -193,10 +193,14 @@ class InkEditor extends DrawingEditor {
|
||||
return AnnotationEditorParamsType.INK_COLOR;
|
||||
}
|
||||
|
||||
get colorValue() {
|
||||
get color() {
|
||||
return this._drawingOptions.stroke;
|
||||
}
|
||||
|
||||
get opacity() {
|
||||
return this._drawingOptions["stroke-opacity"];
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
onScaleChanging() {
|
||||
if (!this.parent) {
|
||||
|
||||
@ -15,6 +15,7 @@
|
||||
|
||||
import { AnnotationEditorType, AnnotationPrefix } from "../../shared/util.js";
|
||||
import {
|
||||
ColorScheme,
|
||||
OutputScale,
|
||||
PixelsPerInch,
|
||||
SupportedImageMimeTypes,
|
||||
@ -535,7 +536,7 @@ class StampEditor extends AnnotationEditor {
|
||||
black = "#cfcfd8";
|
||||
if (this._uiManager.hcmFilter !== "none") {
|
||||
black = "black";
|
||||
} else if (window.matchMedia?.("(prefers-color-scheme: dark)").matches) {
|
||||
} else if (ColorScheme.isDarkMode) {
|
||||
white = "#8f8f9d";
|
||||
black = "#42414d";
|
||||
}
|
||||
|
||||
17
src/pdf.js
17
src/pdf.js
@ -45,13 +45,7 @@ import {
|
||||
VerbosityLevel,
|
||||
} from "./shared/util.js";
|
||||
import {
|
||||
build,
|
||||
getDocument,
|
||||
PDFDataRangeTransport,
|
||||
PDFWorker,
|
||||
version,
|
||||
} from "./display/api.js";
|
||||
import {
|
||||
applyOpacity,
|
||||
changeLightness,
|
||||
fetchData,
|
||||
getFilenameFromUrl,
|
||||
@ -69,6 +63,13 @@ import {
|
||||
stopEvent,
|
||||
SupportedImageMimeTypes,
|
||||
} from "./display/display_utils.js";
|
||||
import {
|
||||
build,
|
||||
getDocument,
|
||||
PDFDataRangeTransport,
|
||||
PDFWorker,
|
||||
version,
|
||||
} from "./display/api.js";
|
||||
import { AnnotationEditorLayer } from "./display/editor/annotation_editor_layer.js";
|
||||
import { AnnotationEditorUIManager } from "./display/editor/tools.js";
|
||||
import { AnnotationLayer } from "./display/annotation_layer.js";
|
||||
@ -98,6 +99,7 @@ globalThis.pdfjsLib = {
|
||||
AnnotationLayer,
|
||||
AnnotationMode,
|
||||
AnnotationType,
|
||||
applyOpacity,
|
||||
build,
|
||||
changeLightness,
|
||||
ColorPicker,
|
||||
@ -154,6 +156,7 @@ export {
|
||||
AnnotationLayer,
|
||||
AnnotationMode,
|
||||
AnnotationType,
|
||||
applyOpacity,
|
||||
build,
|
||||
changeLightness,
|
||||
ColorPicker,
|
||||
|
||||
@ -14,6 +14,7 @@
|
||||
*/
|
||||
|
||||
import {
|
||||
applyOpacity,
|
||||
changeLightness,
|
||||
getFilenameFromUrl,
|
||||
getPdfFilenameFromUrl,
|
||||
@ -324,4 +325,21 @@ describe("display_utils", function () {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("applyOpacity", function () {
|
||||
it("Check that the opacity is applied correctly", function () {
|
||||
if (isNodeJS) {
|
||||
pending("OffscreenCanvas is not supported in Node.js.");
|
||||
}
|
||||
const canvas = new OffscreenCanvas(1, 1);
|
||||
const ctx = canvas.getContext("2d");
|
||||
ctx.fillStyle = "white";
|
||||
ctx.fillRect(0, 0, 1, 1);
|
||||
ctx.fillStyle = "rgb(123, 45, 67)";
|
||||
ctx.globalAlpha = 0.8;
|
||||
ctx.fillRect(0, 0, 1, 1);
|
||||
const [r, g, b] = ctx.getImageData(0, 0, 1, 1).data;
|
||||
expect(applyOpacity(123, 45, 67, ctx.globalAlpha)).toEqual([r, g, b]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -36,13 +36,7 @@ import {
|
||||
VerbosityLevel,
|
||||
} from "../../src/shared/util.js";
|
||||
import {
|
||||
build,
|
||||
getDocument,
|
||||
PDFDataRangeTransport,
|
||||
PDFWorker,
|
||||
version,
|
||||
} from "../../src/display/api.js";
|
||||
import {
|
||||
applyOpacity,
|
||||
changeLightness,
|
||||
fetchData,
|
||||
getFilenameFromUrl,
|
||||
@ -60,6 +54,13 @@ import {
|
||||
stopEvent,
|
||||
SupportedImageMimeTypes,
|
||||
} from "../../src/display/display_utils.js";
|
||||
import {
|
||||
build,
|
||||
getDocument,
|
||||
PDFDataRangeTransport,
|
||||
PDFWorker,
|
||||
version,
|
||||
} from "../../src/display/api.js";
|
||||
import { AnnotationEditorLayer } from "../../src/display/editor/annotation_editor_layer.js";
|
||||
import { AnnotationEditorUIManager } from "../../src/display/editor/tools.js";
|
||||
import { AnnotationLayer } from "../../src/display/annotation_layer.js";
|
||||
@ -82,6 +83,7 @@ const expectedAPI = Object.freeze({
|
||||
AnnotationLayer,
|
||||
AnnotationMode,
|
||||
AnnotationType,
|
||||
applyOpacity,
|
||||
build,
|
||||
changeLightness,
|
||||
ColorPicker,
|
||||
|
||||
@ -257,6 +257,7 @@
|
||||
|
||||
:is(.annotationLayer, .annotationEditorLayer) {
|
||||
.annotationCommentButton {
|
||||
color-scheme: light dark;
|
||||
--comment-button-bg: light-dark(white, #1c1b22);
|
||||
--comment-button-fg: light-dark(#5b5b66, #fbfbfe);
|
||||
--comment-button-active-bg: light-dark(#0041a4, #a6ecf4);
|
||||
|
||||
@ -22,6 +22,7 @@ const {
|
||||
AnnotationLayer,
|
||||
AnnotationMode,
|
||||
AnnotationType,
|
||||
applyOpacity,
|
||||
build,
|
||||
changeLightness,
|
||||
ColorPicker,
|
||||
@ -78,6 +79,7 @@ export {
|
||||
AnnotationLayer,
|
||||
AnnotationMode,
|
||||
AnnotationType,
|
||||
applyOpacity,
|
||||
build,
|
||||
changeLightness,
|
||||
ColorPicker,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user