javascript - 尝试对简单的 PNG 进行着色并在 Canvas 中的蒙版元素内进行绘制

标签 javascript canvas png pixel composite

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

问题在这里... A. 您必须绘制到临时 Canvas 并在剪切矩形之后应用“GlobalCompositeOperation source-atop”。之后绘制的所有内容都被成功剪切成矩形形状。然后整个内容被复制(绘制)到主 Canvas 上。我被告知这样做是为了让编程在“复合”操作后识别多个元素。我不得不说这效果非常好!但这是问题 B...

要在图像上进行“getData”(以更改颜色),我认为您必须将图像放置在 Canvas 上,并且执行所有图像像素操作会搞砸“复合”操作,所以我尝试绘制将 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 内置了一种裁剪方法。

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

执行此操作,所有新绘图都将被剪切在 140x140 矩形内:

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

这是代码的简化重新设计:

  1. 绘制一个填充 Canvas 的灰色矩形。
  2. 在 [30,30] 处绘制一个蓝色 140x140 矩形。
  3. 使用 context.clip() 将所有新绘图剪辑到蓝色矩形中
  4. 绘制一个 trim 后的橙色矩形。
  5. 绘制一个 trim 后的紫色矩形。
  6. 取消剪辑,以便新绘图在 Canvas 上的任何位置都可见。
  7. 绘制波形图(未裁剪)。
  8. 使用.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>

关于javascript - 尝试对简单的 PNG 进行着色并在 Canvas 中的蒙版元素内进行绘制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33457512/

相关文章:

javascript - 选择下拉菜单输入多个选择。 JavaScript

javascript - 与父级相同大小的 Canvas

html - css3 border-image的透明png问题

html - html Canvas 的圆形裁剪

html - setTimeout 或 setInterval 或 requestAnimationFrame

Swift SpriteKit : png image appears black while the game is being run. 我该如何解决这个问题?

c++ - Gnuplot - 保存输出

javascript - 可以在类里面调用 fancybox 吗?

javascript - 从javascript传递值到表单

javascript - 检查元素是否在数组中