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)就是指定图片质量,数值越大质量越高
H5利用canvas实现海报功能的更多相关文章
- 微信小程序利用canvas生成海报分享图片
一 . 效果 这是借用女神照生成的分享的海报,图片来自网络. 新增了poster组件和更新图片自适应 二 . 准备 准备两张图片连接,最好是自己开发账号验证的https图片链接. 三 . 实现思路 其 ...
- 利用canvas实现倒计时功能
wxml代码:<view class=“page-body”><view class=“page-body-wrapper”><canvas canvas-id=“can ...
- H5上传图片并使用canvas制作海报
马上就要"十一"国庆节了,又恰逢公司已经三周岁了,所以市场部和产品共同策划了一个"正青春,共成长"的主题代言活动,准备在国庆节以及中秋节期间让公司员工和用户为公 ...
- 利用canvas阴影功能与双线技巧绘制轨道交通大屏项目效果
利用canvas阴影功能与双线技巧绘制轨道交通大屏项目效果 前言 近日公司接到一个轨道系统的需求,需要将地铁线路及列车实时位置展示在大屏上.既然是大屏项目,那视觉效果当然是第一重点,咱们可以先来看看项 ...
- 小程序利用canvas 绘制图案 (生成海报, 生成有特色的头像)
小程序利用canvas 绘制图案 (生成海报, 生成有特色的头像) 微信小程序生成特色头像,海报等是比较常见的.下面我来介绍下实现该类小程序的过程. 首先选择前端来通过 canvas 绘制.这样比较节 ...
- H5标签-canvas实现颜色拾取功能
HTML5 <canvas> 标签是用于绘制图像,不过,<canvas> 元素本身并没有绘制能力(它仅仅是图形的容器),必须使用脚本(通常是 JS)来完成实际的绘图任务. &l ...
- 利用Canvas进行绘制XY坐标系
首先来一发图 绘制XY的坐标主要是利用Canvas setLeft和setBottom功能(Canvas内置坐标的功能) 1.首先WPF中的坐标系都是从左到右,从上到下的 即左上角位置(0,0)点,所 ...
- 关于h5绘制canvas生成图片的注意点!
1.第一个是关于移动端自适应的问题: 答:如果是最后只要一张canvas生成的图片,而不是要绘制的canvas的图形,则不需要考虑自适应,绘制canvas的时候的宽高,可以直接写成UI提供的图的大小, ...
- 10分钟,利用canvas画一个小的loading界面
首先利用定义下canvas得样式 <canvas width="1024" height="720" id="canvas" styl ...
随机推荐
- 『编程题全队』Beta 阶段冲刺博客五
1.提供当天站立式会议照片一张 2.每个人的工作 (有work item 的ID) (1) 昨天已完成的工作 孙志威: 1.为新建提醒框添加了正则匹配限制 2.添加了新建Reminder的功能 3.初 ...
- mysql复杂查询
所谓复杂查询,指涉及多个表.具有嵌套等复杂结构的查询.这里简要介绍典型的几种复杂查询格式. 一.连接查询 连接是区别关系与非关系系统的最重要的标志.通过连接运算符可以实现多个表查询.连接查询主要包括内 ...
- PLSQL 使用ODBC 数据源导入来自SQLSERVER的数据
1. 创建ODBC数据源 方法: 打开控制命令 Win10 运行->输入 control 查看方式大图标--选择 管理工具 2. 安装了 64位的plsql 应该也选用 64位的ODBC数据源 ...
- U9财务体系
- Ubuntu16.04 ERROR 1698 (28000): Access denied for user 'root'@'localhost' 解决流程
mysql版本 5.7.22 安装完成后出现问题 ERROR 1698 (28000): Access denied for user 'root'@'localhost' 可能是因为初始密码为空:按 ...
- Linux定时器crontab的使用
参数 Usage: crontab [参数] 文件 crontab [参数] crontab -n [主机名] Options: -u <user> 定义用户 -e 编辑工作表 -l 列出 ...
- hdu1728 逃离迷宫
给定一个m × n (m行, n列)的迷宫,迷宫中有两个位置,gloria想从迷宫的一个位置走到另外一个位置,当然迷宫中有些地方是空地,gloria可以穿越,有些地方是障碍,她必须绕行,从迷宫的一个位 ...
- Git如何合并分支代码
如果是在IDEA中使用Git,可以直接合并代码. 我当前的开发分支,是feature/bing,现在我需要合并分支 feature/xxs 上的代码,这个过程只需要在IDEA中完成. 1.更新代码,会 ...
- linux保存住github的账号和密码
我是用 shell 命令来执行 git 操作的,所以就决定在 --global 配置一下用户名和密码,不用每次手动输入了. 设置步骤 1. 首先需要 ftp 连接到你的 Linux 服务器,在根目录( ...
- 自学Linux Shell5.1-shell父子关系
点击返回 自学Linux命令行与Shell脚本之路 5.1-shell父子关系 1 shell常见的种类 bash是Linux标准默认的Shell,是BunrneAgain Shell的缩写,内部命 ...