SVG 渲染到画布上,在视网膜显示器上模糊 [英] SVG rendered into canvas blurred on retina display
问题描述
我在将 SVG 渲染到画布时遇到了问题.在 Retina 显示器上,画布呈现为 base64 url 并设置为 SRC into 模糊.
我尝试了下面列表中描述的各种方法,但都没有成功:
- https://tristandunn.com/2014/01/24/rendering-svg-on-canvas/
- 如何修复 HTML5 中的模糊文本画布?
- 画布绘图和视网膜显示:可行吗?
- https://www.html5rocks.com/en/tutorials/canvas/hidpi/
现在我不知道我该怎么做才能让它变得更好.请查看我的结果:jsfiddle.net/a8bj5fgj/2/
更新小提琴修复:jsfiddle.net/a8bj5fgj/7/
Retina display
视网膜和超高分辨率显示器的像素尺寸小于人眼所能分辨的平均尺寸.渲染一条线最终看起来像一条更亮的线.为了解决检测高分辨率显示的页面所涉及的问题,会将默认的 CSS 像素大小更改为 2.
DOM 知道这一点并调整其渲染以进行补偿.但是 Canvas 并不知道,它的渲染只是放大了.画布的默认显示渲染类型是双线性插值.这可以平滑从一个像素到下一个像素的过渡,这对于照片来说非常有用,但对于线条、文本、SVG 等则不太好.
一些解决方案
首先是在画布上关闭双线性过滤.这可以通过 CSS 规则
image-rendering: pixelated;
来完成,虽然这不会创造在 DOM 上渲染的 SVG 的质量,但会减少一些用户体验的模糊外观.在将 SVG 渲染到画布时,您应该关闭图像平滑,因为这会降低 svg 图像的质量.SVG 在内部呈现,并且在将内部副本呈现到画布上时不需要额外的平滑处理.
要做到这一点
ctx.imageSmoothingEnabled = false;
检测 CSS 像素大小.窗口变量
devicePixelRatio
返回与实际屏幕物理像素大小相比的 CSS 像素大小.视网膜和高分辨率设备的值通常为 2.然后您可以使用它来设置画布分辨率以匹配物理像素分辨率.但是有一个问题,因为
devicePixelRatio
并非在所有浏览器上都支持,并且devicePixelRatio
受页面缩放设置的影响.因此,最基本的是使用
devicePixelRatio
并假设很少有人放大超过 200%.
Code 假设 canvas.style.width
和 canvas.style.height
已经正确设置.
if(devicePixelRatio >= 2){画布宽度 *= 2;画布高度 *= 2;}
既然您已经提高了分辨率,您还必须增加渲染尺寸.这可以通过画布转换完成,最好将其创建为函数.
function setCanvasForRetina(canvas){画布宽度 *= 2;画布高度 *= 2;canvas.setTransform(2,0,0,2,0,0);}
<块引用>
注意我没有通过devicePixelRatio"的值增加像素大小这是因为视网膜设备只有2倍的分辨率,如果纵横比大于2是因为客户端放大了.尊重画布的预期行为,如果可以,我不会针对缩放设置进行调整.虽然这不是规则只是建议.
更好的猜测
以上两种方法要么是止损解决方案,要么是简单的猜测.您可以通过检查某些系统来提高您的胜算.
Retina 显示器目前为一组固定的设备(手机、平板电脑、笔记本电脑)提供一组固定的分辨率.
您可以查询window.screen.width
和window.screen.height
以确定绝对物理像素分辨率并将其与已知的视网膜显示器分辨率相匹配.您还可以查询 userAgent 以确定设备类型和品牌.
将所有这些放在一起,您可以改进猜测.下一个函数会猜测显示器是否为视网膜.您可以使用类似的方法来确定设备是否为视网膜,然后相应地增加画布分辨率.
以下代码的信息可在 wiki Retina Display Models 中找到此信息可以是机器如果您想保持最新状态,请使用 Wiki 的 SPARQL 接口进行查询.
Demo 猜是否是 Retina.
rWidth.textContent = screen.widthrHeight.textContent = 屏幕高度aWidth.textContent = screen.availWidthaHeight.textContent = screen.availHeightpWidth.textContent = 内部宽度pHeight.textContent = 内部高度dWidth.textContent = document.body.clientWidthdHeight.textContent = document.body.clientHeight//doWidth.textContent = document.body.offsetWidth//doHeight.textContent = document.body.offsetHeight//sWidth.textContent = document.body.scrollWidth//sHeight.textContent = document.body.scrollHeightpAspect.textContent = devicePixelRatiouserA.textContent = navigator.userAgent函数 isRetina(){//来源 https://en.wikipedia.org/wiki/Retina_Display#Modelsvar knownRetinaResolutions = [[272,340], [312,390], [960,640], [1136,640], [1334,750], [1920,1080], [2048,1536], [2732,2040]], [2560,1600], [2880,1800], [4096,2304], [5120,2880];var knownPhones = [[960,640], [1136,640], [1334,750], [1920,1080]];var knownPads = [[2048,1536], [2732,2048]];var knownBooks = [[2304,1440], [2560,1600], [2880,1800], [4096,2304], [5120,2880]];var hasRetinaRes = knownRetinaResolutions.some(known => known[0] === screen.width && known[1] === screen.height);var isACrapple =/(iPhone|iPad|iPod|Mac OS X|MacPPC|MacIntel|Mac_PowerPC|Macintosh)/.test(navigator.userAgent);var hasPhoneRes = knownPhones.some(known => known[0] === screen.width && known[1] === screen.height);var isPhone =/iPhone/.test(navigator.userAgent);var hasPadRes = knownPads.some(known => known[0] === screen.width && known[1] === screen.height);var isPad =/iPad/.test(navigator.userAgent);var hasBookRes = knownBooks.some(known => known[0] === screen.width && known[1] === screen.height);var isBook =/Mac OS X|MacPPC|MacIntel|Mac_PowerPC|Macintosh/.test(navigator.userAgent);var isAgentMatchingRes = (isBook && hasBookRes && !isPad && !isPhone) ||(isPad && hasPadRes && !isBook && !isPhone) ||(isPhone && hasPhoneRes && !isBook && !isPad)返回 devicePixelRatio >= 2 &&isACrapple &&hasRetinaRes &&isAgentMatchingRes;}guess.textContent = isRetina() ?是":否";
div, h1, span {字体系列:宋体;}跨度 {字体粗细:粗体}
<h1>系统信息</h1><div>设备分辨率:<span id = "rWidth"></span>通过<span id = "rHeight"></span>像素<div>可用分辨率:<span id = "aWidth"></span>通过<span id = "aHeight"></span>像素
<div>页面分辨率:<span id = "pWidth"></span>通过 </span>CSS 像素
<div>文档客户端资源:<span id = "dWidth"></span>通过 </span>CSS 像素
<div>像素方面:<span id = "pAspect"></span>
<div>用户代理:<span id="userA"></span>
<h3>最佳猜测是retina "<span id = "guess"></span>!"</h3>