5

I'm using the script below to get the most dominant color of an image, but Salesforce doesn't allow me to read the content image from Javascript due to CORS policy. Do you know how i could achieve this ?

BROWSER ERROR

enter image description here NB : The image is loaded as an Attachment object from Apex.

component.cmp

<aura:component>

  <div aura:id="header" class="heading" >
     <div id="content>
      </div>
  </div>
<c:UtilsComponent aura:id="utilities"/>
</aura:component>

componentRender.js

({
    render :  function(cmp, helper){

        this.superRender();

        if(cmp.isValid()){

            setTimeout($A.getCallback(function(){

                var utils = cmp.find('utilities');
                var primeColor = utils.getImagePrimeColor();
                var rgba = '#' + String(primeColor.r) + String(primeColor.g) + String(primeColor.b) + String(primeColor.a);
                console.log(rgba);
                var header = cmp.find('header').getElement();
                header.style.setProperty('background', 'linear-gradient(to left, transparent, ' + rgba + '), url(' + cmp.get('v.thumbnail') + ') no-repeat center')
                header.style.setProperty('background-size', 'cover');

            },500));
        }
    }

})

UtilsComponentController.js

    getPrimeColorFromImage : function(component, event, helper){

            var imgSrc = '/servlet/servlet.FileDownload?file=00P0X00001Z4DPIUA3';
            var src = imgSrc;

            var imgEl = new Image;
            imgEl.crossOrigin = ''; 
            imgEl.src = src;

            var blockSize = 5, // only visit every 5 pixels
                defaultRGB = {r:0,g:0,b:0}, // for non-supporting envs
                canvas = document.createElement('canvas'),
                context = canvas.getContext && canvas.getContext('2d'),
                data, width, height,
                i = -4,
                length,
                rgb = {r:0,g:0,b:0},
                count = 0;

            if (!context) {
                return defaultRGB;
            }

            height = canvas.height = imgEl.naturalHeight || imgEl.offsetHeight || imgEl.height;
            width = canvas.width = imgEl.naturalWidth || imgEl.offsetWidth || imgEl.width;

            context.drawImage(imgEl, 0, 0);

            try {
                data = context.getImageData(0, 0, width, height);
            } catch(e) {
                /* security error, img on diff domain */
                return defaultRGB;
            }

            length = data.data.length;

            while ( (i += blockSize * 4) < length ) {
                ++count;
                rgb.r += data.data[i];
                rgb.g += data.data[i+1];
                rgb.b += data.data[i+2];
            }

            // ~~ used to floor values
            rgb.r = ~~(rgb.r/count);
            rgb.g = ~~(rgb.g/count);
            rgb.b = ~~(rgb.b/count);

            return rgb;

        }
2
  • Could you include all of the code related to the lightning component? Also, where is this component being hosted (internally, in a community, etc.)? Commented Jul 5, 2019 at 18:11
  • i've édited the question with your requirements. It's a simple component that i'm testing on my dev org. The getPrimeColorFroImage() function executes well but the exception is throw because of CORS policy from Salesforce although the image is actually stored on my dev org database...
    – Bryce
    Commented Jul 5, 2019 at 19:06

1 Answer 1

4

This is a restriction not related to Lighting CORS; all browsers block this sort of behavior to protect against various security exploits. Instead, call a server action and retrieve the file in Apex, then process the results client-side.


Example:

Controller

doInit: function(c, e, h) {
  var a = component.get("c.getImage");
  a.setParams({ attachmentId: "00P0X00001Z4DPIUA3" });
  a.setCallback(response => h.getPrimeColorFromImage(response.getReturnValue(), c);
  $A.enqueueAction(a);
}

Helper

getPrimeColorFromImage(data, c) {
  var image = new Image();
  image.src = data;
  // rest of code //
}

Apex

@AuraEnabled public static String getImage(Id attachmentId) {
  Attachment a = [SELECT Body, ContentType FROM Attachment WHERE Id = :attachmenetId];
  return 'data:'+a.contenttype+';base64,'+EncodingUtil.base64Encode(a.Body);
}
3
  • Just try this and the browser still block access to the image with cors policy. I've edited the question with a screen of the browser error...the CORS exception is throw at this instruction imgEl.src = src ;
    – Bryce
    Commented Jul 5, 2019 at 19:27
  • 1
    @Bryce I added some snippets of what I'm advocating--you need to call Apex, and in Apex return base64 data (which I also made a full data URL for ease of use, then render that src, and from there, you can do as you like.
    – sfdcfox
    Commented Jul 5, 2019 at 19:41
  • This works perferctly! Thank you very much for your help @sfdcfox
    – Bryce
    Commented Jul 5, 2019 at 21:07

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .