javascript html5画布沿着路径应用过滤器

6mw9ycah  于 2023-01-01  发布在  Java
关注(0)|答案(1)|浏览(124)

我有一个图像和图像中的一个对象。我想只增加图像中与对象相关的部分的亮度。我可以根据path或其他画布来查找对象。是否可以仅对图像的一部分应用CanvasRenderingContext2D.filter
我天真地尝试了以下基于a full-image brightness control solution的方法:

const imageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/e/ec/Carl_Friedrich_Gauss_1840_by_Jensen.jpg/800px-Carl_Friedrich_Gauss_1840_by_Jensen.jpg";
const ctx = canvas.getContext("2d");

ctx.fillText("Please wait loading image..",20,20);
const image = new Image;
image.src = imageUrl;
image.onload = () => {
  canvas.width = image.width;
  canvas.height = image.height;     
  ctx.drawImage(image, 0, 0);
  slider.addEventListener("mousemove", () => {
    if (slider.value !== slideOldVal) {
      setBrightness(Number(slider.value));
    }
    val.textContent = slider.value;
    slideOldVal = Number(slider.value);
  });
}

function setBrightness(value) {
    ctx.drawImage(image, 0, 0);

    ctx.filter = `brightness(${value + 100}%)`;
    ctx.strokeStyle = `rgb(255,255,255,0)`;
    ctx.lineWidth = 16;
 
    let path2 = new Path2D();
    path2.moveTo(220, 60);
    path2.arc(170, 60, 50, 0, 2 * Math.PI);
    ctx.stroke(path2);
    
    ctx.filter = `brightness(${100}%)`;
}

var slideOldVal;
Brightness<input id="slider" type="range" min="-100" max="400" value="0" step="1"></input><span id="val"></span><br>
<canvas id="canvas"></canvas>

这是一个尝试增加亮度沿圆形路径位于左上角的图像。这个代码实际上什么也没有完成。
有没有一种方法可以使用HTML5画布只增加部分图像的亮度?

s5a0g9ez

s5a0g9ez1#

滤镜只会应用于下一次绘制,但在这里下一次绘制将是完全透明的,给定你的strokeStyle。你想要的是用那个滤镜再次绘制图像,但只在弧线的笔划将在的地方。
对此,你有各种解决方案。
其中之一是使用compositing,这将允许你使用你的笔触作为一个遮罩,并应用过滤器只在它。即使这样,你会有各种各样的方式来建立这个,一些取决于如果你的原始图像有透明度,一些使用屏幕外画布等。

const imageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/e/ec/Carl_Friedrich_Gauss_1840_by_Jensen.jpg/800px-Carl_Friedrich_Gauss_1840_by_Jensen.jpg";
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
const path2 = new Path2D();
// I moved a bit the arc so that the filter is better visible
path2.moveTo(320, 160);
path2.arc(270, 160, 50, 0, 2 * Math.PI);

ctx.fillText("Please wait loading image..",20,20);
const image = new Image;
image.src = imageUrl;
image.onload = () => {
  canvas.width = image.width;
  canvas.height = image.height;
  ctx.lineWidth = 16;
  ctx.drawImage(image, 0, 0);
  slider.addEventListener("input", () => {
    setBrightness(Number(slider.value));
    val.textContent = slider.value;
  });
}

function setBrightness(value) {
  // start with only the arc stroke on the context
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  ctx.stroke(path2);
  // use it as a mask so that the image is only visible where the stroke is
  // with the expected filter applied
  ctx.filter = `brightness(${value + 100}%)`;
  ctx.globalCompositeOperation = "source-in";    
  ctx.drawImage(image, 0, 0);
  // draw the image again, only where we didn't draw yet,
  // without filter
  ctx.filter = "none";
  ctx.globalCompositeOperation = "destination-atop";
  ctx.drawImage(image, 0, 0);

  // reset gCO
  ctx.globalCompositeOperation = "source-over";
}
Brightness<input id="slider" type="range" min="-100" max="400" value="0" step=".1"><span id="val"></span><br>
<canvas id="canvas"></canvas>

另一个解决方案是,因为您所做的一切都是drawImage()一个资源,所以从该资源创建一个CanvasPattern,并将其用作strokeStyle,代码较少,但可能不适合所有用例。
一个二个一个一个
最后,由于您只使用亮度过滤器,因此可以使用混合模式来获得类似的效果,虽然与CSS过滤器不完全相同,但这将具有在Safari浏览器中工作的优势。

const imageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/e/ec/Carl_Friedrich_Gauss_1840_by_Jensen.jpg/800px-Carl_Friedrich_Gauss_1840_by_Jensen.jpg";
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
const path2 = new Path2D();
path2.moveTo(320, 160);
path2.arc(270, 160, 50, 0, 2 * Math.PI);

ctx.fillText("Please wait loading image..",20,20);
const image = new Image;
image.src = imageUrl;
image.onload = () => {
  canvas.width = image.width;
  canvas.height = image.height;
  ctx.lineWidth = 16;
  ctx.drawImage(image, 0, 0);
  slider.addEventListener("input", () => {
    setBrightness(Number(slider.value));
    val.textContent = slider.value;
  });
}

function setBrightness(value) {
  ctx.drawImage(image, 0, 0);
  // kind of hackish multipass "overlay" blending to approach brightness()
  // I'm sure there are better ways to do this
  ctx.strokeStyle = value < 0 ? "black" : "white";
  const numberOfPass = Math.abs(value) / 200;
  ctx.globalCompositeOperation = "overlay";
  for (let i = 0; i < numberOfPass - 1; i++) {
    ctx.stroke(path2);
  }
  const lastPassAlpha = numberOfPass - Math.round(numberOfPass);
  ctx.globalAlpha = lastPassAlpha || 1;
  ctx.stroke(path2);
  ctx.globalAlpha = 1;
  ctx.globalCompositeOperation = "source-over";
}
Brightness<input id="slider" type="range" min="-100" max="400" value="0" step="0.1"></input><span id="val"></span><br>
<canvas id="canvas"></canvas>

相关问题