2

I have an image approximately 8000x4000 pixels which I want to plot using leaflet. This image is broken up into blobs of unique colour, each representing a region.

Here is an example of part of the image to show what it looks like:

an example of a section of image

I'm able to plot the image using leaflet pretty trivially:

var map = L.map('map', {
    crs: L.CRS.Simple,
    minZoom: -2
});

var bounds = [[0,0], [3616,8192]];

var provinces = L.imageOverlay(
    'myimage.png', 
    bounds, 
    {opacity: 0.7}
).addTo(map);

I have a translation object for recolouring the image, and I want to use it to transform all pixels of a specific colour to pixels of a different specific colour. The reason is so that I can make heatmaps, based on attributes in each region. This is the problem I need help with.

var colour_mapping = {'#4287f5':'#42f5ef', '#a3911c':'#de3510', ...}

I've seen answers on stack overflow detailing how to change specific pixels of a canvas, but I don't know how best to achieve the effect working within Leaflet.

i.e. https://stackoverflow.com/questions/60415024/how-would-i-replace-all-pixels-of-a-specific-rgb-in-a-png-with-another-rgb-in-ja

4
  • How do you intend to deal with borders between blobs, where there is no clean color but pixels of mixed colors from neighboring blobs?
    – TomazicM
    Jan 11 at 16:24
  • The png itself does not have mixed colours, if that is what you're asking. If you instead mean that once plotted in leaflet the colours are blended then ideally it would blend between the two target colours, but if that is too difficult then draw such pixels as black, and failing that ignore them entirely as an excusable edge case. Jan 11 at 16:42
  • Can you provide a sample of such PNG, so I can do some testing?
    – TomazicM
    Jan 11 at 16:47
  • Sure thing, the specific png used is here: gitlab.com/anbennar/anbennar-vicky3-dev/-/blob/main/map_data/… Jan 11 at 16:50

1 Answer 1

1

Image pixell can be recolored by first loading image to canvas, changing colors there and then converting canvas to data URL with canvas.toDataURL() method and then loading image overlay from data URL.

Code for converting two colors #36A036 and #42DF86 to red could then look something like this (gathered from various answers on StackOverflow site):

async function loadImage(url) {
  return new Promise(r => { let i = new Image(); i.onload = (() => r(i)); i.src = url; });
}

function replaceColor(canvas, ctx, src, dst) {
  const im = ctx.getImageData(0, 0, canvas.width, canvas.height);
  for (var i = 0; i < im.data.length; i += 4) {
    if (
      im.data[i] === src[0] &&
      im.data[i + 1] === src[1] &&
      im.data[i + 2] === src[2]
    ) {
      im.data[i] = dst[0];
      im.data[i + 1] = dst[1];
      im.data[i + 2] = dst[2];
    }
  }
  ctx.putImageData(im, 0, 0);
}

function convertToRGB(hexColor){
  var aRgbHex = hexColor.match(/.{1,2}/g);
  var aRgb = [
    parseInt(aRgbHex[0], 16),
    parseInt(aRgbHex[1], 16),
    parseInt(aRgbHex[2], 16)
  ];
  return aRgb;
}

loadImage('data/image-layer.png').then(function(img) {
  const canvas = document.createElement('canvas');
  canvas.width = img.width;
  canvas.height = img.height;
  const ctx = canvas.getContext('2d');
  ctx.drawImage(img, 0, 0);
  replaceColor(canvas, ctx, convertToRGB('36A036'), [255, 0, 0]);
  replaceColor(canvas, ctx, convertToRGB('42DF86'), [255, 0, 0]);
  const imageDataURL = canvas.toDataURL();
  const imageOverlay = L.imageOverlay(imageDataURL, [[29.0, -118.2],[29.1, -118.4]]);
  imageOverlay.addTo(map);
});

With this code the following image overlay

enter image description here

is converted to

enter image description here

3
  • What method were you using to test this? I'm getting the error "Uncaught (in promise) DOMException: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The canvas has been tainted by cross-origin data." Jan 11 at 21:02
  • Since image canvas gets modified, source of the image has to be CORS enabled for the client retrieving the image. In my case image was on the same server as web app, so no such problems for me.
    – TomazicM
    Jan 11 at 21:06
  • I'm going to have to read up on CORS to understand what you mean by that, however it's a separate issue so I'll accept this answer, thank you. Jan 11 at 21:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.