您的位置:68399皇家赌场 > 服务器租用 > www.68399.com:HTML5平移支付学习笔记之Canvas根基

www.68399.com:HTML5平移支付学习笔记之Canvas根基

发布时间:2019-11-15 19:21编辑:服务器租用浏览(138)

    HTML5:使用Canvas实时管理Video

    2015/09/11 · HTML5 · Canvas

    本文由 伯乐在线 - cucr 翻译,唐尤华 校稿。未经许可,防止转发!
    法语出处:mozilla。款待出席翻译组。

    结合HTML5下的videocanvas的成效,你能够实时管理录像数据,为正值播放的摄像增加琳琅满指标视觉效果。本学科演示怎样利用JavaScript代码达成chroma-keying特效(也被叫做“蓝灰显示屏效应”卡塔尔国。

    请看那么些实例.

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

    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> 上看出拍戏头捕获到的镜头了:

    www.68399.com 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.webkitU普拉多L.createObjectU瑞鹰L(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>

    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秒后把录制帧内容渲染到画布上(下方右图卡塔 尔(英语:State of Qatar)

    www.68399.com 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.toDataU奥德赛L; //转为base64并保存 } //准期捕获 function timer(delta){ setTimeout(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 的帧内容(夭寿哇,做完这几个动作非常的大心把饼干洒了后生可畏地。。。(“▔□▔)/)

    www.68399.com 3

    只顾这里我们运用了 canvas.toDataURL 方法来保存帧画面。

    接着正是数据剖析管理了,大家得以经过相比较前后捕获的帧画面来推断录制头是不是监控到变化,那么如何做啊?

    深谙设计的校友分明平时使用二个图层功用 —— 混合形式:

    www.68399.com 4

    当有八个图层时,对顶层图层设置“差值/Difference”的混合方式,能够看透地见到多少个图层的差别:

    www.68399.com 5

    “图A”是自己2018年在公司楼下拍的照片,然后本身把它微微调亮了一小点,并在地方画了一个X 和 O 得到“图B”。接着小编把它们以“差值”方式混合在一块,获得了最右的那张图。

    JavaScript

    “差值”格局原理:要掺杂图层双方的LANDGB值中各类值分别进行比较,用高值减去低值作为合成后的水彩,常常用金红图层合成意气风发图像时,能够得到负片效果的反相图像。用藕荷色的话不发生别的变动(茶褐亮度最低,下层颜色减去最小颜色值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.ULacrosseL.createObjectU宝马X3L(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.toDataURubiconL(); //转为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>

    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>

    功效如下(夭寿啊,做完那么些动作我又把Pepsi-Cola洒在键盘上了。。。(#--)/ 卡塔尔国

    www.68399.com 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.toDataU牧马人L(); //转为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.isLoop伊夫r){ //只需在第贰回循环里实行 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();

    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 来推广差别高亮像素的亮度值,不然得出的数值实在太小了。大家运营下页面(图片比较大加载会有一点点慢卡塔尔国

    www.68399.com 7

    透过试(xia卡塔 尔(英语:State of Qatar)验(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 抓包能够看看其哀告参数很简单:

    www.68399.com 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,通过  的地址访谈页面,开采录像头竟然失效了~

    通过Google的文书档案能够查出,那是为了安全性思索,非 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 中得重复登Land Rover扑。

    当时便能平常访谈录像头了,我们对代码做下管理,当差别检验发掘分外时,创造意气风发份日记,最小间距时间为5秒(但是后来察觉没供给,因为腾讯网已经有做了光阴限定,大约10秒后本事揭橥新的日志卡塔尔

    JavaScript

    //定期捕获 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 : '', 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)
                }
            });
        }

    奉行职能:

    www.68399.com 9

    日志也是妥妥的出来了:

    www.68399.com 10

    点开就可以观望这些的这张图纸了:

    www.68399.com 11

    要留心的是,新浪对日记宣布数据是有做天天额度限定来防刷的,抵达限额的话会产生当天的随笔和文章也敬敏不谢公布,所以得严苛运用:

    www.68399.com 12

    唯独这种方式仅能申报卓殊图片,权且不能让大家当即收悉告急,有意思味的童鞋可以试着再写个 chrome 插件,依期去拉取日记列表做判别,假设有新扩大日记则触发页面 alert。

    别的大家自然期望能直接对闯入者进行警告,那块相比较好办 —— 搞个警报的节拍,在特别的时候接触播放就能够:

    JavaScript

    //播放音频 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); //设定张开页面十秒钟后才起来监察和控制

    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 评论

    www.68399.com 13

    1、FFMpeg进行录像编码所急需的组织:

    1.第一个Canvas程序 

    文书档案内容

    正文使用的XHTML文书档案如下所示。

    XHTML

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "; <html xmlns="; <head> <style> body { background: black; color:#CCCCCC; } #c2 { background-image: url(foo.png); background-repeat: no-repeat; } div { float: left; border :1px solid #444444; padding:10px; margin: 10px; background:#3B3B3B; } </style> <script type="text/javascript;version=1.8" src="main.js"></script> </head> <body onload="processor.doLoad()"> <div> <video id="video" src="video.ogv" controls="true"/> </div> <div> <canvas id="c1" width="160" height="96"/> <canvas id="c2" width="160" height="96"/> </div> </body> </html>

    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
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
            "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
      <head>
        <style>
          body {
            background: black;
            color:#CCCCCC;
          }
          #c2 {
            background-image: url(foo.png);
            background-repeat: no-repeat;
          }
          div {
            float: left;
            border :1px solid #444444;
            padding:10px;
            margin: 10px;
            background:#3B3B3B;
          }
        </style>
        <script type="text/javascript;version=1.8" src="main.js"></script>
      </head>
     
      <body onload="processor.doLoad()">
        <div>
          <video id="video" src="video.ogv" controls="true"/>
        </div>
        <div>
          <canvas id="c1" width="160" height="96"/>
          <canvas id="c2" width="160" height="96"/>
        </div>
      </body>
    </html>

    上述代码关键部分如下:

    1.创设了八个canvas成分,ID分别为c1和c2。c1用来显示当前帧的原始摄像,c2是用来体现奉行chroma-keying特效后的摄像;c2预加载了一刘震云态图片,将用来顶替录像中的背景观部分。
    2.JavaScript代码从main.js文件导入;这段脚本使用JavaScript 1.8的性状,所以在导入脚本时,第22行中钦命了本子。
    3.当网页加载时,main.js中的processor.doLoad()方法会运转。

    为了实现调用FFMpeg的API完毕摄像的编码,以下结构是必得的:

     

    JavaScript代码

    main.js中的JS代码包罗三个措施。

    AVCodec:AVCodec结构保留了一个编解码器的实例,完毕实际的编码作用。平常大家在前后相继中定义二个指向AVCodec结构的指针指向该实例。
    AVCodecContext:AVCodecContext表示AVCodec所代表的上下文音讯,保存了AVCodec所需求的有的参数。对于得以达成编码成效,大家得以在此个布局中安装大家内定的编码参数。平常也是概念叁个指南针指向AVCodecContext。
    AVFrame:AVFrame结构保留编码以前的像素数量,并视作编码器的输入数据。其在前后相继中也是一个指针的花样。
    AVPacket:AVPacket表示码流包结构,饱含编码之后的码流数据。该组织得以不定义指针,以三个指标的款式定义。
    在大家的主次中,我们将这几个组织构成在了三个结构体中:

    看的是HTML5运动支付即学即用那本书,首先学习Canvas底蕴,废话没多少说,直接看率先个例证。

    初始化chroma-key

    doLoad()方法在XHTML文书档案初叶加载时调用。那么些方法的作用是为chroma-key管理代码打算所需的变量,设置叁个风云侦听器,当客商开播录制时大家能检查实验到。

    JavaScript

    doLoad: function() { this.video = document.getElementById("video"); this.c1 = document.getElementById("c1"); this.ctx1 = this.c1.getContext("2d"); this.c2 = document.getElementById("c2"); this.ctx2 = this.c2.getContext("2d"); let self = this; this.video.addEventListener("play", function() { self.width = self.video.videoWidth / 2; self.height = self.video.videoHeight / 2; self.timerCallback(); }, false); },

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    doLoad: function() {
        this.video = document.getElementById("video");
        this.c1 = document.getElementById("c1");
        this.ctx1 = this.c1.getContext("2d");
        this.c2 = document.getElementById("c2");
        this.ctx2 = this.c2.getContext("2d");
        let self = this;
        this.video.addEventListener("play", function() {
            self.width = self.video.videoWidth / 2;
            self.height = self.video.videoHeight / 2;
            self.timerCallback();
          }, false);
      },

    这段代码获取XHTML文档中video成分和五个canvas成分的援用,还拿到了五个canvas的图样上下文的引用。那一个将在我们兑现chroma-keying特效时采取。

    add伊夫ntListener()监听video元素,当客户按下摄像上的播放开关时被调用。为了回应顾客重放,这段代码获取录制的大幅和惊人,並且减半(我们就要推行chroma-keying效果时将录制的轻重减半卡塔尔国,然后调用timerCallback()方法来运营摄像捕捉和视觉效果计算。

    /*****************************************
    Struct: CodecCtx
    Description: FFMpeg编解码器上下文
    *****************************************/
    typedef struct
    {
    AVCodec *codec; //指向编解码器实例
    AVFrame *frame; //保存解码之后/编码早先的像素数量
    AVCodecContext *c; //编解码器上下文,保存编解码器的有个别参数设置
    AVPacket pkt; //码流包结构,满含编码码流数据
    } CodecCtx;
    2、FFMpeg编码的重大步骤:

     

    放大计时器回调

    沙漏回调函数在录像开首播报时被调用(当“播放”事件发生时卡塔 尔(阿拉伯语:قطر‎,然后负担自身周期调用,为每一帧录像完结keying特效。

    JavaScript

    timerCallback: function() { if (this.video.paused || this.video.ended) { return; } this.computeFrame(); let self = this; setTimeout(function () { self.timerCallback(); }, 0); },

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    timerCallback: function() {
        if (this.video.paused || this.video.ended) {
          return;
        }
        this.computeFrame();
        let self = this;
        setTimeout(function () {
            self.timerCallback();
          }, 0);
      },

    回调函数首先检查摄疑似否正在播放;若无,回调函数不做别的事并及时回到。

    接下来调用computeFrame()方法,该措施对现阶段录像帧实施chroma-keying特效。

    回调函数做的尾声生龙活虎件事便是调用setTimeout(),来让它自己尽快地被重新调用。在实际碰到中,你或然会依照摄像的帧率来安装调用频率。

    (1)、输入编码参数

     

    拍卖摄像帧数据

    computeFrame()方法,如下所示,实际上肩负抓取每大器晚成帧的多寡和推行chroma-keying特效。

    JavaScript

    computeFrame: function() { this.ctx1.drawImage(this.video, 0, 0, this.width, this.height); let frame = this.ctx1.getImageData(0, 0, this.width, this.height); let l = frame.data.length / 4; for (let i = 0; i < l; i ) { let r = frame.data[i * 4 0]; let g = frame.data[i * 4 1]; let b = frame.data[i * 4 2]; if (g > 100 && r > 100 && b < 43) frame.data[i * 4 3] = 0; } this.ctx2.putImageData(frame, 0, 0); return; }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    computeFrame: function() {
        this.ctx1.drawImage(this.video, 0, 0, this.width, this.height);
        let frame = this.ctx1.getImageData(0, 0, this.width, this.height);
        let l = frame.data.length / 4;
     
        for (let i = 0; i < l; i ) {
          let r = frame.data[i * 4 0];
          let g = frame.data[i * 4 1];
          let b = frame.data[i * 4 2];
          if (g > 100 && r > 100 && b < 43)
            frame.data[i * 4 3] = 0;
        }
        this.ctx2.putImageData(frame, 0, 0);
        return;
      }

    当它被调用后,video元素将显得近年来的录像帧数据,如下所示:

    www.68399.com 14

    在第2行,录像帧被复制到第三个canvas ctx1的图样上下文中,中度和幅度值钦命为大家前边封存的帧大小的四分之二。注意,您能够通过传递video成分到绘图上下文的drawImage()方法来绘制当前摄像帧。其结果是:

    www.68399.com 15

    第3行代码通过调用第多个canvas上下文的getImageData()方法,来收获原始图像数据当前录像帧的叁个别本。它提供了原本的31人像素图像数据,那样我们就能够进行操作。第4行代码通过将帧图像数据的路程度除以4,来总结图像的总像素数。

    第6行代码循环扫描全数像素,获取每一个像素的红、绿、蓝值,同一时间和预订义的背景象进行比较,那一个背景象将用foo.png中导入的背景图像替换。

    被检查实验成背景的每多个像素,将它的阿尔法值替换为零,注脚该像素是完全透明的。结果,最后的图像背景有些是百分之百透明的,那样在第13行代码,把它被绘制到对象的光景文中时,效果是内容叠合到静态背景上。

    通过发生的图像看起来像这么:

    www.68399.com 16

    在录制播放时屡次那样做,这样风度翩翩帧接大器晚成帧管理,呈现出chroma-key的特效。

    请看那些实例。

    1 赞 1 收藏 评论

    这一步我们可以安装叁个刻意的安插文件,并将参数遵照某个事写入这么些布局文件中,再在前后相继中分析这么些布局文件得到编码的参数。如若参数没多少的话,大家得以一直运用命令行将编码参数字传送入就可以。

     

    有关作者:cucr

    www.68399.com 17

    博客园天涯论坛:@hop_ping 个人主页 · 小编的小说 · 17

    www.68399.com 18

    (2)、依据须要初步化须求的FFMpeg结构

     

    首先,全体涉及到编解码的的效果,都不得不要注册音摄像编解码器之后能力运用。注册编解码调用上边包车型大巴函数:

    代码如下:

    avcodec_register_all();
    编解码器注册成功之后,根据钦命的CODEC_ID查找内定的codec实例。CODEC_ID平日钦命了编解码器的格式,在那间大家利用当前接纳最为广泛的H.264格式为例。查找codec调用的函数为avcodec_find_encoder,其声称格式为:

     

    AVCodec *avcodec_find_encoder(enum AVCodecID id);
    该函数的输入参数为叁个AVCodecID的枚举类型,再次回到值为二个指向AVCodec结构的指针,用于收纳找到的编解码器实例。若无找到,那么该函数会回来二个空指针。调用方法如下:

     

    /* find the mpeg1 video encoder */
    ctx.codec = avcodec_find_encoder(AV_CODEC_ID_H264); //根据CODEC_ID查找编解码器对象实例的指针
    if (!ctx.codec)
    {
    fprintf(stderr, “Codec not foundn”);
    return false;
    }
    AVCodec查找成功后,下一步是分配AVCodecContext实例。分配AVCodecContext实例须要大家前面查找到的AVCodec作为参数,调用的是avcodec_alloc_context3函数。其声明格局为:

     1 <!DOCTYPE html>

    AVCodecContext *avcodec_alloc_context3(const AVCodec *codec);
    其性状同avcodec_find_encoder相近,重返一个指向AVCodecContext实例的指针。如若分配失利,会再次回到三个空指针。调用情势为:

     2 <html>

    ctx.c = avcodec_alloc_context3(ctx.codec); //分配AVCodecContext实例
    if (!ctx.c)
    {
    fprintf(stderr, “Could not allocate video codec contextn”);
    return false;
    }
    需注意,在分配成功现在,应将编码的参数设置赋值给AVCodecContext的分子。

     3 <head>

    当今,AVCodec、AVCodecContext的指针都早就分配好,然后以那三个对象的指针作为参数张开编码器对象。调用的函数为avcodec_open2,注脚方式为:

     4 <meta charset="utf-8" />

    int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options);
    该函数的前五个参数是大家赶巧创制的多少个指标,第3个参数为三个字典类型对象,用于保存函数施行进程总不能够识别的AVCodecContext和别的一些私有设置选项。函数的重回值表示编码器是还是不是展开成功,若成功再次来到0,失败重回多个负数。调用格局为:

     5 <style type="text/css">

    if (avcodec_open2(ctx.c, ctx.codec, NULL) < 0) //依照编码器上下文张开编码器
    {
    fprintf(stderr, “Could not open codecn”);
    exit(1);
    }
    接下来,我们供给管理AVFrame对象。AVFrame表示录像原始像素数据的多个容器,管理该类型数据需求八个步骤,其一是分配AVFrame对象,其二是分配实际的像素数量的积攒空间。分配成对象空间肖似于new操作符同样,只是须求调用函数av_frame_alloc。假诺退步,那么函数重返一个空指针。AVFrame对象分配成功后,必要设置图像的分辨率和像素格式等。实际调用进程如下:

     6      canvas {

    ctx.frame = av_frame_alloc(); //分配AVFrame对象
    if (!ctx.frame)
    {
    fprintf(stderr, “Could not allocate video framen”);
    return false;
    }
    ctx.frame->format = ctx.c->pix_fmt;
    ctx.frame->width = ctx.c->width;
    ctx.frame->height = ctx.c->height;
    分配像素的蕴藏空间供给调用av_image_alloc函数,其宣称形式为:

     7     border-width: 5px;

    int av_image_alloc(uint8_t *pointers[4], int linesizes[4], int w, int h, enum AVPixelFormat pix_fmt, int align);
    该函数的八个参数分别表示AVFrame结构中的缓存指针、各样颜色分量的增加率、图像分辨率(宽、高卡塔尔、像素格式和内部存款和储蓄器对其的尺寸。该函数会再次回到分配的内部存款和储蓄器的深浅,假诺失利则赶回三个负值。具体调用格局如:

     8     border-style: dashed;

    ret = av_image_alloc(ctx.frame->data, ctx.frame->linesize, ctx.c->width, ctx.c->height, ctx.c->pix_fmt, 32);
    if (ret < 0)
    {
    fprintf(stderr, “Could not allocate raw picture buffern”);
    return false;
    }
    (3)、编码循环体

     9     border-color: rgba(20, 126, 239, 0.50)

    到此甘休,我们的计划职业早就大约产生,上边开端实行实际编码的巡回进度。用伪代码大致表示编码的流水生产线为:

    10 }

    while (numCoded < maxNumToCode)
    {
    read_yuv_data();
    encode_video_frame();
    write_out_h264();
    }
    其中,read_yuv_data部分间接使用fread语句读取就能够,只须要驾驭的是,四个颜色分量Y/U/V的地点分别为AVframe::data[0]、AVframe::data[1]和AVframe::data[2],图像的小幅度分别为AVframe::linesize[0]、AVframe::linesize[1]和AVframe::linesize[2]。要求介怀的是,linesize中的值经常指的是stride实际不是width,也正是说,像素保存区大概是包涵一定幅度的无效边区的,在读取数据时需注意。

    11 </style>

    编码前此外部须求要做到的操作时起头化AVPacket对象。该目的保存了编码之后的码流数据。对其开展发轫化的操作特别轻松,只须求调用av_init_packet并传到AVPacket对象的指针。随后将AVPacket::data设为NULL,AVPacket::size赋值0.

    12 

    顺理成章将原本的YUV像素值保存到了AVframe结构中事后,便得以调用avcodec_encode_video2函数举办实际的编码操作。该函数可谓是全部工程的核心所在,其宣称格局为:

    13 </head>

    int avcodec_encode_video2(AVCodecContext *avctx, AVPacket *avpkt, const AVFrame *frame, int *got_packet_ptr);
    其参数和重临值的意思:

    14 <body>

    avctx: AVCodecContext结构,钦命了编码的部分参数;
    avpkt: AVPacket对象的指针,用于保存输出码流;
    frame:AVframe结构,用于传入原始的像素数量;
    got_packet_ptr:输出参数,用于标记AVPacket中是否业本来就有了全部的意气风发帧;
    重临值:编码是不是成功。成功再次回到0,战败则赶回负的错误码
    经过输出参数*got_packet_ptr,大家得以判定是否应当生机勃勃帧完整的码流数据包输出,如若是,那么能够将AVpacket中的码流数据输出出来,其地方为AVPacket::data,大小为AVPacket::size。具体调用情势如下:

    15 hello HTML5!

    /* encode the image */
    ret = avcodec_encode_video2(ctx.c, &(ctx.pkt), ctx.frame, &got_output); //将AVFrame中的像素新闻编码为AVPacket中的码流
    if (ret < 0)
    {
    fprintf(stderr, “Error encoding framen”);
    exit(1);
    }

    16 <canvas id="c1" width="300" height="300" ></canvas>

    if (got_output)
    {
    //拿到一个整机的编码帧
    printf(“Write frame = (size=])n”, frameIdx, ctx.pkt.size);
    fwrite(ctx.pkt.data, 1, ctx.pkt.size, io_param.pFout);
    av_packet_unref(&(ctx.pkt));
    }
    之所以,多个生龙活虎体化的编码循环提就足以选拔上边包车型客车代码完毕:

    17 </body>

    /* encode 1 second of video */
    for (frameIdx = 0; frameIdx < io_param.nTotalFrames; frameIdx )
    {
    av_init_packet(&(ctx.pkt)); //初始化AVPacket实例
    ctx.pkt.data = NULL; // packet data will be allocated by the encoder
    ctx.pkt.size = 0;

    18 <script type="text/javascript">

    fflush(stdout);
    
    Read_yuv_data(ctx, io_param, 0);        //Y分量
    Read_yuv_data(ctx, io_param, 1);        //U分量
    Read_yuv_data(ctx, io_param, 2);        //V分量
    
    ctx.frame->pts = frameIdx;
    
    /* encode the image */
    ret = avcodec_encode_video2(ctx.c, &(ctx.pkt), ctx.frame, &got_output); //将AVFrame中的像素信息编码为AVPacket中的码流
    if (ret < 0) 
    {
        fprintf(stderr, "Error encoding framen");
        exit(1);
    }
    
    if (got_output) 
    {
        //获得一个完整的编码帧
        printf("Write frame = (size=])n", frameIdx, ctx.pkt.size);
        fwrite(ctx.pkt.data, 1, ctx.pkt.size, io_param.pFout);
        av_packet_unref(&(ctx.pkt));
    }
    

    19   //canvas对象的拿到

    } //for (frameIdx = 0; frameIdx < io_param.nTotalFrames; frameIdx )
    (4)、收尾管理

    20   var canvas=document.getElementById("c1");

    假若大家就此结束编码器的百分百运转进程,大家会发觉,编码达成以往的码流相比较原本的数量少了风流倜傥帧。那是因为大家是基于读取原始像素数据结束来剖断循环截止的,那样结尾大器晚成帧还保留在编码器中并未有输出。所以在闭馆全部解码进度从前,大家必得继续实施编码的操作,直到将最后生龙活虎帧输出结束。实施那项操作依然调用avcodec_encode_video2函数,只是表示AVFrame的参数设为NULL就可以:

    21   //拿到绘图用的上下文对象

    /* get the delayed frames */
    for (got_output = 1; got_output; frameIdx )
    {
    fflush(stdout);

    22   var ctx=canvas.getContext("2d"); 

    ret = avcodec_encode_video2(ctx.c, &(ctx.pkt), NULL, &got_output);      //输出编码器中剩余的码流
    if (ret < 0)
    {
        fprintf(stderr, "Error encoding framen");
        exit(1);
    }
    
    if (got_output) 
    {
        printf("Write frame = (size=])n", frameIdx, ctx.pkt.size);
        fwrite(ctx.pkt.data, 1, ctx.pkt.size, io_param.pFout);
        av_packet_unref(&(ctx.pkt));
    }
    

    23   //绘图管理

    } //for (got_output = 1; got_output; frameIdx )
    然后,大家就能够按布置关闭编码器的黄金时代生龙活虎零件,截至全部编码的流水生产线。编码器组件的放飞流程可类比创立流程,须要关闭AVCocec、释放AVCodecContext、释放AVFrame中的图像缓存和对象自己:

    24   ctx.fillStyle="rgb(255,0,0)";

    avcodec_close(ctx.c);
    av_free(ctx.c);
    av_freep(&(ctx.frame->data[0]));
    av_frame_free(&(ctx.frame));
    3、总结

    25   ctx.fillRect(50,50,200,200);

    运用FFMpeg进行录制编码的要紧流程如:

    26   ctx.fillStyle="rgba(0,0,255,0.5)";

    先是解析、管理输入参数,如编码器的参数、图像的参数、输入输出文件;
    确立全方位FFMpeg编码器的各样零件工具,顺序依次为:avcodec_register_all -> avcodec_find_encoder -> avcodec_alloc_context3 -> avcodec_open2 -> av_frame_alloc -> av_image_alloc;
    编码循环:av_init_packet -> avcodec_encode_video2(两次) -> av_packet_unref
    闭馆编码器组件:avcodec_close,av_free,av_freep,av_frame_free

    27   ctx.fillRect(100,100,200,200);

    28   <!--alert("hello");-->

    29 </script>

    30 </html>

    复制代码

    知识点:

     

    Canvas 的宗旨用法

     

     1)取得Canvas对象

     

     2卡塔 尔(英语:State of Qatar)从Canvas对象中获取绘图用的上下文

     

     3卡塔尔国使用上下文中的方法与天性进行绘图

     

     颜色的钦点方法

     

      1)ctx.fillStyle="#FF0000";

     

      2)ctx.fillStyle="rgb(255,0,0)";

     

      3卡塔 尔(阿拉伯语:قطر‎ctx.fillStyle="rgba(0,0,255,0.5)"; 最终那些指发光度的。。。

     

    2.路径

     

      绘制叁个简约的三角,效果:

     

     

     

     代码如下:

     

     

    复制代码

     1 <!DOCTYPE html>

     2 <html>

     3 <head>

     4 <meta charset="utf-8" />

     5 <style type="text/css">

     6      canvas {

     7     border-width: 5px;

     8     border-style: dashed;

     9     border-color: rgba(20, 126, 239, 0.50)

    10 }

    11 </style>

    12 

    13 </head>

    14 <body>

    15 hello HTML5!

    16 <canvas id="c1" width="300" height="300" ></canvas>

    17 </body>

    18 <script type="text/javascript">

    19   //canvas对象的获取

    20   var canvas=document.getElementById("c1");

    21   //获得绘图用的上下文对象

    22   var ctx=canvas.getContext("2d"); 

    23   //路线绘制开头

    24   ctx.beginPath();

    25   //路线的绘图

    26   ctx.moveTo(0,0);

    27   ctx.lineTo(0,290);

    28   ctx.lineTo(290,290);

    29   //路线绘制甘休

    30   ctx.closePath();

    31   //举行绘图管理

    32   ctx.fillStyle="rgb(200,0,0)"

    33   ctx.fill();

    34   <!--alert("hello");-->

    35 </script>

    36 </html>

    复制代码

     知识点:

     

     调节路径时采取的点子:

      1) beginPath() 重新载入参数路线的开端

     

      2) closePath() 关闭到几日前葬身鱼腹的门路

     

      3) moveTo() 钦定绘图开端时的主脑(x,y卡塔 尔(阿拉伯语:قطر‎

     

      4) lineTo() 绘制早前一回绘图地方到(x,y卡塔尔国的直线

     

     绘制路线时行使的艺术:

     

     1卡塔尔stroke() 绘制路线

     

     2卡塔尔国fill()填充路线

     

     钦赐绘图样式时使用的性质

     

     1卡塔尔fillStyle 内定填充时使用的颜色与体制

     

     2卡塔尔国strokeStyle 钦命路径的线颜色与体制

     

     3卡塔 尔(英语:State of Qatar)lineWidth 钦命路线线的粗细

     

      上面制作三个当顾客触摸显示屏时在触摸地点绘制三角形的实例程序 (书上的是顾客触摸显示屏时绘制,今后改一下,鼠标移动时在运动之处绘制三角形卡塔尔效果:

     

     

     

    代码如下:

     

     

    复制代码

     1 <!DOCTYPE html>

     2 <html>

     3 <head>

     4 <meta charset="utf-8" />

     5 <meta name="viewport" content="width=320,user-scalable=no" />

     6 <style type="text/css">

     7      canvas {

     8     border-width: 5px;

     9     border-style: dashed;

    10     border-color: rgba(20, 126, 239, 0.50)

    11 }

    12 </style>

    13 

    14 </head>

    15 <body>

    16 hello HTML5!

    17 <canvas id="c1" width="300" height="300" ></canvas>

    18 </body>

    19 

    20 <script type="text/javascript">

    21 

    22 function getPointOnCanvas(canvas, x, y) {

    23   var bbox = canvas.getBoundingClientRect();

    24   return { x: x - bbox.left * (canvas.width / bbox.width),

    25        y: y - bbox.top * (canvas.height / bbox.height)};

    26 }

    27   //canvas对象的获得

    28   var canvas=document.getElementById("c1");

    29   //拿到绘图用的上下文对象

    30   var ctx=canvas.getContext("2d"); 

    31   //设置Canvas的onmouse事件

    32   canvas.onmousemove=function(event)

    33   {

    34       //得到鼠标移动处的坐标

    35       var x=event.pageX;

    36       var y=event.pageY;

    37       var canvas=event.target;

    38       var loc=getPointOnCanvas(canvas,x,y);

    39       console.log("mouse down at point(x:" loc.x ",y:" loc.y ")");

    40       

    41       var r=Math.random()*10 25;

    42       //路线内定

    43       

    44       ctx.beginPath();

    45       ctx.moveTo(loc.x,loc.y);

    46       ctx.lineTo(loc.x,loc.y r);

    47       ctx.lineTo(loc.x r,loc.y r);

    48       ctx.lineTo(loc.x,loc.y);

    本文由68399皇家赌场发布于服务器租用,转载请注明出处:www.68399.com:HTML5平移支付学习笔记之Canvas根基

    关键词: 68399皇家赌场 HTML5 JavaScript ffmpeg

上一篇:【www.68399.com】WebSocket 教程

下一篇:没有了