用javascript进行图像编辑

用javascript进行图像编辑,javascript,html,canvas,Javascript,Html,Canvas,在创建html5游戏引擎的过程中,我已经能够做一些不错的事情,并获得一些很酷的功能。在一份制作游戏的合同上,我被要求看看是否可以从精灵图像中去除背景色。我看到了这一点的好处,因为我们可以在PNG上使用JPG,从而减小图像的大小 有什么方法可以用纯javascript实现这一点吗?我希望能够在不使用canvas元素的情况下实现这一点,这样可以更快,但如果必须这样做,也没关系 如果必须这样做,我还有一个问题,我不想让画布对象显示我使用的画布对象,我可以将画布对象与document.createEle

在创建html5游戏引擎的过程中,我已经能够做一些不错的事情,并获得一些很酷的功能。在一份制作游戏的合同上,我被要求看看是否可以从精灵图像中去除背景色。我看到了这一点的好处,因为我们可以在PNG上使用JPG,从而减小图像的大小

有什么方法可以用纯javascript实现这一点吗?我希望能够在不使用canvas元素的情况下实现这一点,这样可以更快,但如果必须这样做,也没关系

如果必须这样做,我还有一个问题,我不想让画布对象显示我使用的画布对象,我可以将画布对象与document.createElement一起使用,而不将其应用于文档吗?那太好了,因为它不必呈现到网页上。如果不是的话,我想我可以把画布对象移到左边看不见的地方


最后,您认为预处理图像的一个好方法是将图像发送到服务器cgi脚本并让其返回json像素数组吗?

即使在图像编辑程序中手动删除背景,也不需要复杂的边框。至少,您必须实现某种类型的抗锯齿

此外,操纵压缩成有损格式的图像不是一个好主意

压缩(就大小而言)优于具有相同颜色和特定类型渐变的连续填充的简单图像。JPG只适用于以不可预测的方式混合了大量不同颜色的异构图像。我喜欢照片。我猜这是游戏中的精灵所不希望看到的。再说一遍,JPG是一种格式

至于Canvas元素,它根本不需要连接到DOM树

使给定颜色透明的最幼稚的算法是:绘制图像,获取其像素数据,迭代数据,并将每个像素颜色与给定颜色进行比较。如果匹配,则将alpha设置为0

您将需要的画布API方法:

在它的简单性部分有点棘手的是。要检查此类阵列中的每个像素,请执行以下操作:

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];
}
for(变量i=0;i
即使在图像编辑程序中手动删除背景,也不是一项简单的任务。至少,您必须实现某种类型的抗锯齿

此外,操纵压缩成有损格式的图像不是一个好主意

压缩(就大小而言)优于具有相同颜色和特定类型渐变的连续填充的简单图像。JPG只适用于以不可预测的方式混合了大量不同颜色的异构图像。我喜欢照片。我猜这是游戏中的精灵所不希望看到的。再说一遍,JPG是一种格式

至于Canvas元素,它根本不需要连接到DOM树

使给定颜色透明的最幼稚的算法是:绘制图像,获取其像素数据,迭代数据,并将每个像素颜色与给定颜色进行比较。如果匹配,则将alpha设置为0

您将需要的画布API方法:

在它的简单性部分有点棘手的是。要检查此类阵列中的每个像素,请执行以下操作:

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];
}
for(变量i=0;i
就我个人而言,我不会走这条路。JPEG图像是压缩的,这意味着无论您定义为背景色的内容在压缩文件中都可能发生轻微变化(即,您将得到经典的JPEG伪影)。此外,除非为背景色定义一个范围,否则将无法支持部分透明度,这反过来会使编辑更加复杂。在我看来,在这里,在文件大小和性能/质量之间进行权衡是不值得的

话虽如此,从图像访问像素数据的唯一方法是首先将其放置在画布上。正如您所提到的,您可以在内存中使用屏幕外的画布,而无需将其附加到文档中

如果我正确理解了您的最后一个问题,则无法在服务器端使用canvas元素。要在服务器上处理像素数据,必须使用类似PHP的图像库之类的工具

如果所有这些都不影响您只使用PNG图像,下面是一些示例代码,可以从加载的图像中删除指定的背景颜色:

$(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";
});
$(文档).ready(函数(){
var matte_color=[0,255,0,255];//rgba:[0,255];
//通过擦除蒙版颜色来处理加载的图像元素
//以及将转换后的图像附加到文档。
函数handleLoadeImage(){
擦除蒙版();//消除蒙版。
//将canvas元素附加到需要它的文档中。
document.getElementById(“父容器”).appendChild(画布);
}
//给定顶部定义的蒙版颜色,将所有像素清除为100%透明度
//在加载的精灵中。
函数抹去蒙版(){
canvas.width=sprite.width;
canvas.height=sprite.height;
context.drawImage(sprite,0,0);//在画布上绘制图像,以便读取像素。
//从画布获取像素数据。
var image_data=context.getImageData(0,0,sprite.width,sprite.height);
var data=image_data.data;//获得直接句柄是一个巨大的性能提升。
var end=sprite.width*sprite.height*4;//宽x高x RGBA
//在图像的每个像素上循环,并根据需要清除蒙版像素。
对于(变量i=0;i imageElement.src=canvas.toDataURL("image/png");
// 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;
}
var canvas = new fabric.Canvas('c');
var imgInstance = new fabric.Image(imgElement); 
canvas.add(imgInstance);//initialize the Canvas with the image