Issue
I have an image approximately 8000x4000 pixels. This image is broken up into blobs of colour.
Here is an example of part of the image to show what it looks like:
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 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. 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. How would I replace all pixels of a specific RGB in a PNG with another RGB in javascript?
Solution
As you already figured yourself to be able to manipulate an image 'on the fly' you have to paint it onto a html <canvas>
element first. On the other hand Leaflet's imageOverlay()
method expects an URL to an actual image - so the manipulated canvas alone won't bring you too far.
There's hope though. The canvas object offers a method called toDataURL()
which returns something you can feed into imageOverlay()
.
Let's break-down what you'll have to do:
- Create an empty Image and use it to load your map
- If loading of the image finished, create a canvas the size of your image
- Draw the image to the canvas
- Loop over the canvas' image data obtained via
ctx.getImageData()
. This will return a large array of red, green, blue and alpha values for each pixel in the canvas. As yourcolour_mapping
object consists of hex values e.g. #4dc8c8, we first need to convert the rgb values to hex to be able to look up the object for a match. If we found a match, get the replacement color and convert the hex value to rgb to ultimately change the color. - Draw the manipulated image data onto the canvas.
- Get the data URL using
toDataURL()
and finally callimageOverlay()
.
Here's an example showcasing the replacement of two colors by white:
var map = L.map('map').setView([0.5, 0.5], 9);
var imageUrl = './js/UAZyt.png';
imageUrl = "https://corsproxy.io/?https://i.stack.imgur.com/UAZyt.png"
let image = new Image();
image.crossOrigin = "anonymous"
image.onload = (e) => {
imageBounds = [
[0, 0],
[1, 1]
];
let canvas = document.createElement("canvas");
let ctx = canvas.getContext("2d");
canvas.width = e.target.naturalWidth;
canvas.height = e.target.naturalHeight;
ctx.drawImage(e.target, 0, 0);
let colour_mapping = {
'#4dc8c8': '#ffffff',
'#be8eff': '#ffffff'
};
let imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
let r, g, b, hex, hex2;
for (let a = 0; a < imageData.data.length; a += 4) {
r = imageData.data[a];
g = imageData.data[a + 1];
b = imageData.data[a + 2];
hex = "#" + ((r << 16) | (g << 8) | b).toString(16);
if (colour_mapping[hex]) {
hex2 = colour_mapping[hex].match(/[0-9a-f]{2}/g);
imageData.data[a] = parseInt(hex2[0], 16);
imageData.data[a + 1] = parseInt(hex2[1], 16);
imageData.data[a + 2] = parseInt(hex2[2], 16);
}
}
ctx.putImageData(imageData, 0, 0);
L.imageOverlay(canvas.toDataURL(), imageBounds).addTo(map);
}
image.src = imageUrl;
#map {
height: 360px;
}
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<div id="map"></div>
Answered By - obscure
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.