html5拍照功能实现代码(htm5上传文件)

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

点评:在HTML5规范的支持下,WebApp在手机上拍照已经成为可能。在下面,我将讲解Web
App如何用手机进行拍照,显示在页面上并上传到服务器

Canvas入门(3):图像处理和绘制文字,canvas图像处理

来源:

一、图像处理(非特别说明,所有结果均来自最新版Google)

在HTML 5中,不仅可以使用Canvas
API绘制图形,也可以用于处理网络或磁盘中的图像文件,然后绘制在画布中。绘制图像时,需要使用drawImage()方法:

drawImage(image,x,y):image是图像引用,x,y是绘制图像时在画布中的起始位置

drawImage(image,x,y,w,h):前三个同上,w,h是绘制时图像的宽度和高度,可以用于缩放图像

drawImage(image,sx,sy,sw,sh,dx,dy,dw.dh):
将画布中已经绘制好的图像的全部或者局部复制到画布的另一个位置。sx,sy,sw,sh分别是原图中被复制区域的起始位置宽高,dx,dy,dw,dh
表示复制后图像在画布中的起始位置和高宽。

   1: // 获取canvas 的ID

   2:     var canvas = document.getElementById('canvas');

   3:     if (canvas == null)

   4:     {

   5:         return false;

   6:     }

   7:     // 获取上下文

   8:     var context = canvas.getContext('2d');

   9:     context.fillStyle = '#eeeeff';

  10:     context.fillRect(0,0,400,300);

  11:     var image = new Image();

12: image.src = ‘my.jpg’;

// onload事件实现边绘制边加载

  13:     image.onload = function()

  14:     {

  15:         drawImage(context,image);

  16:     };

  17:     function drawImage(context,image)

  18:     {

  19:         for (var i = 0; i < 7; i++) {

  20:             context.drawImage(image,0+i*50,0+i*25,100,100);

  21:         };

  22:     }

效果:

等边处理

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

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'));
    };
};

1、 视频流

图片 1

1、图像平铺

   1: // 获取canvas 的ID

   2:     var canvas = document.getElementById('canvas');

   3:     if (canvas == null)

   4:     {

   5:         return false;

   6:     }

   7:     // 获取上下文

   8:     var context = canvas.getContext('2d');

   9:     context.fillStyle = '#eeeeff';

  10:     context.fillRect(0,0,400,300);

  11:     var image = new Image();

  12:     image.src = 'my.jpg';

  13:     // onload事件实现边绘制边加载

  14:     image.onload = function()

  15:     {

  16:         drawImage(canvas,context,image);

  17:     };

  18:     function drawImage(canvas,context,image)

  19:     {

  20:         // 平铺比例

  21:         var scale = 5;

  22:         // 缩小图像后宽度

  23:         var n1 = image.width / scale;

  24:         // 缩小图像后高度

  25:         var n2 = image.height / scale;

  26:         // 横向平铺个数

  27:         var n3 = canvas.width / n1;

  28:         // 纵向平铺个数

  29:         var n4 = canvas.height / n2;

  30:         for(var i = 0; i < n3; i++)

  31:         {

  32:             for(var j=0; j < n4; j++)

  33:             {

  34:                 context.drawImage(image,i*n1,j*n2,n1,n2);

  35:             }

  36:         }

  37:     }

效果:

图片 2

在HTML
5中,利用context.createPattern(image,type)也可以实现平铺,type取值同background-image的平铺值一样。

   1: image.onload = function()

   2:     {

   3:         // drawImage(canvas,context,image);

   4:         var ptrn = context.createPattern(image,'repeat');

   5:         context.fillStyle = ptrn;

   6:         context.fillRect(0,0,400,300);

   7:     };

能同样实现平铺(图片没有缩放,所以是原图大小平铺)

2、图像裁剪

   1: // 获取canvas 的ID

   2:     var canvas = document.getElementById('canvas');

   3:     if (canvas == null)

   4:     {

   5:         return false;

   6:     }

   7:     // 获取上下文

   8:     var context = canvas.getContext('2d');

   9:     // 获取渐变对象

  10:     var g1 = context.createLinearGradient(0,400,300,0);

  11:     // 添加渐变颜色

  12:     g1.addColorStop(0,'rgb(255,255,0)');

  13:     g1.addColorStop(1,'rgb(0,255,255)');

  14:     context.fillStyle = g1;

  15:     context.fillRect(0,0,400,300);

  16:     var image = new Image();

  17:     // onload事件实现边绘制边加载

  18:     image.onload = function()

  19:     {

  20:         drawImage(context,image);

  21:     };

  22:     image.src = 'my.jpg';

  23:     function drawImage(context,image)

  24:     {

  25:         create5StarClip(context);

  26:         context.drawImage(image,-50,-150,300,300);

  27:     }

  28:     function create5StarClip(context)

  29:     {

  30:         var dx = 100;

  31:         var dy = 0;

  32:         var s  = 150;

  33:          // 创建路径

  34:          context.beginPath();

  35:          context.translate(100,150);

  36:          var x = Math.sin(0);

  37:          var y = Math.cos(0);

  38:          var dig = Math.PI/5 *4;

  39:          // context.moveTo(dx,dy);

  40:          for (var i = 0; i < 5; i++) {

  41:              var x = Math.sin(i * dig);

  42:              var y = Math.cos(i * dig);

  43:              context.lineTo(dx+x*s,dy+y*s);

  44:          }

  45:          context.clip();

  46:     }

效果:

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);
            }
            // 居中剪切
            // ... ...
            // 截屏操作
            // ... ...
    };
};

HTML5 The Media Capture
API提供了对摄像头的可编程访问,用户可以直接用getUserMedia获得摄像头提供的视频流。我们需要做的是添加一个HTML5的Video标签,并将从摄像头获得视频作为这个标签的输入来源(请注意目前仅Chrome和Opera支持getUserMedia)。

图片 3

3、像素处理

   1: // 获取canvas 的ID

   2:     var canvas = document.getElementById('canvas');

   3:     if (canvas == null)

   4:     {

   5:         return false;

   6:     }

   7:     // 获取上下文

   8:     var context = canvas.getContext('2d');

   9:     var image = new Image();

  10:     image.src = 'my.jpg';

  11:     // onload事件实现边绘制边加载

  12:     image.onload = function()

  13:     {

  14:         context.drawImage(image,0,0);

  15:         // 获取原图像素

  16:         var imageData = context.getImageData(0,0,image.width,image.height);

  17:         for (var i = 0,n= imageData.data.length; i <n; i += 4) {

  18:             // red

  19:             imageData.data[i+0] = 255-imageData.data[i+0];

  20:             // green

  21:             imageData.data[i+1] = 255-imageData.data[i+2];

  22:             // blue

  23:             imageData.data[i+2] = 255-imageData.data[i+1];

  24:         };

  25:         // 将调整后的像素应用到图像

  26:         context.putImageData(imageData,0,0);

  27:     };

getImageData(sx,sy,sw,sh):表示获取像素区域的起始坐标和
高宽,返回一个具有width,height,data等属性CanvasPixelArray对象,其中data属性存放像素数据的数组,形如
[r1,g1,b1,a1,r2,g2,b2,a2……],r1,g1,b1,a1分别是第一个像素的红绿蓝值及透明度,以此类推。

putImageData(imagedata,dx,dy[,dirtyx,dirtyy,dirtyWidth,dirtyHeight]):
将像素数据重新绘制到图像上。imagedata是像素数组,dx,dy表示重绘的起始位置,后面四个参数是给出一个矩形的左上角坐标和高宽。

Canvas API的像素操作只有部分浏览器支持,截图效果来自新版的火狐浏览器

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

图片 4

参考这个方案,我们可以实现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);
    });
};

代码如下:

图片 5

二、绘制文字

   1: // 获取canvas 的ID

   2:     var canvas = document.getElementById('canvas');

   3:     if (canvas == null)

   4:     {

   5:         return false;

   6:     }

   7:     // 获取上下文

   8:     var context = canvas.getContext('2d');

   9:     context.fillStyle = '#00f';

  10:     // 设置文字属性

  11:     context.font = 'italic 30px sans-serif';

  12:     context.textBaseline = 'top';

  13:     // 填充字符串

  14:     context.fillText('Canvas绘制文字',0,0);

  15:     context.font = 'bold 30px sans-serif';

  16:     // 轮廓字符串

  17:     context.strokeText('改变位置了',50,50);

fillText(string,x,y[,maxwidth]):前三个不解释,maxwidth表示显示文字的最大宽度,可防止文字溢出

strokeText(string,x,y[,maxwidth]:同上。

文字属性设置

font:设置字体

textAlign:水平对齐方式,取值可是start/end/left/right/center.默认是start

textBaseline:垂直对齐方式,取值可是top/hanging/middle/alphabetic/ideographic/bottom.默认是alphabetic

最终效果

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));

<videoidvideoid=”video”autoplay=””></video>
<script>
varvideo_element=document.getElementById(‘video’);
if(navigator.getUserMedia){//operashoulduseopera.getUserMedianow
navigator.getUserMedia(‘video’,success,error);
}
functionsuccess(stream){
video_element.src=stream;
}
</script>

图片 6

下一篇:9个JQuery和5个JavaScript经典面试题

参考

  • 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的问题: 我在canvas中画了多个图形,有图像(image)、直线

canvas可以实现
首先canvas要响应鼠标事件(onmousedown之类)
之后所有的图形必须要创建相应的对象,来记录他们所在的位置以及大小还有zOrder(层叠位置,在2个对象重叠的时候决定谁在上面),相应的对象放到一个数组里并按zOrder排序
当canvas的鼠标click事件触发后,按照zOrder的顺序来检测鼠标坐标在不在某个对象的区域里,如果在,则执行相应的函数
 

2、 拍照

关注html5通过canvas文本在完成的图形上可以加上文字?有演示视频?

在每个 canvas对象中都拥有一个 path 对象,定义完路径的轮廓,此时 canvas
画面中没有显示任何路径,开发人员需要继续调用 stroke()/fill()
函数来完成将路径渲染到画面的最后一步。路径的轮廓颜色和填充颜色由
strokeStyle 和 fillStyle
属性决定。还可以通过canvas文本在完成的图形上加上文字。推荐你一个视频吧啊,比我讲的清楚,搜一下“HTML5
矢量绘图新功能- Canvas 基本用法”
 

来源:
一、图像处理(非特别说明,所有结果均来自最新版Goog…

拍照功能,我们采用HTML5的Canvas实时捕获Video标签的内容,Video元素能作为Canvas图像的输入,这一点很棒。主要代码如下:

 

代码如下:

JavaScript Code复制内容到剪贴板
var canvas=document.createElement(‘canvas’);
var ctx=canvas.getContext(’2d’);
var cw=vw;
var ch=vh;
ctx.fillStyle=”#ffffff”;
ctx.fillRect(0,0,cw,ch);
ctx.drawImage(video_element,0,0,vvw,vvh,0,0,vw,vh);
document.body.append(canvas);

3、 图片获取

下面我们要从Canvas获取图片数据,其核心思路是用canvas的toDataURL将Canvas的数据转换为base64位编码的PNG图像,类似于“data:image/png;base64,xxxxx”的格式。

代码如下:

var imgData=canvas.toDataURL(“image/png”);

因为真正图像数据是base64编码逗号之后的部分,所以我们实际服务器处理的图像数据应该是这部分,我们可以用两种办法来获取。

第一种:是在前端截取22位以后的字符串作为图像数据,例如:

代码如下:

var data=imgData.substr(22);

如果要在上传前获取图片的大小,可以使用:

 

代码如下:

var
length=atob(data).length;//atobdecodesastringofdatawhichhasbeenencodedusingbase-64encoding

第二种:是在后端获取传输的数据后用后台语言截取22位以后的字符串。例如PHP里:

代码如下:

$image=base64_decode(str_replace(‘data:image/jpeg;base64,’,”,$data);

4、 图片上传

在前端可以使用Ajax将上面获得的图片数据上传到后台脚本。例如使用jQuery时:

代码如下:

$.post(‘upload.php’,{‘data’:data});

 在后台我们用PHP脚本接收数据并存储为图片。

代码如下:

functionconvert_data($data){
$image=base64_decode(str_replace(‘data:image/jpeg;base64,’,”,$data);
save_to_file($image);
}
functionsave_to_file($image){
$fp=fopen($filename,’w’);
fwrite($fp,$image);
fclose($fp);
}

请注意,以上的解决方案不仅能用于Web
App拍照上传,并且你可以实现把Canvas的输出转换为图片上传的功能。这样你可以使用Canvas为用户提供图片编辑,例如裁剪、上色、涂鸦的画板功能,然后把用户编辑完的图片保存到服务器上。

发表评论

电子邮件地址不会被公开。 必填项已用*标注