feat(sign): Add signature color picker and custom signature colors (#4441)

# 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

<img width="771" height="553" alt="image"
src="https://github.com/user-attachments/assets/3a715723-d281-4175-8a33-c68cb53e2b47"
/>

<img width="514" height="445" alt="image"
src="https://github.com/user-attachments/assets/c928fbb2-63db-4f44-bc15-9b556af7b3a5"
/>

<img width="514" height="445" alt="image"
src="https://github.com/user-attachments/assets/ea31f2f2-9790-4166-9d33-69771546858d"
/>

Closes #4413

<!--
Please provide a summary of the changes, including:

- What was changed
- Why the change was made
- Any challenges encountered

Closes #(issue_number)
-->

---

## 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 <bszucs1209@gmail.com>
Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
This commit is contained in:
Balázs Szücs 2025-09-29 15:46:26 +02:00 committed by GitHub
parent 51aa03b256
commit 69b2701fbf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 62 additions and 6 deletions

View File

@ -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

View File

@ -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%;

View File

@ -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";

View File

@ -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;
}
});

View File

@ -50,6 +50,10 @@
</div>
<div class="tab-container drawing-pad-container" th:data-title="#{sign.draw}">
<div class="signature-color-picker">
<label for="signature-color" th:text="#{sign.colour}">Signature Colour</label>
<input id="signature-color" name="signature-color" type="color" value="#000000" />
</div>
<canvas id="drawing-pad-canvas"></canvas>
<br>
<button id="clear-signature" class="btn btn-outline-danger mt-2" onclick="signaturePad.clear()"
@ -92,7 +96,7 @@
<div th:each="sig : ${signatures}" th:if="${sig.category == 'Personal'}"
class="small-file-container-saved d-flex flex-column justify-content-center align-items-center">
<div class="drag-icon"><svg xmlns="http://www.w3.org/2000/svg" height="24px"
viewBox="0 -960 960 960" width="24px" fill="#e8eaed">
fill="#e8eaed" viewBox="0 -960 960 960" width="24px">
<path
d="M360-160q-33 0-56.5-23.5T280-240q0-33 23.5-56.5T360-320q33 0 56.5 23.5T440-240q0 33-23.5 56.5T360-160Zm240 0q-33 0-56.5-23.5T520-240q0-33 23.5-56.5T600-320q33 0 56.5 23.5T680-240q0 33-23.5 56.5T600-160ZM360-400q-33 0-56.5-23.5T280-480q0-33 23.5-56.5T360-560q33 0 56.5 23.5T440-480q0 33-23.5 56.5T360-400Zm240 0q-33 0-56.5-23.5T520-480q0-33 23.5-56.5T600-560q33 0 56.5 23.5T680-480q0 33-23.5 56.5T600-400ZM360-640q-33 0-56.5-23.5T280-720q0-33 23.5-56.5T360-800q33 0 56.5 23.5T440-720q0 33-23.5 56.5T360-640Zm240 0q-33 0-56.5-23.5T520-720q0-33 23.5-56.5T600-800q33 0 56.5 23.5T680-720q0 33-23.5 56.5T600-640Z">
</path>
@ -114,7 +118,7 @@
<div th:each="sig : ${signatures}" th:if="${sig.category == 'Shared'}"
class="small-file-container-saved d-flex flex-column justify-content-center align-items-center">
<div class="drag-icon"><svg xmlns="http://www.w3.org/2000/svg" height="24px"
viewBox="0 -960 960 960" width="24px" fill="#e8eaed">
fill="#e8eaed" viewBox="0 -960 960 960" width="24px">
<path
d="M360-160q-33 0-56.5-23.5T280-240q0-33 23.5-56.5T360-320q33 0 56.5 23.5T440-240q0 33-23.5 56.5T360-160Zm240 0q-33 0-56.5-23.5T520-240q0-33 23.5-56.5T600-320q33 0 56.5 23.5T680-240q0 33-23.5 56.5T600-160ZM360-400q-33 0-56.5-23.5T280-480q0-33 23.5-56.5T360-560q33 0 56.5 23.5T440-480q0 33-23.5 56.5T360-400Zm240 0q-33 0-56.5-23.5T520-480q0-33 23.5-56.5T600-560q33 0 56.5 23.5T680-480q0 33-23.5 56.5T600-400ZM360-640q-33 0-56.5-23.5T280-720q0-33 23.5-56.5T360-800q33 0 56.5 23.5T440-720q0 33-23.5 56.5T360-640Zm240 0q-33 0-56.5-23.5T520-720q0-33 23.5-56.5T600-800q33 0 56.5 23.5T680-720q0 33-23.5 56.5T600-640Z">
</path>
@ -144,6 +148,11 @@
th:class="${font.name.toLowerCase()+'-font'}"></option>
</select>
</div>
<!-- Color picker for text signatures -->
<div class="signature-color-picker">
<label for="signature-color-text" th:text="#{sign.colour}">Colour</label>
<input id="signature-color-text" name="signature-color-text" type="color" value="#000000" />
</div>
<div class="margin-auto-parent">
<button id="save-text-signature" class="btn btn-outline-success mt-2 margin-center"
onclick="addDraggableFromText()" th:text="#{sign.add}"></button>