【问题标题】:I want to change the color of an image inside a image in html5-canvas我想更改 html5-canvas 中图像内图像的颜色
【发布时间】:2021-04-23 11:31:36
【问题描述】:

我正在使用画布制作徽章。 为了绘制图像,我使用了代码:

let image = new Image()
image.src = 'imageSource'
image.onload = () => {
 ctx.drawImage(image, xOffset, yOffset, newWidth, newHeight)

 // to color the image at the back (works properly)

 ctx.globalCompositeOperation = 'source-in'
 ctx.fillStyle = 'someColour'
 ctx.fillRect(0, 0, this.canvas.width, this.canvas.height)
 ctx.globalCompositeOperation = 'source-over'

  // icon in the middle

  let iconImage = new Image()
  iconImage.src = 'iconSource'
  iconImage.onload = () => {
      ctx.drawImage(iconImage, xOffset, yOffset, width, height)

      // i need to be able to fill color in this iconImage only
}
  

预览是这样的。

canvas-image

现在,为了给图像着色,我尝试使用不同的混合模式。当我为image 的背景工作时,它工作正常。我尝试以同样的方式为iconImage 执行此操作,但没有成功。我想给中间的图标上色而不改变任何其他东西。

【问题讨论】:

    标签: javascript reactjs html5-canvas


    【解决方案1】:

    早上无聊,给大家做个例子在这个例子中你可以看到画布中的所有元素都可以修改。

    注意:由于 CORS 问题(Tainted canvases may not be exported),这里不能编辑外部图像的颜色,所以使用选择文件导入图像然后更改图像颜色!

    const canvas = document.querySelector("canvas");
    const ctx = canvas.getContext("2d")
    const inputs = document.querySelectorAll("input");
    const xOffset = 30, yOffset = 10, width = canvas.width-60, height = canvas.height-20;
    
    var inputValues = {stroke:"#8db5c2",fill:"white",text:"Text",image:"https://i.stack.imgur.com/8eLMW.png",imageColor:"grey"}
    
    inputs.forEach(input => {
      input.addEventListener("input", function() {
        if(this.id === "image") {
          if (!input.files || !input.files[0]) return;
          const FR = new FileReader();
          FR.onloadend = (evt) => {
              inputValues = {...inputValues,[this.id]:FR.result};
              DrawBadge(inputValues)
          };
          FR.readAsDataURL(input.files[0]);
        } else {
          inputValues = {...inputValues,[this.id]:this.value};
          DrawBadge(inputValues)
        }
      })
    })
    
    DrawBadge(inputValues)
    
    function DrawBadge ({stroke, fill, text, image ,imageColor}) {
      //Draw Badge
      ctx.strokeStyle = stroke;
      ctx.lineWidth = 15;
      ctx.fillStyle = fill;
      roundRect(ctx, xOffset, yOffset, width, height, {
        tl: 1,
        tr: 1,
        bl: width/2,
        br: width/2,
      });
      //Draw Text
      ctx.font = "20px Arial";
      ctx.textAlign = 'center';
      ctx.textBaseline = 'middle';
      ctx.fillStyle = "black";
      ctx.fillText(text,width/2+xOffset,height*0.8);
      //Draw Image
      const firstImage = new Image();
      const insideWidth = 80, insideHeight = 80;
      firstImage.src = image;
      // Because of the CORS issue just show image as it is
      if(image === "https://i.stack.imgur.com/8eLMW.png") {
        firstImage.onload = () => {
          ctx.drawImage(firstImage, (width/2)-(insideWidth/2)+xOffset,height*0.2,insideWidth , insideHeight);
         }
      // you should use this function for changing image color
      } else {
        firstImage.onload = () => {
          //Make new canvas for image
          const imageCtx = document.createElement("canvas").getContext("2d");
          const insideImage = new Image();
          imageCtx.canvas.width = insideWidth;
          imageCtx.canvas.height = insideHeight;
          imageCtx.save();
          imageCtx.fillStyle = imageColor;
          imageCtx.fillRect(0, 0, insideWidth, insideHeight);
          //Here magic happend 
          imageCtx.globalCompositeOperation = "destination-in";
          imageCtx.drawImage(firstImage,0,0,insideWidth,insideHeight);
          //Then export our canvas to png image
          insideImage.src = imageCtx.canvas.toDataURL("image/png");
          insideImage.onload = () => {
              ctx.drawImage(insideImage,(width/2)-(insideWidth/2)+xOffset,height*0.2,insideWidth,insideHeight);
          }
        }
      }
    }
    
    function roundRect(ctx, x, y, width, height, radius, fill, stroke){
      ctx.beginPath();
      ctx.moveTo(x + radius.tl, y);
      ctx.lineTo(x + width - radius.tr, y);
      ctx.quadraticCurveTo(x + width, y, x + width, y + radius.tr);
      ctx.lineTo(x + width, y + height - radius.br);
      ctx.quadraticCurveTo(x + width, y + height, x + width - radius.br, y + height);
      ctx.lineTo(x + radius.bl, y + height);
      ctx.quadraticCurveTo(x, y + height, x, y + height - radius.bl);
      ctx.lineTo(x, y + radius.tl);
      ctx.quadraticCurveTo(x, y, x + radius.tl, y);
      ctx.closePath();
      ctx.fill();
      ctx.stroke();
    }
    body {
     display: flex;
    }
    #inputs {
      display: flex;
      flex-direction: column;
    }
    canvas {
       border: 1px solid;
    }
    <body>
      <div id="inputs">
        Stroke Color: <input id="stroke" type="color" value="#8db5c2">
        Fill Color: <input id="fill" type="color" value="#ffffff">
        Text: <input id="text" type="text" value="Text">
        <lable>
        Image:<input id="image" type="file"accept="image/png, image/jpeg">
         ImageColor: <input id="imageColor" type="color" value="#808080">
         </lable>
      </div>
      <canvas width="220" height="190"></canvas>
    </body>

    【讨论】:

    • 太棒了。但是你如何改变'insideImage'的颜色呢?。
    • 我可以通过制作另一个画布来做到这一点,我会为你做的。
    • 这正是我想要的。非常感谢!!
    • 没问题,很乐意帮助你:)
    猜你喜欢
    • 2015-05-23
    • 2012-04-21
    • 1970-01-01
    • 2014-08-15
    • 2014-12-17
    • 1970-01-01
    • 2013-03-29
    • 1970-01-01
    相关资源
    最近更新 更多