canvas 实现图片局部模糊_导出的图片为什么会糊?!

文章探讨了在canvas中实现图片局部模糊后,导出jpeg格式图片出现模糊的原因。通过对DOM转图片原理的分析,发现JPEG的有损压缩导致了图片质量下降。通过调整canvas导出JPEG的质量参数,解决了图片边缘模糊的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

a3d935c8b7d206c9b9e31a2693a63201.png

文章:李蕊(成都中心)

排版:陈倩

5a6222b46e32e75b7d93ab6fc4cee950.gif 81e8ce104ffa8d4f209d9642fc070e85.gif

背景:

某天我收到来自公司首席设计师的一则钉钉消息:轻设计编辑器导出的图片为什么会模糊?当我看到这个问题时,脑海中不禁产生了下面的疑问:怎么会模糊呢?是不是添加到编辑器的图片本身就是模糊的?

之后根据转赠给我的“作品”在编辑器里导出后发现,问题还真存在!换作较为准确的描述应该是:导出jpeg格式的自定义小尺寸图片会导致图片上的某些组件边缘虚化(特别是文字)。

  基础概念

什么是图片?

在计算机上看到的图片可以称为“数字图像”,按存储方式可分为两种:点阵图(Bitmap)和矢量图(Vector)。这里讨论的是点阵图,点阵图又称为位图,在Photoshop里放大一张图片可以看到一个一个的“方格”,即是“像素”,位图就是由像素阵列的排列来呈现图像的。每个像素可以表达色彩的位数是不同的,色彩位数越多,可用的颜色就越多,图像越逼真。

如何界定模糊?

一种是图片本身被放大后,单位面积内精细度降低,就会失真变模糊,因为图片的像素信息是固定的(点阵图)。还有一种情况是超高分辨率电脑屏幕下查看一张图片会比在低分辨率电脑屏幕上感觉模糊,例如Retina屏幕。所以若是要在超高分辨率下保持清晰,需要把图片精细度提高才能让肉眼看上去达到舒适感。

生成图片的原理是什么(dom-to-image源码分析)?

1. 整体思路

step1:利用XMLSerializer的serializeToString()构造一个字符串,以XML形式表示指定的DOM树

step2:利用SVG的将来自不同XML名称空间的元素包含进去,这里指上面的(X)HTML

step3:将SVG转为CANVAS

step4:利用HTMLCanvasElement.toDataURL() 生成不同格式的图片文件

2. 关键函数

0992ddf118daa86ebf5acae8e4d03681.png

3. 特殊处理

将DOM转换成XMLString之前,还需要处理字体文件和图片,通过ajax下载成blob数据再转换成base64以解决跨域问题。首先通过getComputedStyle(node)可以获取Node的样式,找出fontFamily和图片src,再查找字体的文件地址。

通过document.styleSheets获取样式表数组,注意根据每个CSSOM样式表接口的ownerNode属性区分其可读性,见下图:

  • ownerNode.tagName === 'STYLE'  则cssRules 可读取  内部样式表

  • ownerNode.tagName === 'LINK'  则cssRules 不可读取  外部样式表

5f18fcfb2bdc1e0a95281b67b2b31627.png

获取cssRules后,根据type === CSSRule.FONT_FACE_RULE 找到字体样式,从而获取字体文件路径,匹配对应的fontFamily对应的字体即是需要下载的。见下图:

b72288e56bb77cd56e6bcdce9414132c.png

最后一步替换htmlStr里的字体和图片的url为base64格式,大体流程及完成。一些浏览器兼容性问题一并考虑,篇幅关系这里就不一一讲解了。

55f764361a345a1a68608293a335d8b9.png

生成图片的关键在于:将 htmlStr塞到svg里,转换成svg,再将 svg 转换成 canvas

SVG的元素允许包含不同的XML命名空间。在浏览器的上下文中,就是我们的Xhtml, 极具包容性的接收了它

9158b319e7d162bdd544040d4a139bdf.png

最后通过blob2base64把svg转换到canvas里,生成图片

生成图片的格式

canvas生成后,可以通过toDataURL() 转为不同格式的图片。下面是常见的两种图片格式:

  • PNG格式: 便携式网络图形,无损压缩的位图图形格式,带有alpha通道。

  • JPEG格式:JPEG是常见的一种格式,有损压缩,以去除冗余的图像和彩色数据获取极高的压缩率,用以减小图片大小。

解决方案

清楚了上面的基础知识,我对前端生成图片有了大致的概念,接下来是定位“模糊”原因。分别导出 png格式和jpeg格式图片,发现只有jpeg格式才会出现边缘模糊,如下图:

f4227206b3cbd2f1770c5572b3aadbe6.png

因为相同的canvas数据导出的图片却因为格式不同效果不同,怀疑 jpeg格式边缘模糊有可能是因为图片质量被压缩了。那么canvas转成不同格式的图片质量是如何控制的呢?在MDN上可以找到答案:

官方解释:

即使在清贫的岁月,也不能失去对幸福美好的向往,那些摆脱平庸的梦总能编制我们简单的生活,为我们简单的时光点缀希望。不能说我们总要多热爱生活,但总要有一颗懂得欣赏和珍惜的心。

由此可见,导出png格式的图片是没有质量参数的,而导出jpeg格式的图片是有质量参数可设置的,而且默认是0.92。经过测试,当质量参数设置为1.0时,质量最好,导出效果与png一致。

下图是质量为0.1和1.0的效果对比:

70dd3d3f3e430183173c8abe872d4b69.png

总  结

前端canvas生成图片的整体流程和思路就是上述所讲,最后通过优化jpeg格式导出的质量参数解决了模糊的问题,如有不同观点和方案可以留言进行讨论。

bf4dac5036ccbbb0e457be69e6e1bb4f.png

想要了解更多技术知识

快来关注我们吧c1dec9e591fc7549afc11ea780d841f6.png

0b0bacd0ffbe48864e0e6743475e05f0.png

a7aea48a0c97cce2cadc1f0c107aa78c.png
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值