├── .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 | --------------------------------------------------------------------------------