From 69b2701fbfeea7eb054721b042157894052003d6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bal=C3=A1zs=20Sz=C3=BCcs?=
<127139797+balazs-szucs@users.noreply.github.com>
Date: Mon, 29 Sep 2025 15:46:26 +0200
Subject: [PATCH] feat(sign): Add signature color picker and custom signature
colors (#4441)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
# Description of Changes
Added sign custom colour as per #4413
### Example doc
[lorem-ipsum_signed.pdf](https://github.com/user-attachments/files/22310651/lorem-ipsum_signed.pdf)
### UI/Picture
Closes #4413
---
## Checklist
### General
- [x] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [x] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [x] I have performed a self-review of my own code
- [x] My changes generate no new warnings
### Documentation
- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)
### UI Changes (if applicable)
- [x] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)
### Testing (if applicable)
- [x] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.
---------
Signed-off-by: Balázs Szücs
Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
---
.../main/resources/messages_en_GB.properties | 1 +
.../src/main/resources/static/css/sign.css | 16 +++++++++++++++
.../main/resources/static/js/pages/sign.js | 20 ++++++++++++++++++-
.../static/js/sign/signature-canvas.js | 18 ++++++++++++++---
.../src/main/resources/templates/sign.html | 13 ++++++++++--
5 files changed, 62 insertions(+), 6 deletions(-)
diff --git a/app/core/src/main/resources/messages_en_GB.properties b/app/core/src/main/resources/messages_en_GB.properties
index 0a58ddc26..1859c4868 100644
--- a/app/core/src/main/resources/messages_en_GB.properties
+++ b/app/core/src/main/resources/messages_en_GB.properties
@@ -1233,6 +1233,7 @@ sign.previous=Previous page
sign.maintainRatio=Toggle maintain aspect ratio
sign.undo=Undo
sign.redo=Redo
+sign.colour=Signature Colour
#repair
repair.title=Repair
diff --git a/app/core/src/main/resources/static/css/sign.css b/app/core/src/main/resources/static/css/sign.css
index 39ea4c9be..0b1524e07 100644
--- a/app/core/src/main/resources/static/css/sign.css
+++ b/app/core/src/main/resources/static/css/sign.css
@@ -10,6 +10,22 @@ select#font-select option {
text-align: center;
}
+.signature-color-picker {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.5rem;
+ margin: 0.5rem 0 0.75rem;
+}
+
+.signature-color-picker input[type="color"] {
+ width: 42px;
+ height: 32px;
+ padding: 0;
+ border: 1px solid var(--bs-border-color, #ced4da);
+ border-radius: 6px;
+ background: transparent;
+}
+
#drawing-pad-canvas {
background: rgba(125, 125, 125, 0.2);
width: 100%;
diff --git a/app/core/src/main/resources/static/js/pages/sign.js b/app/core/src/main/resources/static/js/pages/sign.js
index 36902aa7b..ec02e75b3 100644
--- a/app/core/src/main/resources/static/js/pages/sign.js
+++ b/app/core/src/main/resources/static/js/pages/sign.js
@@ -7,6 +7,12 @@ window.goToFirstOrLastPage = goToFirstOrLastPage;
let currentPreviewSrc = null;
+function getSelectedSignatureColor() {
+ const textPicker = document.getElementById('signature-color-text');
+ const drawPicker = document.getElementById('signature-color');
+ return (textPicker && textPicker.value) || (drawPicker && drawPicker.value) || '#000000';
+}
+
function toggleSignatureView() {
const gridView = document.getElementById("gridView");
const listView = document.getElementById("listView");
@@ -242,9 +248,19 @@ const signaturePadCanvas = document.getElementById("drawing-pad-canvas");
const signaturePad = new SignaturePad(signaturePadCanvas, {
minWidth: 1,
maxWidth: 2,
- penColor: "black",
+ penColor: "#000000",
});
+// Keep pad color in sync if draw picker exists
+(function initPadColorSync() {
+ const drawPicker = document.getElementById('signature-color');
+ if (!drawPicker) return;
+ if (drawPicker.value) signaturePad.penColor = drawPicker.value;
+ drawPicker.addEventListener('input', () => {
+ signaturePad.penColor = drawPicker.value || '#000000';
+ });
+})();
+
function addDraggableFromPad() {
if (signaturePad.isEmpty()) return;
const startTime = Date.now();
@@ -328,6 +344,7 @@ function addDraggableFromText() {
const sigText = document.getElementById("sigText").value;
const font = document.querySelector("select[name=font]").value;
const fontSize = 100;
+ const color = getSelectedSignatureColor();
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
@@ -340,6 +357,7 @@ function addDraggableFromText() {
canvas.width = textWidth;
canvas.height = paragraphs.length * textHeight * 1.35; // for tails
ctx.font = `${fontSize}px ${font}`;
+ ctx.fillStyle = color;
ctx.textBaseline = "top";
diff --git a/app/core/src/main/resources/static/js/sign/signature-canvas.js b/app/core/src/main/resources/static/js/sign/signature-canvas.js
index a3f7b1e90..042236d69 100644
--- a/app/core/src/main/resources/static/js/sign/signature-canvas.js
+++ b/app/core/src/main/resources/static/js/sign/signature-canvas.js
@@ -4,9 +4,21 @@ const redoButton = document.getElementById("signature-redo-button");
const signaturePad = new SignaturePad(signaturePadCanvas, {
minWidth: 1,
maxWidth: 2,
- penColor: 'black',
+ penColor: '#000000', // default color
});
+(function initSignatureColor() {
+ const colorInput = document.getElementById('signature-color');
+ if (!colorInput) return;
+
+ if (colorInput.value) {
+ signaturePad.penColor = colorInput.value;
+ }
+ colorInput.addEventListener('input', () => {
+ signaturePad.penColor = colorInput.value || '#000000';
+ });
+})();
+
let undoData = [];
signaturePad.addEventListener("endStroke", () => {
@@ -16,10 +28,10 @@ signaturePad.addEventListener("endStroke", () => {
window.addEventListener("keydown", (event) => {
switch (true) {
case event.key === "z" && event.ctrlKey:
- undoButton.click();
+ undoButton?.click();
break;
case event.key === "y" && event.ctrlKey:
- redoButton.click();
+ redoButton?.click();
break;
}
});
diff --git a/app/core/src/main/resources/templates/sign.html b/app/core/src/main/resources/templates/sign.html
index cefb488fe..d6032db3f 100644
--- a/app/core/src/main/resources/templates/sign.html
+++ b/app/core/src/main/resources/templates/sign.html
@@ -50,6 +50,10 @@