首页 > web前端 > H5教程 > HTML5 Canvas处理头像上传的图文代码详细介绍

HTML5 Canvas处理头像上传的图文代码详细介绍

黄舟
发布: 2017-03-07 16:02:15
原创
1910 人浏览过

最近社区系统需要支持移动端,其中涉及到用户头像上传,头像有大中小三种尺寸,在PC端,社区用Flash来处理头像编辑和生成,但该Flash控件的界面不友好而且移动端对Flash的支持不好,考虑到这些问题,最后我们选用Canvas来完成图像尺寸缩放和图片数据获取。

等边处理

头像一般都是正方形,首先我们需要获取图片宽度和高度的最小值,用该最小值作为边长居中裁剪图片,最终得到一个正方形的图片:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

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的尺寸限制:

1

2

3

4

5

chrome          = 32767x32767

iPod Touch 16GB = 1448x1448

iPad Mini       = 2290x2289

iPhone 3        = 1448x1448

iPhone 5        = 2290x2289

登录后复制

参考以上数据,我们先给Canvas设置一个最大的宽度:

1

var MAX_WIDTH = 1000;

登录后复制

clipSquareImage函数中加入最大宽度的检测,如果超过限制,则创建一个临时的canvas进行图片缩放处理,最后对该临时的Canvas进行居中剪切:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

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接口提供非常方便的缩放功能:

1

2

3

4

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提出了一个方案:对图片进行若干次的等比例缩小,最后再放大到目标尺寸:

canvas高清缩放

参考这个方案,我们可以实现antialiasScale抗锯齿缩放函数:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

fn.antialisScale = function(img, width, height) {

    var offlineCanvas = document.createElement(&#39;canvas&#39;),

        offlineCtx = offlineCanvas.getContext(&#39;2d&#39;),

        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完成缩放工作,生成头像图片的三种尺寸:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

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(&#39;image/png&#39;));   

        }

        callback.call(that, result);

    });

};

登录后复制

PHP存储base64图片数据

Canvas.toDataURL()获取的默认图像数据格式是:data:image/png;base64, + base64数据:

1

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAADElEQVQImWNgoBMAAABpAAFEI8ARAAAAAElFTkSuQmCC

登录后复制

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

1

2

3

4

5

6

7

8

9

10

<?php

    $imgData = $_POST[&#39;imgData&#39;];

    // 截取有用的部分

    list($type, $imgData) = explode(&#39;;&#39;, $imgData);

    list(, $imgData)      = explode(&#39;,&#39;, $imgData);

    // base64 编码中使用了加号,

    // 如果通过url传递base64数据,+号会转换成空格

    $imgData = str_replace(&#39; &#39;, &#39;+&#39;, $imgData);

    // 存储文件

    $success = file_put_contents(&#39;PATH/XXX.png&#39;, base64_decode($imgData));

登录后复制

参考

  • 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

 以上就是HTML5 Canvas处理头像上传的图文代码详细介绍的内容,更多相关内容请关注PHP中文网(www.php.cn)!



相关标签:
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板