H5 中html 页面存为图片并长按 保存

时间:2024-02-25 16:34:16
最近接到的一个新需求:页面一个静态H5,中间有一页是输入信息,然后跳转到最后一页,自动将页面生成图片,用户可以长按图片保存到手机上。

展示一下最后一页的样子:

 

刚拿到这个需求,在网上看了很多文章,最普遍的是使用 html2canvas + canvas2image  来实现。于是,跟着前人的脚步,踏上了一个不断采坑采坑采坑的旅程。

下面直接描述我在做这个需求过程中遇到的问题以及解决办法吧:

1.html2canvas 图片跨域:

这个问题网上很多解决办法:

这个是最常用的, 刚开始我只是加了红色框里面的这一句,但是并没有任何作用,依旧报错。后来看到有人说,加上前面那一句,所以果断在加进去。

这两句其实表达的是同一个意思:允许图片跨域。

当然,也有网友说,直接给一个空值就可以,我当时试了一下,并不ok~~~~.

 

 

2.多次使用canvas drawImage 方法图片展示问题

2.1 图片加载顺序问题

在我这个需求里面,肯定是文字描述以及二维码是展示在图片上面的,刚开始我是

1. drawImage   文字,

2. drawImage    二维码

3. drawImage   背景大图

然而,结果让我大吃一惊,只有背景图加载渲染出来了。然后,通过无所不能的网络才知道:drawImage 的顺序应该是:图片最底下的需要最先加载渲染。

2.2 图片显示不完整

在2.1 问题出现的同时还遇到了这个问题,图片渲染不完整,这。。nima。。。需求才刚开始做,怎么这样为难一个小女子。。。

不过有问题嘛,就解决咯。

图片渲染不完整,原因就是:在图片还没有加载完成的时候,canvas 就开始进行渲染。

 因此解决办法就是:等图片加载完成后再进行drawImage 操作就可以啦,上~~~~代码:

 

 

3.canvas 保存为图片的跨域问题

遇到这个问题,我真的是花了一堆一堆的时间来看文章,看博客,,。

这会万能的网友给我的解决办法并没有任何效果:

他们说:1.把图片取下来放在自己服务器上(我用的公司的图片服务器。但是和我的放代码服务器不是同一个地址啊)

2. 用canvas2Image 啊,然而,,这不也是跨域么,,并没有啥,,用。

3.还有啥来着,,忘了,反正那天搞得我精神崩溃,,,也没解决到问题,,后来实在忍不住,问了公司的大神:大神说:你用base64 的呢。。

一语惊喜梦中人,对啊,这种方法多棒,这样就不会跨域了啊。当时为了赶进度,直接在线吧图片转成basa64  ,然后存成一个js 文件。

当时是这样的:红框里表示的是文件的格式。。、

 

至此,我的html 已经转为canvas  并且从canvas 转为img 存在页面上了,,

 

后来我在看这一段,觉得似乎不太好,这个文件显得很大,所以我想在用这个文件的时候在把它转成base64 的格式,,

1.利用canvas todataUrl 将图片转为base64

但是这种方法不可避免的会出现跨域的问题,pass

2.base64.js  

这个文件中中文转码会出问题,而且我试过了,基本的字符串转码都是ok 的,但是对于文件转码就会出问题

3.浏览器原生的并且都支持的一个东西: window.atob     and   window.btoa

window.atob  是将base64 格式转换为字符串或者二进制编码格式

window.btoa  是将字符串或者二进制编码 格式转换为base64  格式  所以上面的base64.js 真的,,别浪费时间精力去看了,,

那文件编码解码呢?

原生的也有方法:FileRender()  这个构造函数,

var reader = new FileReader();

reader.onload = function(e) {

// e.target.result

};

reader.readAsDataURL(file);

这种方法没有测试过o(╥﹏╥)o。。

所以,目前为止,需要把文件转为base64. 格式的,我并没有找到合适的方法或者js 插件来操作,如果各位有什么好的办法,麻烦告诉我(* ̄︶ ̄)。

 

 

4. 图片模糊并且窗口中只显示了一部分

才定义canvas 的时候,我是给canvas 定义了一个宽高的,宽高是背景图的大小,因此在drawImage 的时候是按照canvas 实际尺寸进行渲染。

但是转为图片的时候是按照窗口的尺寸来进行的,因此图片会模糊,如果给图片设置canvas 宽高的话,图片在窗口中又显示不完整。

因此,就需要计算设备的retio,

基本思路:计算出ratio  ---> 然后canvas 转 img (按照canvas 实际尺寸进行渲染) ---> 图片按照窗口大小进行缩放

这个方法直接返回的是设备的ratio..

然后我们在进行canvas 渲染的时候,

在后面进行图片渲染的时候,图片的宽度直接除以 ratio ,这样图片就能完整的显示在窗口中。

 

 

 

5. ios10.2 canvas 转图片 一片黑

至此,页面是呈现出来了,并且在我的安卓(华为)上测试是ok

但是需求的同学(ios)告诉我:她的手机上最后一页是黑色的和,顶部有个白色框,,,我一懵,天,不会ios 不支持吧。

于是,用了旁边座位同学的手机。恩,也不行。。

啊啊啊啊啊,要崩溃。

在网上看了一下,有一种解决办法就是:使用双缓冲(出现黑屏的可能就是在drawImage 的时候计算量很大,然后渲染卡顿不成功)

大概思路就是:在新建一个cachecanvas 刚开始其实是把图片渲染在这个缓存的canvas 中的,然后在将cachecanvas 中的内容渲染到需要在页面展示的canvas 中。

我在中间使用了一个延时,时间虽然很短,但是这样也能确保cachacanvas 确实渲染完成在进行正式的canvas 渲染。

这样,我周围座位上的ios 上最后一页都能显示出来了,,但是那个ios10.2 的依旧不行,,啊,网上查了一下,这个版本的问题一直存在,所以,(꒦_꒦) ,

 

 就这样,这个需求在我不断采坑的过程中,好像也快完结了,这里很少直接贴代码进来,因为贴进来似乎看的不太好,所以我基本上是截图的。

 

最后,几个小tips :

1.直接将网页图片存成base64 格式的,如果图片很少,可以,如果图片很多,还是建议不要这么操作了,比较一个base64的数据格式就已经很大了。。。

2.图片先压缩,然后在进行base64格式编码吧

3.对于drawImage 的位置,是相对于canvas  实际尺寸的。所以如果使用百分比,建议先得到窗口的宽高,然后在进行赋值。

4. 在使用canvas   fillText 的时候,有一个限制最大宽度,就是fillText 的最后一个参数(直接写数值即可,不用带单位,默认似乎是px)。

5.对于一般的H5,还是对图片进行预加载一下吧,。。(网上很多图片预加载的方法,自行查找哦)。