最近我看到了一篇关于如何解决 HTML2Canvas 导出图片模糊的问题的博客。在过去的项目中,我也使用过 HTML2Canvas 插件将活动页面导出为图片,并且好像也遇到了类似的问题,尽管记忆已经有些模糊了。今天我想仔细研究一下这个问题的原因。
在网上可以找到很多关于 HTML2Canvas 导出图片模糊的问题的讨论,结果发现大部分博客提供的解决方案都是相同的,即通过对 Canvas 的尺寸进行比例放大然后再缩小来解决。但实际上,我并不理解这样的操作究竟是如何使图片变得更清晰的。
首先,我们需要了解一些相关的知识。
devicePixelRatio = 物理像素 / 设备独立像素 (也就是一个css像素)
设备独立像素 dips:代表可以通过程序控制使用的虚拟像素,是一个总体概念,包括了CSS像素,所以前端把它当做CSS逻辑像素理解
css像素:指的是CSS中使用的逻辑像素。px是一个相对单位,相对的是设备物理像素。例如刚才的设备独立像素设置为了 1440 * 900, 那么你的浏览器宽度就是 1440px
css像素和物理像素的关系: devicePixelRatio = 物理像素 / 设备独立像素 (也就是一个css像素等于 devicePixelRatio 个物理像素,可以想象的到,如果 devicePixelRatio 越高那么你的页面更清楚,像素的密度越大可以展示的细节就越多
通过上面三个概念就可以知道,设备的 devicePixelRatio 越高,通常情况下页面会更清晰。这是因为较高的 devicePixelRatio 意味着设备具有更高的像素密度,可以显示更多的像素在同样的物理尺寸上。
当 devicePixelRatio 较高时,浏览器会在渲染网页时使用更多的物理像素来显示每个 CSS 像素,从而提供更高的图像质量和更细腻的显示效果。这可以使文本、图像和其他元素的细节更加清晰、锐利,并且减少了马赛克或锯齿状的外观。
那么在 htmlcanvas2 里面导出图片为什么模糊呢;
我们要知道当图片的 CSS 宽度大于其实际宽度时,浏览器会对图像进行拉伸或缩放以适应所设置的 CSS 尺寸。这种情况下,如果图片被拉伸得过分,可能会导致图像像素被拉伸到不同大小的像素格上,从而使图像变得模糊。
我是不太理解为什么下面这种操作就可以让图片变得高清
const domObj = document.getElementById(dom);
const canvas = document.createElement('canvas');
// 获取设备dpi
const dpi = devicePixelRatio > 1 ? devicePixelRatio : 1;
// 获取dom原宽高
const width = parseInt(domObj.offsetWidth, 10);
const height = parseInt(domObj.offsetHeight, 10);
// 调整画布大小
canvas.width = dpi * width;
canvas.height = dpi * height;
canvas.style.width = width + 'px';
canvas.style.height = height + 'px';
const ctx = canvas.getContext('2d');
// 放大画布
ctx.scale(dpi, dpi);
在这里他首先将画布的width设置为了放大,然后又通过 scale 放大了 ,这里一系列的放大难道就可以让图片清晰吗?
举个:浏览器的 dpr 如果是 2 你就在再放大 1css像素也只能放下 2物理像素。如果两张图片分别是1080x500和2160x1000,并且以相同的CSS尺寸(例如宽度为500像素)显示,那么浏览器会将这两张图片都缩放到相同的CSS尺寸来显示。因此,无论图片的原始分辨率如何,它们被缩放到相同的CSS尺寸后,它们的清晰度是相同的。所以,只用通过 html2canvas 导出图片即可。它自己会缩放对应的 dpr,当然宽高可能需要注意一下。
所以我们只要将画布放大对应的 dpr 倍数就可以
参考文档