• H5利用canvas实现海报功能


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

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

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

    解决方法: 当拍照后,获取input中的图片数据,利用exif.jsExif.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)就是指定图片质量,数值越大质量越高

  • 相关阅读:
    aspx页面按钮写返回上一页代码
    Javascript呼叫.axd文档
    获取GridView TemplateField的数据
    对象失去焦点时自己动提交数据 V2
    从图片路径获取图片尺寸
    双击一个图片然后跳转到另一个页面去
    Javascript alert消息换行
    ASP.NET播放Flash(.SWF)视频
    绑定List<T>到asp:Table控件
    Linux系统下的多线程编程条件变量&信号量
  • 原文地址:https://www.cnblogs.com/caizhenbo/p/9728738.html
Copyright © 2020-2023  润新知