【问题标题】:Improving image quality of CSS-downscaled elements提高 CSS 缩小元素的图像质量
【发布时间】:2016-12-09 04:24:37
【问题描述】:

我正在使用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>

Demo also on JSFiddle

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


请缩小,看看那条线有多嘈杂,即使缩放是以0.25 为步长并使用 CSS 完成的。 我怎样才能摆脱这种像素噪音? 这个问题发生在最新的 Google Chrome 和 Microsoft Edge 中,在其他浏览器中未经测试。无论是否使用 3D GPU 加速,都会出现此问题。

注意:显然,这是Minimal, Complete, and Verifiable example,实际工作要复杂得多。

数百个线条形状按程序绘制到画布上(每行toDataUrl(每行约40ms)异步缓存到img元素,这样屏幕平移——这也是一个必需的功能——工作更顺畅,因为在屏幕上移动 img 元素比移动 canvas 元素(或在单个画布上重绘所有线条)便宜得多,无论是元素本身、容器还是被翻译成给定方向的浏览器视口。

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

以下是我试过的东西列表,没有效果:

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

我也尝试在缩小时使用filter: blur,但它是did not yield a better quality,因为在屏幕上呈现给定形状之后应用了模糊效果。

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


这个问题与similar questions 调查因缩小导致的不良图像质量有什么不同?

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

【问题讨论】:

  • 我在 Chromium 中看不到任何像素噪点。版本 48.0.2564.82 Ubuntu 15.04(64 位)。
  • 为什么您认为设置图像尺寸或使用变换会有所不同?这个问题确实和类似的问题没有什么不同。如果设置图像渲染属性没有帮助,您只能尝试使用更大的图像开始,例如。对于 200x200px 目标分辨率,使用 400x400px 图像,并且下采样结果在非整数比例下应该更平滑。
  • 像素图像缩小的方式也因操作系统和浏览器而异。我在 MBP - Retina 和标准屏幕(Firefox 和 Safari)上进行了测试。我觉得没问题(尝试缩放):imgur.com/a/E2l2B
  • 我个人认为 SVG 会是这里的出路。 可缩放矢量图形等等。例如,您提供的演示是一个简单的path,其中一条贝塞尔曲线带有marker-end 箭头。
  • @john-white 如果您以与渲染不同的尺寸显示图像,您已经在客户端进行下采样。

标签: javascript css canvas


【解决方案1】:

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

即使是 mipmap 方法也行不通。

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

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

【讨论】:

  • 看来我确实需要采用不同的方法并削减一些交互功能。顺便说一句,使用 mipmap 方法,我按比例增加了实际形状的 scale 大小,因此从不实际缩放低于其原始大小的 0.5 的形状。从视觉上看,它会产生非常高质量的图像,但由于必须进行所有重新缓存,因此对性能的要求很高。
【解决方案2】:

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

正如您在 demo 中看到的那样,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>

显然并不完美。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-07
    • 1970-01-01
    • 2013-02-15
    • 2020-06-12
    • 1970-01-01
    相关资源
    最近更新 更多