前端开发人员可能会遇到这样一个问题。

当设计人员给到一个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,};};

至此完成。您可以自己动手实验啦~~~

非常感谢您的阅读!您的支持是我的动力!

PhotoShop图层混合模式的Canvas实现相关推荐

  1. Photoshop图层混合模式计算公式大全(转)

    混合模式可以将两个图层的色彩值紧密结合在一起,从而创造出大量的效果.在这些效果的背后实际是一些简单的数学公式在起作用.下面我将介绍photoshop cs2中所有混合模式的数学计算公式.另外还介绍了不 ...

  2. Photoshop图层混合模式计算公式大全

    下面是photoshop cs2中所有混合模式的数学计算公式,另外还介绍了不透明度,这些公式仅适用于RGB图像,对于Lab颜色图像而言,这些公式将不再适用. 1.Opacity 不透明度 C=d*A+ ...

  3. Photoshop图层混合模式公式(Unity,CG实现)

    本文主要目的来自于在unity符合美术在ps里面的演示效果. 两个图层叠加到一起的效果,废话不多说直接看效果: 图片资源在文章末尾 完整代码也在末尾 目录 目录 Multiply 正片叠底 Scree ...

  4. Photoshop图层混合模式的计算公式

    嗨,PS也是有算法的,感性认识一下上升到理性认识了 :) 其中:正片叠底和滤色是一对逆运算.正片叠底相当于变暗,滤色变亮,可以比较快速处理曝光过度和曝光不足的图片,复制原图层到新图层,2个图层直接运算 ...

  5. matlab实现图层线性光的代码,Photoshop图层混合模式之线性光模式分析

    (全文共1330字,8图,约占手机屏数7-8屏)***>"线性光"模式是一个由混合色决定混合效果的模式,混合色的明暗决定了混合色的混合方式.分析:"线性光" ...

  6. Photoshop PS图层混合模式详解

    Photoshop 7.0的图层混合选项中增添了"线性加深"模式."线性减淡"模式."亮光"模式."线性光"模式和&qu ...

  7. Ps算法Python实现:图层混合模式-色相

    1.相关文章 最近想要实现Photoshop图层混合中的色相模式,在网上查阅了众多关于混合模式实现的文章: Photoshop图层混合模式详解 PS中混合模式是什么意思? photoshop图层混合模 ...

  8. 手把手教你Photoshop中的图层混合模式(二)

    这篇教程我们继续来讲解Photoshop中的图层混合模式. 对于叠加.柔光.强光.亮光.线性光和点光模式,公式都比较复杂,所以我们不去介绍具体的计算公式了,大家有兴趣可以在网上查阅资料,我们这里介绍一 ...

  9. python图层合并_Ps算法Python实现:图层混合模式-色相

    1.相关文章 最近想要实现Photoshop图层混合中的色相模式,在网上查阅了众多关于混合模式实现的文章: 其中关于色相模式的描述基本为:色相混合模式是选择基色的亮度和饱和度值与混合色进行混合而创建的 ...

最新文章

  1. swift -charts框架雷达图
  2. 【 FPGA/IC 】谈谈复位
  3. markdown编辑器语法——背景色
  4. 【Android基础】 Launch Mode
  5. SSH 安全性和配置入门
  6. ML之FE:特征工程中常用的一些处理手段(缺失值填充、异常值检测等)及其对应的底层代码的实现
  7. 如何击败腾讯_击败股市
  8. 过春节,坐汽车回家的朋友,注意了。。
  9. niginx的高可用配置(HA)
  10. 理解saltstack 里cmd.run 配合onlyif和unless使用
  11. SQL Server Junior Database Administrator方案相关的访谈问答
  12. Storm入门学习随记
  13. 海康威视-网络通讯库错误码
  14. php 心愿墙系统源码,php开发|源码|微信留言板|微信表白墙|吐槽墙|心愿墙|2017V2.1版...
  15. Python 文本生僻字判定和拼音标注脚本
  16. 7步打造持续盈利的会员体系
  17. matlab ill,Matlab跑GMM聚类时出现Ill-conditioned covariance created at iteration xx错误提示
  18. javaweb调用python修改微信运动步数,使用小米运动接口
  19. 启用计算机来宾账号,开启Windows 10来宾账户
  20. OE链面临区块链生态新机遇

热门文章

  1. 如何写一个前端组件-以bootstrap-tab为例
  2. JavaScript 异步
  3. Vue使用Export2Excel导出表格时隐藏表头
  4. CSDN快速转载文章方法(简单)
  5. Luogu P2572 [SCOI2010]序列操作 线段树。。
  6. 收集了很多音乐播放器类的Android项目源码,非常不错的开源项目
  7. 一个绿色版本的LAMP包. (快速构建linux下的php开发环境)
  8. js封装一个判断数据类型的函数
  9. 合并多个Excel文件
  10. linux打开文件夹安装,Linux Supervisor的安装与使用入门