js操作像素实现图片编辑

基础概念

众所周知,图片是由一个个像素点组成.每一个像素点包含四个值,决定了渲染出来的状态.这四个值为rgba(red, green, blue, alpha).

前三个值是红绿蓝,值的大小范围从0255,或者从0%100%之间.

第四个值alpha,规定了色彩的透明度,它的范围为01之间.其中0代表完全透明,1代表完全可见.

红绿蓝是色彩中的三元色,通过设置这三种颜色所占的比重,可以变幻出其他所有颜色.

比如某个标签的文字想设置为红色,就可以通过css设置rgba值(代码如下).

span {color: rgba(255, 0, 0, 1);
}

既然每个像素点可以通过rgba的值来表达,那么一张图片所包含的所有像素点都可以转换成数据.如果修改某部分像素点的rgba值,那该图片渲染出来的效果就会发生变化,这样便实现了图片的编辑.

那怎么把图片转化成由像素点组成的数据呢?

实现

图片转换数据

一段简单的html结构如下,页面上放置一个原始图片和一个canvas画布,宽高都为300;

<body><p class="image"><img src="./img/rect.png" width="300" height="300" /></p><canvas id="myCanvas" width="300" height="300"></canvas>
<body>

首先编写一个getImageData函数将原始图片转化成数据(代码如下).

图片转换成像素数据按以下两步操作.

  • 调用ctx.drawImage将图片绘制到画布上
  • 调用ctx.getImageData获取像素数据
    const dom = document.getElementById("myCanvas"); // canvas画布getImageData(dom,"./img/rect.png").then((data)=>{console.log(data); // 打印输出像素数据})function getImageData(dom,url){const ctx = dom.getContext("2d");   // 设置在画布上绘图的环境const image = new Image();image.src= url;//获取画布宽高const w = dom.width;const h = dom.height;return new Promise((resolve)=>{image.onload = function(){ctx.drawImage(image, 0, 0 ,w,h);                           // 将图片绘制到画布上const imgData = ctx.getImageData(0,0,w,h);    // 获取画布上的图像像素resolve(imgData.data)  // 获取到的数据为一维数组,包含图像的RGBA四个通道数据ctx.clearRect(0,0,w,h);}     }) 
}

最终的打印出来的数据结果(data)如下:

data = [255, 255, 255, 255, 255, 61, 61, 255, 255, 0, 0, 255, 255,...]

data是一维数组,数组的前四个值[255, 255, 255, 255]为图片第一个像素点的rgba值(ctx.getImageData返回的透明度大小范围是从0 - 255的),[255, 61, 61, 255]
是图片第二个像素点的rgba值,后面依次类推.如此便成功的将图片转化成了数据.

数据格式化

虽然图片成功转化成了数据,但这样的数据结构很难操作,我们期待能够将数据结构的表现形式与图片展示效果保持一致.

假如存在四个都是黑色的像素点(如下图),总宽高都为2,值为[0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255].

通过某个函数转换,数据就变成了下列格式.

[[[0, 0, 0, 255],[[0, 0, 0, 255]]], // 第一行[[0, 0, 0, 255],[[0, 0, 0, 255]]]  // 第二行
]

上列数据格式和图片的展示结构保持了一致,可以很清晰的看出当前图形有多少行,每一行又有多少个像素点,
以及每一个像素点的rgba值.

综合上面描述,可以编写函数normalize(代码如下)实现数据格式的转换.

const dom = document.getElementById("myCanvas"); // canvas画布getImageData(dom,"./img/rect.png").then((data)=>{console.log(normalize(data,dom.width,dom.height)); // 打印格式化后的像素数据
})function normalize(data,width,height){const list = [];const result = [];const len = Math.ceil(data.length/4);// 将每一个像素点的rgba四个值组合在一起for(i = 0;i<len;i++){const start = i*4;list.push([data[start],data[start+1],data[start+2],data[start+3]]);}//根据图形的宽和高将数据进行分类for(hh = 0;hh < height;hh++){const tmp = [];for(ww = 0; ww < width;ww++){tmp.push(list[hh*width + ww]);}result.push(tmp);}return result;
}

换肤需求

通过normalize函数的转换,一维数组的图片数据转换成了矩阵形式.有了矩阵,我们就可以更加方便的实现编辑图片的需求.

首选我们简单实现一个图片换肤的需求,将图片中的黑色全部变成黄色(最终效果图如下).

上方的原始图片包含红蓝绿黑四种颜色,下方是换肤后生成的新图片.

实现代码如下,peeling函数负责变换图片的颜色.

观察代码,由于黑色的rgb值是(0,0,0).那么只需要判断出像素点是黑色,就重置其rgb值为(255,255,0)便能将图片中所有的黑色换成黄色.

const dom = document.getElementById("myCanvas"); // canvas画布getImageData(dom,"./img/rect.png").then((data)=>{data = peeling(data,dom.width,dom.height); // 换肤drawImage(dom,data); // 绘制图像
})function peeling(data,w,h){data = normalize(data,w,h); // 转化成多维数组// 将黑色变成黄色 (0,0,0) -> (255,255,0)   for(let i = 0;i<data.length;i++){for(let j = 0;j<data[i].length;j++){//排除透明度的比较if(data[i][j].slice(0,3).join("") == "000"){data[i][j] = [255,255,0,data[i][j][3]];}}}return restoreData(data); // 转化成一维数组
}

矩阵的数据操作完了,还需要调用restoreData函数将多维数组再转回一维数组传给浏览器渲染.

 function restoreData(data){const result = [];for(let i = 0;i<data.length;i++){for(let j = 0;j<data[i].length;j++){result.push(data[i][j][0],data[i][j][1],data[i][j][2],data[i][j][3]);}}return result;}

渲染图片

数据处理完毕后,还需将处理完的数据data传递给drawImage函数渲染成新图片(代码如下).

渲染图像主要调用以下两个api.

  • ctx.createImageData.创建新的空白ImageData对象,通过.data.set重新赋值.
  • ctx.putImageData.将像素数据绘制到画布上.
const dom = document.getElementById("myCanvas"); // canvas画布getImageData(dom,"./img/rect.png").then((data)=>{data = peeling(data,dom.width,dom.height); // 换肤drawImage(dom,data); // 绘制图像
})function drawImage(dom,data){const ctx = dom.getContext("2d");const matrix_obj = ctx.createImageData(dom.width,dom.height);matrix_obj.data.set(data);ctx.putImageData(matrix_obj,0,0);  
}

至此新图片便成功渲染了出来,效果图如下.

回顾上述操作,编辑图像主要分解成以下三步.

  • 将原始图片转化成矩阵数据(多维数组)
  • 依据需求操作矩阵
  • 将修改后的矩阵数据渲染成新图片

上述第二步操作是图像编辑的核心,很多复杂的变换效果可以通过编写矩阵算法实现.

为了加深理解,利用上述知识点实现一个图片旋转的需求.

图片旋转

假定存在最简单的情况如下图所示,其中左图存在四个像素点.第一行有两个像素点12(这里用序号代替rgba值).

第二行也有两个像素点34.数据源转换成矩阵data后的值为 [[[1],[2]],[[3],[4]]].

如何将左图按顺时针旋转90度变成右图?

通过观察图中位置关系,只需要将data中的数据做位置变换,让data = [[[1],[2]],[[3],[4]]]变成data = [[[3],[1]],[[4],[2]]],就可以实现图片变换.

四个像素点可以直接用索引交换数组的值,但一张图片动辄几十万个像素,那该如何进行操作?

这种情况下通常需要编写一个基础算法来实现图片的旋转.

首先从下图中寻找规律,图中有左 - 中 - 右三种图片状态,为了从左图的1-2-3-4变成右图的3-1-4-2,可以通过以下两步实现.

  • 寻找矩阵的高度的中心轴线,上下两侧按照轴线进行数据交换.比如左图1 - 23 - 4之间可以画一条轴线,上下两侧围绕轴线交换数据,第一行变成了3 - 4,第二行变成了1 - 2.通过第一步操作变成了中图的样子.

  • 中图的对角线3 - 2和右图一致,剩下的将对角线两侧的数据对称交换就可以变成右图.比如将中图的14进行值交换.操作完后便实现了图片的旋转.值得注意的是4的数组索引是[0][1],而1的索引是[1][0],刚好索引顺序颠倒.

通过以上描述规律便可编写下面函数实现图片的旋转.

const dom = document.getElementById("myCanvas"); // canvas画布// getImageData 获取像素数据 
getImageData(dom,"./img/rect.png").then((data)=>{data = rotate90(data,dom.width,dom.height); // 顺时针旋转90度drawImage(dom,data); // 绘制图像
})function rotate90(data,w,h){data = normalize(data,w,h); // 转化成矩阵// 围绕中间行上下颠倒const mid = h/2; // 找出中间行for(hh = 0;hh < mid;hh++){const symmetric_hh = h - hh -1; // 对称行的索引for(ww = 0;ww<w;ww++){let tmp = data[hh][ww];data[hh][ww] = data[symmetric_hh][ww];data[symmetric_hh][ww] = tmp;}}// 根据对角线进行值交换for(hh = 0;hh < h;hh++){for(ww = hh+1;ww<w;ww++){let tmp = data[hh][ww];data[hh][ww] = data[ww][hh];data[ww][hh] = tmp;}}return restoreData(data); // 转化成一维数组
}

由于我们定义的canvas宽高都为300,上面的旋转算法只适用于正方形(长方形的图片要另外编写).

最终页面展示的效果图如下(上面是原始图片,下面是画布生成的新图片).

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/252576.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

批量修改图片像素大小:Python GUI 交互界面实现

批量修改图片像素大小&#xff1a;Python GUI 交互界面实现 1、Python 修改图片像素大小 Python 的 PIL 包可以实现图片的读写、像素大小的设置。 安装 pillow 第三方模块&#xff1a; pip install pillow 设置图片大小的示例代码&#xff1a; from PIL import Imageimg …

如何调整图片分辨率大小(适用于电脑/手机)

随着智能手机快速发展&#xff0c;相机分辨率也从几百万像素升级到上千万&#xff0c;甚至上亿像素&#xff1b;超高像素的图片不仅会占用越来越多的存储空间&#xff0c;还会在上传和分享时耗费不少时间&#xff1b;而且在一些特殊APP或者网站上传图片时&#xff0c;可能对图片…

修改图片像素怎么修改

修改图片像素怎么修改&#xff1f;因为我们对图片尺寸的大小修改有很多需求。比如在运营网店就非常需要的&#xff0c;我们会有非常多的图片需要处理。而不同的网店平台还有不同的图片像素限制&#xff0c;比如某宝宝贝描述的图片尺寸要:宽500*高500像素,图片大小要在120KB以内…

Vue.js官网版教程

前言 这是vue官网案例学习&#xff0c;记录一下 序言 vue.js介绍 Vue.js 渐进式 JavaScript 框架https://learning.dcloud.io/#/?vid0 第1节 安装与部署 https://learning.dcloud.io/#/?vid1 <!-- 开发环境版本&#xff0c;包含了有帮助的命令行警告 --> <scri…

0基础js新手JavaScript学习入门教程

1 下载所需工具 chrome&#xff0c;谷歌开发的一款浏览器。vscode&#xff0c;微软开发的一款写代码的工具。 JavaScript代码需要浏览器来运行&#xff0c;用来控制网页的各种行为。 浏览器地址栏访问的是网页&#xff0c;因此JavaScript需要放到网页里。 2 先创建1个网页 …

简单粗暴的JavaScript学习教程,前端入门的不二之选!

JavaScript 是网景&#xff08;Netscape&#xff09;公司开发的一种基于客户端浏览器、面向&#xff08;基于&#xff09;对象、事件驱动式的网页脚本语言。JavaScript语言的前身叫作Livescript。 JavaScript的特点&#xff1a; 简单、易学、易用&#xff1b;跨平台&#xff…

对于初学者的JavaScript 教程

JavaScript是世界上最流行的轻量级、解释型编译编程语言。它也被称为网页的脚本语言。它以开发网页而闻名&#xff0c;许多非浏览器环境也使用它。JavaScript 可用于客户端开发以及服务器端开发。 JavaScript 可以通过两种方式添加到您的 HTML 文件中&#xff1a; 内部 JS&…

node.js入门教程(一)

1. 初识 Node.js Node.js 是 一个基于 Chrome V8 引擎的 JavaScript 运行环境 。 Node.js 的官网地址&#xff1a; https://nodejs.org/zh-cn/ ① 浏览器 是 JavaScript 的 前端运行环境 。 ② Node.js 是 JavaScript 的 后端运行环境 。 ③ Node.js 中 无法调用 DOM 和…

最通俗易懂的JavaScript入门教程

前言&#xff1a;“成功没有捷径&#xff0c;脚踏实地一步一个脚印&#xff0c;该来的总会来&#xff0c;不好高骛远&#xff0c;不急功近利&#xff0c;付出总会有回报&#xff0c;不管处于哪个阶段&#xff0c;都要一步一个脚印&#xff0c;踏实的走好每一步&#xff01;” 你…

Vue.js入门教程(适合初学者)

Vue.js入门教程 Vue官网网址&#xff1a;Vue.js 中文网 Vue.js Vue.js是渐进式JavaScript 框架&#xff0c;是一套构建用户界面的渐进式框架。也可以说Vue.js 是一个用来构建网页界面的 JavaScript 库。 Vue的常用使用方式有两种&#xff1a; 一、使用<script>标签&am…

尚硅谷JavaScript高级教程(javascript实战进阶)学习笔记

前言 这个是我学习过程中的笔记&#xff0c;分享给大家&#xff0c;希望对大家有用。 学习内容是尚硅谷JavaScript高级教程(javascript实战进阶)&#xff0c;这里是视频链接。 我在前面有两篇对于web前端HTML和CSS的学习笔记&#xff0c;有需要的可以看一下哈。 黑马程序员版…

Threejs入门教程

一、本地搭建Threejs官方文档网站 1.官网地址&#xff1a;https://github.com/mrdoob/three.js 下载压缩包并解压或使用git clone 若github过慢&#xff0c;则使用gitee对应网址&#xff1a;three.js: mrdoob/three.js 同步库 2.目录解析 3.启动方式 在three.js项目根目录下…

Javascript机器学习教程

Javascript机器学习教程 使用 Javascript 和 TensorflowJS 通过动手项目从头开始掌握机器学习 课程英文名&#xff1a;Machine Learning with Javascript 此视频教程共1.0小时&#xff0c;中英双语字幕&#xff0c;画质清晰无水印&#xff0c;源码附件全 下载地址 课程编号…

CAD梦想画图中删除命令

“删除”命令用于删除在CAD作图过程中的图线和多余的图线。用户既可以先选择对象再执行“删除”&#xff0c;也可以先执行“删除”命令再选择对象。选择“删除”命令后&#xff0c;CAD屏幕上的十字光标将会变成一个拾取框&#xff0c;选择需要删除的对象&#xff0c;按enter键。…

CAD怎么删除图块注释?删除CAD图块注释步骤

CAD设计过程中&#xff0c;有时候会在图纸中添加许多注释&#xff0c;如&#xff1a;文字注释&#xff0c;图块注释&#xff0c;标注样式注释等。当需要删除图纸中的CAD图块注释时&#xff0c;你知道该如何操作吗&#xff1f;本节课程小编就来给大家分享一下浩辰CAD软件中删除C…

AutoCAD单独卸载,不影响其他软件,CAD 2021安装失败,怎么完全彻底卸载删除清理干净CAD 2021各种残留注册表和文件?

AIOC超级工具箱 AIOC超级工具箱是专门为了针对Autodesk类软件卸载不干净而导致Autodesk安装失败问题进行研发的Autodesk一键卸载工具。现在虽然360或一些卸载软件提供了强力卸载Autodesk的工具&#xff0c;可以将Autodesk注册表和一些Autodesk目录的Autodesk残留信息删除&…

CAD卸载重新安装方法,使用清理卸载工具完全彻底删除干净CAD各种残留注册表和文件。

CAD没有按照正确方式卸载&#xff0c;导致CAD安装失败。现在虽然360或者其他一些卸载软件提供了强力卸载清理CAD的工具&#xff0c;可以将CAD注册表和一些CAD目录的CAD残留信息删除干净&#xff0c;但仍不能确保将CAD所有相关dll程序文件、exe可执行文件和注册表信息全部彻底删…

CAD 卸载工具,完美彻底卸载清除干净cad各种残留注册表和文件

CAD提示安装未完成&#xff0c;某些产品无法安装该怎样解决呢&#xff1f;&#xff0c;一些朋友在win7或者win10系统下安装CAD失败提示CAD安装未完成&#xff0c;某些产品无法安装&#xff0c;也有时候想重新安装CAD的时候会出现本电脑windows系统已安装CAD&#xff0c;你要是不…

【AutoCAD 卸载工具,完全彻底删除清理干净AutoCAD各种残留注册表和文件】

AutoCAD卸载工具&#xff0c;完全彻底删除干净AutoCAD各种残留注册表和文件。AutoCAD安装失败&#xff0c;怎么完全彻底删除清理干净AutoCAD各种残留注册表和文件呢&#xff1f;有些同学想把AutoCAD重新安装&#xff0c;但是AutoCAD安装失败显示失败&#xff0c;有时AutoCAD安装…

CAD单独卸载,不影响其他软件,CAD专用卸载修复工具,一键完全彻底卸载删除CAD软件的专用卸载工具

AIOC超级工具箱 小伙伴是不是遇到 CAD/3dmax/maya/Revit/Inventor 安装失败或者安装不了的问题了呢&#xff1f;AUTODESK系列软件着实令人头疼&#xff0c;CAD/3dmax/maya/Revit/Inventor安装失败之后不能完全卸载&#xff01;&#xff01;&#xff01;&#xff08;比如maya&a…