If I load an image, how can I loop through all its pixels and turn the white ones (or which ever color I specify) to be turned transparent?
I have an idea on how to
Its pretty simple to do using getImageData
and putImageData
just note you can take a pretty significant hit on performance the larger the image gets. You just need to determine if the current pixel is white, then change its alpha to 0.
Live Demo
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
image = document.getElementById("testImage");
canvas.height = canvas.width = 135;
ctx.drawImage(image,0,0);
var imgd = ctx.getImageData(0, 0, 135, 135),
pix = imgd.data,
newColor = {r:0,g:0,b:0, a:0};
for (var i = 0, n = pix.length; i <n; i += 4) {
var r = pix[i],
g = pix[i+1],
b = pix[i+2];
// If its white then change it
if(r == 255 && g == 255 && b == 255){
// Change the white to whatever.
pix[i] = newColor.r;
pix[i+1] = newColor.g;
pix[i+2] = newColor.b;
pix[i+3] = newColor.a;
}
}
ctx.putImageData(imgd, 0, 0);
It was also asked if you could make the values sort of fuzzy to check. Its really easy, just check if its in a certain range. The following will turn off white to pure white transparent.
// If its white or close then change it
if(r >=230 && g >= 230 && b >= 230){
// Change the white to whatever.
pix[i] = newColor.r;
pix[i+1] = newColor.g;
pix[i+2] = newColor.b;
pix[i+3] = newColor.a;
}
More resources
Loktar may have a method that 'works', but it's performance is rather dismal. This can be a problem if you have lots of images, you don't want your website to drain laptop/mobile-devices batteries, or if you just want speed. Here is a method that works far more efficiently. Click on the "Run Code Snippet" button for a demo of it in action.
'use-strict'
let fileInput = document.getElementById('fileInput'),
theCANVAS = document.getElementById('theCanvas'),
theCANVASctx = theCANVAS.getContext('2d'),
imgTMP = document.getElementById('imgTMP'),
rComponent = document.getElementById('r'),
gComponent = document.getElementById('g'),
bComponent = document.getElementById('b'),
aComponent = document.getElementById('a'),
transColor = "rgba(255, 255, 255, 1)",
transCode = 0xffffffff;
let makeColorTransparent =
function(canvasContext, transparentID, width, height) {
// where all the magic happens
let theImageData = canvasContext.getImageData(0, 0, width, height),
theImageDataBufferTMP = new ArrayBuffer(theImageData.data.length),
theImageDataClamped8TMP = new Uint8ClampedArray(theImageDataBufferTMP),
theImageDataUint32TMP = new Uint32Array(theImageDataBufferTMP),
n = theImageDataUint32TMP.length;
theImageDataClamped8TMP.set(theImageData.data);
imgDataLoop: while (n--) {
// effciency at its finest:
if (theImageDataUint32TMP[n] !== transparentID)
continue imgDataLoop;
theImageDataUint32TMP[n] = 0x00000000; // make it transparent
}
theImageData.data.set(theImageDataClamped8TMP);
theCANVASctx.putImageData(theImageData, 0, 0);
},
downloadCanvas = function(downloadfilename) {
theCanvas.toBlob(function(theIMGblob) {
var thedataURL = URL.createObjectURL(theIMGblob),
theAtagLink = document.createElement('a');
theAtagLink.download = '(proccessed)' + downloadfilename;
document.body.appendChild(theAtagLink);
theAtagLink.href = thedataURL;
theAtagLink.click();
});
};
fileInput.onchange = function(fileevent) {
let efiles = fileevent.target.files,
localTransColor = transColor,
localTransCode = transCode;
let cur = efiles.length,
nextfile = function() {
if (!cur--) {
imgTMP.src = '';
return;
}
let fr = new FileReader();
console.log(efiles[cur]);
fr.onload = function(dataevt) {
fr.onload = null;
let theArrayBuffer = dataevt.target.result,
theblob = new Blob([theArrayBuffer]);
imgTMP.src = URL.createObjectURL(theblob);
imgTMP.onload = function() {
imgTMP.onload = null;
let theImagesWidth = imgTMP.naturalWidth,
theImagesHeight = imgTMP.naturalHeight;
theCANVAS.width = theImagesWidth;
theCANVAS.height = theImagesHeight;
theCANVASctx.fillStyle = localTransColor;
theCANVASctx.clearRect(
0,
0,
theImagesWidth,
theImagesHeight
);
theCANVASctx.drawImage(imgTMP, 0, 0);
makeColorTransparent(
theCANVASctx,
localTransCode,
theImagesWidth,
theImagesHeight
);
//now, download the file:
downloadCanvas(efiles[cur].name);
//Finally, procced to proccess the next file
nextfile();
};
};
fr.readAsArrayBuffer(efiles[cur]);
};
nextfile();
}
rComponent.oninput = gComponent.oninput =
bComponent.oninput = aComponent.oninput =
function() {
rComponent.value = Math.max(0, Math.min(rComponent.value, 255));
gComponent.value = Math.max(0, Math.min(gComponent.value, 255));
bComponent.value = Math.max(0, Math.min(bComponent.value, 255));
aComponent.value = Math.max(0, Math.min(aComponent.value, 255));
};
rComponent.onchange = gComponent.onchange =
bComponent.onchange = aComponent.onchange =
function() {
transColor = 'rgba(' +
rComponent.value + ',' +
gComponent.value + ',' +
bComponent.value + ',' +
aComponent.value / 255 + ',' +
')';
// numberical equivelent of the rgba
transCode =
rComponent.value * 0x00000001 +
gComponent.value * 0x00000100 +
bComponent.value * 0x00010000 +
aComponent.value * 0x01000000;
};
<pre>rgba(<input type="number" value="255" max="255" min="0" step="1" id="r" maxlength="3" minlength="1" />,<input type="number" value="255" max="255" min="0" step="1" id="g" maxlength="3" minlength="1" />,<input type="number" value="255" max="255" min="0" step="1" id="b" maxlength="3" minlength="1" />,<input type="number" value="255" max="255" min="0" step="1" id="a" maxlength="3" minlength="1" />)</pre>
<input type="file" name="filefield" multiple="multiple" accept="image/*" id="fileInput" /><br />
<img id="imgTMP" />
<canvas id="theCanvas"></canvas>
<style>input[type=number]{width: 3em}#theCanvas {display: none}</style>
You can use an image processing framework to not handle pixel data manually.
In the case of MarvinJ, given a color, you can set all pixels to transparent with a single line:
image.setColorToAlpha(0, 0);
Input image:
Result:
Runnable Example:
var canvas = document.getElementById("canvas");
image = new MarvinImage();
image.load("https://i.imgur.com/UuvzbLx.png", imageLoaded);
function imageLoaded(){
image.setColorToAlpha(0, 0);
image.draw(canvas);
}
<script src="https://www.marvinj.org/releases/marvinj-0.8.js"></script>
<div style="width:400px; height:352px; background-image: linear-gradient(45deg, #808080 25%, transparent 25%),
linear-gradient(-45deg, #808080 25%, transparent 25%),
linear-gradient(45deg, transparent 75%, #808080 75%),
linear-gradient(-45deg, transparent 75%, #808080 75%);
background-size: 20px 20px;
background-position: 0 0, 0 10px, 10px -10px, -10px 0px;">
<canvas id="canvas" width="400" height="352"></canvas>
</div>