html5 canvas处理头像上传-mile米乐体育

最近社区系统需要支持移动端,其中涉及到用户头像上传,头像有大中小三种尺寸,在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.todata);     }; };

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.todata);             }         callback.call(that, result);     }); };

php存储base64图片数据

canvas.todata获取的默认图像数据格式是:data:image/png;base64,  base64数据:

data:image/png;base64,ivborw0kggoaaaansuheugaaaauaaaafcayaaacnbyblaaaadeleqvqimwngobmaaabpaafei8araaaaaelftksuqmcc

当把canvas截屏数据传给后台时,后台需要截断开头的字段data:image/png;base64,,获取后面那串真正的base64数据:

 

参考

  • save a base64 encoded canvas image to a png file using php
  • html5 canvas drawimage: how to apply antialiasing
  • maximum size of a canvas element
  • how to save a png image server-side, from a base64 data string
  • how to send formdata objects with ajax-requests in jquery
展开全文
内容来源于互联网和用户投稿,文章中一旦含有米乐app官网登录的联系方式务必识别真假,本站仅做信息展示不承担任何相关责任,如有侵权或涉及法律问题请联系米乐app官网登录删除

最新文章

知识分享
这条河堤道路,路面窄到一条中心线都画不出来,各种电动车、三轮车、摩托车、机动车、非机动车往...…
知识分享
导语:为何汽车备用胎和正常轮胎尺寸不一样?老司机:症结主要在这三处汽车的备胎分为三种,一种...…
知识分享
首先,我们需要将油箱里面废弃的机油排出,先拧下油箱底部的螺丝,排出废油,再更换滤清器(注意...…
知识分享
二手车价格通常会因为车漆喷涂范围加大而降低,但并非所有喷过漆的车辆都不能入手,例如处理过划...…
网站地图