如何在 html5 和 javascript 中编辑像素并删除画布图像中的白色背景
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11472273/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
how to edit pixels and remove white background in a canvas image in html5 and javascript
提问by omega
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 do this, but the looping process should be like a 2d array, so it would involve two for loops.
我有一个关于如何做到这一点的想法,但循环过程应该像一个二维数组,所以它会涉及两个 for 循环。
I was thinking I would start on the top row first pixel, iterating to the right, if its a white pixel, then i turn it transparent, and move 1 pixel to the right, if its not white, then I stop. Then in the same row, I start from the left most pixel, and check, if white, I turn it transparent, then move 1 pixel to the left, etc, etc...
我想我会从顶行的第一个像素开始,向右迭代,如果它是白色像素,那么我把它变成透明,然后向右移动 1 个像素,如果它不是白色,那么我停止。然后在同一行,我从最左边的像素开始,检查,如果是白色,我把它变成透明,然后向左移动 1 个像素,等等......
Then I move 1 row down and repeat the whole process..
然后我向下移动 1 行并重复整个过程..
This way I don't remove any white pixels in the actual image.
这样我就不会删除实际图像中的任何白色像素。
回答by Loktar
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.
它使用起来非常简单getImageData
,putImageData
只需注意,图像越大,性能就会受到相当大的影响。您只需要确定当前像素是否为白色,然后将其 alpha 更改为 0。
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
更多资源
回答by Gabriel Ambrósio Archanjo
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:
在MarvinJ的情况下,给定颜色,您可以使用一行将所有像素设置为透明:
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>
回答by 3.1415926535897932384626433833
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.
Loktar 可能有一种“有效”的方法,但它的性能相当糟糕。如果您有很多图片,您不希望网站耗尽笔记本电脑/移动设备的电池,或者您只想要速度,这可能会成为一个问题。这是一种更有效的方法。单击“运行代码片段”按钮以查看它的实际演示。
'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>