纯JS实现Canvas像素逐行/分批显示效果

作者:像素猫

时间:2026-10-23

浏览:117

本文介绍如何使用纯JavaScript结合Canvas API实现图像的像素级逐渐显示效果。通过getImageData获取矩形像素的RGBA数据,利用数组索引规律(每4个值对应一个像素)提取特定像素点,并结合定时器与分批处理逻辑,将原矩形像素逐步渲染至新区域,展示Canvas图像处理的基本思路与代码实现。

文章目录

前言与效果展示

前言

对于初学者而言,此前可能未曾接触过像素级操作的实际案例。本文整理相关资料并实现了该功能,逻辑较为简单,仅供交流参考。以下是最终呈现的效果,由于主要侧重于思路演示,视觉效果相对基础。

前言与效果展示

前言与效果展示

前言与效果展示

实现思路与核心API

实现思路

核心逻辑是通过JavaScript控制,使左上角的矩形图像随时间推移,逐步显示在其右下方区域。

首先构建整体架构,由于涉及像素操作,必须使用Canvas元素。

接着绘制一个矩形,并获取其所有像素的数值,即每个像素包含的四个分量:红(r)、绿(g)、蓝(b)和透明度(a)。这可以通过getImageData方法实现,该方法接收四个参数:起始坐标X和Y,以及矩形的宽度和高度。

最后,利用定时器实现逐步显示的效果。显示操作可通过putImageData完成,该方法接收三个参数:待显示的图像数据对象,以及目标坐标的X和Y值。

代码实现与像素数据处理

接下来开始编写代码:

可以先实现无定时器的基础版本,尝试获取原矩形1/10的像素点并直接显示,以验证数据获取的正确性。


<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <style>
  body{
   background-color: black;
  }
  canvas{
   background-color: white;
  }
 </style>
 <title>Title</title>
 <script>
  window.onload = function(){
   var oC = document.querySelector("#c");
   var oGc = oC.getContext("2d");
   oGc.fillRect(0,0,100,100);//画原矩形

   var rectData = oGc.getImageData(0,0,100,100);//获取原矩形的像素点的值
   var w = rectData.width;//原矩形的宽
   var h = rectData.height;//原矩形的长

   var dataC = randomData(w*h,w*h/10);//randomData方法实现随机从原矩形的像素点中抽取一部分出来
   var newData = oGc.createImageData(w,h);//创造一个新的矩形


   //dataC数组中存放的是第几个像素,*4是为了把图片的data数组定位到这个像素的数据的第一个值,然后加一是第二个,以此类推。
   for(var j=0;j<dataC.length;j++){
    newData.data[4*dataC[j]]=rectData.data[4*dataC[j]];
    newData.data[4*dataC[j]+1]=rectData.data[4*dataC[j]+1];
    newData.data[4*dataC[j]+2]=rectData.data[4*dataC[j]+2];
    newData.data[4*dataC[j]+3]=rectData.data[4*dataC[j]+3];
   }
   oGc.putImageData(newData,w,h);

   function randomData(allNum,nowNum) {
    var dataA = [];
    var dataB = [];
    for(var i=0;i<allNum;i++){
     dataA.push(i);
    }

    for(var i=0;i<nowNum;i++){
     dataB.push(dataA.splice(Math.floor(Math.random()*dataA.length),1));

    }
    return dataB;

   }

  }
 </script>
</head>
<body>
<canvas id="c" width="400" height="400"></canvas>
</body>
</html>

其中,getImageData返回的data属性是一个一维数组,数组中按顺序存储了所需的rgba四个数值,具体存放格式如下:

  • data[0]存储第一个像素点的r值
  • data[1]存储第一个像素点的g值
  • data[2]存储第一个像素点的b值
  • data[3]存储第一个像素点的a值
  • data[4]存储第二个像素点的r值
  • data[5]存储第二个像素点的g值

依此类推,每4个元素构成一个像素的完整rgba数据。

随后,在数组dataC中存储已提取的像素点位置索引,通过乘以4并分别加1、2、3来定位每个像素点对应的rgba四个具体值。此时即可实现抽取部分像素点进行显示的功能。

前言与效果展示

代码优化与分批显示逻辑

最后,对代码进行优化改进。

第一步,改进randomData函数,使其返回的数组包含原矩形的所有像素点索引。


function randomData(allNum,nowNum) {
    var dataA = [];
    var dataB = [];
    for(var i=0;i<allNum;i++){
     dataA.push(i);
    }

    for(var i=0;i<allNum/nowNum;i++){
     var otherData = [];
     for(var j=0;j<nowNum;j++){
      otherData.push(dataA.splice(Math.floor(Math.random()*dataA.length),1));
     }
     dataB.push(otherData);
    }
    return dataB;
   }

通过嵌套for循环,使返回的dataB数组被划分为若干组,每组包含特定数量的像素点。

接着增加定时器逻辑,最终完整代码如下:


<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <style>
  body{
   background-color: black;
  }
  canvas{
   background: #fff;
  }
 </style>
 <title>Title</title>
 <script>
  window.onload = function(){
   var oC = document.querySelector("#c");
   var oGc = oC.getContext("2d");
   oGc.fillRect(0,0,100,100);

   var rectData = oGc.getImageData(0,0,100,100);
   var w = rectData.width;
   var h = rectData.height;


   var dataC = randomData(w*h,w*h/10);
   var newData = oGc.createImageData(w,h);

   var iNum = 0;

   var timer = setInterval(function () {
    for(var j=0;j<dataC[iNum].length;j++){
     newData.data[4*dataC[iNum][j]]=rectData.data[4*dataC[iNum][j]];
     newData.data[4*dataC[iNum][j]+1]=rectData.data[4*dataC[iNum][j]+1];
     newData.data[4*dataC[iNum][j]+2]=rectData.data[4*dataC[iNum][j]+2];
     newData.data[4*dataC[iNum][j]+3]=rectData.data[4*dataC[iNum][j]+3];

    }
    oGc.putImageData(newData,w,h);

    if(iNum<9){
     iNum++;
    }
    else{
     iNum=0;
     oGc.clearRect(w,h,w,h);
     for(var i=0;i<newData.data.length;i++){
      newData.data[i]=0;
     }
    }
   },200);


   function randomData(allNum,nowNum) {
    var dataA = [];
    var dataB = [];
    for(var i=0;i<allNum;i++){
     dataA.push(i);
    }

    for(var i=0;i<allNum/nowNum;i++){
     var otherData = [];
     for(var j=0;j<nowNum;j++){
      otherData.push(dataA.splice(Math.floor(Math.random()*dataA.length),1));
     }
     dataB.push(otherData);
    }
    return dataB;
   }

  }
 </script>
</head>
<body>
<canvas id="c" width="400" height="400"></canvas>
</body>
</html>

其中第31至35行的for循环作用与前例相同,即将原矩形的像素数据传递给新矩形。但此次通过iNum变量实现分批次的传递与显示。请注意,这里的dataC(即randomData函数返回的数组)是一个二维数组。最后通过if-else判断来控制计时器的继续执行或停止。

总结

总结

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对本站的支持。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章