H5利用canvas实现海报功能

最近接到一个需求,微信中用户上传图片生成海报。这个需求比较常规,实现思路也比较简单,通过利用用户的input输入,对所上传的图片进行处理,最后通过第三方库html2canvas合成对应的图片即可。思路虽然简单,但是在实现的过程中会遇到各种各样的小问题,现在就将遇到的问题进行一次总结。

1、iphone以及部分android机型通过摄像头拍摄的照片被旋转了90度

原因:由于目前的手机拍照基本都在2M以上,而ios中只要超过2M图片就会自动旋转。拍照后直接取出来的UIimage(用UIImagePickerControllerOriginalImage取出),它本身的imageOrientation属性是3,即UIImageOrientationRight。如果这个图片直接使用则没事,但是如果对它进行裁剪、缩放等操作后,它的这个imageOrientation属性会变成0。此时这张图片用在别的地方就会发生旋转。imageOrientation是只读的,不能直接修改其值。

解决方法: 当拍照后,获取input中的图片数据,利用exif.js(Exif.js 提供了 JavaScript 读取图像的原始数据的功能扩展,例如:拍照方向、相机设备型号、拍摄时间、ISO 感光度、GPS 地理位置等数据。)获取到Orientation属性,此属性有四个值

1 表示旋转0度,也就是没有旋转。
6 表示顺时针旋转90度
8 表示逆时针旋转90度
3 旋转180度
我们要做的就是在拍照后,从input中获取到图片,然后得到它的Orientation值,根据Orientation值再对图片进行进一步处理,处理代码如下:

import EXIF from ‘exif-js‘;
var file = {
    upload: function(e) {
        var file = e.target.files[0];
        var type = file.type.split(‘/‘)[0];
        if (type != ‘image‘) {
            alert(‘请上传图片‘);
            return;
        }

        var size = Math.floor(file.size / 1024 / 1024);
        if (size > 3) {
            alert(‘图片大小不得超过3M‘);
            return;
        };

        var reader = new FileReader();
        reader.readAsDataURL(file);

        var orientation = null;
        //获取照片方向角属性,用户旋转控制
        EXIF.getData(file, function() {
            EXIF.getAllTags(this);
            orientation = EXIF.getTag(this, ‘Orientation‘);

        });

        reader.onloadstart = function() {};
        reader.onloadend = function(e) {
            var dataURL = reader.result;
            var imaged = new Image();
            imaged.src = dataURL;
            imaged.onload = function() {
                var canvas = document.createElement(‘canvas‘);
                var ctx = canvas.getContext(‘2d‘);
                //普通环境下设置canvas的宽高
                var w = 0,
                    h = 0;
                if (this.width < 750) {
                    w = this.width;
                    h = this.height;
                    canvas.width = w;
                    canvas.height = h;
                } else {
                    w = 750;
                    canvas.width = w;
                    var scale = this.width / this.height;
                    w = w > this.width ? this.width : w;
                    h = w / scale;
                    canvas.height = h;
                }
                // if (navigator.userAgent.match(/iphone/i) || navigator.userAgent.match(/samsung/i)) {
                if (orientation != "") {
                    switch (orientation) {
                        case 3:
                            ctx.rotate(180 * Math.PI / 180);
                            ctx.drawImage(this, -w, -h, w, h);
                            break;
                        case 6:
                            //这里由于将图片纠正了回来,所以也要重新设置canvas的高已达到高度自适应
                            canvas.width = 750;
                            var scale = this.height / this.width;
                            canvas.height = canvas.width / scale;
                            h = 750 > this.height ? this.height : 750;
                            w = h / scale;
                            ctx.rotate(90 * Math.PI / 180);
                            ctx.drawImage(this, 0, -h, w, h);
                            break;
                        case 8:
                            ctx.rotate(270 * Math.PI / 180);
                            ctx.drawImage(this, -h, 0, h, w);
                            break;
                        case 2:
                            ctx.translate(w, 0);
                            ctx.scale(-1, 1);
                            ctx.drawImage(this, 0, 0, w, h);
                            break;
                        case 4:
                            ctx.translate(w, 0);
                            ctx.scale(-1, 1);
                            ctx.rotate(180 * Math.PI / 180);
                            ctx.drawImage(this, -w, -h, w, h);
                            break;
                        case 5:
                            ctx.translate(w, 0);
                            ctx.scale(-1, 1);
                            ctx.rotate(90 * Math.PI / 180);
                            ctx.drawImage(this, 0, -w, h, w);
                            break;
                        case 7:
                            ctx.translate(w, 0);
                            ctx.scale(-1, 1);
                            ctx.rotate(270 * Math.PI / 180);
                            ctx.drawImage(this, -h, 0, h, w);
                            break;
                        default:
                            ctx.drawImage(this, 0, 0, w, h);
                    }
                } else {
                    ctx.drawImage(this, 0, 0, w, h);
                }
                //接下来对图片进行操作

            };
        };
    },
    event: function() {
        $(".uploadfile").change(function(e) {
            file.upload(e);
        });

    },
    init: function() {
        this.event();

    }
};

module.exports = file; 

2、获取微信用户头像生成海报无法显示

原因:  由于微信用户的头像是微信的域名,canvas由于安全机制的原因,限制了使用跨域的图片,所以无法显示用户头像的图片。

解决方法:

(1)后端在获取用户头像的时候,将头像图片保存到服务器,生成该域名下新的图片链接

(2)使用nginx作为代理,将对应请求转发到微信头像图片的服务器。这里展示第二种方法的实现

前端将图片地址修改为对应的代理服务器域名地址

data.avatar.replace(‘thirdwx.qlogo.cn/‘, ‘proxy.newmedium.xyz/wximg/‘)

nginx 代理配置

     server {
        listen       80;
        server_name  xxxxxx;
        add_header Access-Control-Allow-Origin *;
        location /wximg/ {
            proxy_pass http://thirdwx.qlogo.cn/;
        }
    }

由于项目静态文件域名上了cdn,所以我们只能采用不同的域名作为代理域名,这里又涉及到跨域问题,还需要在服务器和前端处理一部,设置header 为Access-Control-Allow-Origin *,前端设置为允许跨域

    html2canvas(document.querySelector(".poster"), {
           backgroundColor: ‘#ffffff‘,
           useCORS: true
     })

三个步骤,一步都不能少。

3、页面有声音播放时调用html2canvas生成海报后,iphone手机会有重复声音

测试发现html2canvas在使用的时候如果页面有音频播放,在ios系统中,音频会被复制一份,并且保持播放的状态。

刚开始一直找不到原因,最后没有办法,从源码中找html2canvas的实现原理找到了问题所在。 html2canvas在将dom转化为canvas的时候,会把页面复制到一个iframe,然后在计算出对应元素标签所在的位置进行处理。所以在复制页面的时候,将音频播放标签aduio也复制到了iframe,随后canvas完成后会删除iframe标签,但是复制到了iframe的音频已经开始播放进程,无法跟随iframe内容的清除而销毁。

最后在html2canvas 的官方文档中找到了解决方法。Html2canvas暴露接口ignoreElements,我们只要将aduio标签置为忽略就行了。

html2canvas(document.querySelector(".poster"), {
    useCORS: true,
    ignoreElements: function(el) {
        if (el.tagName == ‘AUDIO‘) {
            return true;
        }
   });

4、海报上传数据太大

将canvas转化为base64数据的时候,有时候用户选择文件图片有点大,导致上传性能差。最后查阅资料,可以通过toDataURL方法指定canvas 转化为base64 图片的质量来解决这个问题。

canvas.toDataURL("images/jpeg",0) ,第一个参数就是把图片编码为jpeg格式,第二个参数(0-1)就是指定图片质量,数值越大质量越高

原文地址:https://www.cnblogs.com/caizhenbo/p/9728738.html

时间: 2024-08-25 19:03:16

H5利用canvas实现海报功能的相关文章

利用canvas绘制图形

绘制图有很多种方法,可以借助flash实现,也可以使用SVG和VML来绘图.本章将要学习一种新的绘图方法--使用Canvas元素,它是基于HTML5原生的绘图功能.使用Canvas元素,可以绘制图形,也可以实现动画.它方便了使用Javascript脚本的前端开发人员,寥寥的竖行代码,就可以在Canvas元素中实现各种图形及动画.本章将介绍如何使用Canvas元素来绘制一些简单的图形.本章主要知识点如下:·认识Canvas元素·使用Canvas绘图·Canvas与JavaScript之间的互动·利

利用Canvas进行绘制XY坐标系

首先来一发图 绘制XY的坐标主要是利用Canvas setLeft和setBottom功能(Canvas内置坐标的功能) 1.首先WPF中的坐标系都是从左到右,从上到下的 即左上角位置(0,0)点,所以XY的Canvas要以(RenderTransformOrigin="0,0",为中心点)进行270°旋转,然后平移<TranslateTransform Y="{Binding ActualHeight,ElementName=canvasInPath}"/&

10分钟,利用canvas画一个小的loading界面(顺便讨论下绘制效率问题)

首先利用定义下canvas得样式 <canvas width="1024" height="720" id="canvas" style="border: 1px solid #808080;display: block;margin: 100px auto;>你的游览器不支持canvas</canvas> 这里主要要说的就是宽高,不要在style里面定义,不然会被拉伸.(对于这点,建议大家看下W3c文档,不是很

10分钟,利用canvas画一个小的loading界面

首先利用定义下canvas得样式 <canvas width="1024" height="720" id="canvas" style="border: 1px solid #808080;display: block;margin: 100px auto;>你的游览器不支持canvas</canvas> 这里主要要说的就是宽高,不要在style里面定义,不然会被拉伸.(对于这点,建议大家看下W3c文档,不是很

关于h5绘制canvas生成图片的注意点!

1.第一个是关于移动端自适应的问题: 答:如果是最后只要一张canvas生成的图片,而不是要绘制的canvas的图形,则不需要考虑自适应,绘制canvas的时候的宽高,可以直接写成UI提供的图的大小,比如UI提供的图是 750 * 1280 ,则绘制canvas的时候,所有的数据都可以 以375*640来进行计算,固定好即可!这个跟后台绘制图片的原理一样,我们不需要考虑自适应,ui给什么图,或者说我们希望要多大的图片,我们直接绘制即可,因为图片最后自己可以按比例伸缩,默认即是自适应! 2.关于H

Android利用canvas画各种图形

canvas通俗的说就是一张画布,我们可以使用画笔paint,在其上面画任意的图形. 原理: 可以把canvas视为Surface的替身或者接口,图形便是绘制在Surface上的.Canvas封装了所有的绘制调用.通过Canvas, 绘制到Surface上的内容首先存储到一个内存区域(也就是对应的Bitmapz中),该Bitmap最终会呈现到窗口上. 使用: 1.Canvas可以直接new Canvas(): 2.在View中重写OnDraw()方法,里面有一个Canvas,今天讨论的内容. 方

android 下 利用webview实现浏览器功能

android 下 利用webview实现浏览器功能: 1.界面添加WEBVIEW控件. 2.在界面.JAVA代码页面(protected void onCreate(Bundle savedInstanceState) 方法中)添加如下代码: //#region WebView wb=(WebView)findViewById(R.id.Wb_Main); //设置WebView属性,能够执行Javascript脚本 wb.getSettings().setJavaScriptEnabled(

利用 canvas 破解 某拖动验证码

案例: https://www.capy.me/products/  whois 查询发现应该是一个日本公司出的. 测试:尼玛,点来点去原来就4张图片来来回回切换,专业点好不好...... Part 1 识别 读取原图: 随便多刷新几次,读两张图片,用 PS 补成原图. 对比图片:利用canvas的特性 getImageData 读取像素,然后和你想要识别的图片对比,找出被挖出去的部分. 计算补全: 然后就简单啦,计算好被挖出部分在x 和 y 方向的偏移量,然后把 小图移动过去,OK 搞定...

&lt;canvas合成海报&gt;所遇问题及解决方案总结

最近做了一个用canvas合成海报图片的移动端项目,由于一点canvas基础都没有,所以去网上搜了一位前辈的demo,但是开发过程中遇到了很多问题,现将所遇问题及解决方法总结如下: 1.移动端canvas项目适配全屏问题 问题描述:由于canvas的width和height只能设置px值,不支持rem单位,所以想在移动设备屏幕分辨率繁杂的情况下达到canvas铺满全屏的效果很困难. 解决方法:通过js获取到手机屏幕的clientWidth值,赋给canvas,以此来达到适配全屏的效果: var