gpt4 book ai didi

javascript - SVG 渲染成 Canvas ,在视网膜显示器上模糊

转载 作者:搜寻专家 更新时间:2023-11-01 04:22:42 45 4
gpt4 key购买 nike

我在将 SVG 渲染到 Canvas 上时遇到问题。在视网膜显示 Canvas 呈现为 base64 url​​ 并设置为 SRC 到是模糊的。

enter image description here

我尝试了以下列表中描述的各种方法,但没有成功:

  • https://tristandunn.com/2014/01/24/rendering-svg-on-canvas/
  • How do I fix blurry text in my HTML5 canvas?
  • Canvas drawing and Retina display: doable?
  • https://www.html5rocks.com/en/tutorials/canvas/hidpi/

  • 现在我不知道我应该怎么做才能让它变得更好。
    请查看我的结果:jsfiddle.net/a8bj5fgj/2/

    编辑:

    更新了修复的 fiddle :jsfiddle.net/a8bj5fgj/7/

    最佳答案

    Retina显示屏

    视网膜和超高分辨率显示器的像素尺寸小于人眼的平均分辨率。渲染一条线最终看起来像一条更轻的线。为了解决涉及检测高分辨率显示的页面的问题,会将默认 CSS 像素大小更改为 2。

    DOM 知道这一点并调整其渲染以进行补偿。但 Canvas 不知道,它的渲染只是按比例放大。 Canvas 的默认显示渲染类型是双线性插值。这可以平滑从一个像素到下一个像素的过渡,这对于照片来说非常有用,但对于线条、文本、SVG 等来说就不那么好了。

    一些解决方案

  • 首先是在 Canvas 上打开双线性过滤。这可以通过 CSS 规则 image-rendering: pixelated; 来完成。虽然这不会创建在 DOM 上呈现的 SVG 的质量,但它会减少一些用户体验的模糊外观。
  • 将 SVG 渲染到 Canvas 时,您应该关闭图像平滑,因为这会降低 svg 图像的质量。 SVG 在内部渲染,当内部副本渲染到 Canvas 上时不需要额外的平滑处理。

    为此 ctx.imageSmoothingEnabled = false;
  • 检测 CSS 像素大小。窗口变量 devicePixelRatio 返回 CSS 像素的大小与实际屏幕物理像素大小的比较。 Retina 和高分辨率设备的值通常为 2。然后您可以使用它来设置 Canvas 分辨率以匹配物理像素分辨率。

    但是存在一个问题,因为并非所有浏览器都支持devicePixelRatio,并且devicePixelRatio受页面缩放设置的影响。

    因此,最基本的使用 devicePixelRatio 并假设很少有人放大 200%。

  • 代码假设 canvas.style.widthcanvas.style.height 已经正确设置。
    if(devicePixelRatio >= 2){        
    canvas.width *= 2;
    canvas.height *= 2;
    }

    现在您已经增加了分辨率,您还必须增加渲染大小。这可以通过 Canvas 变换来完成,最好将其创建为一个函数。
    function setCanvasForRetina(canvas){
    canvas.width *= 2;
    canvas.height *= 2;
    canvas.setTransform(2,0,0,2,0,0);
    }

    Note I do not increase the pixel size by the value of "devicePixelRatio" This is because retina devices will only have a resolution of 2 times, if the aspect ratio is greater than 2 it is because the client has zoomed in. To honor the expected behaviour of the canvas I do not adjust for zoom setting if I can. Though that is not a rule just a suggestion.



    更好的猜测

    以上两种方法要么是权宜之计,要么是简单的猜测。你可以通过检查一些系统来提高你的几率。

    Retina 显示器目前针对一组固定的设备(手机、平板电脑、笔记本电脑)提供一组固定的分辨率。

    您可以查询 window.screen.widthwindow.screen.height 以确定绝对物理像素分辨率并将其与已知的视网膜显示分辨率相匹配。您还可以查询 userAgent 以确定设备类型和品牌。

    将它们放在一起,您可以改进猜测。下一个函数会猜测显示器是否为视网膜。您可以使用类似的方法来确定设备是否为视网膜,然后相应地增加 Canvas 分辨率。

    wiki Retina Display Models 中找到的以下代码的信息 如果您想保持最新,可以使用 Wiki 的 SPARQL 接口(interface)对这些信息进行机器查询。

    演示 猜猜 Retina。

    rWidth.textContent = screen.width
    rHeight.textContent = screen.height

    aWidth.textContent = screen.availWidth
    aHeight.textContent = screen.availHeight

    pWidth.textContent = innerWidth
    pHeight.textContent = innerHeight

    dWidth.textContent = document.body.clientWidth
    dHeight.textContent = document.body.clientHeight

    //doWidth.textContent = document.body.offsetWidth
    //doHeight.textContent = document.body.offsetHeight

    //sWidth.textContent = document.body.scrollWidth
    //sHeight.textContent = document.body.scrollHeight

    pAspect.textContent = devicePixelRatio

    userA.textContent = navigator.userAgent



    function isRetina(){
    // source https://en.wikipedia.org/wiki/Retina_Display#Models
    var knownRetinaResolutions = [[272,340], [312,390], [960,640], [1136,640 ], [1334,750 ], [1920,1080], [2048,1536], [2732,2048], [2304,1440], [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)
    return devicePixelRatio >= 2 &&
    isACrapple &&
    hasRetinaRes &&
    isAgentMatchingRes;
    }

    guess.textContent = isRetina() ? "Yes" : "No";
    div, h1, span {
    font-family : arial;
    }
    span {
    font-weight : bold
    }
    <div class="r-display" id="info">
    <h1>System info</h1>
    <div>Device resolution :
    <span id = "rWidth"></span> by <span id = "rHeight"></span> pixels
    </div>
    <div>Availabe resolution :
    <span id = "aWidth"></span> by <span id = "aHeight"></span> pixels
    </div>
    <div>Page resolution :
    <span id = "pWidth"></span> by <span id = "pHeight"> </span> CSS pixels
    </div>
    <div>Document client res :
    <span id = "dWidth"></span> by <span id = "dHeight"> </span> CSS pixels
    </div>
    <div>Pixel aspect :
    <span id = "pAspect"></span>
    </div>
    <div>User agent :
    <span id="userA"></span>
    </div>
    <h3>Best guess is retina "<span id = "guess"></span>!"</h3>
    </div>


    从你的片段

    这可能会做你想要的。由于我不拥有任何苹果产品,因此除了在 isRetina 上强制设置为 true 之外,我无法对其进行测试。

        function isRetina() {
    // source https://en.wikipedia.org/wiki/Retina_Display#Models
    var knownRetinaResolutions = [[272, 340], [312, 390], [960, 640], [1136, 640], [1334, 750], [1920, 1080], [2048, 1536], [2732, 2048], [2304, 1440], [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);


    return devicePixelRatio >= 2 && isACrapple && hasRetinaRes && isAgentMatchingRes;
    }

    function svgToImage(svg){
    function svgAsImg() {
    var canvas, ctx;
    canvas = document.createElement("canvas");
    ctx = canvas.getContext("2d");
    var width = this.width;
    var height = this.height;
    var scale = 1;
    if(isRetina()){
    width *= 2;
    height *= 2;
    scale = 2;
    }

    canvas.width = width;
    canvas.height = height;
    ctx.setTransform(scale, 0, 0, scale, 0, 0);
    ctx.imageSmoothingEnabled = false; // SVG rendering is better with smoothing off
    ctx.drawImage(this,0,0);
    DOMURL.revokeObjectURL(url);
    try{
    var image = new Image();
    image.src = canvas.toDataURL();
    imageContainer.appendChild(image);
    image.width = this.width;
    image.height = this.height;
    }catch(e){ // in case of CORS error fallback to canvas
    canvas.style.width = this.width + "px"; // in CSS pixels not physical pixels
    canvas.style.height = this.height + "px";
    imageContainer.appendChild(canvas); // just use the canvas as it is an image as well
    }
    };
    var url;
    var img = new Image();
    var DOMURL = window.URL || window.webkitURL || window;
    img.src = url = DOMURL.createObjectURL(new Blob([svg], {type: 'image/svg+xml'}));
    img.onload = svgAsImg;
    }

    svgToImage(svgContainer.innerHTML);
    <div id="svgContainer"><svg width="31" height="40" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 43 55" fill="#736b9e"><path d="m 40.713968,30.966202 c 0.0028,0.05559 -0.01078,0.114956 -0.044,0.178882 -1.545645,2.974287 -2.853499,5.591663 -4.339695,7.673668 -0.788573,1.104704 -2.095869,2.778673 -2.874223,3.773068 -0.994236,1.02684 -6.879641,7.657944 -6.167884,7.049648 -1.292899,1.235403 -5.717368,5.476022 -5.717368,5.476022 0,0 -4.323294,-3.985179 -5.928388,-5.591297 C 14.037321,47.920078 10.708239,43.994015 9.6976253,42.770306 8.6870114,41.546601 8.5086687,40.900753 6.8441265,38.818752 5.8958518,37.63265 4.1376268,34.24638 3.0745121,32.156026 2.9037625,31.86435 2.7398218,31.568267 2.5826899,31.268005 2.5509386,31.228498 2.5238331,31.18779 2.5044312,31.145084 2.4575955,31.041974 2.4164305,30.951055 2.3805569,30.87146 0.95511134,28.003558 0.15221914,24.771643 0.15221914,21.351725 c 0,-11.829154 9.58943056,-21.41858234 21.41858286,-21.41858234 11.829152,0 21.418583,9.58942834 21.418583,21.41858234 0,3.457576 -0.820406,6.72314 -2.275417,9.614477 z M 21.52596,1.5031489 c -10.866018,0 -19.6746717,8.8086521 -19.6746717,19.6746741 0,10.866016 8.8086537,19.674669 19.6746717,19.674669 10.866018,0 19.674672,-8.808648 19.674672,-19.674669 0,-10.866022 -8.808654,-19.6746741 -19.674672,-19.6746741 z" /><g transform="translate(6.5,6) scale(0.060546875)"><path d="M32 384h272v32H32zM400 384h80v32h-80zM384 447.5c0 17.949-14.327 32.5-32 32.5-17.673 0-32-14.551-32-32.5v-95c0-17.949 14.327-32.5 32-32.5 17.673 0 32 14.551 32 32.5v95z"></path><g><path d="M32 240h80v32H32zM208 240h272v32H208zM192 303.5c0 17.949-14.327 32.5-32 32.5-17.673 0-32-14.551-32-32.5v-95c0-17.949 14.327-32.5 32-32.5 17.673 0 32 14.551 32 32.5v95z"></path></g><g><path d="M32 96h272v32H32zM400 96h80v32h-80zM384 159.5c0 17.949-14.327 32.5-32 32.5-17.673 0-32-14.551-32-32.5v-95c0-17.949 14.327-32.5 32-32.5 17.673 0 32 14.551 32 32.5v95z"></path></g></g></svg>
    </div>
    <div id="imageContainer"></div>


    请注意。

    大多数拥有 6/6 视力(帝国国家为 20/20)的人很难看出 Canvas 的略微模糊显示和清晰的 DOM 之间的区别。您应该问自己,您是否需要仔细观察才能确定?你能在正常观看距离看到模糊吗?

    还有一些将显示器缩放到 200% 的人这样做是有充分理由的(视力受损),并且不会欣赏你绕过他们的设置。

    关于javascript - SVG 渲染成 Canvas ,在视网膜显示器上模糊,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41763580/

    45 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com