提高CSS缩小元素的图像质量

Improving image quality of CSS-downscaled elements

本文关键字:图像质量 元素 缩小 CSS 提高      更新时间:2023-09-26

我正在使用transform: scale(x)缩小我出色的图形编辑器的内容。当缩小时,比例向0(不包括)下降,当放大时,比例上升,最高可达1(包括),这意味着完全缩放或初始比例。

然而,当大幅缩小时,图像质量开始变得非常嘈杂——请考虑以下示例,并注意缩小将如何使图像外观变得嘈杂:

var graphContainer = document.getElementById("graph-container");
var zoomInButton = document.getElementById("zoom-in-button");
var zoomOutButton = document.getElementById("zoom-out-button");
var zoomLevel = 1;
zoomInButton.addEventListener("click", function () {
    zoomLevel = Math.max(1, zoomLevel - 0.25);
    graphContainer.style.transform = "scale(" + (1 / zoomLevel) + ")";
});
zoomOutButton.addEventListener("click", function () {
    zoomLevel = zoomLevel + 0.25;
    graphContainer.style.transform = "scale(" + (1 / zoomLevel) + ")";
});
#editor-container {
    background-color: #001723;
}
#graph-container { transform-origin: top center; }
<div id="editor-container">
    <button id="zoom-in-button">Zoom in</button>
    <button id="zoom-out-button">Zoom out</button>
    <div id="graph-container">
        <img class="shape" src="http://i.imgur.com/zsWkcGz.png" />
    </div>
</div>

也在JSFiddle 上演示

此图像是一个画布绘制的形状,以交互方式可视化两个图形节点之间的连接,并导出为png


请缩小,看看这条线有多吵,即使缩放是在0.25和CSS的步骤中完成的如何消除此像素噪声该问题发生在最新的谷歌Chrome和微软Edge中,未在其他浏览器中测试。无论是否使用3D GPU加速,都会出现此问题。

注意:显然,这是一个最小、完整和可验证的例子,实际工作要复杂得多。

成群的线条形状按程序绘制在画布上(每行<1ms),然后在空闲时使用toDataUrl异步缓存到img元素(每行约40ms),这样屏幕平移(这也是一项必需的功能)工作得更顺利,因为在屏幕上移动img元素比移动canvas元素(或在单个画布上重新绘制所有行)便宜得多,无论是元素本身、容器,还是转换为给定方向的浏览器视口。

因此,生成mipmaps并不是一个真正的选项,或者只是作为最后的手段,因为它将带来显著的性能损失(每个mip级别都必须缓存到一个单独的图像上,至少会将性能减半)。不过,我相信这是可以避免的。幸运的是,在每一个缩放步骤上重新绘制线条形状都会抹杀幻灯片的性能。

以下是我尝试过的事情的列表,没有效果:

  • 通过在形状元素本身或容器上定义以下CSS属性值来提示更好的图像质量:
image-rendering: pixelated | optimizeSpeed | optimizeQuality
  • 使用伪transform强制提升渲染层到GPU加速
  • scale3d代替scale
  • img.widthimg.height减半,然后通过加倍img.style.widthimg.style.height进行补偿
  • 不将画布结果缓存到img中,而是直接显示canvas元素(性能较慢,质量较差)

我也尝试过在缩小时使用filter: blur,但它并没有产生更好的质量,因为模糊效果本身是在屏幕上渲染给定形状后应用的。

除了创建每个形状的下采样版本,有效地创建软件渲染的mipmap(LOD)系统之外,我还能做些什么来消除这种像素噪声(正如我所写,它希望强烈避免)


这个问题与一系列类似的问题有什么不同,这些问题都是通过缩小尺度来调查糟糕的图像质量的

  • 在这里,容器被缩小了(并进行了CSS转换),而不是单独的图像元素。没有对实际的图像数据进行任何操作,这是类似主题中讨论的内容

使用SVG图像而不是PNG可以获得更好的结果,而且它们也很容易生成并嵌入到代码中,甚至不需要托管它们。

正如你在这个演示中看到的,SVG不会像素化或变得模糊,你会在像Retina这样的高分辨率屏幕上得到更好的结果。

SVG代码:

<svg class="shape" width="440px" height="319px" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
        <path d="M1,316.040132 C1,316.040132 241.5837,339.680482 241.5837,163.497447 C241.5837,-12.6855883 439,2.31775322 439,2.31775322" id="Path" stroke="#50E3C2" stroke-width="2"></path>
    </g>
</svg>

显然不是完美的。

对具有尖锐边缘的图像进行插值将不可避免地产生伪影。即使它是抗锯齿的,即使它是模糊的。你可以在Photoshop中测试这个,你会得到同样的结果。

即使是mipmap方法也不起作用。

固有的问题是像素无法保留复杂矢量形状的所有信息;当你挤压像素时,形状就会丢失。有两种提高质量的解决方案:

  • 要么在缩放图片之前以更高的分辨率渲染图片,这样就有更多的像素来存储形状的意图
  • 或者直接按照目标比例渲染矢量形状