Bug/498/signature slow firefox mobile (#3322)

# Description of Changes

Please provide a summary of the changes, including:

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

Closes #(498)

---

## Checklist

### General

- [ ] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [ ] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/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/HowToAddNewLanguage.md)
(if applicable)
- [ ] I have performed a self-review of my own code
- [ ] 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/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md#6-testing)
for more details.

---------

Co-authored-by: Reece Browne <reece@stirling.pdf>
This commit is contained in:
Reece Browne 2025-04-15 21:44:21 +12:00 committed by GitHub
parent 1c27944329
commit 6da84338dc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 28 additions and 26 deletions

View File

@ -26,7 +26,6 @@ window.addEventListener("keydown", (event) => {
function undoDraw() {
const data = signaturePad.toData();
if (data && data.length > 0) {
const removed = data.pop();
undoData.push(removed);
@ -35,7 +34,6 @@ function undoDraw() {
}
function redoDraw() {
if (undoData.length > 0) {
const data = signaturePad.toData();
data.push(undoData.pop());
@ -52,24 +50,18 @@ function addDraggableFromPad() {
}
function getCroppedCanvasDataUrl(canvas) {
let originalCtx = canvas.getContext('2d');
let originalCtx = canvas.getContext('2d', { willReadFrequently: true });
let originalWidth = canvas.width;
let originalHeight = canvas.height;
let imageData = originalCtx.getImageData(0, 0, originalWidth, originalHeight);
let minX = originalWidth + 1,
maxX = -1,
minY = originalHeight + 1,
maxY = -1,
x = 0,
y = 0,
currentPixelColorValueIndex;
let minX = originalWidth + 1, maxX = -1, minY = originalHeight + 1, maxY = -1;
for (y = 0; y < originalHeight; y++) {
for (x = 0; x < originalWidth; x++) {
currentPixelColorValueIndex = (y * originalWidth + x) * 4;
let currentPixelAlphaValue = imageData.data[currentPixelColorValueIndex + 3];
if (currentPixelAlphaValue > 0) {
for (let y = 0; y < originalHeight; y++) {
for (let x = 0; x < originalWidth; x++) {
let idx = (y * originalWidth + x) * 4;
let alpha = imageData.data[idx + 3];
if (alpha > 0) {
if (minX > x) minX = x;
if (maxX < x) maxX = x;
if (minY > y) minY = y;
@ -81,14 +73,14 @@ function getCroppedCanvasDataUrl(canvas) {
let croppedWidth = maxX - minX;
let croppedHeight = maxY - minY;
if (croppedWidth < 0 || croppedHeight < 0) return null;
let cuttedImageData = originalCtx.getImageData(minX, minY, croppedWidth, croppedHeight);
let cutImageData = originalCtx.getImageData(minX, minY, croppedWidth, croppedHeight);
let croppedCanvas = document.createElement('canvas'),
croppedCtx = croppedCanvas.getContext('2d');
let croppedCanvas = document.createElement('canvas');
let croppedCtx = croppedCanvas.getContext('2d');
croppedCanvas.width = croppedWidth;
croppedCanvas.height = croppedHeight;
croppedCtx.putImageData(cuttedImageData, 0, 0);
croppedCtx.putImageData(cutImageData, 0, 0);
return croppedCanvas.toDataURL();
}
@ -114,10 +106,20 @@ function resizeCanvas() {
signaturePad.clear();
}
new IntersectionObserver((entries, observer) => {
const debounce = (fn, delay = 100) => {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => fn(...args), delay);
};
};
const debouncedResize = debounce(resizeCanvas, 200);
new IntersectionObserver((entries) => {
if (entries.some((entry) => entry.intersectionRatio > 0)) {
resizeCanvas();
debouncedResize();
}
}).observe(signaturePadCanvas);
new ResizeObserver(resizeCanvas).observe(signaturePadCanvas);
new ResizeObserver(debouncedResize).observe(signaturePadCanvas);

View File

@ -43,13 +43,13 @@
</div>
<script type="module" th:src="@{'/pdfjs-legacy/pdf.mjs'}"></script>
<div class="tab-group show-on-file-selected">
<div class="tab-container" th:title="#{sign.upload}" th:data-title="#{sign.upload}">
<div class="tab-container"th:data-title="#{sign.upload}">
<div
th:replace="~{fragments/common :: fileSelector(name='image-upload', disableMultipleFiles=false, multipleInputsForSingleRequest=true, accept='image/*', inputText=#{imgPrompt})}">
</div>
</div>
<div class="tab-container drawing-pad-container" th:title="#{sign.draw}" th:data-title="#{sign.draw}">
<div class="tab-container drawing-pad-container" th:data-title="#{sign.draw}">
<canvas id="drawing-pad-canvas"></canvas>
<br>
<button id="clear-signature" class="btn btn-outline-danger mt-2" onclick="signaturePad.clear()"
@ -62,7 +62,7 @@
onclick="redoDraw()"></button>
</div>
<div class="tab-container" th:title="#{sign.saved}" th:data-title="#{sign.saved}">
<div class="tab-container" th:data-title="#{sign.saved}">
<div class="saved-signatures-section" th:if="${not #lists.isEmpty(signatures)}">
<!-- Preview Modal -->
@ -134,7 +134,7 @@
</div>
</div>
<div class="tab-container" th:title="#{sign.text}" th:data-title="#{sign.text}">
<div class="tab-container" th:data-title="#{sign.text}">
<label class="form-check-label" for="sigText" th:text="#{text}"></label>
<textarea class="form-control" id="sigText" name="sigText" rows="3"></textarea>
<label th:text="#{font}"></label>