Imported base64 Signatures are low quality

Product: pdftron

Product Version: 8.7.0

Please give a brief summary of your issue:
(Think of this as an email subject)

i am working in a project with laravel/vue, i export the signature created in the signature tool as base 64 images to a database using the examples provided in the official documentation, then i import the using the same code in the docs but when i do i have two problems, the image that is loaded is pale while in preview, and blurry when used, also you can no longer change the color to the signature just change the opacity, with new signatures everything works normal but for imported one it doesn’t, after some testing with a base64 to image decoder i found out that the exported images are blurry and since that is what i pass to the functions they look that way when imported i’ll post the code used here and some images for demostration

const viewerElement = document.getElementById('webviewer');

        WebViewer({
            path: '/js/WebViewer/lib',
            initialDoc: this.initialDoc,
            extension: 'pdf',
        }, viewerElement)
            .then((instance) => {

                const { documentViewer, annotationManager } = instance.Core;

                const signatureTool = documentViewer.getTool('AnnotationCreateSignature');

                documentViewer.addEventListener('documentLoaded', () => {

                    instance.UI.setLanguage(that.locale);

                    let signatures = JSON.parse(that.savedSignatures);

                    signatures = signatures.map(a => a.base64_signature);

                    signatureTool.importSignatures(["data:image/png;base64, " + signatures[0]]); //base64 images array

                    document.getElementById('app').setAttribute('style', 'padding: 0');
                    document.getElementById('loader-container').classList.add('d-none');
                    document.getElementById('all-pages-content').removeAttribute('style')
                    document.getElementById('downloadButton').setAttribute('style', 'visibility: visible')
                    document.getElementById('pdf-ui').setAttribute('style', 'visibility: visible')

                });

                documentViewer.addEventListener('annotationsLoaded', async () => {
                    annotationManager.addEventListener('annotationDrawn', async (annotationList) => {
                        console.log('1')
                        annotationList.forEach(annotation => {
                            if (annotation.Subject === "Signature")
                                that.extractAnnotationSignature(annotation, documentViewer);
                        })
                    })
                });

                let saveSignedPdf = document.getElementById('downloadButton');

                saveSignedPdf.addEventListener('click', async () => {

                    console.log('control')

                    const doc = documentViewer.getDocument();
                    const xfdfString = await annotationManager.exportAnnotations();
                    const data = await doc.getFileData({
                        // saves the document with annotations in it
                        xfdfString
                    });
                    const arr = new Uint8Array(data);
                    const blob = new Blob([arr], {type: 'application/pdf'});

                    await that.processDocument(blob)
                    // Add code for handling Blob here
                })

                // instance.disableElements(['downloadButton', 'printButton']);
                // instance.disableElements(['toolbarGroup-Insert']);

                return instance
            });
    },
    methods:{
        async processDocument(blob, tool='') {

            let passwordFile = "";

            let that = this;

            Swal.fire({
                title: this.messages.notifications.processing,
                html: this.messages.notifications.saving_changes,
                willOpen: async () => {
                    Swal.showLoading();

                    let formData = new FormData();
                    formData.append('files', blob);
                    formData.append('fileName', that.filename);
                    formData.append('passwordFile', passwordFile);
                    formData.append('website_id', that.websiteId);
                    formData.append('customer_id', that.customerId);
                    formData.append('locale', that.locale);
                    formData.append('pdf_service_id', that.pdfServiceId);
                    if (tool) formData.append('other_tool', tool);

                    const config = {
                        headers: {
                            'content-type': 'multipart/form-data',
                            'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content,
                        }
                    }

                    await axios.post(that.processDocumentUrl, formData, config)
                        .then(function (response) {
                            if (!response.data.success) {
                                return Swal.fire({
                                    icon: "error",
                                    title: that.messages.notifications.error,
                                    text: that.messages.notifications.error_text,
                                });
                            }
                            let link = document.createElement('a')
                            link.href = window.URL.createObjectURL(blob);
                            link.download = that.filename;
                            link.click()
                            window.location.href = response.data.data.redirectionUrl;
                        })
                        .catch(function (error) {
                            that.output = error;
                            console.log("could not reach backend")
                        });
                },
                showConfirmButton: false,
                allowOutsideClick: false
            });
        },
        async extractAnnotationSignature(annotation, docViewer) {

            let that = this;
            // Create a new Canvas to draw the Annotation on
            const canvas = document.createElement('canvas');
            // Reference the annotation from the Document
            const pageMatrix = docViewer.getDocument().getPageMatrix(annotation.PageNumber);
            // Set the height & width of the canvas to match the annotation
            canvas.height = annotation.Height;
            canvas.width = annotation.Width;
            const ctx = canvas.getContext('2d');
            // Translate the Annotation to the top Top Left Corner of the Canvas ie (0, 0)
            ctx.translate(-annotation.X, -annotation.Y);
            // Draw the Annotation onto the Canvas
            annotation.draw(ctx, pageMatrix);
            // Convert the Canvas to a Blob Object for Upload
            canvas.toBlob((blob) => {

                let formData = new FormData();
                formData.append('signature', blob);
                formData.append('customer_id', that.customerId);

                const config = {
                    headers: {
                        'content-type': 'multipart/form-data',
                        'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content,
                    }
                }

                axios.post(that.saveSignatureUrl, formData, config)
                    .then(function (response) {
                        if (!response.data.success) {
                            console.log("could not save signature for future use")
                        }
                        else {
                            console.log("saved signature for future use")
                        }
                    })
                    .catch(function (error) {
                        that.output = error;
                        console.log("could not reach backend")
                    });
            });
        }
    }

in the web demos and other sites that uses pdftron like smallpdf this issue doesn’t happen so if you can help me it would be greatly appreciated

here is the base64 string for the blurry signature

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

Please describe your issue and provide steps to reproduce it:
(The more descriptive your answer, the faster we are able to help you)

Please provide a link to a minimal sample where the issue is reproducible:

Hi,

Thank you for reporting this issue.
We will investigate and let you know when we have further information.

Wanbo

Hi,

Do you mean the same code works with our demo website?

Wanbo

what I mean is that the code in the example exports signatures in base64 strings like the one I posted in this thread which result in the signature tool to display the signature as a poor quality signature that can not be manipulated because is a static image not an object whose properties can be changed, which makes no sense at all to say the least, instead you should have used the exportSignatures function in that example and explain the difference in results you get when using base64 strings and array of path points, in my case i’m saving signatures in this way

[[[{“x”:41.45077720207254,“y”:1.0362694300518136},{“x”:39.37823834196891,“y”:7.253886010362695},{“x”:35.233160621761655,“y”:15.544041450777204},{“x”:22.797927461139896,“y”:37.30569948186529},{“x”:8.290155440414507,“y”:63.21243523316063},{“x”:1.0362694300518134,“y”:76.68393782383421},{“x”:1.0362694300518134,“y”:77.72020725388602},{“x”:3.10880829015544,“y”:77.72020725388602},{“x”:8.290155440414507,“y”:77.72020725388602},{“x”:21.761658031088082,“y”:67.35751295336789},{“x”:50.777202072538856,“y”:53.88601036269431},{“x”:90.15544041450777,“y”:41.450777202072544},{“x”:95.33678756476684,“y”:39.37823834196892},{“x”:97.40932642487046,“y”:39.37823834196892},{“x”:97.40932642487046,“y”:40.41450777202073},{“x”:93.2642487046632,“y”:49.74093264248705},{“x”:83.93782383419688,“y”:66.32124352331607},{“x”:79.79274611398964,“y”:72.53886010362694},{“x”:73.57512953367875,“y”:79.79274611398965},{“x”:75.64766839378238,“y”:79.79274611398965},{“x”:80.82901554404144,“y”:76.68393782383421},{“x”:97.40932642487046,“y”:65.28497409326425},{“x”:112.95336787564766,“y”:60.10362694300519},{“x”:140.93264248704662,“y”:52.84974093264249},{“x”:143.00518134715026,“y”:52.84974093264249},{“x”:143.00518134715026,“y”:58.03108808290156},{“x”:143.00518134715026,“y”:60.10362694300519},{“x”:143.00518134715026,“y”:61.139896373057},{“x”:145.07772020725386,“y”:61.139896373057},{“x”:163.7305699481865,“y”:55.958549222797934},{“x”:180.31088082901553,“y”:47.668393782383426},{“x”:189.63730569948186,“y”:41.450777202072544},{“x”:197.92746113989637,“y”:33.160621761658035},{“x”:198.96373056994815,“y”:30.051813471502594}]]]

because when this string is provided to the signature tool it renders the signature as a high quality object that can be manipulated as it should be, but that is something i had to research on the API docs because the example gave me a code that “works” but with bad results, so please fix that mistake because other people that is not familiar with this kind of API’s or programming will spend several hours trying to figure out what they did wrong when the problem is not then but the code provided by the example

Thanks for the feedback, I have created a ticket in our backlog to improve the documentation.

Wanbo