纯JavaScript实现HTML5 Canvas六种特效滤镜示例


Posted in Javascript onJune 28, 2013

小试牛刀,实现了六款简单常见HTML5 Canvas特效滤镜,并且封装成一个纯JavaScript可调用的API文件gloomyfishfilter.js。支持的特效滤镜分别为:
1.反色
2.灰色调
3.模糊
4.浮雕
5.雕刻
6.镜像

滤镜原理解释:
1.反色:获取一个像素点RGB值r, g, b则新的RGB值为(255-r, 255-g, 255-b)
2.灰色调:获取一个像素点RGB值r, g, b则新的RGB值为

newr = (r * 0.272) + (g * 0.534) + (b * 0.131); 
newg = (r * 0.349) + (g * 0.686) + (b * 0.168); 
newb = (r * 0.393) + (g * 0.769) + (b * 0.189);

3.模糊:基于一个5*5的卷积核
4.浮雕与雕刻:
基于当前像素的前一个像素RGB值与它的后一个像素的RGB值之差再加上128
5.镜像:模拟了物体在镜子中与之对应的效果。
杂项准备
1.如何获取Canvas 2d context对象
var canvas = document.getElementById("target"); 
canvas.width = source.clientWidth; 
canvas.height = source.clientHeight; 
if(!canvas.getContext) { 
console.log("Canvas not supported. Please install a HTML5compatible browser."); 
return; 
} 
// get 2D context of canvas and draw image 
tempContext = canvas.getContext("2d");

2.如何绘制一个DOM img对象到Canvas对象中
var source = document.getElementById("source"); 
tempContext.drawImage(source, 0, 0, canvas.width,canvas.height);

3.如何从Canvas对象中获取像素数据
var canvas = document.getElementById("target"); 
varlen = canvas.width * canvas.height * 4; 
var canvasData = tempContext.getImageData(0, 0, canvas.width, canvas.height); 
var binaryData = canvasData.data;

4.如何对DOM对象实现鼠标Click事件绑定
function bindButtonEvent(element, type, handler) 
{ 
if(element.addEventListener){ 
element.addEventListener(type, handler,false); 
}else { 
element.attachEvent('on'+type, handler);// for IE6,7,8 
} 
}

5.如何调用实现的gfilter API完成滤镜功能
<scriptsrc="gloomyfishfilter.js"></script> //导入API文件 
gfilter.colorInvertProcess(binaryData, len); //调用 API

6.浏览器支持:IE, FF, Chrome上测试通过,其中IE上支持通过以下标签实现:
<meta http-equiv="X-UA-Compatible"content="chrome=IE8">

效果演示:
纯JavaScript实现HTML5 Canvas六种特效滤镜示例 
应用程序源代码:
CSS部分:
#svgContainer { 
width:800px; 
height:600px; 
background-color:#EEEEEE; 
} 
#sourceDiv { float: left; border: 2px solid blue} 
#targetDiv { float: right;border: 2px solid red}

filter1.html中HTML源代码:
<!DOCTYPE html> 
<html> 
<head> 
<meta http-equiv="X-UA-Compatible" content="chrome=IE8"> 
<meta http-equiv="Content-type" content="text/html;charset=UTF-8"> 
<title>Canvas Filter Demo</title> 
<link href="default.css" rel="stylesheet" /> 
<script src="gloomyfishfilter.js"></scrip> 
</head> 
<body> 
<h1>HTML Canvas Image Process - By Gloomy Fish</h1> 
<div id="svgContainer"> 
<div id="sourceDiv"> 
<img id="source" src="../test.png" /> 
</div> 
<div id="targetDiv"> 
<canvas id="target"></canvas> 
</div> 
</div> 
<div id="btn-group"> 
<button type="button" id="invert-button">反色</button> 
<button type="button" id="adjust-button">灰色调</button> 
<button type="button" id="blur-button">模糊</button> 
<button type="button" id="relief-button">浮雕</button> 
<button type="button" id="diaoke-button">雕刻</button> 
<button type="button" id="mirror-button">镜像</button> 
</div> 
</body> 
</html>

filter1.html中JavaScript源代码:
var tempContext = null; // global variable 2d context 
window.onload = function() { 
var source = document.getElementById("source"); 
var canvas = document.getElementById("target"); 
canvas.width = source.clientWidth; 
canvas.height = source.clientHeight; if (!canvas.getContext) { 
console.log("Canvas not supported. Please install a HTML5 compatible browser."); 
return; 
} 
// get 2D context of canvas and draw image 
tempContext = canvas.getContext("2d"); 
tempContext.drawImage(source, 0, 0, canvas.width, canvas.height); 
// initialization actions 
var inButton = document.getElementById("invert-button"); 
var adButton = document.getElementById("adjust-button"); 
var blurButton = document.getElementById("blur-button"); 
var reButton = document.getElementById("relief-button"); 
var dkButton = document.getElementById("diaoke-button"); 
var mirrorButton = document.getElementById("mirror-button"); 
// bind mouse click event 
bindButtonEvent(inButton, "click", invertColor); 
bindButtonEvent(adButton, "click", adjustColor); 
bindButtonEvent(blurButton, "click", blurImage); 
bindButtonEvent(reButton, "click", fudiaoImage); 
bindButtonEvent(dkButton, "click", kediaoImage); 
bindButtonEvent(mirrorButton, "click", mirrorImage); 
} 
function bindButtonEvent(element, type, handler) 
{ 
if(element.addEventListener) { 
element.addEventListener(type, handler, false); 
} else { 
element.attachEvent('on'+type, handler); // for IE6,7,8 
} 
} 
function invertColor() { 
var canvas = document.getElementById("target"); 
var len = canvas.width * canvas.height * 4; 
var canvasData = tempContext.getImageData(0, 0, canvas.width, canvas.height); 
var binaryData = canvasData.data; 
// Processing all the pixels 
gfilter.colorInvertProcess(binaryData, len); 
// Copying back canvas data to canvas 
tempContext.putImageData(canvasData, 0, 0); 
} 
function adjustColor() { 
var canvas = document.getElementById("target"); 
var len = canvas.width * canvas.height * 4; 
var canvasData = tempContext.getImageData(0, 0, canvas.width, canvas.height); 
var binaryData = canvasData.data; 
// Processing all the pixels 
gfilter.colorAdjustProcess(binaryData, len); 
// Copying back canvas data to canvas 
tempContext.putImageData(canvasData, 0, 0); 
} 
function blurImage() 
{ 
var canvas = document.getElementById("target"); 
var len = canvas.width * canvas.height * 4; 
var canvasData = tempContext.getImageData(0, 0, canvas.width, canvas.height); 
// Processing all the pixels 
gfilter.blurProcess(tempContext, canvasData); 
// Copying back canvas data to canvas 
tempContext.putImageData(canvasData, 0, 0); 
} 
function fudiaoImage() 
{ 
var canvas = document.getElementById("target"); 
var len = canvas.width * canvas.height * 4; 
var canvasData = tempContext.getImageData(0, 0, canvas.width, canvas.height); 
// Processing all the pixels 
gfilter.reliefProcess(tempContext, canvasData); 
// Copying back canvas data to canvas 
tempContext.putImageData(canvasData, 0, 0); 
} 
function kediaoImage() 
{ 
var canvas = document.getElementById("target"); 
var len = canvas.width * canvas.height * 4; 
var canvasData = tempContext.getImageData(0, 0, canvas.width, canvas.height); 
// Processing all the pixels 
gfilter.diaokeProcess(tempContext, canvasData); 
// Copying back canvas data to canvas 
tempContext.putImageData(canvasData, 0, 0); 
} 
function mirrorImage() 
{ 
var canvas = document.getElementById("target"); 
var len = canvas.width * canvas.height * 4; 
var canvasData = tempContext.getImageData(0, 0, canvas.width, canvas.height); 
// Processing all the pixels 
gfilter.mirrorProcess(tempContext, canvasData); 
// Copying back canvas data to canvas 
tempContext.putImageData(canvasData, 0, 0); 
}

滤镜源代码(gloomyfishfilter.js):
var gfilter = { 
type: "canvas", 
name: "filters", 
author: "zhigang", 
getInfo: function () { 
return this.author + ' ' + this.type + ' ' + this.name; 
}, 
/** 
* invert color value of pixel, new pixel = RGB(255-r, 255-g, 255 - b) 
* 
* @param binaryData - canvas's imagedata.data 
* @param l - length of data (width * height of image data) 
*/ 
colorInvertProcess: function(binaryData, l) { 
for (var i = 0; i < l; i += 4) { 
var r = binaryData[i]; 
var g = binaryData[i + 1]; 
var b = binaryData[i + 2]; binaryData[i] = 255-r; 
binaryData[i + 1] = 255-g; 
binaryData[i + 2] = 255-b; 
} 
}, 
/** 
* adjust color values and make it more darker and gray... 
* 
* @param binaryData 
* @param l 
*/ 
colorAdjustProcess: function(binaryData, l) { 
for (var i = 0; i < l; i += 4) { 
var r = binaryData[i]; 
var g = binaryData[i + 1]; 
var b = binaryData[i + 2]; 
binaryData[i] = (r * 0.272) + (g * 0.534) + (b * 0.131); 
binaryData[i + 1] = (r * 0.349) + (g * 0.686) + (b * 0.168); 
binaryData[i + 2] = (r * 0.393) + (g * 0.769) + (b * 0.189); 
} 
}, 
/** 
* deep clone image data of canvas 
* 
* @param context 
* @param src 
* @returns 
*/ 
copyImageData: function(context, src) 
{ 
var dst = context.createImageData(src.width, src.height); 
dst.data.set(src.data); 
return dst; 
}, 
/** 
* convolution - keneral size 5*5 - blur effect filter(模糊效果) 
* 
* @param context 
* @param canvasData 
*/ 
blurProcess: function(context, canvasData) { 
console.log("Canvas Filter - blur process"); 
var tempCanvasData = this.copyImageData(context, canvasData); 
var sumred = 0.0, sumgreen = 0.0, sumblue = 0.0; 
for ( var x = 0; x < tempCanvasData.width; x++) { 
for ( var y = 0; y < tempCanvasData.height; y++) { 
// Index of the pixel in the array 
var idx = (x + y * tempCanvasData.width) * 4; 
for(var subCol=-2; subCol<=2; subCol++) { 
var colOff = subCol + x; 
if(colOff <0 || colOff >= tempCanvasData.width) { 
colOff = 0; 
} 
for(var subRow=-2; subRow<=2; subRow++) { 
var rowOff = subRow + y; 
if(rowOff < 0 || rowOff >= tempCanvasData.height) { 
rowOff = 0; 
} 
var idx2 = (colOff + rowOff * tempCanvasData.width) * 4; 
var r = tempCanvasData.data[idx2 + 0]; 
var g = tempCanvasData.data[idx2 + 1]; 
var b = tempCanvasData.data[idx2 + 2]; 
sumred += r; 
sumgreen += g; 
sumblue += b; 
} 
} 
// calculate new RGB value 
var nr = (sumred / 25.0); 
var ng = (sumgreen / 25.0); 
var nb = (sumblue / 25.0); 
// clear previous for next pixel point 
sumred = 0.0; 
sumgreen = 0.0; 
sumblue = 0.0; 
// assign new pixel value 
canvasData.data[idx + 0] = nr; // Red channel 
canvasData.data[idx + 1] = ng; // Green channel 
canvasData.data[idx + 2] = nb; // Blue channel 
canvasData.data[idx + 3] = 255; // Alpha channel 
} 
} 
}, 
/** 
* after pixel value - before pixel value + 128 
* 浮雕效果 
*/ 
reliefProcess: function(context, canvasData) { 
console.log("Canvas Filter - relief process"); 
var tempCanvasData = this.copyImageData(context, canvasData); 
for ( var x = 1; x < tempCanvasData.width-1; x++) 
{ 
for ( var y = 1; y < tempCanvasData.height-1; y++) 
{ 
// Index of the pixel in the array 
var idx = (x + y * tempCanvasData.width) * 4; 
var bidx = ((x-1) + y * tempCanvasData.width) * 4; 
var aidx = ((x+1) + y * tempCanvasData.width) * 4; 
// calculate new RGB value 
var nr = tempCanvasData.data[aidx + 0] - tempCanvasData.data[bidx + 0] + 128; 
var ng = tempCanvasData.data[aidx + 1] - tempCanvasData.data[bidx + 1] + 128; 
var nb = tempCanvasData.data[aidx + 2] - tempCanvasData.data[bidx + 2] + 128; 
nr = (nr < 0) ? 0 : ((nr >255) ? 255 : nr); 
ng = (ng < 0) ? 0 : ((ng >255) ? 255 : ng); 
nb = (nb < 0) ? 0 : ((nb >255) ? 255 : nb); 
// assign new pixel value 
canvasData.data[idx + 0] = nr; // Red channel 
canvasData.data[idx + 1] = ng; // Green channel 
canvasData.data[idx + 2] = nb; // Blue channel 
canvasData.data[idx + 3] = 255; // Alpha channel 
} 
} 
}, 
/** 
* before pixel value - after pixel value + 128 
* 雕刻效果 
* 
* @param canvasData 
*/ 
diaokeProcess: function(context, canvasData) { 
console.log("Canvas Filter - process"); 
var tempCanvasData = this.copyImageData(context, canvasData); 
for ( var x = 1; x < tempCanvasData.width-1; x++) 
{ 
for ( var y = 1; y < tempCanvasData.height-1; y++) 
{ 
// Index of the pixel in the array 
var idx = (x + y * tempCanvasData.width) * 4; 
var bidx = ((x-1) + y * tempCanvasData.width) * 4; 
var aidx = ((x+1) + y * tempCanvasData.width) * 4; 
// calculate new RGB value 
var nr = tempCanvasData.data[bidx + 0] - tempCanvasData.data[aidx + 0] + 128; 
var ng = tempCanvasData.data[bidx + 1] - tempCanvasData.data[aidx + 1] + 128; 
var nb = tempCanvasData.data[bidx + 2] - tempCanvasData.data[aidx + 2] + 128; 
nr = (nr < 0) ? 0 : ((nr >255) ? 255 : nr); 
ng = (ng < 0) ? 0 : ((ng >255) ? 255 : ng); 
nb = (nb < 0) ? 0 : ((nb >255) ? 255 : nb); 
// assign new pixel value 
canvasData.data[idx + 0] = nr; // Red channel 
canvasData.data[idx + 1] = ng; // Green channel 
canvasData.data[idx + 2] = nb; // Blue channel 
canvasData.data[idx + 3] = 255; // Alpha channel 
} 
} 
}, 
/** 
* mirror reflect 
* 
* @param context 
* @param canvasData 
*/ 
mirrorProcess : function(context, canvasData) { 
console.log("Canvas Filter - process"); 
var tempCanvasData = this.copyImageData(context, canvasData); 
for ( var x = 0; x < tempCanvasData.width; x++) // column 
{ 
for ( var y = 0; y < tempCanvasData.height; y++) // row 
{ 
// Index of the pixel in the array 
var idx = (x + y * tempCanvasData.width) * 4; 
var midx = (((tempCanvasData.width -1) - x) + y * tempCanvasData.width) * 4; 
// assign new pixel value 
canvasData.data[midx + 0] = tempCanvasData.data[idx + 0]; // Red channel 
canvasData.data[midx + 1] = tempCanvasData.data[idx + 1]; ; // Green channel 
canvasData.data[midx + 2] = tempCanvasData.data[idx + 2]; ; // Blue channel 
canvasData.data[midx + 3] = 255; // Alpha channel 
} 
} 
}, 
};
Javascript 相关文章推荐
TopList标签和JavaScript结合两例
Aug 12 Javascript
统计出现最多的字符次数的js代码
Dec 03 Javascript
javascript控制swfObject应用介绍
Nov 29 Javascript
jquery制作漂亮的弹出层提示消息特效
Dec 23 Javascript
jquery插件star-rating.js实现星级评分特效
Apr 15 Javascript
javascript中html字符串转化为jquery dom对象的方法
Aug 27 Javascript
jQuery Easyui快速入门教程
Aug 21 Javascript
浅谈jquery上下滑动的注意事项
Oct 13 Javascript
H5基于iScroll实现下拉刷新和上拉加载更多
Jul 18 Javascript
Angularjs实现控制器之间通信方式实例总结
Mar 27 Javascript
vue项目上传Github预览的实现示例
Nov 06 Javascript
ES6顶层对象、global对象实例分析
Jun 14 Javascript
jquery中通过父级查找进行定位示例
Jun 28 #Javascript
javascript实现文字图片上下滚动的具体实例
Jun 28 #Javascript
JavaScript操纵窗口的方法小结
Jun 28 #Javascript
网站如何做到完全不需要jQuery也可以满足简单需求
Jun 27 #Javascript
js获取当前日期代码适用于网页头部
Jun 27 #Javascript
jquery仿QQ商城带左右按钮控制焦点图片切换滚动效果
Jun 27 #Javascript
JQUERY实现左侧TIPS滑进滑出效果示例
Jun 27 #Javascript
You might like
Linux下进行MYSQL编程时插入中文乱码的解决方案
2007/03/15 PHP
php ftp文件上传函数(基础版)
2010/06/03 PHP
PHP 面向对象程序设计(oop)学习笔记 (二) - 静态变量的属性和方法及延迟绑定
2014/06/12 PHP
PHP爬虫之百万级别知乎用户数据爬取与分析
2016/01/22 PHP
php 从指定数字中获取随机组合的简单方法(推荐)
2017/04/05 PHP
Laravel解决nesting level错误和隐藏index.php的问题
2019/10/12 PHP
可拖动窗口,附带鼠标控制渐变透明,开启关闭功能
2006/06/26 Javascript
扩展jQuery对象时如何扩展成员变量具体怎么实现
2014/04/25 Javascript
使用typeof方法判断undefined类型
2014/09/09 Javascript
Javascript基础知识(二)事件
2014/09/29 Javascript
JavaScript进阶练习及简单实例分析
2016/06/03 Javascript
分享JavaScript监听全部Ajax请求事件的方法
2016/08/28 Javascript
jQuery实现弹窗居中效果类似alert()
2017/02/27 Javascript
微信小程序用户信息encryptedData详解
2018/08/24 Javascript
vue实现在一个方法执行完后执行另一个方法的示例
2018/08/25 Javascript
React 使用Hooks简化受控组件的状态绑定
2019/03/18 Javascript
vue之封装多个组件调用同一接口的案例
2020/08/11 Javascript
Vue+element+cookie记住密码功能的简单实现方法
2020/09/20 Javascript
[01:04:02]DOTA2-DPC中国联赛 正赛 Elephant vs IG BO3 第二场 1月24日
2021/03/11 DOTA
windows下python和pip安装教程
2018/05/25 Python
python如何爬取网站数据并进行数据可视化
2019/07/08 Python
wxPython修改文本框颜色过程解析
2020/02/14 Python
利用PyQt中的QThread类实现多线程
2020/02/18 Python
python爬虫开发之urllib模块详细使用方法与实例全解
2020/03/09 Python
pygame实现飞机大战
2020/03/11 Python
基于HTML5 FileSystem API的使用介绍
2013/04/24 HTML / CSS
HTML5 canvas基本绘图之绘制线条
2016/06/27 HTML / CSS
西班牙英格列斯百货官网:El Corte Inglés
2016/09/25 全球购物
英国行业制服供应商:Alexandra
2019/09/14 全球购物
进程的查看和调度分别使用什么命令
2013/12/14 面试题
党员干部承诺书范文
2014/03/25 职场文书
中药学专业毕业生推荐信
2014/07/10 职场文书
2014党员学习《反腐倡廉警示教育读本》思想汇报
2014/09/13 职场文书
2019财务转正述职报告
2019/06/27 职场文书
jQuery class属性操作addClass()与removeClass()、hasClass()、toggleClass()
2021/03/31 jQuery
Win11如何修改dns?Win11修改dns图文教程
2022/01/18 数码科技