为什么 HTML5 canvas svg 过滤器有损?
Why is HTML5 canvas svg filter lossy?
下面是您应该能够在浏览器中 运行 的示例代码。它应该首先加载图像。图像显示后,您可以点击它查看原始图像和带有 identitdy svg 滤镜的图像之间的差异。
可能很难直接在浏览器上看到,但您可以将结果下载为图像并在任何图像查看器中打开。结果不是很奇怪。它有类似于某种压缩伪影的斑点区域。
所以我的问题是:
- 应用任何 svg 过滤器是否会导致质量下降?
- 为什么会这样? (可能是我漏掉了,文档里没有提到)
- 如何实现无损 svg 滤镜?
<body>
<canvas id='canvas' width=850 height=850></canvas>
<svg width="0" height="0" style="position:absolute;z-index:-1;">
<defs>
<filter id="identity" x="0" y="0" width="100%" height="100%">
<feComponentTransfer></feComponentTransfer>
</filter>
</defs>
</svg>
</body>
<script>
canvas = document.getElementById('canvas')
image = new Image()
image.src = 'https://cms-assets.tutsplus.com/uploads/users/127/posts/31341/final_image/1_10.png'
image.onload = function() {
let ctx = canvas.getContext('2d')
ctx.drawImage(this, 0, 0)
canvas.image = this
}
canvas.onclick = function() {
let ctx = this.getContext('2d')
ctx.clearRect(0, 0, this.width, this.height)
ctx.filter = 'none'
ctx.drawImage(this.image, 0, 0)
ctx.globalCompositeOperation = 'difference'
ctx.filter = 'url(#identity)'
ctx.drawImage(this.image, 0, 0)
// 20x the difference
ctx.filter = 'brightness(20)'
ctx.drawImage(canvas, 0, 0)
}
</script>
线性 RGB V sRGB(对数)
使用线性颜色模型通常会导致颜色精度下降。始终使用 sRGB 以获得最佳效果。
默认颜色插值过滤器是线性 RGB
feComponentTransfer
的默认颜色模型是线性 RGB,可能会产生一些瑕疵。
强制滤镜使用 sRGB 使用属性 color-interpolation-filters="sRGB"
下面的示例片段显示使用 sRGB 时没有损失。当您看到图像时,单击它以查看结果。应该全黑不亏。
<body>
<canvas id='canvas' width=850 height=850></canvas>
<svg width="0" height="0" style="position:absolute;z-index:-1;">
<defs>
<filter id="identity" x="0" y="0" width="100%" height="100%">
<feComponentTransfer color-interpolation-filters="sRGB"></feComponentTransfer>
</filter>
</defs>
</svg>
</body>
<script>
canvas = document.getElementById('canvas')
image = new Image()
const ctx = canvas.getContext('2d')
image.src = 'https://cms-assets.tutsplus.com/uploads/users/127/posts/31341/final_image/1_10.png'
image.onload = () => ctx.drawImage(image, 0, 0);
canvas.onclick = function() {
ctx.globalCompositeOperation = 'source-over'
ctx.filter = 'none'
ctx.drawImage(image, 0, 0)
ctx.globalCompositeOperation = 'difference'
ctx.filter = 'url(#identity)'
ctx.drawImage(image, 0, 0)
ctx.filter = 'brightness(20)'
ctx.drawImage(canvas, 0, 0)
}
</script>
下面是您应该能够在浏览器中 运行 的示例代码。它应该首先加载图像。图像显示后,您可以点击它查看原始图像和带有 identitdy svg 滤镜的图像之间的差异。
可能很难直接在浏览器上看到,但您可以将结果下载为图像并在任何图像查看器中打开。结果不是很奇怪。它有类似于某种压缩伪影的斑点区域。
所以我的问题是:
- 应用任何 svg 过滤器是否会导致质量下降?
- 为什么会这样? (可能是我漏掉了,文档里没有提到)
- 如何实现无损 svg 滤镜?
<body>
<canvas id='canvas' width=850 height=850></canvas>
<svg width="0" height="0" style="position:absolute;z-index:-1;">
<defs>
<filter id="identity" x="0" y="0" width="100%" height="100%">
<feComponentTransfer></feComponentTransfer>
</filter>
</defs>
</svg>
</body>
<script>
canvas = document.getElementById('canvas')
image = new Image()
image.src = 'https://cms-assets.tutsplus.com/uploads/users/127/posts/31341/final_image/1_10.png'
image.onload = function() {
let ctx = canvas.getContext('2d')
ctx.drawImage(this, 0, 0)
canvas.image = this
}
canvas.onclick = function() {
let ctx = this.getContext('2d')
ctx.clearRect(0, 0, this.width, this.height)
ctx.filter = 'none'
ctx.drawImage(this.image, 0, 0)
ctx.globalCompositeOperation = 'difference'
ctx.filter = 'url(#identity)'
ctx.drawImage(this.image, 0, 0)
// 20x the difference
ctx.filter = 'brightness(20)'
ctx.drawImage(canvas, 0, 0)
}
</script>
线性 RGB V sRGB(对数)
使用线性颜色模型通常会导致颜色精度下降。始终使用 sRGB 以获得最佳效果。
默认颜色插值过滤器是线性 RGB
feComponentTransfer
的默认颜色模型是线性 RGB,可能会产生一些瑕疵。
强制滤镜使用 sRGB 使用属性 color-interpolation-filters="sRGB"
下面的示例片段显示使用 sRGB 时没有损失。当您看到图像时,单击它以查看结果。应该全黑不亏。
<body>
<canvas id='canvas' width=850 height=850></canvas>
<svg width="0" height="0" style="position:absolute;z-index:-1;">
<defs>
<filter id="identity" x="0" y="0" width="100%" height="100%">
<feComponentTransfer color-interpolation-filters="sRGB"></feComponentTransfer>
</filter>
</defs>
</svg>
</body>
<script>
canvas = document.getElementById('canvas')
image = new Image()
const ctx = canvas.getContext('2d')
image.src = 'https://cms-assets.tutsplus.com/uploads/users/127/posts/31341/final_image/1_10.png'
image.onload = () => ctx.drawImage(image, 0, 0);
canvas.onclick = function() {
ctx.globalCompositeOperation = 'source-over'
ctx.filter = 'none'
ctx.drawImage(image, 0, 0)
ctx.globalCompositeOperation = 'difference'
ctx.filter = 'url(#identity)'
ctx.drawImage(image, 0, 0)
ctx.filter = 'brightness(20)'
ctx.drawImage(canvas, 0, 0)
}
</script>