在画布(和 img)上使用最近邻和 CSS 缩放
使用 CSS zoom
属性时,如何说服浏览器使用“最近邻居”,而不是“双线性”或任何其他更高级的缩放算法?
我的设置是一个包含画布的 div,该 div 通过 JavaScript 将其缩放设置为
和为了获得最近的邻居,我在 CSS 中使用 image-rendering: -webkit-optimize-contrast
。该应用程序可在此处使用(“z”放大,“shift-z”缩小),我的CSS是此处
这是 OSX 上 Chrome 中所需的效果(缩放设置为 3200%):
但在 Windows 7 上的 Chrome 中也有同样的情况:
在这两种情况下,它都是“vanilla”Chrome(版本 15.xx)框中,没有打开实验标志。
如何说服 Windows 上的 Chrome 使用最近邻居?就此而言,我如何才能说服所有浏览器? Safari 也不使用最近邻(到目前为止,该应用程序仅适用于基于 WebKit 的浏览器)
CSS image-rendering
属性确实会影响 Chrome /OSX 并给了我想要的效果。但 Chrome/Windows 和 Safari(5.1)/OSX 似乎都完全忽略了它。有些感觉告诉我我只是运气不好,但我想我应该问一下。
在 div 容器上使用 zoom
非常简单,并且在 Chrome/OSX 中运行得非常好,如果我必须在内部缩放画布,我也可以这样做。但如果可能的话,我更喜欢一行代码解决方案!
更新:我发现使用image-rendering:optimizeSpeed
有帮助。然而,它在 Chrome/Windows 中似乎很挑剔。如果我将其设置在太多元素上(我最初尝试过,我的容器和所有画布),它不会生效。但如果我只将其应用到 canvas
上,我就可以完成 98% 的任务。
现在我的问题是我第一次在放大时绘制,它工作得很好,所有其他后续绘制操作在发生时都是模糊的,然后恢复到正确的最近邻居(我的应用程序首先绘制到草稿画布中,然后将绘图应用到真实的画布上)。 Chrome 坚持使用双线性的草稿画布有些奇怪。我认为通过一些挖掘我可以解决这个问题。
更新2: Chrome/Windows 上的image-rendering
似乎没有很好地实现,并且存在一些问题。我现在可以确认 Chrome/Windows 不支持 optimizeSpeed
和 optimizeQuality
值。如果您为它们设置图像渲染,Chrome 将忽略该设置。 Chrome/Windows 确实可以识别 -webkit-optimize-contrast
,但它并不能一致地使用它。 Chrome 会几乎随机地在双线性缩放算法和最近邻算法之间切换。我无法始终如一地让 Chrome 使用最近邻居。
我尝试在 Windows 上构建 Chromium 17,其行为方式相同。
Firefox (8.0.1) 看起来很有前途,因为它似乎很好地遵守了 -moz-crisp-edges
。最初我将 Chrome 定位为这个应用程序的“理想浏览器”,我可能会切换到 Firefox。
最后,Chrome 似乎正在酝酿对图像渲染的适当支持,只是还没有完全实现。 WebKit 本身声称完全支持所有图像渲染值,但我猜测 Chrome 使用的 WebKit 构建尚未完全更新到此新修复。
When using the CSS zoom
property, how can I convince the browser to use "nearest neighbor", instead of "bilinear" or any other more advanced zooming algorithms?
My setup is a div that contains a canvas, and the div gets its zoom set via JavaScript to be <div style="zoom:3200%">...</div>
and to get nearest neighbor, I am using image-rendering: -webkit-optimize-contrast
in my CSS. The app is available here ('z' zooms in, 'shift-z' zooms back out), and my css is here
Here is the desired effect in Chrome on OSX (zoom is set to 3200%):
But here is the same thing in Chrome on Windows 7:
In both cases it is "vanilla" Chrome (version 15.x.x) out of the box, no experimental flags are turned on.
How can I convince Chrome on Windows to use nearest neighbor? For that matter, how can I convince all browsers? Safari also does not use nearest neighbor (so far the app only works in WebKit based browsers)
The CSS image-rendering
property does affect Chrome/OSX and gives me the desired effect. But Chrome/Windows and Safari(5.1)/OSX both seem to completely ignore it. Something tells me I'm just out of luck, but I figured I'd ask.
Using zoom
on the div container is so simple and works beautifully in Chrome/OSX, if I must resort to scaling my canvases internally, I can do that too. But would prefer the literally one line of code solution if possible!
UPDATE: I have found the use of image-rendering: optimizeSpeed
helps. However it seems finicky in Chrome/Windows. If I set it on too many elements (I initially tried, my containers and all canvases), it doesn't take effect. But if I apply it to just canvas
, I get 98% of the way there.
Now my problem is the first time I draw while zoomed in, it works perfectly, all other subsequent drawing actions are fuzzy while they are taking place, then revert to the correct nearest-neighbor afterwards (my app draws into a scratch canvas first, then applies the drawing to the real canvas). There is something odd about the scratch canvas where Chrome insists on using bilinear. I think with some digging I can resolve that.
UPDATE2: It seems like image-rendering
on Chrome/Windows just isn't implemented well and is a bit buggy. I can now confirm that the values optimizeSpeed
and optimizeQuality
are not supported on Chrome/Windows. If you set image-rendering to them, Chrome will ignore the set. Chrome/Windows does recognize -webkit-optimize-contrast
, however it does not use it consistently. Chrome will flip between what looks to be a bilinear scaling algorithm and nearest-neighbor almost at random. I've not been able to consistently get Chrome to use nearest-neighbor.
I tried a build of Chromium 17 on Windows and it behaves the same way.
Firefox (8.0.1) is looking pretty promising though as it does seem to honor -moz-crisp-edges
quite well. Originally I was targeting Chrome as my "ideal browser" for this app, I might just switch over to Firefox.
In the end, it seems like proper support for image-rendering
is in the pipeline for Chrome, just not quite there yet. WebKit itself claims to fully support all image-rendering values, but I'm guessing the build of WebKit that Chrome uses hasn't quite updated to this new fix.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
有一个办法。我在这里问了一个与此类似的问题:如何在没有抗锯齿的情况下拉伸图像 并得到了非常好的回应。从那时起,我对它进行了相当多的修改,但这是一个简单的版本,单击时会拉伸(没有抗锯齿): http://jsfiddle.net/howlermiller/U2eBZ/1/
不过,这是令人难以置信的黑客行为。除非必须,否则不要使用它。每次点击图像时它都必须重新创建图像,因此对于大图像来说,速度会很慢而且很糟糕。但它确实可以在 Chrome/Windows 上运行。
编辑: 支持此功能现已支持 CSS3 规范! 支持超级不稳定< /a> 在目前,但是 Chrome 刚刚添加了支持,所以我希望我们能够使用不久之后。美好时光!
演示
There is a way. I asked a question similar to this over here: How to stretch images with no antialiasing and got a really good response. I've modified it quite a bit since then, but here's a simple version which stretches (w/out anti-aliasing) when clicked: http://jsfiddle.net/howlermiller/U2eBZ/1/
It's incredibly hackish though. Don't use it unless you must. It has to re-create the image every time you click on it, so with a big image it would be slow and terrible. But it does work on Chrome/Windows.
Edit: This is supported in the CSS3 spec now! Support is super spotty at the moment, but Chrome just added support so I'm hopeful that we'll be able to use it before too long. Good times!
Demo
ctx.webkitImageSmoothingEnabled=false 现在似乎从 22 开始就可以工作。
ctx.webkitImageSmoothingEnabled=false now seems to work since 22.
由于您无论如何都在使用画布,因此您也可以实现自己的缩放并手动实现最近邻居调整大小。
我怀疑即使你解决了这个问题,有一天你也会遇到其他问题。
@Timothy 的答案似乎有一些很好的代码,您可以使用它来帮助进行实际的数学计算。
Since you're using canvas anyway, you might as well implement your own zoom and manually implement nearest neighbour resizing.
I suspect even if you solve this problem, you'll run into something else one day.
@Timothy's answer seems to have some good code you can use to help with the actual math.