尝试为简单的 PNG 上色并在 canvas 中绘制遮罩元素

trying to colorize a simple PNG and draw inside a mask element in canvas

我尝试创建一个 HTML canvas,放置一个矩形...然后在该矩形内绘制各种形状和 RGBa PNG...所有这些都被剪裁在尺寸内矩形。然后我尝试在您按下 HTML 按钮输入时更改 PNG 的颜色。 (代码中的进一步注释。)

这是问题... A. 您必须绘制到临时 canvas 并在剪切矩形之后应用 "GlobalCompositeOperation source-atop"。之后绘制的所有内容都成功地剪裁成矩形。然后将整个东西复制(绘制)到 MAIN canvas。有人告诉我这样做是为了让编程在 "composite" 操作后识别多个元素。我不得不说这很好用!!但这是问题 B...

要在图像上设置 "getData"(更改颜色),我认为您必须将图像放在 canvas 上,并且进行所有图像像素操作会搞砸 "composite" 操作,所以我尝试将 PNG 绘制到第三个 canvas,进行像素更改,然后将其绘制到临时 canvas... 将其添加到其余元素。 ...THEEENNN 将其全部绘制到主要 canvas。不起作用。见代码。请大家帮忙,我气死了要嚼中子

<!DOCTYPE HTML>
<html>
<head>
</head>
<body>
<canvas id="theCanvas" width="200" height="200" style="border:2px solid #000000;"></canvas>
<canvas id="tempCanvas" width="200" height="200" style="display:none;"></canvas>
<canvas id="anotherCanvas" width="200" height="200" style="display:none;"></canvas>
<form>
<input type="button" id="changeColor" value="Click to Change Color of Graphic">
</form>
<script type="text/javascript" src="hereWeGoAgain_GHELP.js"></script>
</body>
</html>
//------------------------------------- JS
window.addEventListener("load", eventWindowLoaded, false);

function eventWindowLoaded () {
    canvasApp();
}
function canvasApp() {

    var canvas = document.getElementById('theCanvas');// the main canvas, where it all goes in the end
    var context = canvas.getContext('2d');

    var tempCanvas = document.getElementById('tempCanvas');// the canvas to do my "source-atop" stuff...
    var tempContext = tempCanvas.getContext('2d');

    var anotherCanvas = document.getElementById('anotherCanvas');
    var anotherContext = anotherCanvas.getContext('2d');

// ...and Im thinking I should draw the RGBA PNG here, before placing it in the temp canvas, with the other elements

    var cc = document.getElementById('changeColor');
    cc.addEventListener('click', function(){changeColorFunction('ff0000');}, false);
// the HTML form button to change the PNG color

    var colorOfThePlacedPNG = "#000000";
    var imagesToLoad = 0;
    var imagesLoaded = 0;

    function drawScreen() {

        tempContext.fillStyle="#999999";
        tempContext.fillRect(0,0,200,200); //color the whole temp canvas area grey....
        tempContext.fillStyle="#2baae1";
        tempContext.fillRect(30,30,140,140);//now draw a light blue rect inside....

        tempContext.globalCompositeOperation="source-atop"; // now make everything drawn AFTERWARDS be clipped (masked) inside the blue rect

// when I comment out the above "global Comp Op"... everything draws to the main canvas normally...just not clipped(masked) however

        tempContext.fillStyle="#f47e1f";
        tempContext.fillRect(150,100,150,150);//SO heres an orange box intentionally clipped off the bottom right in the blue rect
        tempContext.fillStyle="#d89bc5";
        tempContext.fillRect(40,50,80,200);//AND heres a light purple rect intentionally clipped at the bottom of the blue rect

        getTheImageData(); //draw PNG to another canvas, convert image data, put in tempContext

        //tempContext.restore();//dont know if I need this
        context.drawImage(tempCanvas, 0, 0);// and then FINALLY draw all to the main canvas
        }
        var loaded = function(){
            imagesLoaded += 1;
            if(imagesLoaded === imagesToLoad){ 
                drawScreen();
            }
        }
    var loadImage = function(url){
            var image = new Image();   
            image.addEventListener("load",loaded);
            imagesToLoad += 1;
            image.src = url;
            return image;
            }
    function changeColorFunction(e) {
            colorOfThePlacedPNG = e;
            drawScreen();
    }
    function getTheImageData(){
        anotherContext.drawImage(testPNGimage, 0, 0);// draw to the third canvas(another canvas)
            var imgData = anotherContext.getImageData(0, 0, 200, 200);
                    // how do i color it red? ....like #ff0000 ???
            var i;
            for (i = 0; i < imgData.data.length; i += 4) {
                imgData.data[i] = 255 - imgData.data[i];
                imgData.data[i+1] = 255 - imgData.data[i+1];
                imgData.data[i+2] = 255 - imgData.data[i+2];
                imgData.data[i+3] = 255;
            }
            tempContext.putImageData(imgData, 0, 0);
    }
        var testPNGimage = loadImage("test.png");// the PNG is just a 75X75px black squiggle drawn in pshop
}

你把事情搞得太复杂了!

canvas.

内置了裁剪方法

使用剪辑而不是合成和多个 canvases。

执行此操作,所有新绘图将被裁剪到您的 140x140 矩形内:

context.beginPath();
context.rect(30,30,140,140);
context.clip();

下面是您的代码的简化重新设计:

  1. 绘制一个灰色矩形填充 canvas。
  2. 在 [30,30] 处绘制一个 140x140 的蓝色矩形。
  3. context.clip()
  4. 将所有新绘图剪辑到蓝色矩形中
  5. 画一个剪裁好的橙色矩形。
  6. 画一个剪裁的紫色矩形。
  7. 取消剪辑,这样新绘图将在 canvas 上的任何位置可见。
  8. 绘制波浪形图像(未剪裁)。
  9. 使用.getImageData反转每个像素的颜色。

还有一个演示:

var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;

var img=new Image();
img.crossOrigin='anonymous';
img.onload=start;
img.src="https://dl.dropboxusercontent.com/u/139992952/multple/squiggle.png";
function start(){

  //color the whole canvas area grey....
  ctx.fillStyle="#999999";
  ctx.fillRect(0,0,200,200); 

  //now draw a light blue rect inside....
  ctx.fillStyle="#2baae1";
  ctx.beginPath();
  ctx.rect(30,30,140,140);
  ctx.fill();

  // save the unclipped context state
  ctx.save();

  // cause all new drawings to be clipped inside
  // the blue 140x140 rect at [30,30]
  ctx.clip();

  //SO heres an orange box intentionally clipped off the bottom right in the blue rect
  ctx.fillStyle="#f47e1f";
  ctx.fillRect(150,100,150,150);

  //AND heres a light purple rect intentionally clipped at the bottom of the blue rect
  ctx.fillStyle="#d89bc5";
  ctx.fillRect(40,50,80,200);

  // restore the context state (releases clipping for new drawings)
  ctx.restore();

  // draw the squiggley line image -- it's not clipped in the blue rect
  ctx.drawImage(img,0,0);

  // invert the colors using getImageData
  var imgData = ctx.getImageData(0, 0, 200, 200);
  var i;
  for (i = 0; i < imgData.data.length; i += 4) {
    imgData.data[i] = 255 - imgData.data[i];
    imgData.data[i+1] = 255 - imgData.data[i+1];
    imgData.data[i+2] = 255 - imgData.data[i+2];
    imgData.data[i+3] = 255;
  }
  ctx.putImageData(imgData, 0, 0);

}
body{ background-color: ivory; }
#canvas{border:1px solid red; margin:0 auto; }
<canvas id="canvas" width=200 height=200></canvas>