• 解决 canvas 绘图在高清屏中的模糊问题


    解决 canvas 绘图在高清屏中的模糊问题

    为什么模糊

    CSS 像素是一个抽象单位(1 px),浏览器根据某种规则将 css 像素转化为屏幕需要的实际像素值。

    在高清屏之前,屏幕上显示一个像素点需要 1 x 1 个 css 像素。在高清屏,同样大小的屏幕上要显示一个点,就需要 n x 1 个 css 像素。这里的 n 就是设备像素比 devicePixelRatio >= 2.

    也就是说,同样大小的区域,高清屏需要更多的 css 像素:css 像素不够,则会放大内容——变得模糊;css 像素足够,则会缩小内容——变得清晰。放大、缩小的比例由 devicePixelRatio 决定。

    比如说 iPhone 4s,它的 devicePixelRatio 为 2,假设屏幕上有块区域大小为 100px x 100px,上面有张 100px x 100px大小的图片,那么这张图片会被放大 2 倍后再渲染到这块区域,所以看起来就模糊了。

    canvas 绘图在高清屏中模糊

    canvas 属于位图,绘制在它上面的文字、图片、线条也属于位图,经放大后就失真、显得模糊了。要解决这个问题,我们就需要 canvas 拥有更多的 css 像素,即让 canvas 足够大。多大才够呢?太大会不会浪费资源/性能?我们需要因地制宜,根据 devicePixelRatio 来决定画布的大小。

    function setupCanvas(canvas) {
      var dpr = window.devicePixelRatio || 1
      var rect = canvas.getBoundingClientRect()
    
      canvas.width = rect.width * dpr
      canvas.height = rect.height * dpr
    
      var ctx = canvas.getContext('2d')
      ctx.scale(dpr, dpr)
    
      return ctx
    }
    
    // 现在我们只需要根据 UI 设计图绘制需要的内容
    // 由于使用了 setupCanvas,绘制的内容在各种高清屏中表现清晰、一致
    var ctx = setupCanvas(document.querySelector('.my-canvas'));
    ctx.lineWidth = 5;
    ctx.beginPath();
    ctx.moveTo(100, 100);
    ctx.lineTo(200, 200);
    ctx.stroke();
    

    在 setupCanvas 函数中,我们根据屏幕的 devicePixelRatio 对 canvas 画布本身进行放大,然后使用 ctx.scale() 放大 canvas 单位,这样在 ctx 上下文绘制的内容就会被放大,使得最后生成的图片清晰的显示在对应的屏幕上。

    实际上,我们还要兼顾不同大小、不同分辨率的屏幕。一般设计师会给我们宽度为 375px 的设计图,这需要我们根据屏幕大小进行缩放:

    function setupCanvas(canvas) {
      const UI_WIDTH = 375
      const DOC_WIDTH = document.documentElement.clientWidth
      const DPR = window.devicePixelRatio || 1
      let scale = (DPR * DOC_WIDTH / UI_WIDTH).toFIxed(2)
      //let rect = canvas.getBoundingClientRect()
    
      canvas.width = canvas.width * scale
      canvas.height = canvas.height * scale
    
      let ctx = canvas.getContext('2d')
      ctx.scale(scale, scale)
    
      return ctx
    }
    

    术语

    device pixel

    设备像素(又称物理像素、屏幕像素)是显示屏的最小物理单元,是我们在屏幕上能看到的最小点。

    device-independent pixel

    设备无关像素(又称密度无关像素,DIP)是一个抽象单位,表示计算机中的一个虚拟点,由系统转为一个设备像素点。

    devicePixelRatio

    设备像素比,它的值等于设备像素/设备无关像素,devicePixelRatio = DP/DIP

    css pixel

    css 像素是浏览器使用的抽象单位,属于设备无关像素(DIP)。我们看到的内容,是浏览器将 css 像素转化为设备像素后的结果。

    矢量图

    矢量图是根据几何特性来绘制图形,矢量可以是一个点或一条线,矢量图只能靠软件生成,文件占用内在空间较小,因为这种类型的图像文件包含独立的分离图像,可以自由无限制的重新组合。它的特点是放大后图像不会失真。

    位图

    位图图像(bitmap),亦称为点阵图像或绘制图像,是由称作像素(图片元素)的单个点组成的。当放大位图时,图像就失真、模糊了。

    引用

  • 相关阅读:
    iOS App播放完自己的音视频后,如何重新继续播放后台音乐
    苹果APP内购客户付款成功,没收到相应虚拟产品的解决办法
    Xcode11.1 踩坑备忘录
    foaf
    安卓开发:UI组件-图片控件ImageView(使用Glide)和ScrollView
    安卓开发:UI组件-RadioButton和复选框CheckBox
    安卓开发:UI组件-Button和EditText
    安卓开发:UI组件-布局管理器和文本显示
    基础环境系列:PHP7.3.0并连接pache/IIS和MySQL
    基础环境系列:MySQL8.0.12
  • 原文地址:https://www.cnblogs.com/fayin/p/10173984.html
Copyright © 2020-2023  润新知