├── .gitignore
├── readme.md
├── jquery.blend.min.js
└── jquery.blend.js
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # jquery-blend
2 |
3 | Blending modes for jquery
4 |
5 | ### Examples
6 |
7 | #### Basic pattern
8 |
9 | // Overlay with a solid color
10 | $('img').blend({mode: 'overlay', adjustment: 'rgb(114, 25, 219)'});
11 |
12 | // Overlay with an image
13 | $('img').blend({mode: 'difference', adjustment: '/path/to/mask.jpg'});
14 |
15 | #### Usage idea
16 |
17 | $(function() {
18 | $('.display img').each(function() {
19 | $(this).blend({mode: $(this).attr('data-blend-mode'), adjustment: $(this).attr('data-blend-adjustment')});
20 | });
21 | });
22 |
23 |
24 |

25 |
26 |
27 | ### Modes
28 |
29 | - normal
30 |
31 | - darken
32 | - multiply
33 | - colorburn
34 | - linearburn
35 |
36 | - lighten
37 | - screen
38 | - colordodge
39 | - lineardodge
40 |
41 | - overlay
42 | - softlight
43 | - hardlight
44 |
45 | - difference
46 | - exclusion
47 | - subtract
--------------------------------------------------------------------------------
/jquery.blend.min.js:
--------------------------------------------------------------------------------
1 | /* http://farski.github.com/jquery-blend/license.txt */
2 | (function(l){l.fn.blend=function(j){function c(b,a){this.algorithm=b;this.precision=a;this.process=function(g,i){if(this.precision!="subpixel")return[this.algorithm(g[0],i[0]),this.algorithm(g[1],i[1]),this.algorithm(g[2],i[2])]}}j=l.extend({mode:"normal",adjustment:"rgb(128, 128, 128)",opacity:1},j);var q={normal:new c(function(b,a){return a}),darken:new c(function(b,a){return Math.min(b,a)}),multiply:new c(function(b,a){return b*a/255}),colorburn:new c(function(b,a){return a<=0?0:Math.max(255-(255-
3 | b)*255/a,0)}),linearburn:new c(function(b,a){return Math.max(0,b+a-255)}),lighten:new c(function(b,a){return Math.max(b,a)}),screen:new c(function(b,a){return 255-(255-b)*(255-a)/255}),colordodge:new c(function(b,a){return a>=255?255:Math.min(b*255/(255-a),255)}),lineardodge:new c(function(b,a){return Math.min(b+a,255)}),overlay:new c(function(b,a){return b<128?2*b*a/255:255-2*(255-b)*(255-a)/255}),softlight:new c(function(b,a){return b<128?((a>>1)+64)*b*(2/255):255-(191-(a>>1))*(255-b)*(2/255)}),
4 | hardlight:new c(function(b,a){return a<128?2*b*a/255:255-2*(255-b)*(255-a)/255}),difference:new c(function(b,a){return Math.abs(b-a)}),exclusion:new c(function(b,a){return 255-((255-b)*(255-a)/255+b*a/255)}),subtract:new c(function(b,a){return Math.max(b-a,0)})};return this.each(function(){if("getContext"in document.createElement("canvas"))this.onload=function(){var b=this,a=document.createElement("canvas"),g=a.getContext("2d");a.width=this.width;a.height=this.height;g.drawImage(this,0,0);var i=g.getImageData(0,
5 | 0,a.width,a.height),d=i.data,p=q[j.mode];if(j.adjustment.match(/^rgb/)){var k=j.adjustment.match(/rgb\(([0-9]+), ?([0-9]+), ?([0-9]+)/);k=[parseFloat(k[1],10),parseFloat(k[2],10),parseFloat(k[3],10)];for(var h=0;h= 255 ? 255 : Math.min(base * 255 / (255 - adj), 255); }),
50 | lineardodge: new Blender(function(base, adj) { return Math.min((base + adj), 255); }),
51 | //
52 | overlay: new Blender(function(base, adj) { return (base < 128) ? ((2 * base * adj) / 255) : (255 - (2 * (255 - base) * (255 - adj) / 255)); }),
53 | softlight: new Blender(function(base, adj) { return (base < 128) ? (((adj>>1) + 64) * base * (2/255)) : (255 - (191 - (adj>>1)) * (255 - base) * (2 / 255)); }),
54 | hardlight: new Blender(function(base, adj) { return adj < 128 ? (2 * base * adj) / 255 : 255 - ((2 * (255 - base) * (255 - adj)) / 255); }),
55 | //
56 | difference: new Blender(function(base, adj) { return Math.abs(base - adj); }),
57 | exclusion: new Blender(function(base, adj) { return 255 - (((255 - base) * (255 - adj) / 255) + (base * adj / 255)); }),
58 | subtract: new Blender(function(base, adj) { return Math.max((base - adj), 0); })
59 | };
60 |
61 | return this.each(function() {
62 | if ('getContext' in document.createElement('canvas')) {
63 | this.onload = function() {
64 | var self = this;
65 |
66 | var output = document.createElement('canvas');
67 | var outputContext = output.getContext('2d');
68 | output.width = this.width;
69 | output.height = this.height;
70 | outputContext.drawImage(this, 0, 0);
71 | var outputImageData = outputContext.getImageData(0, 0, output.width, output.height);
72 | var outputSubpixels = outputImageData.data;
73 |
74 | var blender = blenders[options.mode];
75 |
76 | if (options.adjustment.match(/^rgb/)) {
77 | var _rgb = options.adjustment.match(/rgb\(([0-9]+), ?([0-9]+), ?([0-9]+)/);
78 | var rgb = [parseFloat(_rgb[1], 10), parseFloat(_rgb[2], 10), parseFloat(_rgb[3], 10)];
79 |
80 | for(var i = 0; i < outputSubpixels.length; i += 4) {
81 | var pixel = [outputSubpixels[i], outputSubpixels[i+1], outputSubpixels[i+2]];
82 | var result = blender.process(pixel, rgb);
83 | outputSubpixels[i+0] = result[0];
84 | outputSubpixels[i+1] = result[1];
85 | outputSubpixels[i+2] = result[2];
86 | }
87 |
88 | outputContext.putImageData(outputImageData, 0, 0);
89 | $(self).replaceWith(output);
90 | } else {
91 | var maskImage = new Image;
92 | maskImage.src = options.adjustment;
93 | maskImage.onload = function() {
94 | var adjustment = document.createElement('canvas');
95 | var adjustmentContext = adjustment.getContext('2d');
96 | adjustment.width = self.width;
97 | adjustment.height = self.height;
98 | adjustmentContext.drawImage(maskImage, 0, 0);
99 | var adjustmentImageData = adjustmentContext.getImageData(0, 0, adjustment.width, adjustment.height);
100 | var adjustmentSubpixels = adjustmentImageData.data;
101 |
102 | for(var i = 0; i < outputSubpixels.length; i += 4) {
103 | var pixel = [outputSubpixels[i], outputSubpixels[i+1], outputSubpixels[i+2]];
104 | var adjPixel = [adjustmentSubpixels[i], adjustmentSubpixels[i+1], adjustmentSubpixels[i+2]];
105 | var result = blender.process(pixel, adjPixel);
106 | outputSubpixels[i+0] = result[0];
107 | outputSubpixels[i+1] = result[1];
108 | outputSubpixels[i+2] = result[2];
109 | }
110 |
111 | outputContext.putImageData(outputImageData, 0, 0);
112 | $(self).replaceWith(output);
113 | };
114 | }
115 | }
116 | }
117 | });
118 | }
119 | })(jQuery);
120 |
--------------------------------------------------------------------------------