画布-在画布保存为图像后,使用橡皮擦绘制黑线。

9

在画布上绘制是完美的。甚至橡皮擦也很好用。问题是,当画布保存为图像时,它会绘制黑线而不是橡皮擦。

为了更好地理解,我添加了屏幕截图和代码。

1. 在擦除时 -

a. 源代码 -

erase(){
      this.ctx.globalCompositeOperation = 'destination-out';
    } 

handleMove(ev){

  // let ctx = this.canvasElement.getContext('2d');
  let currentX = ev.touches[0].pageX - this.offsetX;
  let currentY = ev.touches[0].pageY - this.offsetY;

  this.ctx.beginPath();
  this.ctx.lineJoin = "round";
  this.ctx.moveTo(this.lastX, this.lastY);
  this.ctx.lineTo(currentX, currentY);
  this.ctx.closePath();
  this.ctx.strokeStyle = this.currentColour;
  this.ctx.lineWidth = this.brushSize;
  this.ctx.stroke();      


  this.undoList.push({
    x_start: currentX,
    y_start: currentY,
    x_end: this.lastX,
    y_end: this.lastY,
    color: this.currentColour,
    size: this.brushSize,
    mode: this.ctx.globalCompositeOperation
  });

  this.lastX = currentX;
  this.lastY = currentY;
  
}
输出 -

在此输入图片描述

2. 将Canvas保存为图像 -

a. 代码 -

this.ctx.clearRect(0, 0, this.canvasElement.width, this.canvasElement.height);
    setTimeout(() => {
      
      // this.drawImg(this.newImg);
       for(let i=0; i<this.textAreasList.length; i++){
         let txt = this.textAreasList[i];
         this.ctx.font = this.textAreasList[i].bold + ' ' + this.textAreasList[i].italic + ' ' + this.textAreasList[i].fontSize + ' ' + 'Comic Sans MS';
         this.ctx.fillStyle = this.textAreasList[i].color;  
         if(this.textAreasList[i].left=="" || this.textAreasList[i].left==undefined) {
           this.textAreasList[i].left = 50;
         }
         if(this.textAreasList[i].top=="" || this.textAreasList[i].top==undefined) {
          this.textAreasList[i].top = 50;
        }
         this.ctx.fillText(this.textAreasList[i].value, this.textAreasList[i].left, this.textAreasList[i].top);
       }

       this.redrawCanvas(this.undoUseList);
       let imgPath = this.canvasElement.toDataURL('image/png');
       let message= "";
       this.base64ToGallery.base64ToGallery(imgPath).then(
         res => message = "Image saved to gallery!",
         err => message = "Something went wrong!!"
       );
       this.spinner.hide();
       let toast = this.toastCtrl.create({
         message: message,
         duration: 3000,
         position: 'bottom',
         cssClass: 'changeToast'
       });
       this.navCtrl.push(HomePage);
     }, 5000);
  }



redrawCanvas(arr){
      // this.ctx.globalCompositeOperation = 'source-over';
      for(let i=0; i<arr.length; i++){
        for(let j=0; j< arr[i].length; j++){
          let ctx = this.canvasElement.getContext('2d');
          ctx.globalCompositeOperation = arr[i][j].mode;
          console.log('x start', arr[i][j].x_start);
          console.log('y start', arr[i][j].y_start);
          console.log('x end', arr[i][j].x_end);
          console.log('y end', arr[i][j].y_end);
          ctx.beginPath();
          ctx.lineJoin = "round";
          ctx.moveTo(arr[i][j].x_start, arr[i][j].y_start);
          ctx.lineTo(arr[i][j].x_end, arr[i][j].y_end);
          ctx.closePath();
          ctx.strokeStyle = arr[i][j].color;
          ctx.lineWidth = arr[i][j].size;
          ctx.stroke();
        }
        
      }
      
    }

**b. Output -** 

enter image description here

我不明白为什么在将画布保存为图像时,橡皮擦移动被替换为黑色。

请注意,此处保留了HTML标签。


1
你使用的图片格式是什么? - Janith
1
我正在使用png。 - Flutterian
2个回答

4

那么,您正在使用撤消列表重新绘制画布,对吗?之后,您会使用toDataUrl()输出图像?

在我看来,问题出在

this.undoList.push({
  x_start: currentX,
  y_start: currentY,
  x_end: this.lastX,
  y_end: this.lastY,
  color: this.currentColour, <== Is this an object?
  size: this.brushSize,
  mode: this.ctx.globalCompositeOperation
});

如果this.currentColour是一个对象,我猜属性在代码的其他地方被改变了,当你重构步骤时,你得到的样式是黑色的,不确定是否是默认的。

那么你可以尝试这个方法代替。

this.undoList.push({
  x_start: currentX,
  y_start: currentY,
  x_end: this.lastX,
  y_end: this.lastY,
  color: {
    prop1: this.currentColour.prop1
    prop2: this.currentColour.prop2
    ...
  }
  size: this.brushSize,
  mode: this.ctx.globalCompositeOperation
});

将prop1,prop2等替换为您在该对象中拥有的实际属性。这样,您就创建了一个新的obj(复制它),而不是传递对旧obj的引用。

你可以让它变得更漂亮,但像这样你可以更好地理解推理。


2

我最终解决了问题。我做了以下更改。

redrawCanvas(arr){
      // this.ctx.globalCompositeOperation = 'source-over';
      for(let i=0; i<arr.length; i++){
        for(let j=0; j< arr[i].length; j++){
          let ctx = this.canvasElement.getContext('2d');
          // ctx.globalCompositeOperation = arr[i][j].mode;

          if(arr[i][j].mode== "destination-out"){
            // ctx.globalCompositeOperation = "destionation-out";
            // ctx.strokeStyle = "rgba(0,0,0,0.2)";
            let cImg = new Image();
            cImg.src = this.selectedImage;
            let pattern = ctx.createPattern(cImg, "no-repeat");
            ctx.strokeStyle = pattern;
          }else{
            ctx.strokeStyle = arr[i][j].color;
          }
          console.log('x start', arr[i][j].x_start);
          console.log('y start', arr[i][j].y_start);
          console.log('x end', arr[i][j].x_end);
          console.log('y end', arr[i][j].y_end);
          ctx.beginPath();
          ctx.lineJoin = "round";
          ctx.moveTo(arr[i][j].x_start, arr[i][j].y_start);
          ctx.lineTo(arr[i][j].x_end, arr[i][j].y_end);
          ctx.closePath();
          ctx.lineWidth = arr[i][j].size;
          ctx.stroke();
        }

      }

    }

从代码中可以看出,我新增了一个检查条件,用于判断是笔刷还是橡皮擦。对于橡皮擦,我会检查其是否为destination-out

如果是橡皮擦,我将创建一张新的图片,并设置其strokestyle属性。

因此,可以说我只做了以下这个更改。

if(arr[i][j].mode== "destination-out"){
            // ctx.globalCompositeOperation = "destionation-out";
            // ctx.strokeStyle = "rgba(0,0,0,0.2)";
            let cImg = new Image();
            cImg.src = this.selectedImage;
            let pattern = ctx.createPattern(cImg, "no-repeat");
            ctx.strokeStyle = pattern;
          }else{
            ctx.strokeStyle = arr[i][j].color;
          }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接