代码之家  ›  专栏  ›  技术社区  ›  Govaadiyo

如何从图像画布裁剪颜色部分?

  •  1
  • Govaadiyo  · 技术社区  · 8 年前

    我正在研究基于离子的应用程序。

    我想要像用户用手指填充图像(画布)上的红色一样的功能。我已经完成了填充功能,但我想从画布上裁剪填充部分。我附上一张图片供参考。

    enter image description here

    我想从上面的图片裁剪红色部分。我在谷歌上搜索过,但没有找到任何解决方案。

    1 回复  |  直到 8 年前
        1
  •  5
  •   Community Mohan Dere    5 年前

    创建图像遮罩。

    如果要渲染选择区域(红色),则解决方案很简单。

    创建与图形大小相同的第二个画布,不要将其添加到DOM中。在画布上绘制红色标记内容

    显示画布上的首先渲染图像,然后渲染该标记 使用类似“覆盖”的复合模式在图像上绘制画布,以便可以看到原始图像,并且标记区域为红色。

    现在,您有两个层,一个是图像,另一个是可以用来获取标记内容副本的掩码。

    为此,创建第三个画布,在其上绘制原始图像,然后将合成模式设置为“destination in”。然后在上面画上面具。只保留标记的像素。

    有关更多详细信息,请参见示例

    setTimeout(example,0); // ensures that the run us after parsing
    function example(){
      const ctx = canvas.getContext("2d");
      var w = canvas.width;
      var h = canvas.height;
      var cw = w / 2;  // center 
      var ch = h / 2;
    
      var selectLayer = CImageCtx(w,h); // creates a canvas 
      var selectedContent = CImageCtx(w,h); // the selected content
      document.body.appendChild(selectedContent);
      var image = new Image;  // the image
      image.src = " https://i.stack.imgur.com/QhFct.png";
      // updates the masked result
      function updateSelected(){
        var ctx = selectedContent.ctx;
        ctx.drawImage(image,0,0);
        ctx.globalCompositeOperation = "destination-in";
        ctx.drawImage(selectLayer,0,0);
        ctx.globalCompositeOperation = "source-over";
      }
      function update(){
          // if mouse down then 
          if(mouse.but){
            // clear the mask if on the right image
            if(mouse.oldBut === false && mouse.x > 256){
               selectLayer.ctx.clearRect(0,0,w,h);
               mouse.but = false;
            }else{
               // draw the red 
               selectLayer.ctx.fillStyle = "red";
               fillCircle(mouse.x, mouse.y, 20, selectLayer.ctx);
            }
            // update the masked result
            updateSelected();
          }
    
          // clear the canvas
          ctx.clearRect(0,0,w,h);
          // draw the image
          ctx.drawImage(image,0,0);
          // then draw the marking layer over it with comp overlay
          ctx.globalCompositeOperation = "overlay";
          ctx.drawImage(selectLayer,0,0);
          ctx.globalCompositeOperation = "source-over";
    
          mouse.oldBut = mouse.but;
          requestAnimationFrame(update);
      }
      requestAnimationFrame(update);
    }
    
    
    
    
    
    
    //#############################################################################
    // helper functions not part of the answer
    //#############################################################################
    const mouse  = {
      x : 0, y : 0, but : false,
      events(e){
        const m = mouse;
        const bounds = canvas.getBoundingClientRect();
        m.x = e.pageX - bounds.left - scrollX;
        m.y = e.pageY - bounds.top - scrollY;
        m.but = e.type === "mousedown" ? true : e.type === "mouseup" ? false : m.but;
      }
    };
    (["down","up","move"]).forEach(name => document.addEventListener("mouse" + name,mouse.events));
    const CImage = (w = 128, h = w) => (c = document.createElement("canvas"),c.width = w,c.height = h, c);
    const CImageCtx = (w = 128, h = w) => (c = CImage(w,h), c.ctx = c.getContext("2d"), c);
    const fillCircle = (l,y=ctx,r=ctx,c=ctx) =>{if(l.p1){c=y; r=leng(l);y=l.p1.y;l=l.p1.x }else if(l.x){c=r;r=y;y=l.y;l=l.x}c.beginPath(); c.arc(l,y,r,0,Math.PI*2); c.fill()}
    body { font-family : arial; }
    canvas { border : 2px solid black; }
    Draw on image and the selected parts are shown on the right<br>
    Click right image to reset selection<br>
    <canvas id="canvas" width=256 height=256></canvas>

    已经蒙面了。

    如果红色遮罩已经应用于图像,那么除了根据图像的红色程度进行阈值过滤之外,您可以做的事情不多。但即使这样,你也会遇到深色区域和已经包含红色的区域的问题。

    除非你有原始图像,否则效果会很差。

    如果您有原始图像,则必须访问图像数据,并通过比较每个像素并仅选择不同的像素来创建新图像作为遮罩。这将迫使您仅使用相同的域图像(或使用CORS交叉源标题)