JS封装cavans多种滤镜组件


Posted in Javascript onFebruary 15, 2022

​​前言:

图片处理现在已经成为了我们生活中的刚需,想必大家也经常有这方面的需求。实际前端业务中,也经常会有很多的项目需要用到图片加工和处理。本文以javascript为基础,用html5 + cavans实现多种常见的滤镜效果,并且封装成可调用的js文件(filter.js),且支持本地保存图片。

效果展示:

JS封装cavans多种滤镜组件

一.实现思路

我们知道每张图片都是由若干像素组成,得到的像素是一个数组,颜色又是由RGBA组成,所以数组中每4个点组成一个颜色值,要去实现每个滤镜的特效,就要去有规律的去改变像素值。当我们拿到图片并且通过ctx.drawImage()方法绘制到cavans中后,可以通过ctx.getImageData()方法来获取图片数据。然后就可以通过filter.js来调用方法实现滤镜效果。

二.cavans前置准备

1.获取cavans

let filterCavans = document.getElementById("filterCavans");
filterCavans.width = img.clientWidth;
filterCavans.height = img.clientHeight;

2.获取2d context对象

ctx = filterCavans.getContext("2d");

3.绘制图片到cavans上

let img = document.getElementById("img");
ctx.drawImage(img, 0, 0, img.clientWidth, img.clientHeight);

4.获取在cavans上已绘制图片数据

canvasData = ctx.getImageData( 0, 0, filterCavans.width, filterCavans.height);

三.原理及实现

1.黑白调

原理:判断当前像素的RGB值是否大于255的一半,如大于就全部设置为255,小于就全部设为0

blackWhite(imageData) {
    //所在区域图片的像素集
    let data = imageData.data;
    for (let i = 0; i < data.length; i += 4) {
        let r = data[i];
        let g = data[i + 1];
        let b = data[i + 2];
        if (r > 255 / 2) {
            data[i] = 255
            data[i + 1] = 255
            data[i + 2] = 255
        } else if (r < 255 / 2) {
            data[i] = 0
            data[i + 1] = 0
            data[i + 2] = 0
        }
    }
}

2.灰色调

原理:把当前像素的RGB值 设置为当前像素RGB的平均值

gray(imageData) {
    let data = imageData.data;
    for (let i = 0; i < data.length; i += 4) {
        let r = data[i];
        let g = data[i + 1];
        let b = data[i + 2];

        let average = Math.floor((r + g + b) / 3);
        data[i] = average;
        data[i + 1] = average;
        data[i + 2] = average;
    }
}

3.反转

原理:用255减去当前像素的RGB值

toggle(imageData) {
    let data = imageData.data;
    for (let i = 0, len = data.length; i < len; i += 4) {
        data[i] = 255 - data[i];
        data[i + 1] = 255 - data[i + 1]
        data[i + 2] = 255 - data[i + 2];
    }
}

4.复古

原理:RGB值乘以固定的数值

sepia(imageData) {
    let data = imageData.data;
    for (let i = 0; i < data.length; i += 4) {
        let r = data[i];
        let g = data[i + 1];
        let b = data[i + 2];
        data[i] = (r * 0.393) + (g * 0.769) + (b * 0.189);
    }
}

5.红色蒙版

原理:红色通道取平均值,绿色通道和蓝色通道都设为0

myRed(imageData) {
    let data = imageData.data;
    for (let i = 0; i < data.length; i += 4) {
        let r = data[i];
        let g = data[i + 1];
        let b = data[i + 2];
        data[i] = (r + g + b) / 3;
        data[i + 1] = 0;
        data[i + 2] = 0;
    }
}

6.增加亮度

原理:RGB值直接加上所需要设置亮度delta

brightness(imageData, delta) {
    let data = imageData.data;
    for (let i = 0; i < data.length; i += 4) {
        data[i] += delta;
        data[i + 1] += delta;
        data[i + 2] += delta;
    }
}

7.浮雕

原理:每个像素的RGB值都设置为该位置的初始值 num 减去其上一个像素值得差,最后统一加上128用于控制灰度

carve(imageData) {
    let w = imageData.width, h = imageData.height;
    let data = imageData.data;
    for (let i = h; i > 0; i--) {  // 行
        for (let j = w; j > 0; j--) {  // 列
            for (let k = 0; k < 3; k++) {
                let num = (i * w + j) * 4 + k;
                let numUp = ((i - 1) * w + j) * 4 + k;
                let numDown = ((i + 1) * w + j) * 4 + k;
                data[num] = data[num] - data[numUp - 4] + 128;
            }
        }
    }
}

8.雾化

原理:通过随机方法来设置当前像素点周围的255白色值

fog(imageData) {
    let w = imageData.width, h = imageData.height;
    let data = imageData.data;
    for (let i = h; i > 0; i--) {  // 行
        for (let j = w; j > 0; j--) {  // 列
            let num = (i * w + j) * 4;
            if (Math.random() < 0.1) {
                data[num] = 255;
                data[num + 1] = 255;
                data[num + 2] = 255;
            }
        }
    }
}

9.毛玻璃

原理:用当前点四周一定范围内任意一点的颜色来替代当前点颜色,最常用的是随机的采用相邻点进行替代。

spread(canvasData) {
    let w = canvasData.width, h = canvasData.height;
    for (let i = 0; i < h; i++) {
        for (let j = 0; j < w; j++) {
            for (let k = 0; k < 3; k++) {
                // Index of the pixel in the array  
                let num = (i * w + j) * 4 + k;
                let rand = Math.floor(Math.random() * 10) % 3;
                let num2 = ((i + rand) * w + (j + rand)) * 4 + k;
                canvasData.data[num] = canvasData.data[num2]
            }
        }
    }
}

10.马赛克

原理:将图像分成大小一致的图像块,每一个图像块都是一个正方形,并且在这个正方形中所有像素值都相等。我们可以将这个正方形看作是一个模板窗口,模板中对应的所有图像像素值都等于该模板的左上角第一个像素的像素值,这样的效果就是马赛克效果,而正方形模板的大小则决定了马赛克块的大小,即图像马赛克化的程度。

mosaic(imageData, size) {
    let w = imageData.width, h = imageData.height;
    let data = imageData.data;
    for (let i = 1; i < h - 1; i += size) {
        for (let j = 1; j < w - 1; j += size) {
            let num = (i * w + j) * 4;
            for (let dx = 0; dx < size; dx++) {
                for (let dy = 0; dy < size; dy++) {
                    let x = i + dx;
                    let y = j + dy;
                    let p1 = (x * w + y) * 4;

                    data[p1 + 0] = data[num + 0];
                    data[p1 + 1] = data[num + 1];
                    data[p1 + 2] = data[num + 2];
                }
            }
        }
    }

11.模糊

原理:将当前像素的周边像素的RGB值各自的平均值作为新的RGB值

myBlur(imageData) {
    let w = imageData.width, h = imageData.height;
    let data1 = imageData.data;
    let data2 = imageData.data;

    for (let i = 0; i < h; i++) {  // 行
        for (let j = 0; j < w; j++) {  // 列
            for (let k = 0; k < 3; k++) {
                let num = (i * w + j) * 4 + k;
                let numUp = ((i - 1) * w + j) * 4 + k;
                let numDown = ((i + 1) * w + j) * 4 + k;
                // 对另开内存的data1的改变为什么会反应到data中
                data1[num] = (data2[numUp - 4] + data2[numUp] + data2[numUp + 4]
                    + data2[num - 4] + data2[num] + data2[num + 4]
                    + data2[numDown - 4] + data2[numDown] + data2[numDown + 4]) / 9;
            }
        }
    }
}

四.使用

//黑白调
filter.blackWhite(canvasData);

//保存图片
save() {
    this.download("png");
},
//利用a标签下载
download(type) {
    //设置保存图片的类型
    let imgdata = filterCavans.toDataURL(type);
    //将mime-type改为image/octet-stream,强制让浏览器下载
    let fixtype = function (type) {
        type = type.toLocaleLowerCase().replace(/jpg/i, "jpeg");
        let r = type.match(/png|jpeg|bmp|gif/)[0];
        return "image/" + r;
    };
    imgdata = imgdata.replace(fixtype(type), "image/octet-stream");
    //将图片保存到本地
    let saveFile = function (data, filename) {
        let link = document.createElement("a");
        link.href = data;
        link.download = filename;
        link.click();
    };
    let filename = new Date().toLocaleDateString() + "." + type;
    saveFile(imgdata, filename);
}

到此这篇关于JS封装cavans多种滤镜组件的文章就介绍到这了,更多相关JS封装cavans内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
IE6与IE7中,innerHTML获取param的区别
Mar 15 Javascript
jQuery 白痴级入门教程
Nov 11 Javascript
node.js中的fs.link方法使用说明
Dec 15 Javascript
基于BootStrap的图片轮播效果展示实例代码
May 23 Javascript
vue-router实现webApp切换页面动画效果代码
May 25 Javascript
在element-ui的select下拉框加上滚动加载
Apr 18 Javascript
a标签调用js的方法总结
Sep 05 Javascript
基于Vue 撸一个指令实现拖拽功能
Oct 09 Javascript
微信小程序实现音频文件播放进度的实例代码
Mar 02 Javascript
Javascript异步执行不按顺序解决方案
Apr 30 Javascript
vue webpack build资源相对路径的问题及解决方法
Jun 04 Javascript
Handtrack.js库实现实时监测手部运动(推荐)
Feb 08 Javascript
HTML+JS实现在线朗读器
Feb 15 #Javascript
js中Map和Set的用法及区别实例详解
Feb 15 #Javascript
canvas实现贪食蛇的实践
Vue自定义铃声提示音组件的实现
Jan 22 #Vue.js
JavaScript实例 ODO List分析
Jan 22 #Javascript
JavaScript ES6的函数拓展
Jan 18 #Javascript
Vue提供的三种调试方式你知道吗
Jan 18 #Vue.js
You might like
PHP操作xml代码
2010/06/17 PHP
thinkphp 多表 事务详解
2013/06/17 PHP
php获取qq用户昵称和在线状态(实例分析)
2013/10/27 PHP
JavaScript入门教程 Cookies
2009/01/31 Javascript
某人初学javascript的时候写的学习笔记
2010/12/30 Javascript
Eval and new funciton not the same thing
2012/12/27 Javascript
屏蔽相应键盘按钮操作
2014/03/10 Javascript
ECMAScript6块级作用域及新变量声明(let)
2015/06/12 Javascript
jQuery实现仿新浪微博浮动的消息提示框(可智能定位)
2015/10/10 Javascript
JS+CSS实现分类动态选择及移动功能效果代码
2015/10/19 Javascript
jQuery鼠标悬浮链接弹出跟随图片实例代码
2016/01/08 Javascript
JS上传图片预览插件制作(兼容到IE6)
2016/08/07 Javascript
jquery实现全选、不选、反选的两种方法
2016/09/06 Javascript
AngularJS Select(选择框)使用详解
2017/01/18 Javascript
原生js实现轮播图的示例代码
2017/02/20 Javascript
无法获取隐藏元素宽度和高度的解决方案
2017/03/07 Javascript
微信小程序开发之IOS和Android兼容的问题
2017/09/26 Javascript
浅谈React前后端同构防止重复渲染
2018/01/05 Javascript
js实现带搜索功能的下拉框
2020/01/11 Javascript
解决vue与node模版引擎的渲染标记{{}}(双花括号)冲突问题
2020/09/11 Javascript
[49:58]完美世界DOTA2联赛PWL S3 Magma vs DLG 第一场 12.18
2020/12/19 DOTA
使用python检测手机QQ在线状态的脚本代码
2013/02/10 Python
记录Django开发心得
2014/07/16 Python
pandas 数据索引与选取的实现方法
2019/06/21 Python
Python面向对象封装操作案例详解 II
2020/01/02 Python
python实现可下载音乐的音乐播放器
2020/02/25 Python
Python headers请求头如何实现快速添加
2020/11/03 Python
详解python定时简单爬取网页新闻存入数据库并发送邮件
2020/11/27 Python
python 统计list中各个元素出现的次数的几种方法
2021/02/20 Python
纯css3使用vw和vh实现自适应的方法
2018/02/09 HTML / CSS
伦敦高达60%折扣的钻石珠宝商:Purely Diamonds
2018/06/24 全球购物
团员个人的自我评价
2013/12/02 职场文书
计算机专业应届生求职信
2014/04/06 职场文书
驾驶员安全责任书
2014/07/22 职场文书
2015年感恩父亲节活动策划方案
2015/05/05 职场文书
提取视频中的音频 Python只需要三行代码!
2021/05/10 Python