PhotoShop图层混合模式的Canvas实现
2015-11-16 16:14
621 查看
前端开发人员可能会遇到这样一个问题。
当设计人员给到一个PSD以后,会发现其中有些图层是有图层混合效果的。
这样会产生一个情况就是,我们为了这个效果而不得不将背景+带混合的图层切到一起。
当这样的元素多了以后,我们所切出的图片就会越来越大并且难以修改。
那么,本章我们将讲解如何使用Canvas元素来实现混合模式。
以达到减少图片体量和数量的效果。
首先,我们来讲一下基本实现原理。
大家可能都知道,Canvas是位图处理,Svg是矢量处理。那么什么是位图,什么是矢量图呢?
请看以下图片进行对比:
图像引用自互联网,原文地址:http://jingyan.baidu.com/album/54b6b9c0dbef682d583b4722.html?picindex=2
从上图可知,100%大小的矢量图在缩放到800%的时候并没有出现失真的情况,即:没有马赛克。
而位图则出现了万恶的马赛克,图像已经变得模糊不清了。
那么,为什么我们要使用Canvas呢?
因为网上太多类似的文章了,所以这里直接外链。
就本章节的内容来说,我们使用Canvas是为了使用像素处理。
为了方便读者实践,这里给出两张实验图片。(图片取自网络,请勿用于商业用途,如有侵犯请联系本人进行处理,感激不尽)
原图(假设图片名为:background.jpg)
混合图(假设图片名为:butterfly.png)
实现效果的前置代码:
1.将两张图片加载进来。
2.创建一个canvas元素并获取其context。
3.图片加载完成后触发名为process的函数。
好的,现在我们来仔细看看process函数里都做了什么操作。
好的,现在我们进入华丽时间!~
1.正常模式,processor需要指定为
normal
2.溶解,processor需要指定为 dissolve
3.变暗,processor需要指定为 darken
4.正片叠底,processor需要指定为 multiply
5.颜色加深,processor需要指定为 colorBurn
6.线性加深,processor需要指定为 linearBurn
7.深色,processor需要指定为 darkerColor
8.变亮,processor需要指定为 lighten
9.滤色,processor需要指定为 screen
10.颜色减淡,processor需要指定为 colorDodge
11.线性减淡,processor需要指定为
linearDodge
12.浅色,processor需要指定为 lighterColor
13.叠加,processor需要指定为 overlay
14.柔光,processor需要指定为 softLight
15.强光,processor需要指定为 hardLight
16.亮光,processor需要指定为 vividLight
17.线性光,processor需要指定为 linearLight
18.点光,processor需要指定为 pinLight
19.实色混合,processor需要指定为 hardMix
20.差值,processor需要指定为 difference
21.排除,processor需要指定为 exclusion
22.减去,processor需要指定为 subtract
23.划分,processor需要指定为 divide
至此完成。您可以自己动手实验啦~~~
非常感谢您的阅读!您的支持是我的动力!
当设计人员给到一个PSD以后,会发现其中有些图层是有图层混合效果的。
这样会产生一个情况就是,我们为了这个效果而不得不将背景+带混合的图层切到一起。
当这样的元素多了以后,我们所切出的图片就会越来越大并且难以修改。
那么,本章我们将讲解如何使用Canvas元素来实现混合模式。
以达到减少图片体量和数量的效果。
首先,我们来讲一下基本实现原理。
大家可能都知道,Canvas是位图处理,Svg是矢量处理。那么什么是位图,什么是矢量图呢?
请看以下图片进行对比:
图像引用自互联网,原文地址:http://jingyan.baidu.com/album/54b6b9c0dbef682d583b4722.html?picindex=2
从上图可知,100%大小的矢量图在缩放到800%的时候并没有出现失真的情况,即:没有马赛克。
而位图则出现了万恶的马赛克,图像已经变得模糊不清了。
那么,为什么我们要使用Canvas呢?
因为网上太多类似的文章了,所以这里直接外链。
就本章节的内容来说,我们使用Canvas是为了使用像素处理。
为了方便读者实践,这里给出两张实验图片。(图片取自网络,请勿用于商业用途,如有侵犯请联系本人进行处理,感激不尽)
原图(假设图片名为:background.jpg)
混合图(假设图片名为:butterfly.png)
实现效果的前置代码:
// 指定要使用的处理器,这里暂时不指定 var processor = ""; // 所有的处理器都在这个对象下 var pixProcessor = {}; var imgBackground = new Image(); var imgButterfly = new Image(); imgBackground.onload = imgButterfly.onload = function () { this.loaded = true; if (imgBackground.loaded && imgButterfly.loaded) { process(); } }; imgBackground.src = "background.jpg"; imgButterfly.src = "butterfly.png"; var canvas = document.createElement("canvas"); canvas.width = 610; canvas.height = 502; var context = canvas.getContext("2d");以上代码十分好理解。
1.将两张图片加载进来。
2.创建一个canvas元素并获取其context。
3.图片加载完成后触发名为process的函数。
好的,现在我们来仔细看看process函数里都做了什么操作。
function process() { // 计算蝴蝶图片相对背景图片的中心位置 var centerX = (imgBackground.width - imgButterfly.width) / 2; var centerY = (imgBackground.height - imgButterfly.height) / 2; // 绘制背景图 context.drawImage(imgBackground, 0, 0); // 通过getImageData函数获取背景图片中,蝴蝶图片所应该在的区域的像素数据 var backgroundData = context.getImageData(centerX, centerY, imgButterfly.width, imgButterfly.height); // 缓存ImageData中的data数组,这才是我们要操作的东西 var backgroundPixs = backgroundData.data; // 清空一次画布 context.clearRect(0, 0, canvas.width, canvas.height); // 绘制蝴蝶图 context.drawImage(imgButterfly, centerX, centerY); // 不解释 var butterflyData = context.getImageData(centerX, centerY, imgButterfly.width, imgButterfly.height); // 不解释 var butterflyPixs = butterflyData.data; // 再次绘制背景图 context.drawImage(imgBackground, 0, 0); // 再次绘制蝴蝶图(反正这句话也没什么卵用,忘了当时为啥要写这句话了) context.drawImage(imgButterfly, centerX, centerY); // 若没有定义处理器则不进行处理 if (typeof processor != "undefined") { var newPix; for (var i = 0; i < backgroundPixs.length; i += 4) { // 跳过全透明像素 if (butterflyPixs[i + 3] == 0) continue; // 传入两个图像对应的像素进行处理 newPix = pixProcesser[processor]({ red: backgroundPixs[i], green: backgroundPixs[i + 1], blue: backgroundPixs[i + 2], alpha: backgroundPixs[i + 3] }, { red: butterflyPixs[i], green: butterflyPixs[i + 1], blue: butterflyPixs[i + 2], alpha: butterflyPixs[i + 3] }); if (newPix) { // 将处理好的像素赋值给背景图ImageData(实际上你传给蝴蝶图也没问题,只是下面putImageData的时候需要指向蝴蝶图罢了) backgroundPixs[i] = newPix.red; backgroundPixs[i + 1] = newPix.green; backgroundPixs[i + 2] = newPix.blue; } } // 好的,将处理结果交给浏览器 context.putImageData(backgroundData, centerX, centerY); } if (document.body) { document.appendChild(canvas); } else { window.addEventListener("load", function () { document.appendChild(canvas); }, false); } }
好的,现在我们进入华丽时间!~
1.正常模式,processor需要指定为
normal
pixProcesser.normal = function (background, butterfly) { /// <summary>正常模式</summary> var alpha = butterfly.alpha; return { red: butterfly.red * alpha + background.red * (1 - alpha), green: butterfly.green * alpha + background.green * (1 - alpha), blue: butterfly.blue * alpha + background.blue * (1 - alpha), alpha: butterfly.alpha * alpha + background.alpha * (1 - alpha) } };
2.溶解,processor需要指定为 dissolve
pixProcesser.dissolve: function (background, butterfly) { /// <summary>溶解</summary> // 正式用判断条件 //if (Math.floor(Math.random() * 100) > (butterfly.alpha / 255 * 100)) { // 测试用判断条件 if (Math.floor(Math.random() * 100) > 50) { return background; } else { return butterfly; } };
3.变暗,processor需要指定为 darken
pixProcesser.darken: function (background, butterfly) { /// <summary>变暗</summary> return { red: Math.min(background.red, butterfly.red), green: Math.min(background.green, butterfly.green), blue: Math.min(background.blue, butterfly.blue), alpha: Math.min(background.alpha, butterfly.alpha) }; };
4.正片叠底,processor需要指定为 multiply
pixProcesser.multiply: function (background, butterfly) { /// <summary>正片叠底</summary> return { red: butterfly.red * background.red / 255, green: butterfly.green * background.green / 255, blue: butterfly.blue * background.blue / 255, alpha: butterfly.alpha * background.alpha / 255 }; };
5.颜色加深,processor需要指定为 colorBurn
pixProcesser.colorBurn: function (background, butterfly) { /// <summary>颜色加深</summary> return { red: Math.max(0, background.red + butterfly.red - 255) * 255 / butterfly.red, green: Math.max(0, background.green + butterfly.green - 255) * 255 / butterfly.green, blue: Math.max(0, background.blue + butterfly.blue - 255) * 255 / butterfly.blue, alpha: Math.max(0, background.alpha + butterfly.alpha - 255) * 255 / butterfly.alpha }; };
6.线性加深,processor需要指定为 linearBurn
pixProcesser.linearBurn: function (background, butterfly) { /// <summary>线性加深</summary> return { red: Math.max(0, background.red + butterfly.red - 255), green: Math.max(0, background.green + butterfly.green - 255), blue: Math.max(0, background.blue + butterfly.blue - 255), alpha: Math.max(0, background.alpha + butterfly.alpha - 255) }; };
7.深色,processor需要指定为 darkerColor
pixProcesser.darkerColor: function (background, butterfly) { /// <summary>深色</summary> if ((background.red + background.green + background.blue + background.alpha) < (butterfly.red + butterfly.green + butterfly.blue + butterfly.alpha)) { return background; } else { return butterfly; } };
8.变亮,processor需要指定为 lighten
pixProcesser.lighten: function (background, butterfly) { /// <summary>变亮</summary> return { red: Math.max(background.red, butterfly.red), green: Math.max(background.green, butterfly.green), blue: Math.max(background.blue, butterfly.blue), alpha: Math.max(background.alpha, butterfly.alpha) }; };
9.滤色,processor需要指定为 screen
pixProcesser.screen: function (background, butterfly) { /// <summary>滤色</summary> return { red: 255 - (255 - butterfly.red) * (255 - background.red) / 255, green: 255 - (255 - butterfly.green) * (255 - background.green) / 255, blue: 255 - (255 - butterfly.blue) * (255 - background.blue) / 255, alpha: 255 - (255 - butterfly.alpha) * (255 - background.alpha) / 255 }; };
10.颜色减淡,processor需要指定为 colorDodge
pixProcesser.colorDodge: function (background, butterfly) { /// <summary>颜色减淡</summary> return { red: background.red + butterfly.red * background.red / (255 - butterfly.red), green: background.green + butterfly.green * background.green / (255 - butterfly.green), blue: background.blue + butterfly.blue * background.blue / (255 - butterfly.blue), alpha: background.alpha + butterfly.alpha * background.alpha / (255 - butterfly.alpha) }; };
11.线性减淡,processor需要指定为
linearDodge
pixProcesser.linearDodge: function (background, butterfly) { /// <summary>线性减淡</summary> return { red: Math.min(background.red + butterfly.red, 255), green: Math.min(background.green + butterfly.green, 255), blue: Math.min(background.blue + butterfly.blue, 255), alpha: Math.min(background.alpha + butterfly.alpha, 255) }; };
12.浅色,processor需要指定为 lighterColor
pixProcesser.lighterColor: function (background, butterfly) { /// <summary>浅色</summary> if ((background.red + background.green + background.blue + background.alpha) > (butterfly.red + butterfly.green + butterfly.blue + butterfly.alpha)) { return background; } else { return butterfly; } };
13.叠加,processor需要指定为 overlay
pixProcesser.overlay: function (background, butterfly) { /// <summary>叠加</summary> return { red: 255 - (255 - butterfly.red) * (255 - background.red) / 128, green: 255 - (255 - butterfly.green) * (255 - background.green) / 128, blue: 255 - (255 - butterfly.blue) * (255 - background.blue) / 128, alpha: 255 - (255 - butterfly.alpha) * (255 - background.alpha) / 128 }; };
14.柔光,processor需要指定为 softLight
pixProcesser.softLight: function (background, butterfly) { /// <summary>柔光</summary> return { red: background.red + (2 * butterfly.red - 255) * (Math.sqrt(background.red / 255) * 255 - background.red) / 255, green: background.green + (2 * butterfly.green - 255) * (Math.sqrt(background.green / 255) * 255 - background.green) / 255, blue: background.blue + (2 * butterfly.blue - 255) * (Math.sqrt(background.blue / 255) * 255 - background.blue) / 255, alpha: background.alpha + (2 * butterfly.alpha - 255) * (Math.sqrt(background.alpha / 255) * 255 - background.alpha) / 255 }; };
15.强光,processor需要指定为 hardLight
pixProcesser.hardLight: function (background, butterfly) { /// <summary>强光</summary> return { red: butterfly.red > 128 ? 255 - (255 - butterfly.red) * (255 - background.red) / 128 : butterfly.red * background.red / 128, green: butterfly.green > 128 ? 255 - (255 - butterfly.green) * (255 - background.green) / 128 : butterfly.green * background.green / 128, blue: butterfly.blue > 128 ? 255 - (255 - butterfly.blue) * (255 - background.blue) / 128 : butterfly.blue * background.blue / 128, alpha: butterfly.alpha > 128 ? 255 - (255 - butterfly.alpha) * (255 - background.alpha) / 128 : butterfly.alpha * background.alpha / 128 }; };
16.亮光,processor需要指定为 vividLight
pixProcesser.vividLight: function (background, butterfly) { /// <summary>亮光</summary> return { red: butterfly.red <= 128 ? 255 - (255 - background.red) / (2 * butterfly.red) * 255 : background.red / (2 * (255 - butterfly.red)) * 255, green: butterfly.green <= 128 ? 255 - (255 - background.green) / (2 * butterfly.green) * 255 : background.green / (2 * (255 - butterfly.green)) * 255, blue: butterfly.blue <= 128 ? 255 - (255 - background.blue) / (2 * butterfly.blue) * 255 : background.blue / (2 * (255 - butterfly.blue)) * 255, alpha: butterfly.alpha <= 128 ? 255 - (255 - background.alpha) / (2 * butterfly.alpha) * 255 : background.alpha / (2 * (255 - butterfly.alpha)) * 255 }; };
17.线性光,processor需要指定为 linearLight
pixProcesser.linearLight: function (background, butterfly) { /// <summary>线性光</summary> return { red: Math.min(2 * butterfly.red + background.red - 255, 255), green: Math.min(2 * butterfly.green + background.green - 255, 255), blue: Math.min(2 * butterfly.blue + background.blue - 255, 255), alpha: Math.min(2 * butterfly.alpha + background.alpha - 255, 255) }; };
18.点光,processor需要指定为 pinLight
pixProcesser.pinLight: function (background, butterfly) { /// <summary>点光</summary> if (typeof pixProcesser.pinLightProcess == "undefined") { pixProcesser.pinLightProcess = function (sourceColor, blendColor) { return blendColor <= 128 ? Math.min(sourceColor, 2 * blendColor) : Math.max(sourceColor, 2 * blendColor - 255); }; } return { red: pixProcesser.pinLightProcess(background.red, butterfly.red), green: pixProcesser.pinLightProcess(background.green, butterfly.green), blue: pixProcesser.pinLightProcess(background.blue, butterfly.blue), alpha: pixProcesser.pinLightProcess(background.alpha, butterfly.alpha) }; };
19.实色混合,processor需要指定为 hardMix
pixProcesser.hardMix: function (background, butterfly) { /// <summary>实色混合</summary> return { red: (background.red + butterfly.red) < 255 ? 0 : 255, green: (background.green + butterfly.green) < 255 ? 0 : 255, blue: (background.blue + butterfly.blue) < 255 ? 0 : 255, alpha: (background.alpha + butterfly.alpha) < 255 ? 0 : 255 }; };
20.差值,processor需要指定为 difference
pixProcesser.difference: function (background, butterfly) { /// <summary>差值</summary> return { red: Math.abs(butterfly.red - background.red), green: Math.abs(butterfly.green - background.green), blue: Math.abs(butterfly.blue - background.blue), alpha: Math.abs(butterfly.alpha - background.alpha), }; };
21.排除,processor需要指定为 exclusion
pixProcesser.exclusion: function (background, butterfly) { /// <summary>排除</summary> return { red: (butterfly.red + background.red) - butterfly.red * background.red / 128, green: (butterfly.green + background.green) - butterfly.green * background.green / 128, blue: (butterfly.blue + background.blue) - butterfly.blue * background.blue / 128, alpha: (butterfly.alpha + background.alpha) - butterfly.alpha * background.alpha / 128 }; };
22.减去,processor需要指定为 subtract
pixProcesser.subtract: function (background, butterfly) { /// <summary>减去</summary> return { red: Math.max(0, background.red - butterfly.red), green: Math.max(0, background.green - butterfly.green), blue: Math.max(0, background.blue - butterfly.blue), alpha: Math.max(0, background.alpha - butterfly.alpha) }; };
23.划分,processor需要指定为 divide
pixProcesser.divide: function (background, butterfly) { /// <summary>划分</summary> return { red: (background.red / butterfly.red) * 255, green: (background.green / butterfly.green) * 255, blue: (background.blue / butterfly.blue) * 255, alpha: (background.alpha / butterfly.alpha) * 255, }; };
至此完成。您可以自己动手实验啦~~~
非常感谢您的阅读!您的支持是我的动力!
相关文章推荐
- tomcat 分割catalina日志【log4j配置方式】
- Nginx服务器的安装与一些基本配置总结
- linux 修改系统时间
- tomcat管理多项目,共享jar包
- FFMPEG--最简单的视频网站(点播、直播)
- ecshop 变量表
- centos7的安装及配置
- 面向业务的立体化高可用架构设计
- Xshell连接不上Ubuntu解决方式
- Linux进程间通信(IPC)编程实践(五)消息队列实现回射客户/服务器
- Linux设置服务自启动的三种方式
- Linux Svn 安装过程及配置
- 桌面应用程序和网站引入Mapl中的数学引擎
- linux系统时间和硬件时间设置
- linux静态Ip地址配置
- 腾讯最赚钱的部门是怎么做运维的?
- Centos下配置node.js环境
- Nginx和Tomcat负载均衡实现session共享实现
- 微软产品与各厂商的比较
- Linux用户身份切换