纯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 相关文章推荐
总结一些js自定义的函数
Aug 05 Javascript
js控制div及网页相关属性的代码
Dec 19 Javascript
JavaScript CSS修改学习第二章 样式
Feb 19 Javascript
JavaScript获取/更改文本框的值的实例代码
Aug 02 Javascript
jQuery实现简单的列表式导航菜单效果代码
Aug 31 Javascript
深入探讨前端框架react
Dec 09 Javascript
基于jQuery的左滑出现删除按钮的示例
Aug 29 jQuery
javascript实现文件拖拽事件
Mar 29 Javascript
jQuery插件Validation表单验证详解
May 26 jQuery
JS通过位运算实现权限加解密
Aug 14 Javascript
代码分析vue中如何配置less
Sep 28 Javascript
JS实现的检验身份证格式并输出出生日期,年龄,性别,出生地示例
May 17 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 mongodb操作类定义与用法示例【适合mongodb2.x和mongodb3.x】
2018/06/16 PHP
基于PHP实现短信验证码发送次数限制
2020/07/11 PHP
一个很酷的拖动层的js类,兼容IE及Firefox
2009/06/23 Javascript
基于jQuery的动态表格插件
2011/03/28 Javascript
select标签模拟/美化方法采用JS外挂式插件
2013/04/01 Javascript
js 获取元素下面所有li的两种方法
2014/04/14 Javascript
javascript 自定义回调函数示例代码
2014/09/26 Javascript
js实现大转盘抽奖游戏实例
2015/06/24 Javascript
基于vue.js实现图片轮播效果
2016/12/01 Javascript
Bootstrap多级菜单的实现代码
2017/05/23 Javascript
javascript 中select框触发事件过程的分析
2017/08/01 Javascript
详解如何在webpack中做预渲染降低首屏空白时间
2018/08/22 Javascript
Vue 修改网站图标的方法
2020/12/31 Vue.js
[11:33]DAC2018 4.5SOLO赛决赛 MidOne vs Paparazi第二场
2018/04/06 DOTA
python 基础学习第二弹 类属性和实例属性
2012/08/27 Python
python中查找excel某一列的重复数据 剔除之后打印
2013/02/10 Python
使用python分析git log日志示例
2014/02/27 Python
黑科技 Python脚本帮你找出微信上删除你好友的人
2016/01/07 Python
python 类对象和实例对象动态添加方法(分享)
2017/12/31 Python
微信跳一跳python自动代码解读1.0
2018/01/12 Python
Python 数据处理库 pandas 入门教程基本操作
2018/04/19 Python
Selenium控制浏览器常见操作示例
2018/08/13 Python
python中PS 图像调整算法原理之亮度调整
2019/06/28 Python
Python 控制终端输出文字的实例
2019/07/12 Python
Python从MySQL数据库中面抽取试题,生成试卷
2021/01/14 Python
英国殿堂级有机护肤品牌:Rodial
2017/04/17 全球购物
巴西宠物店在线:Geração Pet
2017/05/31 全球购物
越南电子产品购物网站:FPT Shop
2017/12/02 全球购物
iHerb台湾:维生素、保健品和健康产品
2018/01/31 全球购物
毕业生就业自荐书
2013/12/15 职场文书
创先争优制度
2014/01/21 职场文书
秋游活动策划方案
2014/02/16 职场文书
给女朋友道歉的话大全
2015/01/20 职场文书
暂停营业通知
2015/04/25 职场文书
2015年信息宣传工作总结
2015/05/26 职场文书
写作技巧:如何撰写一份优秀的营销策划书
2019/08/13 职场文书