JavaScript写一个简单的Ps滤镜效果

47次阅读

共计 5578 个字符,预计需要花费 14 分钟才能阅读完成。

效果预览

思路
其实非常非常赶单~CSS3 多了一个 filter 的属性,非常强大(兼容性一般)!我们只要根据输入的值 / 滑块滑动的值来动态更改 css 中 filter 属性的值即可
filter

none 默认值,没有效果。
blur(px) 给图像设置高斯模糊。”radius” 一值设定高斯函数的标准差,或者是屏幕上以多少像素融在一起,所以值越大越模糊;不接受百分比值。

brightness(%) 给图片应用一种线性乘法,使其看起来更亮或更暗。如果值是 0%,图像会全黑。值是 100%,则图像无变化。其他的值对应线性乘数效果。值超过 100% 也是可以的,图像会比原来更亮。如果没有设定值,默认是 1。
contrast(%) 调整图像的对比度。值是 0% 的话,图像会全黑。值是 100%,图像不变。值可以超过 100%,意味着会运用更低的对比。若没有设置值,默认是 1。
drop-shadow(h-shadow v-shadow blur spread color) 给图像设置一个阴影效果。阴影是合成在图像下面,可以有模糊度的,可以以特定颜色画出的遮罩图的偏移版本。函数接受 <shadow>(在 CSS3 背景中定义) 类型的值,除了 ”inset” 关键字是不允许的。该函数与已有的 box-shadow box-shadow 属性很相似;不同之处在于,通过滤镜,一些浏览器为了更好的性能会提供硬件加速。
grayscale(%) 将图像转换为灰度图像。值定义转换的比例。值为 100% 则完全转为灰度图像,值为 0% 图像无变化。值在 0% 到 100% 之间,则是效果的线性乘子。若未设置,值默认是 0;
hue-rotate(deg) 图像应用色相旋转。”angle” 一值设定图像会被调整的色环角度值。值为 0deg,则图像无变化。若值未设置,默认值是 0deg。该值虽然没有最大值,超过 360deg 的值相当于又绕一圈。
invert(%) 反转输入图像。值定义转换的比例。100% 的价值是完全反转。值为 0% 则图像无变化。值在 0% 和 100% 之间,则是效果的线性乘子。若值未设置,值默认是 0。
opacity(%) 转化图像的透明程度。值定义转换的比例。值为 0% 则是完全透明,值为 100% 则图像无变化。值在 0% 和 100% 之间,则是效果的线性乘子,也相当于图像样本乘以数量。若值未设置,值默认是 1。该函数与已有的 opacity 属性很相似,不同之处在于通过 filter,一些浏览器为了提升性能会提供硬件加速。
saturate(%) 转换图像饱和度。值定义转换的比例。值为 0% 则是完全不饱和,值为 100% 则图像无变化。其他值,则是效果的线性乘子。超过 100% 的值是允许的,则有更高的饱和度。若值未设置,值默认是 1。
sepia(%) 将图像转换为深褐色。值定义转换的比例。值为 100% 则完全是深褐色的,值为 0% 图像无变化。值在 0% 到 100% 之间,则是效果的线性乘子。若未设置,值默认是 0;
url() URL 函数接受一个 XML 文件,该文件设置了 一个 SVG 滤镜,且可以包含一个锚点来指定一个具体的滤镜元素。

使用直接就这样
img {
-webkit-filter: contrast(200%); /* Chrome, Safari, Opera */
filter: contrast(200%) opacity(0.5) // 要多少属性加多少;
}
开始操作
写一个过滤属性滑块和输入框,互相绑定值,如果用 vue 就简单了 hhh
//html
<li>
<label for=”contrast”> 对比度 (0-200):</label>
<input id=”contrast” max=”200″ min=”0″ step=”1″ type=”range”>
<input id=”contrast-val” class=”val-box” type=”number”>
</li>
//js
// 注册过滤器
function filter(type) {
// 获取滤镜类型关联的 dom 节点
// 绑定 change 事件,还有回车按键事件

let ele = document.getElementById(type);
let ele_val = document.getElementById(type + ‘-val’);

// 输入框输入值按下回车,把值更新到滑块上
ele_val.addEventListener(‘keyup’,function(e){
if(e.keyCode == 13){
ele.value = ele_val.value;
// 同时更新滤镜效果
setCss(type, ele_val.value);

}
})

// 滑块滑动的时候,把值更新在右边的输入框中
ele.addEventListener(‘change’, function() {
ele_val.value = ele.value;
// 同时更新滤镜效果
setCss(type, ele_val.value);
});
}
写一个文件选择,预览图片
//html
<input id=”file” type=”file” accept=”image/*”>
<!– 图片预览框 –>
<div>
<img id=”img” src=”” alt=””>
</div>
// 选择文件
function fileSelect() {
let img = document.getElementById(‘img’);
document.getElementById(‘file’).onchange = function() {
var reader = new FileReader();
reader.onload = function(e) {
img.src = e.target.result;
}
reader.readAsDataURL(this.files[0]);
}
}
写一个根据输入值更新 CSS 的方法
// 更新 css 属性
function setCss(type, val) {
let img = document.getElementById(‘img’);
// 已经存在某个滤镜, 更改滤镜数值
if (img.style.filter.indexOf(type) > -1) {
// 利用正则则出滤镜名称更改其值
let reg = new RegExp(“(?<=” + type + “)” + “\\(.*\\)”, “g”)
img.style.filter = img.style.filter.replace(reg, function(match) {return `(${val/100})` });
} else {
// 直接添加新滤镜
img.style.filter += `${type}(${val/100})`
}
}
注意

由于这个 demo 只是随便写写,只是前几天用到这个 filter 属性感觉有点厉害,就拿来玩玩,文中的代码写得很丑,也没什么规范,只适用于‘写来玩玩’的范畴,一些输入验证,节流,参数的规范都没有做,见谅。
本来还打算做一个导出使用滤镜后的照片的,用的 html2canvas 来截图导出,然后发现,它不支持!!!不支持这个 css 属性!!截出来的图是原图!这可是真的难受啊马飞,现在还没有解决方案,如果有大佬知道如何保存使用滤镜后的图片到本地的,请在评论区留下您的想法,非常感谢!

辣鸡源码
<!DOCTYPE html>
<html lang=”en”>

<head>
<meta charset=”UTF-8″>
<title>photoshop-web</title>
</head>

<body>
<ul>
<li>
<label for=”brightness”> 亮度 (0-200):</label>
<input id=”brightness” max=”200″ min=”0″ step=”1″ type=”range”>
<input id=”brightness-val” class=”val-box” type=”number”>
</li>
<li>
<label for=”contrast”> 对比度 (0-200):</label>
<input id=”contrast” max=”200″ min=”0″ step=”1″ type=”range”>
<input id=”contrast-val” class=”val-box” type=”number”>
</li>
<li>
<label for=”grayscale”> 灰度 (0-100):</label>
<input id=”grayscale” max=”100″ min=”0″ step=”1″ type=”range”>
<input id=”grayscale-val” class=”val-box” type=”number”>
</li>
<li>
<label for=”saturate”> 饱和度 (0-200):</label>
<input id=”saturate” max=”200″ min=”0″ step=”1″ type=”range”>
<input id=”saturate-val” class=”val-box” type=”number”>
</li>
<li>
<label for=”opacity”> 透明度 (0-100):</label>
<input id=”opacity” max=”100″ min=”0″ step=”1″ type=”range”>
<input id=”opacity-val” class=”val-box” type=”number”>
</li>
<li>
<label for=”invert”> 反相 (0-100):</label>
<input id=”invert” max=”100″ min=”0″ step=”1″ type=”range”>
<input id=”invert-val” class=”val-box” type=”number”>
</li>
</ul>
<button id=”reset”> 重置效果 </button>
<input id=”file” type=”file” accept=”image/*”>
<div>
<img id=”img” src=”” alt=””>
</div>
</body>
<script>
// 选择文件
function fileSelect() {
let img = document.getElementById(‘img’);
document.getElementById(‘file’).onchange = function() {
var reader = new FileReader();
reader.onload = function(e) {
img.src = e.target.result;
}
reader.readAsDataURL(this.files[0]);
}
}
// 重置效果
function reset() {
let reset_btn = document.getElementById(‘reset’);
let val_boxes = document.getElementsByClassName(‘val-box’);
let val_arr = Array.prototype.slice.call(val_boxes);
let img = document.getElementById(‘img’);

reset_btn.addEventListener(‘click’, function() {
// 所有的数据输入重置为空
val_arr.forEach(function(item) {
item.value = “”;
});
// 去掉图片的 css 属性
img.style.filter = “”;
})
}
// 注册过滤器
function filter(type) {
// 获取滤镜类型关联的 dom 节点
// 绑定 change 事件
// 更改右侧输入框的显示的值,以及更新滤镜效果
let ele = document.getElementById(type);
let ele_val = document.getElementById(type + ‘-val’);
ele_val.addEventListener(‘keyup’,function(e){
if(e.keyCode == 13){
ele.value = ele_val.value;
setCss(type, ele_val.value);

}
})
ele.addEventListener(‘change’, function() {
ele_val.value = ele.value;
setCss(type, ele_val.value);
});
}
// 更新 css 属性
function setCss(type, val) {
let img = document.getElementById(‘img’);
// 已经存在某个滤镜, 更改滤镜数值
if (img.style.filter.indexOf(type) > -1) {
let reg = new RegExp(“(?<=” + type + “)” + “\\(.*\\)”, “g”)
img.style.filter = img.style.filter.replace(reg, function(match) {return `(${val/100})` });
} else {
// 直接添加新滤镜
img.style.filter += `${type}(${val/100})`
}
}
window.onload = function() {
// 亮度
filter(‘brightness’);
// 对比度
filter(‘contrast’);
// 灰度
filter(‘grayscale’);
// 饱和度
filter(‘saturate’);
// 透明度
filter(‘opacity’);
// 反相
filter(‘invert’);
// 注册重置
reset();
// 注册文件选择
fileSelect();
}
</script>

</html>

正文完
 0