[SalesForce] Trying to resize image using canvas in a lightning component with locker service

The Component:

<aura:component implements="force:appHostable" controller="Lightning_image_controller">
    <aura:attribute name="imagedata" type="string"></aura:attribute>
    <input type="file" aura:id="file" accept="image/*" onchange="{!c.resize}"/>
    <img src="{!v.imagedata}" />
</aura:component>

so basically, you select an image file and it gets resized.

Controller:

({
    resize : function(component, event, helper){
        helper.resize(component, event, function(r){
            component.set("v.imagedata", r);
        });
    }
})

Helper:

({  
    resize: function(component, event, cb){
        var finput = component.find('file').getElement();
        var imgfile = finput.files[0];`
        var reader = new FileReader()
        reader.addEventListener("load",function(evt){
            var isrc = evt.target.result;
            var image = new Image();
            image.addEventListener("load",function(){
                var canvas = document.createElement('canvas');
                var ctx = canvas.getContext('2d');
                ctx.clearRect(0,0,canvas.width,canvas.height);
                canvas.width = 100;
                canvas.height = 100;
                ctx.drawImage(image, 0,0,100,100);
                var idata = ctx.canvas.toDataURL().toString();
                cb(idata);
            });
            image.src = isrc;
        });
        reader.readAsDataURL(imgfile);
    }  
})

This worked fine before locker service. Now I get an error:

Uncaught TypeError: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The provided value is not of type '(CSSImageValue or HTMLImageElement or HTMLVideoElement or HTMLCanvasElement or ImageBitmap or OffscreenCanvas)'

It seems the proxy object is being passed to drawImage instead. I've tried creating an img object, ImageBitmap,… but proxy gets passed. I've also tried creating img and appending to the document and call component.find('id').getElement(), which i thought should return the element.

It seems everything now is wrapped up in the proxy object. Any ideas on what I'm doing wrong? This is a good way to end friday… thanks

Best Answer

This issue is occurring in a few areas with LockerService: various browser APIs are not expecting a Proxy() object.

As Scott Morisson explains, using Proxy() is part of the design of LockerService, but that should not prevent legitimate use cases. Maybe the context needs to be proxied too, so the drawImage method can unwrap the proxy and pass the raw value to the method.

There is no solution at this point other than set your component to version 39 in order to disable LockerService on that component.

Related Topic