前者完成,来看望机智的前端童鞋怎么防盗

前端完结 SVG 转 PNG

2015/11/16 · JavaScript
· PNG,
SVG

初稿出处: 百度FEX –
zhangbobell   

点评:创设一个只管的用户界面,并允许你说了算图片的轻重。上传到服务器端的数据,并不必要处理enctype为
multi-part/form-data 的意况,仅仅一个不难易行的POST表单处理程序就可以了.
好了,上面附上完整的代码示例

粗粗的笔触是

来看看机智的前端童鞋怎么防盗

前者完成,来看望机智的前端童鞋怎么防盗。2016/07/12 · JavaScript
· 4 评论 ·
HTML5

初稿出处: VaJoy   

洋洋支付的童鞋都是孤独混江湖、夜宿城中村,若是居住的地点安保欠缺,那么出门在外难免担心屋里的财产安全。

骨子里世面上有很多光辉上的防盗设施,但对此灵动的前端童鞋来说,只要有一台附带视频头的微处理器,就足以简不难单地贯彻一个防盗监控系统~

纯 JS 的“防盗”能力很大程度借助于 H5 canvas
的能力,且非凡有意思。若是您对 canvas
还不精通,可以先点这里读书我的不可胜言教程。

step1. 调用视频头

俺们需求先在浏览器上访问和调用录像头,用来监督屋子里的举动。不一样浏览器中调用摄像头的
API 都略有出入,在那里大家以 chrome 做示范:

JavaScript

<video width=”640″ height=”480″ autoplay></video>
<script> var video = document.querySelector(‘video’);
navigator.webkitGetUserMedia({ video: true }, success, error); function
success(stream) { video.src = window.webkitURL.createObjectURL(stream);
video.play(); } function error(err) { alert(‘video error: ‘ + err) }
</script>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<video width="640" height="480" autoplay></video>
 
<script>
    var video = document.querySelector(‘video’);
 
    navigator.webkitGetUserMedia({
                video: true
            }, success, error);
 
    function success(stream) {
        video.src = window.webkitURL.createObjectURL(stream);
        video.play();
    }
 
    function error(err) {
        alert(‘video error: ‘ + err)
    }
</script>

运作页面后,浏览器出于安全性考虑,会询问是或不是允许当前页面访问你的摄像头设备,点击“允许”后便能直接在
<video> 上观看拍摄头捕获到的画面了:

亚洲必赢官网 1

step2. 捕获 video 帧画面

只但是开着录像头监视房间可没有别的意义,浏览器不会帮您对监督画面进行分析。所以那里大家胜利动用脚本捕获
video 上的帧画面,用于在此起彼伏开展多少解析。

从此间伊始大家就要借助 canvas
力量了。在 Canvas入门(五)一文大家介绍过 ctx.drawImage()
方法,通过它可以捕获 video 帧画面并渲染到画布上。

俺们须要创设一个画布,然后这么写:

JavaScript

<video width=”640″ height=”480″ autoplay></video> <canvas
width=”640″ height=”480″></canvas> <script> var video =
document.querySelector(‘video’); var canvas =
document.querySelector(‘canvas’); // video捕获视频头画面
navigator.webkitGetUserMedia({ video: true }, success, error); function
success(stream) { video.src = window.webkitURL.createObjectURL(stream);
video.play(); } function error(err) { alert(‘video error: ‘ + err) }
//canvas var context = canvas.getContext(‘2d’); set提姆eout(function(){
//把当前摄像帧内容渲染到画布上 context.drawImage(video, 0, 0, 640, 480);
}, 5000); </script>

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
<video width="640" height="480" autoplay></video>
<canvas width="640" height="480"></canvas>
 
<script>
    var video = document.querySelector(‘video’);
    var canvas = document.querySelector(‘canvas’);
 
    // video捕获摄像头画面
    navigator.webkitGetUserMedia({
                video: true
            }, success, error);
 
    function success(stream) {
        video.src = window.webkitURL.createObjectURL(stream);
        video.play();
    }
 
    function error(err) {
        alert(‘video error: ‘ + err)
    }
 
    //canvas
    var context = canvas.getContext(‘2d’);
 
    setTimeout(function(){
        //把当前视频帧内容渲染到画布上
        context.drawImage(video, 0, 0, 640, 480);
    }, 5000);
 
</script>

如上代码所示,5秒后把视频帧内容渲染到画布上(下方右图)

亚洲必赢官网 2

step3. 对捕获的五个帧画面执行差距混合

在上头大家提到过,要使得地分辨某个场景,须要对视频画面举行数量解析。

那就是说要怎么辨识我们的房舍是不是有人忽然闯入了吗?答案很不难 —— 定时地破获
video 画面,然后相比较前后两帧内容是不是留存较大转移。

俺们先不难地写一个定时捕获的法门,并将捕获到的帧数据存起来:

JavaScript

//canvas var context = canvas.getContext(‘2d’); var preFrame, //前一帧
curFrame; //当前帧 //捕获并保存帧内容 function captureAndSaveFrame(){
console.log(context); preFrame = curFrame; context.drawImage(video, 0,
0, 640, 480); curFrame = canvas.toDataURL; //转为base64并保存 }
//定时捕获 function timer(delta){ set提姆eout(function(){
captureAndSaveFrame(); timer(delta) }, delta || 500); } timer();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
    //canvas
    var context = canvas.getContext(‘2d’);
    var preFrame,   //前一帧
        curFrame;   //当前帧
 
    //捕获并保存帧内容
    function captureAndSaveFrame(){ console.log(context);
        preFrame = curFrame;
        context.drawImage(video, 0, 0, 640, 480);
        curFrame = canvas.toDataURL;  //转为base64并保存
    }
 
    //定时捕获
    function timer(delta){
        setTimeout(function(){
            captureAndSaveFrame();
            timer(delta)
        }, delta || 500);
    }
 
    timer();

如上代码所示,画布会每隔500飞秒捕获并渲染一次 video
的帧内容(夭寿哇,做完这几个动作不小心把饼干洒了一地。。。\(“▔□▔)/)

亚洲必赢官网 3

在意那里大家利用了 canvas.toDataURL 方法来保存帧画面。

接着就是数据解析处理了,我们得以因而对照前后捕获的帧画面来判断视频头是或不是监控到变化,那么如何是好吧?

精晓设计的校友肯定平时使用一个图层作用 —— 混合格局:

亚洲必赢官网 4

当有四个图层时,对顶层图层设置“差值/Difference”的混合情势,可以看清地看来多个图层的差距:

亚洲必赢官网 5

“图A”是本人二〇一八年在公司楼下拍的肖像,然后我把它稍微调亮了一点点,并在上面画了一个
X 和 O
得到“图B”。接着自己把它们以“差值”格局混合在联合,获得了最右的那张图。

JavaScript

“差值”形式原理:要掺杂图层双方的RGB值中每个值分别展开比较,用高值减去低值作为合成后的颜料,平日用白色图层合成一图像时,能够获取负片效果的反相图像。用黑色的话不发出任何变化(青色亮度最低,下层颜色减去最小颜色值0,结果和原来一样),而用白色会得到反相效果(下层颜色被减去,得到补值),其余颜色则按照它们的亮度水平

1
“差值”模式原理:要混合图层双方的RGB值中每个值分别进行比较,用高值减去低值作为合成后的颜色,通常用白色图层合成一图像时,可以得到负片效果的反相图像。用黑色的话不发生任何变化(黑色亮度最低,下层颜色减去最小颜色值0,结果和原来一样),而用白色会得到反相效果(下层颜色被减去,得到补值),其它颜色则基于它们的亮度水平

在CSS3中,已经有 blend-mode
特性来支撑这几个好玩的交集形式,不过大家发现,在主流浏览器上,canvas
的 globalCompositeOperation 接口也曾经完美协助了图像混合方式:

于是大家再建多一个画布来显示前后两帧差别:

JavaScript

<video width=”640″ height=”480″ autoplay></video> <canvas
width=”640″ height=”480″></canvas> <canvas width=”640″
height=”480″></canvas> <script> var video =
document.querySelector(‘video’); var canvas =
document.querySelectorAll(‘canvas’)[0]; var canvasForDiff =
document.querySelectorAll(‘canvas’)[1]; // video捕获视频头画面
navigator.webkitGetUserMedia({ video: true }, success, error); function
success(stream) { video.src = window.URL.createObjectURL(stream);
video.play(); } function error(err) { alert(‘video error: ‘ + err) }
//canvas var context = canvas.getContext(‘2d’), diffCtx =
canvasForDiff.getContext(‘2d’); //将第三个画布混合格局设为“差别”
diffCtx.globalCompositeOperation = ‘difference’; var preFrame, //前一帧
curFrame; //当前帧 //捕获并保存帧内容 function captureAndSaveFrame(){
preFrame = curFrame; context.drawImage(video, 0, 0, 640, 480); curFrame
= canvas.toDataURL(); //转为base64并保存 } //绘制base64图像到画布上
function drawImg(src, ctx){ ctx = ctx || diffCtx; var img = new Image();
img.src = src; ctx.drawImage(img, 0, 0, 640, 480); } //渲染前后两帧差距function renderDiff(){ if(!preFrame || !curFrame) return;
diffCtx.clearRect(0, 0, 640, 480); drawImg(preFrame); drawImg(curFrame);
} //定时捕获 function timer(delta){ set提姆eout(function(){
captureAndSaveFrame(); renderDiff(); timer(delta) }, delta || 500); }
timer(); </script>

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
<video width="640" height="480" autoplay></video>
<canvas width="640" height="480"></canvas>
<canvas width="640" height="480"></canvas>
 
<script>
    var video = document.querySelector(‘video’);
    var canvas = document.querySelectorAll(‘canvas’)[0];
    var canvasForDiff = document.querySelectorAll(‘canvas’)[1];
 
    // video捕获摄像头画面
    navigator.webkitGetUserMedia({
                video: true
            }, success, error);
 
    function success(stream) {
        video.src = window.URL.createObjectURL(stream);
        video.play();
    }
 
    function error(err) {
        alert(‘video error: ‘ + err)
    }
 
    //canvas
    var context = canvas.getContext(‘2d’),
        diffCtx = canvasForDiff.getContext(‘2d’);
    //将第二个画布混合模式设为“差异”
    diffCtx.globalCompositeOperation = ‘difference’;
 
    var preFrame,   //前一帧
        curFrame;   //当前帧
 
    //捕获并保存帧内容
    function captureAndSaveFrame(){
        preFrame = curFrame;
        context.drawImage(video, 0, 0, 640, 480);
        curFrame = canvas.toDataURL();  //转为base64并保存
    }
 
    //绘制base64图像到画布上
    function drawImg(src, ctx){
        ctx = ctx || diffCtx;
        var img = new Image();
        img.src = src;
        ctx.drawImage(img, 0, 0, 640, 480);
    }
 
    //渲染前后两帧差异
    function renderDiff(){
        if(!preFrame || !curFrame) return;
        diffCtx.clearRect(0, 0, 640, 480);
        drawImg(preFrame);
        drawImg(curFrame);
    }
 
    //定时捕获
    function timer(delta){
        setTimeout(function(){
            captureAndSaveFrame();
            renderDiff();
            timer(delta)
        }, delta || 500);
    }
 
    timer();
 
</script>

成效如下(夭寿啊,做完那些动作我又把7-Up洒在键盘上了。。。(#--)/

亚洲必赢官网 6

可以看看,当前后两帧差别不大时,第多少个画布差不离是盲目标一片,唯有当拍摄头捕获到动作了,第五个画布才有强烈的高亮内容出现。

就此,大家只需求对第八个画布渲染后的图像举办像素分析——判断其高亮阈值是不是达标某个指定预期:

JavaScript

var context = canvas.getContext(‘2d’), diffCtx =
canvasForDiff.getContext(‘2d’); //将第一个画布混合方式设为“差别”
diffCtx.globalCompositeOperation = ‘difference’; var preFrame, //前一帧
curFrame; //当前帧 var diffFrame; //存放差距帧的imageData
//捕获并保存帧内容 function captureAndSaveFrame(){ preFrame = curFrame;
context.drawImage(video, 0, 0, 640, 480); curFrame = canvas.toDataURL();
//转为base64并保存 } //绘制base64图像到画布上 function drawImg(src,
ctx){ ctx = ctx || diffCtx; var img = new Image(); img.src = src;
ctx.drawImage(img, 0, 0, 640, 480); } //渲染前后两帧差距 function
renderDiff(){ if(!preFrame || !curFrame) return; diffCtx.clearRect(0, 0,
640, 480); drawImg(preFrame); drawImg(curFrame); diffFrame =
diffCtx.getImageData( 0, 0, 640, 480 ); //捕获差别帧的imageData对象 }
//总计差别 function calcDiff(){ if(!diffFrame) return 0; var cache =
arguments.callee, count = 0; cache.total = cache.total || 0;
//整个画布都是反动时拥有像素的值的总额 for (var i = 0, l =
diffFrame.width * diffFrame.height * 4; i < l; i += 4) { count +=
diffFrame.data[i] + diffFrame.data[i + 1] + diffFrame.data[i + 2];
if(!cache.isLoopEver){ //只需在率先次循环里执行 cache.total += 255 * 3;
//单个反革命像素值 } } cache.isLoop伊芙r = true; count *= 3; //亮度放大
//重临“差别画布高亮部分像素总值”占“画布全亮景况像素总值”的比重 return
Number(count/cache.total).toFixed(2); } //定时捕获 function
timer(delta){ setTimeout(function(){ captureAndSaveFrame();
renderDiff(); set提姆eout(function(){ console.log(calcDiff()); }, 10);
timer(delta) }, delta || 500); } timer();

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
    var context = canvas.getContext(‘2d’),
        diffCtx = canvasForDiff.getContext(‘2d’);
    //将第二个画布混合模式设为“差异”
    diffCtx.globalCompositeOperation = ‘difference’;
 
    var preFrame,   //前一帧
        curFrame;   //当前帧
 
    var diffFrame;  //存放差异帧的imageData
 
    //捕获并保存帧内容
    function captureAndSaveFrame(){
        preFrame = curFrame;
        context.drawImage(video, 0, 0, 640, 480);
        curFrame = canvas.toDataURL();  //转为base64并保存
    }
 
    //绘制base64图像到画布上
    function drawImg(src, ctx){
        ctx = ctx || diffCtx;
        var img = new Image();
        img.src = src;
        ctx.drawImage(img, 0, 0, 640, 480);
    }
 
    //渲染前后两帧差异
    function renderDiff(){
        if(!preFrame || !curFrame) return;
        diffCtx.clearRect(0, 0, 640, 480);
        drawImg(preFrame);
        drawImg(curFrame);
        diffFrame = diffCtx.getImageData( 0, 0, 640, 480 );  //捕获差异帧的imageData对象
    }
 
    //计算差异
    function calcDiff(){
        if(!diffFrame) return 0;
        var cache = arguments.callee,
            count = 0;
        cache.total = cache.total || 0; //整个画布都是白色时所有像素的值的总和
        for (var i = 0, l = diffFrame.width * diffFrame.height * 4; i < l; i += 4) {
            count += diffFrame.data[i] + diffFrame.data[i + 1] + diffFrame.data[i + 2];
            if(!cache.isLoopEver){  //只需在第一次循环里执行
                cache.total += 255 * 3;   //单个白色像素值
            }
        }
        cache.isLoopEver = true;
        count *= 3;  //亮度放大
        //返回“差异画布高亮部分像素总值”占“画布全亮情况像素总值”的比例
        return Number(count/cache.total).toFixed(2);
    }
 
    //定时捕获
    function timer(delta){
        setTimeout(function(){
            captureAndSaveFrame();
            renderDiff();
            setTimeout(function(){
                console.log(calcDiff());
            }, 10);
 
            timer(delta)
        }, delta || 500);
    }
 
    timer();

注意这里大家采用了 count *= 3
来推广差距高亮像素的亮度值,不然得出的数值实在太小了。我们运行下页面(图片较大加载会有点慢)

亚洲必赢官网 7

透过试(xia)验(bai),个人认为只要 calcDiff() 重返的比率借使超越0.20,那么就可以定性为“一间空屋子,突然有人闯进来”的状态了。

step4. 上报极度图片

当上述的一个钱打二十四个结发现有场景时,需求有某种途径文告大家。有钱有生机的话可以配备个邮件服务器,直接发邮件甚至短信公告到祥和,but
本文走的吃吐少年路线,就不搞的那么高端了。

那么要什么样不难地落到实处充裕图片的报告呢?我暂且想到的是 ——
直接把标题图片发送到某个站点中去。

那里大家挑选腾讯网的“日记”功能,它可以随心所欲上传相关内容。

JavaScript

p.s.,其实那里原来是想直接把图纸传遍新浪相册上的,可惜POST请求的图片实体必要走
file 格式,即不可以透过脚本更改文件的 input[type=file],转 Blob
再上传也没用,只能作罢。

1
p.s.,其实这里原本是想直接把图片传到博客园相册上的,可惜POST请求的图片实体要求走 file 格式,即无法通过脚本更改文件的 input[type=file],转 Blob 再上传也没用,只好作罢。

我们在管理后台成立日记时,通过 Fiddler 抓包可以看看其请求参数很是简单:

亚洲必赢官网 8

之所以得以一向协会一个呼吁:

JavaScript

//十分图片上传处理 function submit(){ //ajax 提交form $.ajax({ url :
”, type : “POST”, data : {
‘__VIEWSTATE’: ”, ‘__VIEWSTATEGENERATOR’: ‘4773056F’,
‘Editor$Edit$txbTitle’: ‘告警’ + Date.now(), ‘Editor$Edit$EditorBody’:
‘<img src=”‘ + curFrame + ‘” />’, ‘Editor$Edit$lkbPost’: ‘保存’ },
success: function(){ console.log(‘submit done’) } }); }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
    //异常图片上传处理
    function submit(){
 
        //ajax 提交form
        $.ajax({
            url : ‘http://i.cnblogs.com/EditDiary.aspx?opt=1’,
            type : "POST",
            data : {
                ‘__VIEWSTATE’: ”,
                ‘__VIEWSTATEGENERATOR’: ‘4773056F’,
                ‘Editor$Edit$txbTitle’: ‘告警’ + Date.now(),
                ‘Editor$Edit$EditorBody’: ‘<img src="’ + curFrame + ‘" />’,
                ‘Editor$Edit$lkbPost’: ‘保存’
            },
            success: function(){
                console.log(‘submit done’)
            }
        });
    }

理所当然如若请求页面跟乐乎域名分裂,是力不从心发送 cookie
导致请求跨域而失效,不过那些很好解决,直接改动 host
即可(怎么修改就不介绍了,自行百度吗)

自身这边改完 host,通过 
的地点访问页面,发现视频头竟然失效了~

通过谷歌(谷歌)的文档可以得知,那是为着安全性考虑,非
HTTPS 的服务端请求都无法对接视频头。可是解决办法也是一对,以 window
系统为例,打开 cmd 命令行面板并定位到 chrome 安装文件夹下,然后实施:

ZSH

chrome
–unsafely-treat-insecure-origin-as-secure=””
–user-data-dir=C:\testprofile

1
chrome –unsafely-treat-insecure-origin-as-secure="http://i.cnblogs.com/h5monitor/final.html"  –user-data-dir=C:\testprofile

行动将以沙箱方式打开一个独门的 chrome
进度,并对点名的站点去掉安全范围。注意我们在新开的 chrome
中得重新登录网易。

那儿便能正常访问视频头了,大家对代码做下处理,当差别检测发现万分时,创立一份日记,最小间隔时间为5秒(不过后来察觉没须要,因为天涯论坛已经有做了光阴限制,大概10秒后才能公布新的日志)

JavaScript

//定时捕获 function timer(delta){ set提姆eout(function(){
captureAndSaveFrame(); renderDiff(); if(calcDiff() > 0.2){
//监控到充裕,发日志 submit() } timer(delta) }, delta || 500); }
set提姆eout(timer, 60000 * 10); //设定打开页面十分钟后才伊始监控
//卓殊图片上传处理 function submit(){ var cache = arguments.callee, now
= Date.now(); if(cache.req提姆e && (now – cache.req提姆e < 5000))
return; //日记成立最小间隔为5秒 cache.req提姆e = now; //ajax 提交form
$.ajax({ url : ”, type :
“POST”, timeout : 5000, data : { ‘__VIEWSTATE’: ”,
‘__VIEWSTATEGENERATOR’: ‘4773056F’, ‘Editor$Edit$txbTitle’: ‘告警’ +
Date.now(), ‘Editor$Edit$EditorBody’: ‘<img src=”‘ + curFrame + ‘”
/>’, ‘Editor$Edit$lkbPost’: ‘保存’ }, success: function(){
console.log(‘submit done’) }, error: function(err){ cache.reqTime = 0;
console.log(‘error: ‘ + err) } }); }

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
    //定时捕获
    function timer(delta){
        setTimeout(function(){
            captureAndSaveFrame();
            renderDiff();
            if(calcDiff() > 0.2){  //监控到异常,发日志
                submit()
            }
 
            timer(delta)
        }, delta || 500);
    }
 
    setTimeout(timer, 60000 * 10);  //设定打开页面十分钟后才开始监控
 
 
    //异常图片上传处理
    function submit(){
        var cache = arguments.callee,
            now = Date.now();
        if(cache.reqTime && (now – cache.reqTime < 5000)) return;  //日记创建最小间隔为5秒
 
        cache.reqTime = now;
 
        //ajax 提交form
        $.ajax({
            url : ‘http://i.cnblogs.com/EditDiary.aspx?opt=1’,
            type : "POST",
            timeout : 5000,
            data : {
                ‘__VIEWSTATE’: ”,
                ‘__VIEWSTATEGENERATOR’: ‘4773056F’,
                ‘Editor$Edit$txbTitle’: ‘告警’ + Date.now(),
                ‘Editor$Edit$EditorBody’: ‘<img src="’ + curFrame + ‘" />’,
                ‘Editor$Edit$lkbPost’: ‘保存’
            },
            success: function(){
                console.log(‘submit done’)
            },
            error: function(err){
                cache.reqTime = 0;
                console.log(‘error: ‘ + err)
            }
        });
    }

施行效果:

亚洲必赢官网 9

日志也是妥妥的出来了:

亚洲必赢官网 10

点开就能收看那些的那张图片了:

亚洲必赢官网 11

要小心的是,和讯对日记发表数量是有做每日额度限制来防刷的,达到限额的话会招致当天的小说和文章也不可能公布,所以得小心使用:

亚洲必赢官网 12

而是这种样式仅能申报非常图片,暂时不能够让我们马上收悉告警,有趣味的童鞋可以试着再写个
chrome 插件,定时去拉取日记列表做判定,如若有新增日记则触发页面 alert。

其它我们自然期待能直接对闯入者进行警戒,那块相比好办 ——
搞个警示的韵律,在极度的时候接触播放即可:

JavaScript

//播放音频 function fireAlarm(){ audio.play() } //定时捕获 function
timer(delta){ set提姆eout(function(){ captureAndSaveFrame(); if(preFrame
&& curFrame){ renderDiff(); if(calcDiff() > 0.2){ //监控到万分//发日记 submit(); //播放音频告警 fireAlarm(); } } timer(delta) }, delta
|| 500); } set提姆eout(timer, 60000 * 10);
//设定打开页面十分钟后才起来监控

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
    //播放音频
    function fireAlarm(){
        audio.play()
    }
 
 
    //定时捕获
    function timer(delta){
        setTimeout(function(){
            captureAndSaveFrame();
            if(preFrame && curFrame){
                renderDiff();
                if(calcDiff() > 0.2){  //监控到异常
                    //发日记
                    submit();
                    //播放音频告警
                    fireAlarm();
                }
            }
            timer(delta)
        }, delta || 500);
    }
 
    setTimeout(timer, 60000 * 10);  //设定打开页面十分钟后才开始监控

最终说一下,本文代码均挂在我的github上,有趣味的童鞋可以自助下载。共勉~

1 赞 4 收藏 4
评论

亚洲必赢官网 13

前言

svg 是一种矢量图形,在 web
上运用很广阔,不过众多时候由于使用的情景,平常须要将 svg 转为 png
格式,下载到本地等。随着浏览器对 HTML 5 的支撑度越来越高,我们得以把 svg
转为 png 的工作交给浏览器来已毕。

示范地址:Canvas Resize Demo
原文作者:Dr. Tom Trenka
原稿日期: 二零一三年5月6日
翻译日期: 二〇一三年3月8日

利用FileReader,读取blob对象,或者是file对象,将图片转化为data
uri的款型。

相似方法

  1. 创建 imageimage,src = xxx.svg;
  2. 成立 canvas,dragImage 将图片贴到 canvas 上;
  3. 使用 toDataUrl 函数,将 canvas 的意味为 url;
  4. new image, src = url, download = download.png;

不过,在转移的时候有时有时会遇上如下的如下的五个难点:

汤姆 Trenka
能为”我”的博客写一篇作品,对自我的话是一个伟大的得体。汤姆是Dojo框架的最初进献者之一,也是自身在SitePen公司的良师益友.我见证了她最一级的天才能力,并且他一个劲第三个以前瞻性的缓解方案预感了众多吃力的题材。他老是站在局外思考,打破常规但却又结实可靠地缓解边缘问题。本文就是一个周全的事例。
近来自家接连被问道要创制一个用户接口API,允许用户上传图片到服务器上(伴随其余的工作),并能在我们公司提供辅助的豁达网站的客户端上利用。常常来说那都是很简单的事务——创建一个form表单,添加一个file类型的input输入框,让用户从计算机里拔取图片,并在form标签上设置enctype=”multipart/form-data”表单属性,然后上传即可。卓殊简单,不是吧?事实上,那里有一个足足简单的例证;点击进入
而是假诺你想要通过某些格局先期处理一下图纸再上传,那该如何做?比如说,你必须先削减图片尺寸,或者要求图片只可以是某些连串的格式,如
png 或者jpg,你如何是好?
用canvas来解决!

使用canvas,在页面上新建一个画布,利用canvas提供的API,将图纸画入这几个画布当中。

标题 1 :浏览器对 canvas 限制

Canvas 的 W3C 的正统上未曾提及 canvas
的最大高/宽度和面积,然而各种厂商的浏览器出于浏览器品质的考虑,在区其他平台上安装了最大的高/宽度或者是渲染面积,当先了那些阈值渲染的结果会是一贫如洗。测试了二种浏览器的
canvas 质量如下:

  • chrome (版本 46.0.2490.80 (64-bit))
    • 最大面积:268, 435, 456 px^2 = 16, 384 px * 16, 384 px
    • 最大宽/高:32, 767 px
  • firefox (版本 42.0)
    • 最大面积:32, 767 px * 16, 384 px
    • 最大宽/高:32, 767px
  • safari (版本 9.0.1 (11601.2.7.2))
    • 最大面积: 268, 435, 456 px^2 = 16, 384 px * 16, 384 px
  • ie 10(版本 10.0.9200.17414)
    • 最大宽/高: 8, 192px * 8, 192px

在相似的 web
应用中,可能很少会超越那几个限制。不过,如若跨越了那些限制,则
会导致导出为空白或者由于内存败露导致浏览器崩溃。

而且从一头来说, 导出 png
也是一项很开销内存的操作,粗略估算一下,导出 16, 384 px * 16, 384 px 的
svg 会消耗 16384 * 16384 * 4 / 1024 / 1024 = 1024 M
的内存。所以,在看似那几个极限值的时候,浏览器也会
反应变慢,能或不能导出成功也跟系统的可用内存大小等等都有关联。

对此那几个标题,有如下二种缓解措施:

  1. 将数据发送给后端,在后端达成 转换;
  2. 前者将 svg 切分成三个图片导出;

第一种艺术可以动用 PhantomJS、inkscape、ImageMagick
等工具,相对来说相比较不难,那里大家主要探索第两种缓解办法。

Canvas简介
canvas
是一个HTML5新增的DOM元素,允许用户在页面上直接地绘制图形,日常是应用JavaScript.而差距的格式标准也是见仁见智的,比如SVG是光栅API(raster
API) 而VML却是向量API(vector API).可以设想动用Adobe
Illustrator(矢量图)作图与行使 Adobe Photoshop (光栅图)作图的界别。

动用canvas.toDataURL(),实行图纸的回落,获得图片的data uri的值

svg 切分成七个图片导出

思路:浏览器即便对 canvas 有尺寸和面积的限量,不过对于 image
元素并不曾精通的限定,也就是率先步生成的 image
其实展现是常规的,大家要做的只是在其次步 dragImage 的时候分很多次将
image 元素切分并贴到 canvas 上然后下载下来。 同时,应留神到 image
的载入是一个异步的进程。

重大代码

JavaScript

// 构造 svg Url,此处省略将 svg 经字符过滤后转为 url 的进度。 var svgUrl
= DomURL.createObjectURL(blob); var svgWidth =
document.querySelector(‘#kity_svg’).getAttribute(‘width’); var
svgHeight =
document.querySelector(‘#kity_svg’).getAttribute(‘height’); //
分片的升幅和冲天,可依照浏览器做适配 var w0 = 8192; var h0 = 8192; //
每行和每列能兼容的分片数 var M = Math.ceil(svgWidth / w0); var N =
Math.ceil(svgHeight / h0); var idx = 0;
loadImage(svgUrl).then(function(img) { while(idx < M * N) { //
要分开的面片在 image 上的坐标和尺寸 var targetX = idx % M * w0, targetY
= idx / M * h0, targetW = (idx + 1) % M ? w0 : (svgWidth – (M – 1) *
w0), targetH = idx >= (N – 1) * M ? (svgHeight – (N – 1) * h0) :
h0; var canvas = document.createElement(‘canvas’), ctx =
canvas.getContext(‘2d’); canvas.width = targetW; canvas.height =
targetH; ctx.drawImage(img, targetX, targetY, targetW, targetH, 0, 0,
targetW, targetH); console.log(‘now it is ‘ + idx); // 准备在前端下载
var a = document.createElement(‘a’); a.download = ‘naotu-‘ + idx +
‘.png’; a.href = canvas.toDataURL(‘image/png’); var click伊夫nt = new
Mouse伊芙nt(‘click’, { ‘view’: window, ‘bubbles’: true, ‘cancelable’:
false }); a.dispatch伊芙nt(click伊夫nt); idx++; } }, function(err) {
console.log(err); }); // 加载 image function loadImage(url) { return new
Promise(function(resolve, reject) { var image = new Image(); image.src =
url; image.crossOrigin = ‘Anonymous’; image.onload = function() {
resolve(this); }; image.onerror = function(err) { reject(err); }; }); }

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
// 构造 svg Url,此处省略将 svg 经字符过滤后转为 url 的过程。
var svgUrl = DomURL.createObjectURL(blob);
var svgWidth = document.querySelector(‘#kity_svg’).getAttribute(‘width’);
var svgHeight = document.querySelector(‘#kity_svg’).getAttribute(‘height’);
 
// 分片的宽度和高度,可根据浏览器做适配
var w0 = 8192;
var h0 = 8192;
 
// 每行和每列能容纳的分片数
var M = Math.ceil(svgWidth / w0);
var N = Math.ceil(svgHeight / h0);
 
var idx = 0;
loadImage(svgUrl).then(function(img) {
 
    while(idx < M * N) {
        // 要分割的面片在 image 上的坐标和尺寸
        var targetX = idx % M * w0,
            targetY = idx / M * h0,
            targetW = (idx + 1) % M ? w0 : (svgWidth – (M – 1) * w0),
            targetH = idx >= (N – 1) * M ? (svgHeight – (N – 1) * h0) : h0;
 
        var canvas = document.createElement(‘canvas’),
            ctx = canvas.getContext(‘2d’);
 
            canvas.width = targetW;
            canvas.height = targetH;
 
            ctx.drawImage(img, targetX, targetY, targetW, targetH, 0, 0, targetW, targetH);
 
            console.log(‘now it is ‘ + idx);
 
            // 准备在前端下载
            var a = document.createElement(‘a’);
            a.download = ‘naotu-‘ + idx + ‘.png’;
            a.href = canvas.toDataURL(‘image/png’);
 
            var clickEvent = new MouseEvent(‘click’, {
                ‘view’: window,
                ‘bubbles’: true,
                ‘cancelable’: false
            });
 
            a.dispatchEvent(clickEvent);
 
        idx++;
    }
 
}, function(err) {
    console.log(err);
});
 
// 加载 image
function loadImage(url) {
    return new Promise(function(resolve, reject) {
        var image = new Image();
 
        image.src = url;
        image.crossOrigin = ‘Anonymous’;
        image.onload = function() {
            resolve(this);
        };
 
        image.onerror = function(err) {
            reject(err);
        };
    });
}

说明:

  1. 出于在前者下载有浏览器包容性、用户体验等题材,在骨子里中,可能需求将转移后的多少发送到后端,并作为一个回落包下载。
  2. 分片的尺寸那里运用的是 8192 *
    9192,在其实中,为了坚实包容性和心得,能够按照浏览器和平台做适配,例如在
    iOS 下的 safari 的最大面积是 4096 *4096。

在canvas(画布)上能做的政工就是读取和渲染图像,并且同意你通过JavaScript操纵图像数据。已经有不少留存的文章来为你演示基本的图像处理——首要关心与各类不相同的图像过滤技术(
image filtering
techniques)——但大家须要的无非是缩放图片并转换到特定的文件格式,而canvas完全可以成功那几个事情。

上传文件。

标题 2 :导出包蕴图表的 svg

在导出的时候,还会蒙受另一个标题:假设 svg
里面富含图表,你会意识经过以上办法导出的 png
里面,原来的图纸是不显得的。一般认为是 svg
里面富含的图形跨域了,不过即使您把这些图形换开支域的图片,如故会并发那种状态。亚洲必赢官网 14

图形中上有些是导出前的 svg,下图是导出后的 png。svg
中的图片是本域的,在导出后不显示。

咱们只要的要求,比如图像中度不当先100像素,不管原始图像有多高。基本的代码如下所示:

自我将以上步骤封装成一个主意:

标题来自

大家按照小说最起始提出的步调,逐步排查,会发现在率先步的时候,svg
中的图片就不出示了。也就是,当 image 元素的 src 为一个 svg,并且 svg
里面包罗图表,那么被含有的图样是不会显得的,固然那么些图形是本域的。

W3C 关于那个题材并没有
做表明,最终在  找到了有关那一个题材的求证。
意思是:禁止这么做是由于安全考虑,svg 里面引用的兼具 外表资源 包罗image, stylesheet, script 等都会被挡住。

其中还举了一个事例:即使没有那几个范围,如若一个论坛允许用户上传那样的 svg
作为头像,就有可能现身那样的风貌,一位黑客上传 svg
作为头像,里面富含代码:<image xlink:href="http://evilhacker.com/myimage.png">(如果那位黑客拥有对于
evilhacker.com 的控制权),那么那位黑客就完全能一呵而就上面的事情:

  • 借使有人查看他的素材,evilhacker.com 就会接到到五回 ping
    的呼吁(进而可以获得查看者的 ip);
  • 可以完毕对于分裂的 ip 地址的人出示不相同等的头像;
  • 可以随时更换头像的外观(而不用经过论坛管理员的稽审)。

见状那里,大致就清楚了全体难点的前后了,当然还有某些缘由恐怕是防止图像递归。

代码如下:

compress(file, quality, callback) {

          if (!window.FileReader || !window.Blob) {

              return errorHandler(‘您的浏览器不协理图片压缩’)();

          }

          var reader = new FileReader();

          var mimeType = file.type || ‘image/jpeg’;

          reader.onload = createImage;

          reader.onerror = errorHandler(‘图片读取战败!’);

          reader.readAsDataURL(file);

          function createImage() {

              var dataURL = this.result;

              var image = new Image();

              image.onload = compressImage;

              image.onerror = errorHandler(‘图片加载战败’);

              image.src = dataURL;

          }

          function compressImage() {

              var canvas = document.createElement(‘canvas’);

              var ctx;

              var dataURI;

              var result;

              canvas.width = this.naturalWidth;

              canvas.height = this.naturalHeight;

              ctx = canvas.getContext(‘2d’);

              ctx.drawImage(this, 0, 0);

              dataURI = canvas.toDataURL(mimeType, quality);

              result = dataURIToBlob(dataURI);

              callback(null, result);

          }

          function dataURIToBlob(dataURI) {

              var type = dataURI.match(/data:([^;]+)/)[1];

              var base64 = dataURI.replace(/^[^,]+,/, ”);

              var byteString = atob(base64);

              var ia = new Uint8Array(byteString.length);

              for (var i = 0; i < byteString.length; i++) {

                  ia[i] = byteString.charCodeAt(i);

              }

              // var blob = getBlob([ia]);

              return new Blob([ia], {type: type});

          }

          function errorHandler(message) {

              return function () {

                  var error = new Error(‘Compression Error:’,
message);

                  callback(error, null);

              };

          }

      },

解决办法

思路:由于安全因素,其实首先步的时候,图片已经显得不出来了。那么大家明日设想的法子是在率先步之后遍历
svg 的构造,将具备的 image 元素的
url、地方和尺寸保存下去。在第三步之后,按梯次贴到 canvas
上。那样,最后导出的 png 图片就会有 svg 里面的 image。第一代码

JavaScript

// 此处略去变通 svg url 的进程 var svgUrl =
DomURL.createObjectURL(blob); var svgWidth =
document.querySelector(‘#kity_svg’).getAttribute(‘width’); var
svgHeight =
document.querySelector(‘#kity_svg’).getAttribute(‘height’); var
embededImages = document.querySelectorAll(‘#kity_svg image’); // 由
nodeList 转为 array embededImages =
Array.prototype.slice.call(embededImages); // 加载底层的图
loadImage(svgUrl).then(function(img) { var canvas =
document.createElement(‘canvas’), ctx = canvas.getContext(“2d”);
canvas.width = svgWidth; canvas.height = svgHeight; ctx.drawImage(img,
0, 0); // 遍历 svg 里面装有的 image 元素
embededImages.reduce(function(sequence, svgImg){ return
sequence.then(function() { var url = svgImg.getAttribute(‘xlink:href’) +
‘abc’, dX = svgImg.getAttribute(‘x’), dY = svgImg.getAttribute(‘y’),
dWidth = svgImg.getAttribute(‘width’), dHeight =
svgImg.getAttribute(‘height’); return loadImage(url).then(function(
sImg) { ctx.drawImage(sImg, 0, 0, sImg.width, sImg.height, dX, dY,
dWidth, dHeight); }, function(err) { console.log(err); }); },
function(err) { console.log(err); }); },
Promise.resolve()).then(function() { // 准备在前者下载 var a =
document.createElement(“a”); a.download = ‘download.png’; a.href =
canvas.toDataURL(“image/png”); var click伊芙nt = new Mouse伊芙nt(“click”,
{ “view”: window, “bubbles”: true, “cancelable”: false });
a.dispatch伊芙nt(click伊芙nt); }); }, function(err) { console.log(err); })
// 省略了 loadImage 函数 // 代码和率先个例子一样

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
// 此处略去生成 svg url 的过程
var svgUrl = DomURL.createObjectURL(blob);
var svgWidth = document.querySelector(‘#kity_svg’).getAttribute(‘width’);
var svgHeight = document.querySelector(‘#kity_svg’).getAttribute(‘height’);
 
var embededImages = document.querySelectorAll(‘#kity_svg image’);
// 由 nodeList 转为 array
embededImages = Array.prototype.slice.call(embededImages);
// 加载底层的图
loadImage(svgUrl).then(function(img) {
 
var canvas = document.createElement(‘canvas’),
ctx = canvas.getContext("2d");
 
canvas.width = svgWidth;
canvas.height = svgHeight;
 
ctx.drawImage(img, 0, 0);
    // 遍历 svg 里面所有的 image 元素
    embededImages.reduce(function(sequence, svgImg){
 
        return sequence.then(function() {
            var url = svgImg.getAttribute(‘xlink:href’) + ‘abc’,
                dX = svgImg.getAttribute(‘x’),
                dY = svgImg.getAttribute(‘y’),
                dWidth = svgImg.getAttribute(‘width’),
                dHeight = svgImg.getAttribute(‘height’);
 
            return loadImage(url).then(function( sImg) {
                ctx.drawImage(sImg, 0, 0, sImg.width, sImg.height, dX, dY, dWidth, dHeight);
            }, function(err) {
                console.log(err);
            });
        }, function(err) {
            console.log(err);
        });
    }, Promise.resolve()).then(function() {
        // 准备在前端下载
        var a = document.createElement("a");
        a.download = ‘download.png’;
        a.href = canvas.toDataURL("image/png");
 
        var clickEvent = new MouseEvent("click", {
            "view": window,
            "bubbles": true,
            "cancelable": false
        });
 
        a.dispatchEvent(clickEvent);
 
        });
 
      }, function(err) {
        console.log(err);
   })
 
   // 省略了 loadImage 函数
   // 代码和第一个例子相同

说明

  1. 事例中 svg 里面的图像是根节点上面的,因而用于表示地方的 x, y
    间接取来即可使用,在其实中,那么些岗位也许须要跟任何属性做一些运算之后得出。假使是根据svg
    库营造的,那么可以间接使用库里面用于固定的函数,比一贯从最底层运算越发方便和标准。
  2. 俺们那里研讨的是本域的图纸的导出难点,跨域的图纸由于「污染了」画布,在举办 toDataUrl 函数的时候会报错。

// 参数,最大中度
var MAX_HEIGHT = 100;
// 渲染
function render(src){
// 创造一个 Image 对象
var image = new Image();
// 绑定 load 事件处理器,加载成功后执行
image.onload = function(){
// 获取 canvas DOM 对象
var canvas = document.getElementById(“myCanvas”);
// 如若中度超标
if(image.height > MAX_HEIGHT) {
// 宽度等比例缩放 *=
image.width *= MAX_HEIGHT / image.height;
image.height = MAX_HEIGHT;
}
// 获取 canvas的 2d 环境目标,
亚洲必赢官网 ,// 可以了解Context是社团者,canvas是房屋
var ctx = canvas.getContext(“2d”);
// canvas清屏
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 重置canvas宽高
canvas.width = image.width;
canvas.height = image.height;
// 将图像绘制到canvas上
ctx.drawImage(image, 0, 0, image.width, image.height);
// !!! 注意,image 没有投入到 dom之中
};
// 设置src属性,浏览器会活动加载。
// 记住必须先绑定事件,才能安装src属性,否则会出一头问题。
image.src = src;
};

然后在在onchange事件中调用下边方法:

结语

在此间和大家大快朵颐了 在前者将 svg 转为 png
的格局和进度中或许会际遇的八个难题,一个是浏览器对 canvas
的尺码限制,另一个是导出图片的标题。当然,这八个难题还有其余的解决办法,同时鉴于文化所限,本文内容难免有漏洞,欢迎大家批评指正。最终谢谢@techird 和 @Naxior 关于这两个难点的座谈。

1 赞 2 收藏
评论

亚洲必赢官网 15

在地点的事例中,你可以利用canvas 的 toDataURL() 方法赢得图像的
Base64编码的值(可以接近通晓为16进制字符串,或者二进制数据流).
注意: canvas 的 toDataURL() 获取的URL以字符串早先,有22个不算的数据
“data:image/png;base64,”,须要在客户端依然服务端举行过滤.
标准化上万一浏览器协理,URL地址的尺寸是绝非界定的,而1024的长短限制,是老一代IE所独有的。

onUploadIdcard(e) {

借问,怎么着收获大家要求的图像呢?
好孩子,很欢悦你能这么问。你并不可以由此File
输入框来直接处理,你从那些文件输入框元素所能获取的但是是用户所选用文件的path路径。依照常规想象,你可以因此那个path路径音讯来加载图像,不过,在浏览器里面那是不具体的。(译者注:浏览器厂商必须有限支撑自己的浏览器相对安全,才能博得市场,至少幸免媒体的抨击,即便允许那样做,那恶意网址可以经过拼凑文件路径来品尝得到某些敏感音讯).
为了完成那几个需要,大家可以运用HTML5的File API
来读取用户磁盘上的文书,并用这几个file来作为图像的源(src,source).

          var _this = this

File API简介
新的File
API接口是在不背离任何安全沙盒规则下,读取和列出用户文件目录的一个门道——
通过沙盒(sandbox)限制,恶意网站并不可以将病毒写入用户磁盘,当然更不可能实施。
俺们要运用的公文读取对象叫做
FileReader,FileReader允许开发者读取文件的情节(具体浏览器的兑现格局恐怕大差别)。

          let file = e.target.files[0];

设若大家已经赢得了图像文件的path路径,那么信赖前边的代码,使用FileReader来加载和渲染图像就变得很不难了:

          var formData = new FormData();

代码如下:

          _this.compress(file, 0.5, function (err, data) {

// 加载 图像文件(url路径)
function loadImage(src){
// 过滤掉 非 image 类型的文件
if(!src.type.match(/image.*/)){
if(window.console){
console.log(“接纳的文件类型不是图形: “, src.type);
} else {
window.confirm(“只可以接纳图片文件”);
}
return;
}
// 创制 FileReader 对象 并调用 render 函数来达成渲染.
var reader = new FileReader();
// 绑定load事件自动回调函数
reader.onload = function(e){
// 调用后面的 render 函数
render(e.target.result);
};
// 读取文件内容
reader.readAsDataURL(src);
};

              if (err) {

请问,如何得到文件呢?
小白兔,要有耐心!大家的下一步就是收获文件,当然有很多方法可以兑现啦。例如:你可以用文本框让用户输入文件路径,但很明确大部分用户都不是开发者,对输入什么值根本就不止解.
为了用户使用方便,大家应用 Drag and Drop API接口。

                  console.log(err);

使用 Drag and Drop API
拖拽接口(Drag and
Drop)卓殊简单——在大部的DOM元素上,你都能够通过绑定事件处理器来贯彻.
只要用户从磁盘上拖动一个文本到dom对象上并推广鼠标,那大家就足以读取这么些文件。代码如下:

                  return;

代码如下:

              }

function init(){
// 获取DOM元素对象
var target = document.getElementById(“drop-target”);
// 阻止 dragover(拖到DOM元素上方) 事件传递
target.addEventListener(“dragover”, function(e){e.preventDefault();},
true);
// 拖动并放大鼠标的事件
target.addEventListener(“drop”, function(e){
// 阻止默许事件,以及事件传播
e.preventDefault();
// 调用后边的加载图像 函数,参数为dataTransfer对象的首个公文
loadImage(e.dataTransfer.files[0]);
}, true);
var setheight = document.getElementById(“setheight”);
var maxheight = document.getElementById(“maxheight”);
setheight.addEventListener(“click”, function(e){
//
var value = maxheight.value;
if(/^\d+$/.test(value)){
MAX_HEIGHT = parseInt(value);
}
e.preventDefault();
},true);
var btnsend = document.getElementById(“btnsend”);
btnsend.addEventListener(“click”, function(e){
//
sendImage();
},true);
};

              formData.append(‘file’, data,’image.png’);

大家还足以做一些别样的拍卖,比如突显预览图。但假诺不想减小图片的话,那很可能没什么用。大家将拔取Ajax通过HTTP
的post格局上传图片数据。下边的例子是应用Dojo框架来形成请求的,当然你也可以选拔任何的Ajax技术来完毕.
Dojo 代码如下:

              $.ajax({

代码如下:

                url: ‘你的接口’,//那里是后台接口须求换掉

// 译者并不懂Dojo,所以将在末端附上jQuery的贯彻
// Remember that DTK 1.7+ is AMD!
require([“dojo/request”], function(request){
// 设置请求URL,参数,以及回调。
request.post(“image-handler.php”, {
data: {
imageName: “myImage.png”,
imageData:
encodeURIComponent(document.getElementById(“canvas”).toDataURL(“image/png”))
}
}).then(function(text){
console.log(“The server returned: “, text);
});
});

                type: ‘POST’,

jQuery 落成如下:

                dataType: ‘json’,

代码如下:

                cache: false,

// 上传图片,jQuery版
function sendImage(){
// 获取 canvas DOM 对象
var canvas = document.getElementById(“myCanvas”);
// 获取Base64编码后的图像数据,格式是字符串
//
“data:image/png;base64,”开始,须求在客户端照旧服务器端将其去掉,前边的片段可以一直写入文件。
var dataurl = canvas.toDataURL(“image/png”);
// 为安全 对URI进行编码
// data%3Aimage%2Fpng%3Bbase64%2C 开头
var imagedata = encodeURIComponent(dataurl);
//var url = $(“#form”).attr(“action”);
// 1. 要是form表单不佳处理,可以选拔某个hidden隐藏域来设置请求地址
// <input type=”hidden” name=”action” value=”receive.jsp” />
var url = $(“input[name=’action’]”).val();
// 2. 也得以直接用某个dom对象的属性来得到
// <input id=”imageaction” type=”hidden” action=”receive.jsp”>
// var url = $(“#imageaction”).attr(“action”);
// 因为是string,所以服务器须要对数据举行转码,写文件操作等。
// 个人约定,所有http参数名字全体大写
console.log(dataurl);
//console.log(imagedata);
var data = {
imagename: “myImage.png”,
imagedata: imagedata
};
jQuery.ajax( {
url : url,
data : data,
type : “POST”,
// 期待的回到值类型
dataType: “json”,
complete : function(xhr,result) {
//console.log(xhr.responseText);
var $tip2 = $(“#tip2”);
if(!xhr){
$tip2.text(‘互连网连接退步!’);
return false;
}
var text = xhr.responseText;
if(!text){
$tip2.text(‘网络错误!’);
return false;
}
var json = eval(“(“+text+”)”);
if(!json){
$tip2.text(‘解析错误!’);
return false;
} else {
$tip2.text(json.message);
}
//console.dir(json);
//console.log(xhr.responseText);
}
});
};

                data: formData,

OK,搞定!你还亟需做的,就是成立一个只管的用户界面,并允许你控制图片的深浅。上传到服务器端的数码,并不必要处理enctype为
multi-part/form-data 的动静,仅仅一个简单的POST表单处理程序就足以了.
好了,下边附上完整的代码示例:

                processData: false,

代码如下:

                contentType: false,

<%@ page language=”java” import=”java.util.*”
pageEncoding=”UTF-8″%>
<%
String path = request.getContextPath();
String basePath =
request.getScheme()+”://”+request.getServerName()+”:”+request.getServerPort()+path+”/”;
%>
<!DOCTYPE html>
<html>
<head>
<title>通过Canvas及File API缩放并上传图片</title>
<meta http-equiv=”pragma” content=”no-cache”>
<meta http-equiv=”cache-control” content=”no-cache”>
<meta http-equiv=”expires” content=”0″>
<meta http-equiv=”keywords” content=”Canvas,File,Image”>
<meta http-equiv=”description”
content=”2013年8月8日,[email protected]”>
<script
src=”;
<script>
// 参数,最大中度
var MAX_HEIGHT = 100;
// 渲染
function render(src){
// 创制一个 Image 对象
var image = new Image();
// 绑定 load 事件处理器,加载成功后举行
image.onload = function(){
// 获取 canvas DOM 对象
var canvas = document.getElementById(“myCanvas”);
// 要是中度超标
if(image.height > MAX_HEIGHT) {
// 宽度等比例缩放 *=
image.width *= MAX_HEIGHT / image.height;
image.height = MAX_HEIGHT;
}
// 获取 canvas的 2d 环境目标,
// 能够驾驭Context是协会者,canvas是房屋
var ctx = canvas.getContext(“2d”);
// canvas清屏
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 重置canvas宽高
canvas.width = image.width;
canvas.height = image.height;
// 将图像绘制到canvas上
ctx.drawImage(image, 0, 0, image.width, image.height);
// !!! 注意,image 没有参预到 dom之中
};
// 设置src属性,浏览器会活动加载。
// 记住必须先绑定事件,才能安装src属性,否则会出一块难点。
image.src = src;
};
// 加载 图像文件(url路径)
function loadImage(src){
// 过滤掉 非 image 类型的公文
if(!src.type.match(/image.*/)){
if(window.console){
console.log(“接纳的文件类型不是图形: “, src.type);
} else {
window.confirm(“只好选取图片文件”);
}
return;
}
// 成立 FileReader 对象 并调用 render 函数来形成渲染.
var reader = new FileReader();
// 绑定load事件自动回调函数
reader.onload = function(e){
// 调用前面的 render 函数
render(e.target.result);
};
// 读取文件内容
reader.readAsDataURL(src);
};
// 上传图片,jQuery版
function sendImage(){
// 获取 canvas DOM 对象
var canvas = document.getElementById(“myCanvas”);
// 获取Base64编码后的图像数据,格式是字符串
//
“data:image/png;base64,”初步,必要在客户端依旧服务器端将其去掉,前面的有些可以直接写入文件。
var dataurl = canvas.toDataURL(“image/png”);
// 为安全 对URI进行编码
// data%3Aimage%2Fpng%3Bbase64%2C 开头
var imagedata = encodeURIComponent(dataurl);
//var url = $(“#form”).attr(“action”);
// 1. 只要form表单不佳处理,可以选拔某个hidden隐藏域来安装请求地址
// <input type=”hidden” name=”action” value=”receive.jsp” />
var url = $(“input[name=’action’]”).val();
// 2. 也得以直接用某个dom对象的习性来获取
// <input id=”imageaction” type=”hidden” action=”receive.jsp”>
// var url = $(“#imageaction”).attr(“action”);
// 因为是string,所以服务器须要对数码举办转码,写文件操作等。
// 个人约定,所有http参数名字全体大写
console.log(dataurl);
//console.log(imagedata);
var data = {
imagename: “myImage.png”,
imagedata: imagedata
};
jQuery.ajax( {
url : url,
data : data,
type : “POST”,
// 期待的回到值类型
dataType: “json”,
complete : function(xhr,result) {
//console.log(xhr.responseText);
var $tip2 = $(“#tip2”);
if(!xhr){
$tip2.text(‘互联网连接败北!’);
return false;
}
var text = xhr.responseText;
if(!text){
$tip2.text(‘互连网错误!’);
return false;
}
var json = eval(“(“+text+”)”);
if(!json){
$tip2.text(‘解析错误!’);
return false;
} else {
$tip2.text(json.message);
}
//console.dir(json);
//console.log(xhr.responseText);
}
});
};
function init(){
// 获取DOM元素对象
var target = document.getElementById(“drop-target”);
// 阻止 dragover(拖到DOM元素上方) 事件传递
target.addEventListener(“dragover”, function(e){e.preventDefault();},
true);
// 拖动并推广鼠标的风浪
target.addEventListener(“drop”, function(e){
// 阻止默许事件,以及事件传播
e.preventDefault();
// 调用后面的加载图像 函数,参数为dataTransfer对象的第三个文件
loadImage(e.dataTransfer.files[0]);
}, true);
var setheight = document.getElementById(“setheight”);
var maxheight = document.getElementById(“maxheight”);
setheight.addEventListener(“click”, function(e){
//
var value = maxheight.value;
if(/^\d+$/.test(value)){
MAX_HEIGHT = parseInt(value);
}
e.preventDefault();
},true);
var btnsend = document.getElementById(“btnsend”);
btnsend.addEventListener(“click”, function(e){
//
sendImage();
},true);
};
window.addEventListener(“DOMContentLoaded”, function() {
//
init();
},false);
</script>
</head>
<body>
<div>
<h1>通过Canvas及File API缩放并上传图片</h1>
<p>从文件夹拖动一张照片到人世的盒子里, canvas 和
JavaScript将会活动的拓展缩放.</p>
<div>
<input type=”text” id=”maxheight” value=”100″/>
<button id=”setheight”>设置图片最大惊人</button>
<input type=”hidden” name=”action” value=”receive.jsp” />
</div>
<div id=”preview-row”>
<div id=”drop-target”
style=”width:400px;height:200px;min-height:100px;min-width:200px;background:#eee;cursor:pointer;”>拖动图片文件到此地…</div>
<div>
<div>
<button id=”btnsend”> 上 传 </button> <span id=”tip2″
style=”padding:8px 0;color:#f00;”></span>
</div>
</div>
<div><h4>缩略图:</h4></div>
<div id=”preview”
style=”background:#f4f4f4;width:400px;height:200px;min-height:100px;min-width:200px;”>
<canvas id=”myCanvas”></canvas>
</div>
</div>
</div>
</body>
</html>

                success: (res) => {

服务端页面,receive.jsp

                  if (res.code === 200) {

代码如下:

                  }else if(res.code==40107){

<%@ page language=”java” import=”java.util.*”
pageEncoding=”UTF-8″%>
<%@page import=”sun.misc.BASE64Decoder”%>
<%@page import=”java.io.*”%>
<%@page import=”org.springframework.web.util.UriComponents”%>
<%@page import=”java.net.URLDecoder”%>
<%!
// 本文件:/receive.jsp
// 图片存放路径
String photoPath = “D:/blog/upload/photo/”;
File photoPathFile = new File(photoPath);
// references:

private boolean saveImageToDisk(byte[] data,String imageName) throws
IOException{
int len = data.length;
//
// 写入到文件
FileOutputStream outputStream = new FileOutputStream(new
File(photoPathFile,imageName));
outputStream.write(data);
outputStream.flush();
outputStream.close();
//
return true;
}
private byte[] decode(String imageData) throws IOException{
BASE64Decoder decoder = new BASE64Decoder();
byte[] data = decoder.decodeBuffer(imageData);
for(int i=0;i<data.length;++i)
{
if(data[i]<0)
{
//调整格外数据
data[i]+=256;
}
}
//
return data;
}
%>
<%
String path = request.getContextPath();
String basePath =
request.getScheme()+”://”+request.getServerName()+”:”+request.getServerPort()+path+”/”;
%>
<%
//若是是IE,那么需求设置为text/html,否则会弹框下载
//response.setContentType(“text/html;charset=UTF-8”);
response.setContentType(“application/json;charset=UTF-8”);
//
String imageName = request.getParameter(“imagename”);
String imageData = request.getParameter(“imagedata”);
int success = 0;
String message = “”;
if(null == imageData || imageData.length() < 100){
// 数据太短,显明不创造
message = “上传战败,数据太短或不存在”;
} else {
// 去除开始不客观的多寡
imageData = imageData.substring(30);
imageData = URLDecoder.decode(imageData,”UTF-8″);
//System.out.println(imageData);
byte[] data = decode(imageData);
int len = data.length;
int len2 = imageData.length();
if(null == imageName || imageName.length() < 1){
imageName = System.currentTimeMillis()+”.png”;
}
saveImageToDisk(data,imageName);
//
success = 1;
message = “上传成功,参数长度:”+len2+”字符,解析文件大小:”+len+”字节”;
}
// 后台打印
System.out.println(“message=”+message);
%>
{
“message”: “<%=message %>”,
“success”: <%=success %>
}

                  }

                },error: function(err) {

                }

              });

          });

      },

搞定

网站地图xml地图