惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

S
Schneier on Security
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Know Your Adversary
Know Your Adversary
G
GRAHAM CLULEY
V
Vulnerabilities – Threatpost
P
Palo Alto Networks Blog
Security Latest
Security Latest
P
Privacy & Cybersecurity Law Blog
Simon Willison's Weblog
Simon Willison's Weblog
A
Arctic Wolf
T
Tor Project blog
T
Threatpost
NISL@THU
NISL@THU
I
InfoQ
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Apple Machine Learning Research
Apple Machine Learning Research
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
aimingoo的专栏
aimingoo的专栏
Microsoft Azure Blog
Microsoft Azure Blog
WordPress大学
WordPress大学
K
Kaspersky official blog
W
WeLiveSecurity
L
LINUX DO - 热门话题
小众软件
小众软件
Recorded Future
Recorded Future
B
Blog RSS Feed
H
Help Net Security
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
IT之家
IT之家
L
Lohrmann on Cybersecurity
Last Week in AI
Last Week in AI
Stack Overflow Blog
Stack Overflow Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
阮一峰的网络日志
阮一峰的网络日志
V
Visual Studio Blog
Blog — PlanetScale
Blog — PlanetScale
雷峰网
雷峰网
爱范儿
爱范儿
C
CXSECURITY Database RSS Feed - CXSecurity.com
T
Threat Research - Cisco Blogs
C
Cyber Attacks, Cyber Crime and Cyber Security
H
Hacker News: Front Page
博客园 - 三生石上(FineUI控件)
N
Netflix TechBlog - Medium
P
Proofpoint News Feed
有赞技术团队
有赞技术团队
N
News and Events Feed by Topic
云风的 BLOG
云风的 BLOG
Scott Helme
Scott Helme
V2EX - 技术
V2EX - 技术

博客园 - 骨月枫🍁

使用vLLM部署Qwen/Qwen3.5-35B-A3B-FP8并且在DIFY中调用 记录个人数组、字符串自己常忘记的方法,以及ES常用处理方式 解决webpack vue 项目打包生成的文件,资源文件均404问题 js 复制粘贴功能记录 记录下工作中使用的pdf.js 记录下jplayer的简单demo js 函数节流 用ajax与fetch调用阿里云免费接口 简要谈谈javascript bind 方法 h5启动原生APP总结 mac上安装mongoDb以及简单使用 mac快捷键整理以及node的基本使用 html5视频video积累 整理下PC和移动获取点击、移动坐标的代码和坑 html5 实现简单的上传 canvas基础学习(四) canvas基础学习(三) canvas基础学习(一) 移动端使用百度分享代码
canvas基础学习(二)
骨月枫🍁 · 2015-11-25 · via 博客园 - 骨月枫🍁

一、图像绘制

canvas绘制图像的方法是ctx.drawImage();该方法有三种使用方式

1、ctx.drawImage(img,x,y);

img是指图像对象,x和y分别是这个图像左上角在canvas画布的坐标,而图像显示的大小为图像本身的像素值,超出canvas画布的部分不显示。

2、ctx.drawImage(img,x,y,w,h);

和上面的那个函数相比,可以控制图像在canvas中显示的宽度和高度,而不再是图片自身的高宽像素

3、ctx.drawImage(img , dx , dy , dw , dh , x , y , w , h);

这个又比之前的函数多了dx、dy、dw、dh这四个参数,这四个参数可以控制图片切片显示在canvas画布中。在图片上同样以左上角为原点,向右为X轴正方向,向下为Y轴正方向,这四个参数表示,在图片中在(dx,dy)这个坐标,切dw和dh大小的切片。然后将这个切片显示在canvas画布上。

最后这个img参数,不单单可以是Image对象,还可以是video对象,也可以是另外的canvas对象。所以可以通过该方法对video视频进行截屏,也可以通过加载canvas制作图像水印、放大镜、以及淘宝双11主会场那样的特效,一个canvas加载另一个canvas,也被称为canvas的离屏技术。

二、图像的像素级处理

1、ctx.getImageData(x , y , w , h);

这个方法是获取画布(x,y)坐标,宽高分别为w和h的像素对象。而这个对象的data属性,则是其rgba的值。一个画布的像素值是从画布的原点,从左向右,从上到下,一排一排的排列下来的。常用取出canvas像素值的方法有两种,一种是采用一层循环,另一种是采用双重for循环,代码如下:

var imageData = ctx.getImageData(0 , 0 , canvasW , canvasH),
      pixelData = imageData.data;
//方式一
for(var i = 0; i < canvasH*canvasW ; i++){
    var  r = pixelData[4*i + 0],
          g = pixelData[4*i + 1],
          b = pixelData[4*i + 2],
              a = pixelData[4*i + 3];
} 
//方式二
for(var y = 0 ; i < canvasH  ; y++){
   for(var x = 0 ; x < canvasW ; x++){
      var pixe = canvasW*y + x,
          r = pixelData[4*pixe + 0],
          g = pixelData[4*pixe + 1],
          b = pixelData[4*pixe + 2],
          a = pixelData[4*pixe + 3];
    }
}

2、ctx.putImageData()

该方法是设置canvas画布上的像素数据,它有七个参数,在w3c上是这么解释的

 我的理解就是将imgData,放在画布上的位置是(x + dirtyX , y + dirtyY),高宽分别是dirtyHeight、dirtyWidth的矩形。

三、canvas图像下载

使用的是canvas对象的toDataURL()方法,它可以将canvas画布中的内容转化为浏览器可下载的本地data数据,然后通过href跳转的方式完成下载,代码如下

var canvas = document.getElementById("canvas");
var imgUrl = canvas.toDataURL("image/png").replace("image/png", "image/octet-stream");
window.location.href = imgUrl;

四、代码demo

1、图片缩放,以及像素变换

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>图像学习</title>
        <style>
            #main,#copy,.contain{
                margin: 15px;
                padding: 0;
                float: left;
                
            }
            #main{
                cursor:move
            }
            .contain *{
                padding: 2px;
                margin: 0;
z            }
            .contain a{
                display: block;
                text-align: center; 
                margin-top:5px;
                font-size:15px;
                line-height: 20px;
            }
        </style>
    </head>
    <body>
        <canvas id="main" width="400" height="300" style="display:block;border: 1px solid #AAA;">
            亲,您的浏览器不支持canvas
        </canvas>
        <div class="contain" style="width: 290px;height: 300px;">
            <div>
                <span>缩放</span>
                <input type="range" id="scaleChange" min="0.5" max="4.0" step="0.03" value="1.0" 
                    style="display:inline-block;width: 240px;"/>
            </div>
            <a href="javascript:void(0)" id="greyChange">灰度转换</a>
            <a href="javascript:void(0)" id="blackChange">黑度转换</a>
            <a href="javascript:void(0)" id="reverChange">反相转换</a>
            <a href="javascript:void(0)" id="blurChange">模糊处理</a>
            <a href="javascript:void(0)" id="mosaicChange">马赛克处理</a>
            <a href="javascript:void(0)" id="downLoadImage">下载右侧图片</a>
        </div>
        <canvas id="copy" width="400" height="300" style="display:block;border: 1px solid #AAA;">
            亲,您的浏览器不支持canvas
        </canvas>
        <canvas id="waterMark" style="display: none;">    
              亲,您的浏览器不支持canvas
              <!--
                      水印作图的canvas,把一个canvas载入另一个canvas的做法叫做,离屏canvas
              -->
        </canvas>
    </body>
    <script>
        document.body.onload = function(){
            var canvas = document.getElementById("main"),
                scaleChange = document.getElementById("scaleChange"),
                copyCanvas = document.getElementById("copy"),
                waterMarkCanvas = document.getElementById("waterMark"),
                ctx = canvas.getContext("2d"),
                copyCtx = copyCanvas.getContext("2d"),
                canvasW = canvas.width,
                canvasH = canvas.height;
            var img = new Image();
            img.src = "img.jpg";
            img.onload = function(){        //当图片加载完毕后,执行canvas画图函数
                init();
            }
            //用于初始化
            function init(){
                toolFunc.handleWaterMark();
                toolFunc.handleScale();
                toolFunc.drawImg();
                toolFunc.handleEffect();
                toolFunc.handleCanvasMove();
            }
            var toolFunc = {
                scaleImgX : 0,
                scaleImgY : 0,
                drawImg : function(moveX , moveY){    //绘制图片
                    var scale = scaleChange.value;
                        //根据比例计算缩放后图像的大小
                        var imgW = canvasW*scale,
                            imgH = canvasH*scale,
                            x = (canvasW - imgW)/2,
                            y = (canvasH - imgH)/2,
                            tempX = x , tempY = y;
                        if(moveX || moveY){
                            x = this.scaleImgX + moveX;
                            y = this.scaleImgY + moveY;
                            if(x >= 0 || y >= 0 || x <= 2*tempX || y <= 2*tempY){
                                return;
                            }
                        }
                        ctx.clearRect(0 , 0 , canvasW , canvasH);
                        ctx.drawImage(img , x , y , imgW , imgH);
                        ctx.drawImage(waterMarkCanvas , 
                            canvasW - waterMarkCanvas.width ,
                            canvasH - waterMarkCanvas.height ,
                            waterMarkCanvas.width , waterMarkCanvas.height);
                        this.scaleImgX = x;
                        this.scaleImgY = y;
                },
                handleWaterMark : function(){        //用于处理水印
                    waterMarkCanvas.width = 200;
                    waterMarkCanvas.height = 70;
                    var waterCtx = waterMarkCanvas.getContext("2d");
                    waterCtx.font = "bold 20px Arial";
                    waterCtx.lineWidth = 1;
                    waterCtx.fillStyle = "white";
                    waterCtx.textAlign = "center";
                    waterCtx.textBaseline = "middle";
                    waterCtx.fillText( "~!~ sky ~!~" , 140 , 50 , waterMarkCanvas.width);
                },
                handleScale : function(){        //用于处理缩放
                    var isScale = false,
                        _this = this;
                    scaleChange.onmousedown = function(){
                        isScale = true;
                    }
                    scaleChange.onmousemove = function(){
                        if(isScale){        //画图
                            _this.drawImg();
                        }
                    }
                    scaleChange.onmouseup = function(){
                        isScale = false;
                    }
                },
                handleEffect : function(){    //处理效果变换
                    var imageData,pixelData;
                    document.getElementById("greyChange").onclick = function(){        //灰度变换
                        imageData = ctx.getImageData(0 , 0 , canvasW , canvasH);
                        pixelData = imageData.data;
                        for(var i = 0; i < canvasH*canvasW ; i++){
                            var r = pixelData[4*i + 0],
                                g = pixelData[4*i + 1],
                                b = pixelData[4*i + 2],
                                grey = r*0.3+g*0.59+b*0.11;//此为灰度图像的算法
                            pixelData[4*i + 0] = grey;
                            pixelData[4*i + 1] = grey;
                            pixelData[4*i + 2] = grey;
                        }
                        copyCtx.putImageData(imageData,0,0,0,0,canvasW,canvasH);
                    }
                    document.getElementById("blackChange").onclick = function(){        //黑度变换
                        imageData = ctx.getImageData(0 , 0 , canvasW , canvasH);
                        pixelData = imageData.data;
                        for(var i = 0; i < canvasH*canvasW ; i++){
                            var r = pixelData[4*i + 0],
                                g = pixelData[4*i + 1],
                                b = pixelData[4*i + 2],
                                grey = (function(n){        //黑度图像就只有黑白两色
                                    if(n > 127){
                                        return 255;
                                    }else{
                                        return 0;
                                    }
                                })(r*0.3+g*0.59+b*0.11);
                            pixelData[4*i + 0] = grey;
                            pixelData[4*i + 1] = grey;
                            pixelData[4*i + 2] = grey;
                        }
                        copyCtx.putImageData(imageData,0,0,0,0,canvasW,canvasH);
                    }
                    document.getElementById("reverChange").onclick = function(){        //反向变换
                        imageData = ctx.getImageData(0 , 0 , canvasW , canvasH);
                        pixelData = imageData.data;
                        for(var i = 0; i < canvasH*canvasW ; i++){
                            var r = pixelData[4*i + 0],
                                g = pixelData[4*i + 1],
                                b = pixelData[4*i + 2];
                            pixelData[4*i + 0] = 255 - r;
                            pixelData[4*i + 1] = 255 - g;
                            pixelData[4*i + 2] = 255 - b;
                        }
                        copyCtx.putImageData(imageData,0,0,0,0,canvasW,canvasH);
                    }
                    document.getElementById("blurChange").onclick = function(){        //模糊处理
                        imageData = ctx.getImageData(0 , 0 , canvasW , canvasH);
                        pixelData = imageData.data;
                        var pixelTmpData = pixelData;    //作为一个备份数据
                        var r = 3 , totalNum = (2*r + 1)*(2*r + 1);    //去上下左右四个方向各3个像素点的平均值
                        for(var i = r ; i < canvasH - r ; i++){
                            for(var j = r ; j < canvasW - r; j++){
                                var totalR,totalG,totalB;
                                totalR = totalG = totalB = 0;
                                for(var m = -r ; m <= r ; m++){
                                    for(var n = -r ; n <= r ; n++){
                                        var pixeY = i + m , piexX = j + n,
                                            pixe = canvasW*pixeY + piexX;
                                        totalR += pixelTmpData[4*pixe + 0];
                                        totalG += pixelTmpData[4*pixe + 1];
                                        totalB += pixelTmpData[4*pixe + 2];
                                    }
                                }
                                var p = i*canvasW + j;
                                pixelData[4*p + 0] = totalR/totalNum;
                                pixelData[4*p + 1] = totalG/totalNum;
                                pixelData[4*p + 2] = totalB/totalNum;
                            }
                        }
                        copyCtx.putImageData(imageData,0,0,0,0,canvasW,canvasH);
                    }
                    document.getElementById("mosaicChange").onclick = function(){    //马赛克处理
                        imageData = ctx.getImageData(0 , 0 , canvasW , canvasH);
                        pixelData = imageData.data;
                        var pixelTmpData = pixelData;    //作为一个备份数据
                        var size = 8,total = size*size;
                        for(var i = 0 ; i < canvasH ; i += size){
                            for( var j = 0 ; j < canvasW ; j += size){
                                var totalR,totalG,totalB;
                                totalR = totalG = totalB = 0;
                                for(var y = 0 ; y < size ; y++){
                                    for(var x = 0 ; x < size ; x++){
                                        var py = i + y,
                                            px = j + x,
                                            pixe = px + py*canvasW;
                                        totalR += pixelTmpData[4*pixe + 0];
                                        totalG += pixelTmpData[4*pixe + 1];
                                        totalB += pixelTmpData[4*pixe + 2];
                                    }
                                }
                                var newR = totalR/total,
                                    newG = totalG/total,
                                    newB = totalB/total;
                                for(var dy = 0 ; dy < size ; dy++){
                                    for(var dx = 0 ; dx < size ; dx++ ){
                                        var py = i + dy,
                                            px = j + dx,
                                            pixe = px + py*canvasW;
                                        pixelData[4*pixe + 0] = newR;
                                        pixelData[4*pixe + 1] = newG;
                                        pixelData[4*pixe + 2] = newB;
                                    }
                                }
                            }
                        }
                        copyCtx.putImageData(imageData,0,0,0,0,canvasW,canvasH);
                    }
                    document.getElementById("downLoadImage").onclick = function(){
                        var loadUrl =  copyCanvas.toDataURL("image/png").replace("image/png", "image/octet-stream");
                        window.location.href = loadUrl;
                    }
                },
                handleCanvasMove:function(){        //处理canvans移动
                    var isCanvasMove = false,
                        lastX,lastY;
                    canvas.onmousedown = function(e){
                        e.preventDefault();
                        isCanvasMove = true;
                        lastX = e.clientX - canvas.getBoundingClientRect().left;
                        lastY = e.clientY - canvas.getBoundingClientRect().top;
                    }
                    canvas.onmousemove = function(e){
                        e.preventDefault();
                        if(!isCanvasMove || scaleChange.value <= 1) return;
                        var x = e.clientX - canvas.getBoundingClientRect().left,
                            y = e.clientY - canvas.getBoundingClientRect().top;
                        var moveX = (x - lastX),
                            moveY = (y - lastY);
                        toolFunc.drawImg(moveX,moveY);
                        lastX = x;
                        lastY = y;
                    }
                    canvas.onmouseup = function(e){
                        e.preventDefault();
                        isCanvasMove = false;
                    }
                    canvas.onmouseout = function(e){
                        e.preventDefault();
                        isCanvasMove = false;
                    }
                }
            };
        }
    </script>
</html>

效果图为

用的图片是

2、图片放大镜

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>canvas放大镜</title>
        <style type="text/css">
            *{
                margin: 0;
                padding: 0;
            }
        </style>
    </head>
    <body>
        <canvas id="main" width="800" height="600" 
            style="display: block;margin: 0 auto;border: 1px solid #AAA;">
            亲,您的浏览器不支持canvas
        </canvas>
        <canvas id="magnify" width="200" height="200" style="display: none;"></canvas>
        <script>
            var canvas = document.getElementById("main"),
                ctx = canvas.getContext("2d"),
                canvasW = canvas.width,
                canvasH = canvas.height,
                magnifyCanvas = document.getElementById("magnify"),
                mCtx = magnifyCanvas.getContext("2d"),
                magnifyR = 100;
            var img = new Image();
            img.src = "magnify.jpg";
            img.onload = function(){
                ctx.drawImage(this , 0 , 0 , canvasW , canvasH);
                handleEvent();
            }
            function handleEvent(){
                var isShow = false;
                canvas.onmousedown = function(e){
                    e.preventDefault();
                    draw(e);
                }
                canvas.onmouseup = function(e){
                    e.preventDefault();
                    draw(e);
                }
                canvas.onmousemove = function(e){
                    e.preventDefault();
                    if(!isShow) return;
                    draw(e);
                }
                canvas.onmouseout = function(e){
                    e.preventDefault();
                    draw(e);
                }
                
                function draw(event){
                    isShow = (event.type == "mousedown" || event.type == "mousemove");
                    ctx.clearRect(0 , 0 , canvas.width , canvas.height);
                    ctx.drawImage(img , 0 , 0 , canvasW , canvasH);
                    if(!isShow) return;
                    var x = event.clientX - canvas.getBoundingClientRect().left,
                        y = event.clientY - canvas.getBoundingClientRect().top;
                    mCtx.save();
                    mCtx.lineWidth = 3;
                    mCtx.strokeStyle = "skyblue";
                    mCtx.beginPath();
                    mCtx.arc(100,100,90,0,Math.PI*2);
                    mCtx.stroke();
                    mCtx.clip();
                    mCtx.drawImage(img , 2*x - 90 , 2*y - 90 , 
                            180 , 180,
                            0 , 0 , magnifyCanvas.width, magnifyCanvas.height);
                    mCtx.closePath();
                    mCtx.restore();
                    ctx.drawImage(magnifyCanvas, (x-(magnifyCanvas.width/2)) , (y-(magnifyCanvas.height/2)) ,
                        magnifyCanvas.width , magnifyCanvas.height);
                }
            }
            
            
        </script>
    </body>
</html>

用的图片是