admin管理员组文章数量:1396094
In the creation of my html5 game engine I've been able to do some nice things and get some cool features. On a contract to make a game I've been asked to see if I can remove the background color from sprite images. And I see the pluses with this since we could use jpgs instead on pngs and decrease the size of the images.
Is there any way I can do this with pure javascript? I'd like to be able to do this without using the a canvas element so it can be faster, but if I have to that's okay.
If I have to do that I have another question, I don't want the canvas object to show that I use, can I use a canvas object with document.createElement without applying it to the document? That would be nice since it wouldn't have to be rendered to the webpage. If not I guess I can just move the canvas object to the left out of view.
Lastly do you think a good way to preprocess the images be to send them to a server cgi script and have it return a json pixel array?
In the creation of my html5 game engine I've been able to do some nice things and get some cool features. On a contract to make a game I've been asked to see if I can remove the background color from sprite images. And I see the pluses with this since we could use jpgs instead on pngs and decrease the size of the images.
Is there any way I can do this with pure javascript? I'd like to be able to do this without using the a canvas element so it can be faster, but if I have to that's okay.
If I have to do that I have another question, I don't want the canvas object to show that I use, can I use a canvas object with document.createElement without applying it to the document? That would be nice since it wouldn't have to be rendered to the webpage. If not I guess I can just move the canvas object to the left out of view.
Lastly do you think a good way to preprocess the images be to send them to a server cgi script and have it return a json pixel array?
Share Improve this question asked Oct 10, 2011 at 20:11 IsaiahIsaiah 2,0232 gold badges20 silver badges29 bronze badges 1-
You have to use Canvas. Also, if you don't want the canvas element to render, add
display:none
to it. – Rob W Commented Oct 10, 2011 at 20:17
5 Answers
Reset to default 4Here is the function for floodfill algorithm, it removed the background from an image which is already drawn on the canvas.
In the following code canvas is the HTML5 canvas element and context it canvas.getContext("2d"). You can change the value of colorRange and try the function with different colors. The last line of the function
imageElement.src=canvas.toDataURL("image/png");
is to show the image inside an img tag. So you need an img and a canvas on your page. If you don't want to show the image in img element just remove the last line.
// Remove backgroud without ajax call, can be used in non IE browsers.
function RemoveBackground(){
var startR,startG,startB;
var canvasData;
var canvasWidth=canvas.width;
var canvasHeight=canvas.height;
canvasData=mainContext.getImageData(0,0,canvasWidth,canvasHeight);
startR = canvasData.data[0];
startG = canvasData.data[1];
startB = canvasData.data[2];
if(startR==0&& startG==0 && startR==0) return;
var pixelStack = [[0, 0]];
while(pixelStack.length)
{
var newPos, x, y, pixelPos, reachLeft, reachRight;
newPos = pixelStack.pop();
x = newPos[0];
y = newPos[1];
pixelPos = (y*canvasWidth + x) * 4;
while(y-- >= 0 && matchStartColor(pixelPos,canvasData,startR,startG,startB)){
pixelPos -= canvasWidth * 4;
}
pixelPos += canvasWidth * 4;
++y;
reachLeft = false;
reachRight = false;
while(y++ < canvasHeight-1 && matchStartColor(pixelPos,canvasData,startR,startG,startB))
{
colorPixel(pixelPos,canvasData);
if(x > 0)
{
if(matchStartColor(pixelPos-4,canvasData,startR,startG,startB))
{
if(!reachLeft){
pixelStack.push([x - 1, y]);
reachLeft = true;
}
}
else if(reachLeft)
{
reachLeft = false;
}
}
if(x < canvasWidth-1)
{
if(matchStartColor(pixelPos+4,canvasData,startR,startG,startB))
{
if(!reachRight)
{
pixelStack.push([x + 1, y]);
reachRight = true;
}
}
else if(reachRight)
{
reachRight = false;
}
}
pixelPos += canvasWidth * 4;
}
}
context.putImageData(canvasData, 0, 0);
imageElement.src=canvas.toDataURL("image/png");
}
// Helper function for remove background color.
function matchStartColor(pixelPos,canvasData,startR,startG,startB)
{
var r = canvasData.data[pixelPos];
var g = canvasData.data[pixelPos+1];
var b = canvasData.data[pixelPos+2];
var colorRange=8;
return ((r >= startR-colorRange && r<=startR+colorRange)
&&( g >= startG-colorRange && g<=startG+colorRange)
&&( b >= startB-colorRange && b<= startB+colorRange));
}
// Helper function for remove background color.
function colorPixel(pixelPos,canvasData)
{
canvasData.data[pixelPos] = 255;
canvasData.data[pixelPos+1] = 255;
canvasData.data[pixelPos+2] = 255;
}
Removing background without choppy borders isn't a trivial task, even by hand in image-editing programs. You'll have to implement some sort of antialiasing, at least.
Moreover, it's not a good idea to manipulate an image pressed into a lossy format.
PNG pression is superior (in terms of size) to JPG on simpler images with continuous fill of the same color and certain types of gradients. JPG is only good for heterogeneous images with lots of different colors mixed in unpredictable manner. Like photos. Which one would not expect in game sprites, I guess. And again – JPG is a lossy format.
As for the Canvas element, it doesn't have to be added to the DOM tree at all.
The most naïve algorithm to make a given color transparent would be such: draw the image, get its pixel data, iterate over the data and pare every pixel color with your given color. If it matches, set the alpha to 0.
Canvas API methods you'll need:
drawImage
getImageData
The somewhat tricky in it's simplicity part is the CanvasPixelArray
. To check each pixel in such arrays, you do something like that:
for (var i = 0; i < pixelAr.length; i += 4) {
var r = pixelAr[i];
var g = pixelAr[i + 1];
var b = pixelAr[i + 2];
var alpha = pixelAr[i + 3];
}
Personally I would not go down this path. JPEG images are pressed, which means that whatever you define as a background color may change slightly in the pressed file (ie. you'll get the classic JPEG artifacting). Furthermore, you won't be able to support partial transparency unless you define a range for your background color, which in turn makes the editing more plicated. The tradeoff between file size and performance/quality is nowhere near worth it here, in my opinion.
Having said that, the only way you can access the pixel data from an image is by placing it on a canvas first. You can, as you mentioned, work with the canvas off-screen in memory without having to append it to the document.
If I understand your last question correctly, you cannot work with a canvas element on the server side. To work with pixel data on your server, you'd have to use something like PHP's image library.
If all of that doesn't sway you in favor of just using PNG images, here's some sample code that will remove a specified background color from a loaded image:
$(document).ready(function() {
var matte_color = [0, 255, 0, 255]; // rgba: [0, 255];
// Handles the loaded image element by erasing the matte color
// and appending the transformed image to the document.
function handleLoadedImage() {
eraseMatte(); // Eliminate the matte.
// Append the canvas element to the document where it is needed.
document.getElementById("parent_container").appendChild(canvas);
}
// Given the matte color defined at the top, clear all pixels to 100% transparency
// within the loaded sprite.
function eraseMatte() {
canvas.width = sprite.width;
canvas.height = sprite.height;
context.drawImage(sprite, 0, 0); // Draw the image on the canvas so we can read the pixels.
// Get the pixel data from the canvas.
var image_data = context.getImageData(0, 0, sprite.width, sprite.height);
var data = image_data.data; // Obtaining a direct handle is a huge performance boost.
var end = sprite.width * sprite.height * 4; // W x H x RGBA
// Loop over each pixel from the image and clear matte pixels as needed.
for (var i = 0; i < end; i += 4) {
if (data[i] == matte_color[0] && data[i + 1] == matte_color[1] &&
data[i + 2] == matte_color[2] && data[i + 3] == matte_color[3]) { // Color match.
data[i] = data[i + 1] = data[i + 2] = data[i + 3] = 0; // Set pixel to transparent.
}
}
// Put the transformed image data back on the canvas.
context.putImageData(image_data, 0, 0);
}
var canvas = document.createElement("canvas");
var context = canvas.getContext("2d");
var sprite = new Image();
sprite.onload = handleLoadedImage;
sprite.src = "sprite.jpg";
});
You can do that using a canvas, don't know if it is possible without it.
An easy way to achieve what you are trying to do is using the getImageData
on your canvas's context:
imgData = myCanvasContext.getImageData(x1, y1, x2, y2);
x1, y1, x2, y2 are the coordenates of the area you want to get data, for the whole use 0, 0, width, height
image. The getImageData
will return you an ImageData
, wich contains an array with rgba values from each pixel. The values will be ordered like this:
https://i.sstatic/tdHNJ.png
You can manipulate the array imgData.data[index]
, editing it values and, consequently, editing the image.
Here is a good article about editing images on html5 with canvas: http://beej.us/blog/2010/02/html5s-canvas-part-ii-pixel-manipulation/
To doesn't show what you are doing, just create the canvas with the css mand display:none;
(...)if I can remove the background color from sprite images. And I see the pluses with this since we could use jpgs instead on pngs(...)
I really remend you to not do that. The jpg pression of the image can make image editing very hard. Removing the background of a jpg image isn't is easy, and it gets harder with the amount of borders on the image. I'm don't think the size that you will economize will pensate the hard work to remove a background from a jpg image.
Not exactly the same, but you can achieve that. I can give you an headstart on this - checkout this jsFiddle. I built this editor using FabricJS.
var canvas = new fabric.Canvas('c');
var imgInstance = new fabric.Image(imgElement);
canvas.add(imgInstance);//initialize the Canvas with the image
本文标签: htmlImage editing with javascriptStack Overflow
版权声明:本文标题:html - Image editing with javascript - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744660393a2618209.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论