TransWikia.com

Javascript Compression in LWC

Salesforce Asked on November 13, 2021

I have a very simple LWC that I am trying to use to compress image files (that happen to be Salesforce attachments). Here is the complete JS:

    import { LightningElement, api } from 'lwc';

export default class ImageCompressor extends LightningElement {

    statusMessage = 'Ready';    // String
    
    constructor() {
        super();
    }

    @api compressImage(imageURL) {

        let img = new Image();
        img.addEventListener('load', function() {
            debugger;
            let canvas = document.createElement('canvas');
            let width = img.width;
            let height = img.height;
            canvas.width = width;
            canvas.height = height;
            let ctx = canvas.getContext("2d");
            ctx.drawImage(img, 0, 0, width, height);
            let compressedImage = canvas.toDataURL('image/jpeg', 0.5);
            this.statusMessage = 'Compression complete';
            const e = new CustomEvent('compressioncomplete', { detail: compressedImage, bubbles: true });
            this.dispatchEvent(e);    
        }, false);        
        img.src = imageURL;
        this.statusMessage = 'Compression started.'
        debugger;
    }

}

I invoke it via its api method in a parent LWC component, passing in the URL of an attachment file:

    compressHandler() {
    let url = this.getImageURL(this.imageList[1].Id);
    debugger;
    this.template.querySelector('c-image-compressor').compressImage(url);
    }

    getImageURL(imageId) {
    return '/servlet/servlet.FileDownload?file=' + imageId;
}

It looks like the code is working fine (the image appears to load OK) but the script errors out at the canvas.toDataURL() line. Hard to interpret the error but everything is working until this line executes.

Any thoughts? Thanks for your help!

2 Answers

In case someone is looking to compress image on client side before uploading to salesforce. Apex getter is not used here. "handleUploadFile()" is called on change event of lightning-input component

handleUploadFile(event) {
    const file = event.target.files[0]

    let img = new Image();
    img.onload = () => {
        debugger;
        let canvas = document.createElement('canvas');
        let width = img.width;
        let height = img.height;
        canvas.width = width;
        canvas.height = height;
        let ctx = canvas.getContext("2d");
        ctx.drawImage(img, 0, 0, width, height);
        let compressedImage = canvas.toDataURL('image/jpeg', 0.5);
        this.statusMessage = 'Compression complete';
        var base64 = compressedImage.split(',')[1];
        this.fileData = {
            'filename': file.name,
            'base64': base64,
            'recordId': this.recordId
        }
  // Call apex imperatively here to upload the image to the desired record
        console.log(this.fileData)

    }
    img.src = URL.createObjectURL(file);
    this.statusMessage = 'Compression started.'
}

Answered by Abhijeet on November 13, 2021

I figured it out. I created a an apex getter that returns the image body as a base64 string and then I use a data URI when constructing the image object.

Does not fall foul of security and works like a charm, even for multi-megabyte files.

Answered by Dave C on November 13, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP