Handle the case where all the image data are in the alpha channel (bug 1975719)

and add an error message in case where there is no data in the image.
This commit is contained in:
Calixte Denizet 2025-07-04 16:36:02 +02:00
parent 2d0ba7db08
commit 6f8796d2c8
6 changed files with 86 additions and 19 deletions

View File

@ -614,6 +614,8 @@ pdfjs-editor-add-signature-save-checkbox = Save signature
pdfjs-editor-add-signature-save-warning-message = Youve reached the limit of 5 saved signatures. Remove one to save more. pdfjs-editor-add-signature-save-warning-message = Youve reached the limit of 5 saved signatures. Remove one to save more.
pdfjs-editor-add-signature-image-upload-error-title = Couldnt upload image pdfjs-editor-add-signature-image-upload-error-title = Couldnt upload image
pdfjs-editor-add-signature-image-upload-error-description = Check your network connection or try another image. pdfjs-editor-add-signature-image-upload-error-description = Check your network connection or try another image.
pdfjs-editor-add-signature-image-no-data-error-title = Cant convert this image into a signature
pdfjs-editor-add-signature-image-no-data-error-description = Please try uploading a different image.
pdfjs-editor-add-signature-error-close-button = Close pdfjs-editor-add-signature-error-close-button = Close
## Dialog buttons ## Dialog buttons

View File

@ -366,21 +366,12 @@ class SignatureExtractor {
let max = -Infinity; let max = -Infinity;
let min = Infinity; let min = Infinity;
for (let i = 0, ii = out.length; i < ii; i++) { for (let i = 0, ii = out.length; i < ii; i++) {
const A = buf[(i << 2) + 3];
if (A === 0) {
max = out[i] = 0xff;
continue;
}
const pix = (out[i] = buf[i << 2]); const pix = (out[i] = buf[i << 2]);
if (pix > max) { max = Math.max(max, pix);
max = pix; min = Math.min(min, pix);
}
if (pix < min) {
min = pix;
}
} }
const ratio = 255 / (max - min); const ratio = 255 / (max - min);
for (let i = 0; i < N; i++) { for (let i = 0, ii = out.length; i < ii; i++) {
out[i] = (out[i] - min) * ratio; out[i] = (out[i] - min) * ratio;
} }
@ -468,6 +459,8 @@ class SignatureExtractor {
} }
const offscreen = new OffscreenCanvas(newWidth, newHeight); const offscreen = new OffscreenCanvas(newWidth, newHeight);
const ctx = offscreen.getContext("2d", { willReadFrequently: true }); const ctx = offscreen.getContext("2d", { willReadFrequently: true });
ctx.fillStyle = "white";
ctx.fillRect(0, 0, newWidth, newHeight);
ctx.filter = "grayscale(1)"; ctx.filter = "grayscale(1)";
ctx.drawImage( ctx.drawImage(
bitmap, bitmap,

View File

@ -718,4 +718,47 @@ describe("Signature Editor", () => {
); );
}); });
}); });
describe("Bug 1975719", () => {
let pages;
beforeEach(async () => {
pages = await loadAndWait("empty.pdf", ".annotationEditorLayer");
});
afterEach(async () => {
await closePages(pages);
});
it("must check that an error is displayed with a monochrome image", async () => {
await Promise.all(
pages.map(async ([_, page]) => {
await switchToSignature(page);
await page.click("#editorSignatureAddSignature");
await page.waitForSelector("#addSignatureDialog", {
visible: true,
});
await page.click("#addSignatureImageButton");
await page.waitForSelector("#addSignatureImagePlaceholder", {
visible: true,
});
const input = await page.$("#addSignatureFilePicker");
await input.uploadFile(
`${path.join(__dirname, "../images/red.png")}`
);
await page.waitForSelector("#addSignatureError", { visible: true });
await page.waitForSelector(
"#addSignatureErrorTitle[data-l10n-id='pdfjs-editor-add-signature-image-no-data-error-title']"
);
await page.waitForSelector(
"#addSignatureErrorDescription[data-l10n-id='pdfjs-editor-add-signature-image-no-data-error-description']"
);
await page.click("#addSignatureErrorCloseButton");
await page.waitForSelector("#addSignatureError", { visible: false });
})
);
});
});
}); });

View File

@ -56,6 +56,10 @@ class SignatureManager {
#errorBar; #errorBar;
#errorDescription;
#errorTitle;
#extractedSignatureData = null; #extractedSignatureData = null;
#imagePath = null; #imagePath = null;
@ -123,6 +127,8 @@ class SignatureManager {
addButton, addButton,
errorCloseButton, errorCloseButton,
errorBar, errorBar,
errorTitle,
errorDescription,
saveCheckbox, saveCheckbox,
saveContainer, saveContainer,
}, },
@ -142,6 +148,8 @@ class SignatureManager {
this.#drawPlaceholder = drawPlaceholder; this.#drawPlaceholder = drawPlaceholder;
this.#drawThickness = drawThickness; this.#drawThickness = drawThickness;
this.#errorBar = errorBar; this.#errorBar = errorBar;
this.#errorTitle = errorTitle;
this.#errorDescription = errorDescription;
this.#imageSVG = imageSVG; this.#imageSVG = imageSVG;
this.#imagePlaceholder = imagePlaceholder; this.#imagePlaceholder = imagePlaceholder;
this.#imagePicker = imagePicker; this.#imagePicker = imagePicker;
@ -161,6 +169,12 @@ class SignatureManager {
SignatureManager.#l10nDescription ||= Object.freeze({ SignatureManager.#l10nDescription ||= Object.freeze({
signature: "pdfjs-editor-add-signature-description-default-when-drawing", signature: "pdfjs-editor-add-signature-description-default-when-drawing",
errorUploadTitle: "pdfjs-editor-add-signature-image-upload-error-title",
errorUploadDescription:
"pdfjs-editor-add-signature-image-upload-error-description",
errorNoDataTitle: "pdfjs-editor-add-signature-image-no-data-error-title",
errorNoDataDescription:
"pdfjs-editor-add-signature-image-no-data-error-description",
}); });
dialog.addEventListener("close", this.#close.bind(this)); dialog.addEventListener("close", this.#close.bind(this));
@ -506,6 +520,18 @@ class SignatureManager {
); );
} }
#showError(type) {
this.#errorTitle.setAttribute(
"data-l10n-id",
SignatureManager.#l10nDescription[`error${type}Title`]
);
this.#errorDescription.setAttribute(
"data-l10n-id",
SignatureManager.#l10nDescription[`error${type}Description`]
);
this.#errorBar.hidden = false;
}
#initImageTab(reset) { #initImageTab(reset) {
if (reset) { if (reset) {
this.#resetTab("image"); this.#resetTab("image");
@ -539,7 +565,7 @@ class SignatureManager {
async () => { async () => {
const file = this.#imagePicker.files?.[0]; const file = this.#imagePicker.files?.[0];
if (!file || !SupportedImageMimeTypes.includes(file.type)) { if (!file || !SupportedImageMimeTypes.includes(file.type)) {
this.#errorBar.hidden = false; this.#showError("Upload");
this.#dialog.classList.toggle("waiting", false); this.#dialog.classList.toggle("waiting", false);
return; return;
} }
@ -601,18 +627,19 @@ class SignatureManager {
console.error("SignatureManager.#extractSignature.", e); console.error("SignatureManager.#extractSignature.", e);
} }
if (!data) { if (!data) {
this.#errorBar.hidden = false; this.#showError("Upload");
this.#dialog.classList.toggle("waiting", false); this.#dialog.classList.toggle("waiting", false);
return; return;
} }
const { outline } = (this.#extractedSignatureData = const lineData = (this.#extractedSignatureData =
this.#currentEditor.getFromImage(data.bitmap)); this.#currentEditor.getFromImage(data.bitmap));
if (!lineData) {
if (!outline) { this.#showError("NoData");
this.#dialog.classList.toggle("waiting", false); this.#dialog.classList.toggle("waiting", false);
return; return;
} }
const { outline } = lineData;
this.#imagePlaceholder.hidden = true; this.#imagePlaceholder.hidden = true;
this.#disableButtons(true); this.#disableButtons(true);

View File

@ -735,8 +735,8 @@ See https://github.com/adobe-type-tools/cmap-resources
<div id="addSignatureError" hidden="true" class="messageBar"> <div id="addSignatureError" hidden="true" class="messageBar">
<div> <div>
<div> <div>
<span class="title" data-l10n-id="pdfjs-editor-add-signature-image-upload-error-title"></span> <span id="addSignatureErrorTitle" class="title" data-l10n-id="pdfjs-editor-add-signature-image-upload-error-title"></span>
<span class="description" data-l10n-id="pdfjs-editor-add-signature-image-upload-error-description"></span> <span id="addSignatureErrorDescription" class="description" data-l10n-id="pdfjs-editor-add-signature-image-upload-error-description"></span>
</div> </div>
<button id="addSignatureErrorCloseButton" class="closeButton" type="button" tabindex="0"><span data-l10n-id="pdfjs-editor-add-signature-error-close-button"></span></button> <button id="addSignatureErrorCloseButton" class="closeButton" type="button" tabindex="0"><span data-l10n-id="pdfjs-editor-add-signature-error-close-button"></span></button>
</div> </div>

View File

@ -227,6 +227,8 @@ function getViewerConfiguration() {
saveContainer: document.getElementById("addSignatureSaveContainer"), saveContainer: document.getElementById("addSignatureSaveContainer"),
saveCheckbox: document.getElementById("addSignatureSaveCheckbox"), saveCheckbox: document.getElementById("addSignatureSaveCheckbox"),
errorBar: document.getElementById("addSignatureError"), errorBar: document.getElementById("addSignatureError"),
errorTitle: document.getElementById("addSignatureErrorTitle"),
errorDescription: document.getElementById("addSignatureErrorDescription"),
errorCloseButton: document.getElementById("addSignatureErrorCloseButton"), errorCloseButton: document.getElementById("addSignatureErrorCloseButton"),
cancelButton: document.getElementById("addSignatureCancelButton"), cancelButton: document.getElementById("addSignatureCancelButton"),
addButton: document.getElementById("addSignatureAddButton"), addButton: document.getElementById("addSignatureAddButton"),