Canvas处理头像上传
未分类
最近社区系统需要支持移动端,其中涉及到用户头像上传,头像有大中小三种尺寸,在PC端,社区用Flash来处理头像编辑和生成,但该Flash控件的界面不友好而且移动端对Flash的支持不好,考虑到这些问题,最后我们选用Canvas来完成图像尺寸缩放和图片数据获取。
等边处理
头像一般都是正方形,首先我们需要获取图片宽度和高度的最小值,用该最小值作为边长居中裁剪图片,最终得到一个正方形的图片:
var ImageEditor = function() {
// 用离线canvas处理图片数据
this.canvas = document.createElement('canvas');
this.context = this.canvas.getContext('2d');
};
var fn = ImageEditor.prototype;
fn.resizeCanvas = function(width, height) {
this.canvas.width = width;
this.canvas.height = height;
};
fn.clipSquareImage = function(url, callback) {
var that = this,
img = new Image();
img.src = url;
img.onload = function() {
// 取宽高最小值作为正方形边长
var eLength = Math.min(img.width, img.height),
picture = img;
// canvas不支持局部截屏,截屏前必须先调节canvas的宽高
that.resizeCanvas(eLength, eLength);
// 将图片以居中裁剪的方式画到canvas中。
// drawImage支持9个参数:图片对象,图片上的剪切坐标XY,
// 剪切宽高,图片在canvas上的坐标XY及图片宽高
that.context.drawImage(picture,
(picture.width - eLength) / 2, (picture.height - eLength) / 2,
eLength, eLength, 0, 0, eLength, eLength);
// 截屏,即获取base64数据
callback.call(that, that.canvas.toDataURL('image/png'));
};
};
Canvas元素大小限制问题
上述clipSquareImage
函数中,由于canvas.toDataURL
接口不提供宽高参数,只能够一次性把整个canvas的屏幕数据截取下来,所以在对Canvas截屏前,我们必须先设置Canvas元素的大小。然而移动端拍照的分辨率极高,宽高大多会在3000以上,当我们根据相片宽高的最小值来设置Canvas的尺寸时,Canvas元素的最小宽度也高达到3000以上。
问题在于,每个平台对Canvas的大小都有限制,如果Canvas的宽度或高度任意一个值超过了平台限制,Canvas将无法进行渲染,canvas.toDataURL
只能获取一张透明的图片数据。
Maximum size of a canvas element中提到了部分平台下Canvas的尺寸限制:
chrome = 32767x32767
iPod Touch 16GB = 1448x1448
iPad Mini = 2290x2289
iPhone 3 = 1448x1448
iPhone 5 = 2290x2289
参考以上数据,我们先给Canvas设置一个最大的宽度:
var MAX_WIDTH = 1000;
在clipSquareImage
函数中加入最大宽度的检测,如果超过限制,则创建一个临时的canvas进行图片缩放处理,最后对该临时的Canvas进行居中剪切:
fn.clipSquareImage = function(url, callback) {
var that = this,
img = new Image();
img.src = url;
img.onload = function() {
// 取图片宽高和Canvas的最大宽度的最小值作为等边长
var eLength = Math.min(img.width, img.height, MAX_WIDTH),
// 剪切对象
picture = img,
tempEditor,
ratio;
// 如果图片尺寸超出限制
if (eLength === MAX_WIDTH) {
// 创建一个临时editor
tempEditor = new ImageEditor();
ratio = img.width / img.height;
// 按图片比例缩放canvas
img.width < img.height ?
tempEditor.resizeCanvas(MAX_WIDTH * ratio, MAX_WIDTH) :
tempEditor.resizeCanvas(MAX_WIDTH, MAX_WIDTH / ratio);
tempEditor.context.drawImage(img, 0, 0, tempEditor.canvas.width, tempEditor.canvas.height);
// 将临时Canvas作为剪切对象
picture = tempEditor.canvas;
eLength = Math.min(tempEditor.canvas.width, tempEditor.canvas.height);
}
// 居中剪切
// ... ...
// 截屏操作
// ... ...
};
};
Canvas锯齿问题
上面我们已经能够通过Canvas裁剪出一张正方形的图片,接下来我们还需要处理头像图片大中小三种尺寸。在Canvas中,drawImage
接口提供非常方便的缩放功能:
var editor = new ImageEditor;
// 将图片缩放到300x300
// drawImage支持5个参数:图片对象,及图片在canvas上的坐标和宽高
editor.context.drawImage(squareImage, 0, 0, 300, 300);
然而大尺寸图片直接用drawImage
进行缩小处理会导致图片出现锯齿。在stack overflow上HTML5 canvas drawImage: how to apply antialiasing提出了一个方案:对图片进行若干次的等比例缩小,最后再放大到目标尺寸:
参考这个方案,我们可以实现antialiasScale
抗锯齿缩放函数:
fn.antialisScale = function(img, width, height) {
var offlineCanvas = document.createElement('canvas'),
offlineCtx = offlineCanvas.getContext('2d'),
sourceWidth = img.width,
sourceHeight = img.height,
// 缩小操作的次数
steps = Math.ceil(Math.log(sourceWidth / width) / Math.log(2)) - 1,
i;
// 渲染图片
offlineCanvas.width = sourceWidth;
offlineCanvas.height = sourceHeight;
offlineCtx.drawImage(img, 0, 0, offlineCanvas.width, offlineCanvas.height);
// 缩小操作
// 进行steps次的减半缩小
for(i = 0; i < steps; i++) {
offlineCtx.drawImage(offlineCanvas, 0, 0,
offlineCanvas.width * 0.5, offlineCanvas.height * 0.5);
}
// 放大操作
// 进行steps次的两倍放大
this.context.drawImage(offlineCanvas, 0, 0,
offlineCanvas.width * Math.pow(0.5, steps),
offlineCanvas.height * Math.pow(0.5, steps),
0, 0, width, height);
};
我们可以用这个函数代替drawImage完成缩放工作,生成头像图片的三种尺寸:
fn.scaleSquareImage = function(url, sizes, callback) {
var that = this;
// 先裁剪一个正方形
that.clipSquareImage(url, sizes, function(data) {
var squareImage = new Image(),
result = [],
i;
squareImage.src = data;
// 抗锯齿缩放
for (i = 0; i < sizes.length; i++) {
that.antialisScale(squareImage, sizes[i], size[i]);
result.push(that.canvas.toDataURL('image/png'));
}
callback.call(that, result);
});
};
PHP存储base64图片数据
Canvas.toDataURL()
获取的默认图像数据格式是:data:image/png;base64,
+ base64数据:
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAADElEQVQImWNgoBMAAABpAAFEI8ARAAAAAElFTkSuQmCC
当把Canvas截屏数据传给后台时,后台需要截断开头的字段data:image/png;base64,
,获取后面那串真正的base64数据:
<?php
$imgData = $_POST['imgData'];
// 截取有用的部分
list($type, $imgData) = explode(';', $imgData);
list(, $imgData) = explode(',', $imgData);
// base64 编码中使用了加号,
// 如果通过url传递base64数据,+号会转换成空格
$imgData = str_replace(' ', '+', $imgData);
// 存储文件
$success = file_put_contents('PATH/XXX.png', base64_decode($imgData));
Canvas处理头像上传的更多相关文章
- 【javascript】html5中使用canvas编写头像上传截取功能
[javascript]html5中使用canvas编写头像上传截取功能 本人对canvas很是喜欢,于是想仿照新浪微博头像上传功能(前端使用canvas) 本程序目前在谷歌浏览器和火狐浏览器测试可用 ...
- vue头像上传与文件压缩
工作中遇到的问题记录:vue开发头像上传组件,后端提供接口,需求为可相册上传,可相机拍摄上传,文件大小限制为2M 需求点分析 移动端调用相册/摄像头实现拍照 图片压缩,当前高像素的相机拍出来的图片都有 ...
- jquery头像上传剪裁插件cropper的前后台demo
因为一个项目要做一个头像上传的功能,因此选择了使用jquery的头像插件cropper,cropper是一款使用简单且功能强大的图片剪裁jQuery插件,但是在使用的时候,有一个很大的坑需要注意,那就 ...
- java web 站点头像上传处理 (springmvc +bootstrap+cropper)
制作头像上传.请依据您的实际需求.改动代码,不全然正确.仅供參考! 前端页面设计使用bootstrap ,头像预览和剪裁工具使用cropper 后台使用springmvc. 如今来看前端的页面设计 前 ...
- 强大的flash头像上传插件(支持旋转、拖拽、剪裁、生成缩略图等)
今天介绍的这款flash上传头像功能非常强大,支持php,asp,jsp,asp.net 调用 头像剪裁,预览组件插件. 本组件需要安装Flash Player后才可使用,请从http://dl.pc ...
- 【Bootstrap-插件使用】Jcrop+fileinput组合实现头像上传功能
作者:Dreawer链接:https://zhuanlan.zhihu.com/p/24465742来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 作者:梦游的龙猫(转 ...
- [Bootstrap-插件使用]Jcrop+fileinput组合实现头像上传功能
很久没有更新博客了,再不写点东西都烂了. 这次更新一个小内容,是两个插件的组合使用,实现头像上传功能. 业务需求: 头像上传功能,要对上传的文件进行剪切,且保证头像到服务器时必须是正方形的. 优化&l ...
- struts 头像上传
java代码: 1 package cn.itcast.nsfw.user.action; import java.io.File; import java.io.IOException; impor ...
- js会员头像上传拖动处理头像类
js会员头像上传拖动处理头像类 点击下载源码文件
随机推荐
- tornado解析http body的过程分析
tornado解析http body的过程分析 在最近写的一个RESTful API Server过程中,发现tornaod对解析POST BODY的内容有限制. 而在以前用web.py则没有这个限制 ...
- EF提供的三种查询方式
這邊簡單介紹一下,ADO.Net Entity Framework 提供的三種查詢方式, Linq to Entities Query Builder Mothed Entity SQL Langua ...
- PHP Zend Studio9.0怎么把代码搞成和服务器端的同步(就是直接在服务器端修改)
Zend Studio 可以直接通过Remote System的方式直接连接服务器端的代码,就是可以直接修改服务器端的代码,不过修改的时间小心点,修改就会立即生效的. 选择Remote Systems ...
- 【二叉树遍历模版】前序遍历&&中序遍历&&后序遍历&&层次遍历&&Root->Right->Left遍历
[二叉树遍历模版]前序遍历 1.递归实现 test.cpp: 12345678910111213141516171819202122232425262728293031323334353637 ...
- Ubuntu环境下手动配置HBase0.94.25
/×××××××××××××××××××××××××××××××××××××××××/ Author:xxx0624 HomePage:http://www.cnblogs.com/xxx0624/ ...
- IIS常见错误及解决
IIS常见错误 1.HTTP 错误 404.3 - Not Found由于扩展配置问题而无法提供您请求的页面.如果该页面是脚本,请添加处理程序.如果应下载文件,请添加 MIME 映射. 解决办法: w ...
- [杂题]HDOJ5515 Game of Flying Circus
嗯...这是一道水题... 鉴于还没人写这题的题解, 那我就来写一发. 题意:有个边长为300米的正方形 嗯 这样标号 有两个人A和S,开始的时候A.S都在1(左下角)那个位置. 两个人都要按照2. ...
- 初识io流条件状态
一 流状态 C++中的输入输出系统负责记录每一个输入输出操作的结果信息,这些当前的状态信息被包含在io_state类型的对象中.io_state是一个枚举类型(就像open_mode一样),以 ...
- import java.util.Scanner;
一.扫描控制台输入 当通过new Scanner(System.in)创建一个Scanner,控制台会一直等待输入,,,,,,,直到敲回车键结束,把所输入的内容传给Scanner,作为扫描对象 ...
- vc2005中没有classwizard这个命令
vc2005中没有classwizard这个命令了 2005下怎么添加鼠标事件 vc2005中没有classwizard这个命令了 取代classwizard 中的添加消息映射,添加类,等等的功能主要 ...