纯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 相关文章推荐
Jquery iframe内部出滚动条
Feb 11 Javascript
在JavaScript里嵌入大量字符串常量的实现方法
Jul 07 Javascript
两个select多选模式的选项相互移动(示例代码)
Jan 11 Javascript
javascript动态添加、修改、删除对象的属性与方法详解
Jan 27 Javascript
jquery实现一个简单好用的弹出框
Sep 26 Javascript
javascript实现一个简单的弹出窗
Feb 22 Javascript
获取JS中网页各种高宽与位置的方法总结
Jul 27 Javascript
基于MVC5和Bootstrap的jQuery TreeView树形控件(一)之数据支持json字符串、list集合
Aug 11 Javascript
jQuery中绑定事件bind() on() live() one()的异同
Feb 23 Javascript
vue webpack实用技巧总结
Apr 24 Javascript
bootstrap 弹出框modal添加垂直方向滚轴效果
Jul 09 Javascript
基于JS判断对象是否是数组
Jan 10 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
PHP数组实例总结与说明
2011/08/23 PHP
php中一个有意思的日期逻辑处理
2012/03/25 PHP
PHP判断远程图片或文件是否存在的实现代码
2014/02/20 PHP
PHP函数超时处理方法
2016/02/14 PHP
JavaScript面向对象编程
2008/03/02 Javascript
写得不错的jquery table鼠标经过变色代码
2013/09/27 Javascript
jQuery处理json数据返回数组和输出的方法
2015/03/11 Javascript
JavaScript控制listbox列表框的项目上下移动的方法
2015/03/18 Javascript
javascript为按钮注册回车事件(设置默认按钮)的方法
2015/05/09 Javascript
javascript事件委托的方式绑定详解
2015/06/10 Javascript
举例详解Python中smtplib模块处理电子邮件的使用
2015/06/24 Javascript
javascript作用域问题实例分析
2015/07/13 Javascript
浅谈jQuery中hide和fadeOut的区别 show和fadeIn的区别
2016/08/18 Javascript
vue实现ToDoList简单实例
2017/02/07 Javascript
BootStrap注意事项小结(五)表单
2017/03/10 Javascript
vue2.0 中#$emit,$on的使用详解
2017/06/07 Javascript
修改 bootstrap table 默认detailRow样式的实例代码
2017/07/21 Javascript
vue路由守卫+登录态管理实例分析
2019/05/21 Javascript
layer.js open 隐藏滚动条的例子
2019/09/05 Javascript
Vue实现摇一摇功能(兼容ios13.3以上)
2021/01/26 Vue.js
一个计算身份证号码校验位的Python小程序
2014/08/15 Python
用python实现面向对像的ASP程序实例
2014/11/10 Python
python实现图像识别功能
2018/01/29 Python
Python基于递归算法实现的汉诺塔与Fibonacci数列示例
2018/04/18 Python
Pandas之drop_duplicates:去除重复项方法
2018/04/18 Python
python+ffmpeg批量去视频开头的方法
2019/01/09 Python
关于不懂Chromedriver如何配置环境变量问题解决方法
2019/06/12 Python
Python 实现自动获取种子磁力链接方式
2020/01/16 Python
Tensorflow中的dropout的使用方法
2020/03/13 Python
python三引号如何输入
2020/07/06 Python
法国女性内衣购物网站:Glamuse
2019/05/13 全球购物
优秀的导游求职信范文
2014/04/06 职场文书
先进基层党组织事迹材料
2014/12/25 职场文书
background-position百分比原理详解
2021/05/08 HTML / CSS
详解Java分布式事务的 6 种解决方案
2021/06/26 Java/Android
MySQL sql模式设置引起的问题
2022/05/15 MySQL