├── CONTRIBUTING.md ├── README.md ├── antimoderate.js ├── antimoderate.min.js ├── bower.json ├── demo ├── 1-tiny.jpg ├── 1.jpg ├── 2-tiny.jpg ├── 2.jpg └── demo.html └── package.json /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to contribute 2 | 3 | Open to all bug reports, questions, and pull requests. 4 | 5 | ## Goals of project 6 | 7 | * To have a library that is dead simple to use 8 | * To keep the amount of overall code to a minimum (we want the lowest overhead library as possible) 9 | * To maintain absolute fallback where nojs or shitty engine will fall back to regular image loading 10 | * To improve the web experience for people with slower internet access 11 | * To have the blur effect be instantaneous 12 | * To have browser coverage and support across the board 13 | * To maintain perfect backwards compatibility 14 | 15 | ## Submitting a pull request 16 | 17 | * Ensure it works on all browsers 18 | * Run the script through [closure-compiler](https://closure-compiler.appspot.com/home) on Advanced to minify. 19 | * Make your changes in a new git branch 20 | 21 | ```shell 22 | git checkout -b my-branch master 23 | ``` 24 | 25 | * Accept the universe's collective thanks for trying to make something a bit nicer 26 | 27 | 28 | ## Have a question or feature request or...? 29 | 30 | * Check existing issues (google: `inurl:github.com/whackashoe/antimoderate MY PROBLEM`) to see if they answer 31 | * If that doesn't work, post an issue with as much relevant information as possible 32 | 33 | ## Code of conduct 34 | 35 | just kidding. 36 | 37 | 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | AntiModerate 2 | === 3 | 4 | The progressive image loading library for great good! 5 | 6 | --- 7 | 8 | 9 | Reduce loading time of page to less than a second on slow connections by loading and rendering nicely blurred micro images on the page while loading full sized images in background which replace as they finish. 10 | 11 | Has a nice blur effect thanks to [StackBlur](https://github.com/flozz/StackBlur/) so you have a good looking page while it is loading. 12 | 13 | Library is space optimized, with gzip it is less than 2kb. 14 | 15 | 16 | ![Example](http://i.imgur.com/fkgiPNe.png) 17 | 18 | ##Installation 19 | 20 | You can install this using `bower` or `npm`: 21 | 22 | ``` 23 | bower install antimoderate 24 | ``` 25 | ``` 26 | npm install antimoderate --save 27 | ``` 28 | 29 | ##Example 30 | 31 | 32 | ```html 33 | 34 | ``` 35 | 36 | ```html 37 | 38 | 43 | ``` 44 | 45 | 46 | ##License 47 | 48 | ###AntiModerate 49 | 50 | ~~~ 51 | Copyright (c) 2016 Jett LaRue 52 | 53 | Do whatever with it. 54 | 55 | ~~~ 56 | 57 | 58 | ###StackBlur Algorithm 59 | 60 | 61 | ~~~ 62 | Copyright (c) 2010 Mario Klingemann 63 | 64 | Permission is hereby granted, free of charge, to any person 65 | obtaining a copy of this software and associated documentation 66 | files (the "Software"), to deal in the Software without 67 | restriction, including without limitation the rights to use, 68 | copy, modify, merge, publish, distribute, sublicense, and/or sell 69 | copies of the Software, and to permit persons to whom the 70 | Software is furnished to do so, subject to the following 71 | conditions: 72 | 73 | The above copyright notice and this permission notice shall be 74 | included in all copies or substantial portions of the Software. 75 | 76 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 77 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 78 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 79 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 80 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 81 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 82 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 83 | OTHER DEALINGS IN THE SOFTWARE. 84 | ~~~ 85 | -------------------------------------------------------------------------------- /antimoderate.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | var scaling_factor = 1.0; 3 | 4 | var am = { 5 | mul_table: [ 6 | 256,256,200,256,72,200,79,256,149,72,15,200,132,79,36,256,198,149,108,72,42,15,240,200,164,132, 7 | 104,79,56,36,17,256,226,198,172,149,127,108,89,72,56,42,28,15,3,240,219,200,181,164,148,132,118,104,91, 8 | 79,67,56,46,36,26,17,9,256,241,226,212,198,185,172,161,149,138,127,117,108,98,89,81,72,64,56,49,42,35, 9 | 28,22,15,9,3,251,240,229,219,209,200,190,181,172,164,156,148,140,132,125,118,111,104,98,91,85,79,73,67, 10 | 62,56,51,46,41,36,31,26,22,17,13,9,5,256,249,241,233,226,219,212,205,198,191,185,179,172,166,161,155, 11 | 149,143,138,133,127,122,117,112,108,103,98,94,89,85,81,76,72,68,64,60,56,53,49,45,42,38,35,31,28,25,22, 12 | 18,15,12,9,6,3,1,251,245,240,235,229,224,219,214,209,204,200,195,190,186,181,177,172,168,164,160,156,152, 13 | 148,144,140,136,132,129,125,121,118,114,111,107,104,101,98,94,91,88,85,82,79,76,73,70,67,64,62,59,56,54, 14 | 51,48,46,43,41,38,36,33,31,29,26,24,22,19,17,15,13,11,9,7,5,3 15 | ], 16 | 17 | shg_table: [9, 11, 12, 13, 13, 14, 14], 18 | 19 | processImage: function(img, idata, scale) 20 | { 21 | var canvas = document.createElement('canvas'); 22 | 23 | var idata_img = new Image(); 24 | idata_img.onload = function() { 25 | w = img.width; 26 | h = img.height; 27 | 28 | canvas.style.width = w + 'px'; 29 | canvas.style.height = h + 'px'; 30 | canvas.width = w; 31 | canvas.height = h; 32 | 33 | var context = canvas.getContext('2d'); 34 | context.clearRect(0, 0, w, h); 35 | context.drawImage(idata_img, 0, 0, w, h); 36 | 37 | var sc = scale || scaling_factor; 38 | radius = (Math.sqrt(w * h) / Math.sqrt(idata_img.naturalWidth * idata_img.naturalHeight)) * sc; 39 | 40 | if (isNaN(radius) || radius < 1) return; 41 | 42 | radius |= 0; 43 | 44 | var imageData = canvas.getContext('2d').getImageData(0, 0, w, h); 45 | 46 | var pixels = imageData.data; 47 | 48 | var x, y, i, p, yp, yi, yw, r_sum, g_sum, b_sum, 49 | r_out_sum, g_out_sum, b_out_sum, 50 | r_in_sum, g_in_sum, b_in_sum, 51 | pr, pg, pb, rbs; 52 | 53 | var div = radius + radius + 1; 54 | var w4 = w << 2; 55 | var wMinus1 = w - 1; 56 | var hMinus1 = h - 1; 57 | var radiusPlus1 = radius + 1; 58 | var sumFactor = radiusPlus1 * (radiusPlus1 + 1) / 2; 59 | 60 | var stackStart = {r:0,g:0,b:0,a:0,next:null}; 61 | var stack = stackStart; 62 | for(i = 1; i < div; i++) { 63 | stack = stack.next = {r:0,g:0,b:0,a:0,next:null}; 64 | 65 | if (i == radiusPlus1) { 66 | var stackEnd = stack; 67 | } 68 | } 69 | stack.next = stackStart; 70 | var stackIn = null; 71 | var stackOut = null; 72 | 73 | yw = yi = 0; 74 | 75 | var mul_sum = am.mul_table[radius]; 76 | var shg_sum = am.shg_table[radius]; 77 | 78 | for(y = 0; y < h; y++) { 79 | r_in_sum = g_in_sum = b_in_sum = r_sum = g_sum = b_sum = 0; 80 | 81 | r_out_sum = radiusPlus1 * (pr = pixels[yi]); 82 | g_out_sum = radiusPlus1 * (pg = pixels[yi+1]); 83 | b_out_sum = radiusPlus1 * (pb = pixels[yi+2]); 84 | 85 | r_sum += sumFactor * pr; 86 | g_sum += sumFactor * pg; 87 | b_sum += sumFactor * pb; 88 | 89 | stack = stackStart; 90 | 91 | for(i = 0; i < radiusPlus1; i++) { 92 | stack.r = pr; 93 | stack.g = pg; 94 | stack.b = pb; 95 | stack = stack.next; 96 | } 97 | 98 | for(i = 1; i < radiusPlus1; i++) { 99 | p = yi + ((wMinus1 < i ? wMinus1 : i) << 2); 100 | r_sum += (stack.r = (pr = pixels[p])) * (rbs = radiusPlus1 - i); 101 | g_sum += (stack.g = (pg = pixels[p+1])) * rbs; 102 | b_sum += (stack.b = (pb = pixels[p+2])) * rbs; 103 | 104 | r_in_sum += pr; 105 | g_in_sum += pg; 106 | b_in_sum += pb; 107 | 108 | stack = stack.next; 109 | } 110 | 111 | 112 | stackIn = stackStart; 113 | stackOut = stackEnd; 114 | for(x = 0; x < w; x++) { 115 | pixels[yi] = (r_sum * mul_sum) >> shg_sum; 116 | pixels[yi+1] = (g_sum * mul_sum) >> shg_sum; 117 | pixels[yi+2] = (b_sum * mul_sum) >> shg_sum; 118 | 119 | r_sum -= r_out_sum; 120 | g_sum -= g_out_sum; 121 | b_sum -= b_out_sum; 122 | 123 | r_out_sum -= stackIn.r; 124 | g_out_sum -= stackIn.g; 125 | b_out_sum -= stackIn.b; 126 | 127 | p = (yw + ((p = x + radius + 1) < wMinus1 ? p : wMinus1)) << 2; 128 | 129 | r_in_sum += (stackIn.r = pixels[p]); 130 | g_in_sum += (stackIn.g = pixels[p+1]); 131 | b_in_sum += (stackIn.b = pixels[p+2]); 132 | 133 | r_sum += r_in_sum; 134 | g_sum += g_in_sum; 135 | b_sum += b_in_sum; 136 | 137 | stackIn = stackIn.next; 138 | 139 | r_out_sum += (pr = stackOut.r); 140 | g_out_sum += (pg = stackOut.g); 141 | b_out_sum += (pb = stackOut.b); 142 | 143 | r_in_sum -= pr; 144 | g_in_sum -= pg; 145 | b_in_sum -= pb; 146 | 147 | stackOut = stackOut.next; 148 | 149 | yi += 4; 150 | } 151 | yw += w; 152 | } 153 | 154 | 155 | for(x = 0; x < w; x++) { 156 | g_in_sum = b_in_sum = r_in_sum = g_sum = b_sum = r_sum = 0; 157 | 158 | yi = x << 2; 159 | r_out_sum = radiusPlus1 * (pr = pixels[yi]); 160 | g_out_sum = radiusPlus1 * (pg = pixels[yi+1]); 161 | b_out_sum = radiusPlus1 * (pb = pixels[yi+2]); 162 | 163 | r_sum += sumFactor * pr; 164 | g_sum += sumFactor * pg; 165 | b_sum += sumFactor * pb; 166 | 167 | stack = stackStart; 168 | 169 | for(i = 0; i < radiusPlus1; i++) { 170 | stack.r = pr; 171 | stack.g = pg; 172 | stack.b = pb; 173 | stack = stack.next; 174 | } 175 | 176 | yp = w; 177 | 178 | for(i = 1; i <= radius; i++) { 179 | yi = (yp + x) << 2; 180 | 181 | r_sum += (stack.r = (pr = pixels[yi])) * (rbs = radiusPlus1 - i); 182 | g_sum += (stack.g = (pg = pixels[yi+1])) * rbs; 183 | b_sum += (stack.b = (pb = pixels[yi+2])) * rbs; 184 | 185 | r_in_sum += pr; 186 | g_in_sum += pg; 187 | b_in_sum += pb; 188 | 189 | stack = stack.next; 190 | 191 | if(i < hMinus1) { 192 | yp += w; 193 | } 194 | } 195 | 196 | yi = x; 197 | stackIn = stackStart; 198 | stackOut = stackEnd; 199 | for(y = 0; y < h; y++) { 200 | p = yi << 2; 201 | pixels[p] = (r_sum * mul_sum) >> shg_sum; 202 | pixels[p+1] = (g_sum * mul_sum) >> shg_sum; 203 | pixels[p+2] = (b_sum * mul_sum) >> shg_sum; 204 | 205 | r_sum -= r_out_sum; 206 | g_sum -= g_out_sum; 207 | b_sum -= b_out_sum; 208 | 209 | r_out_sum -= stackIn.r; 210 | g_out_sum -= stackIn.g; 211 | b_out_sum -= stackIn.b; 212 | 213 | p = (x + (((p = y + radiusPlus1) < hMinus1 ? p : hMinus1) * w)) << 2; 214 | 215 | r_sum += (r_in_sum += (stackIn.r = pixels[p])); 216 | g_sum += (g_in_sum += (stackIn.g = pixels[p+1])); 217 | b_sum += (b_in_sum += (stackIn.b = pixels[p+2])); 218 | 219 | stackIn = stackIn.next; 220 | 221 | r_out_sum += (pr = stackOut.r); 222 | g_out_sum += (pg = stackOut.g); 223 | b_out_sum += (pb = stackOut.b); 224 | 225 | r_in_sum -= pr; 226 | g_in_sum -= pg; 227 | b_in_sum -= pb; 228 | 229 | stackOut = stackOut.next; 230 | 231 | yi += w; 232 | } 233 | } 234 | 235 | var orig_src = img.getAttribute('src'); 236 | if(orig_src != null && orig_src != '') { 237 | var orig_img = new Image(); 238 | orig_img.onload = function() { 239 | img.src = orig_src; 240 | }; 241 | orig_img.src = orig_src; 242 | } 243 | 244 | canvas.getContext('2d').putImageData(imageData, 0, 0); 245 | img.src = canvas.toDataURL(); 246 | }; 247 | 248 | idata_img.src = idata; 249 | } 250 | }; 251 | 252 | 253 | var shg_cur_n=15; 254 | 255 | var i=0; 256 | for(; i < am.mul_table.length;) { 257 | am.mul_table[i++] += 256; 258 | } 259 | 260 | function populate_shg(n){ 261 | for(i = 0; i < n; ++i) { 262 | am.shg_table.push(shg_cur_n); 263 | } 264 | 265 | ++shg_cur_n; 266 | } 267 | 268 | populate_shg(4); 269 | populate_shg(4); 270 | populate_shg(7); 271 | populate_shg(9); 272 | populate_shg(14); 273 | populate_shg(18); 274 | populate_shg(27); 275 | populate_shg(37); 276 | populate_shg(54); 277 | populate_shg(74); 278 | 279 | AntiModerate = { "process": am.processImage }; 280 | })(); -------------------------------------------------------------------------------- /antimoderate.min.js: -------------------------------------------------------------------------------- 1 | (function(){function l(l){for(v=0;vradius)){radius|=0;var v=B.getContext("2d").getImageData(0,0,w,h),c=v.data,x,C,a,d,e,M,f,g,k,y,z,A,m,n,p,r,t,u,E;x=radius+radius+1;var N=w-1,P=h-1,q=radius+1,F=q*(q+1)/2,G={r:0,b:0,a:0,g:0,next:null},b=G;for(a=1;a>I,c[e+1]=g*H>>I,c[e+2]=k*H>>I,f-=y,g-=z,k-=A,y-=a.r,z-=a.b,A-=a.a,d=M+((d=x+radius+1)>I,c[d+1]=g*H>>I,c[d+2]=k*H>>I,f-=y,g-=z,k-=A,y-=a.r,z-=a.b,A-=a.a,d=x+((d=C+q) 2 | 3 | 4 | AntiModerate Demo 5 | 10 | 11 | 12 |

AntiModerate

13 |

The Progressive Image Loader

14 | 15 |

we just pass an image, the base64 image data for the micro image, and then (optionally) a scale for the blur

16 | 17 | AntiModerate.process(img, img.getAttribute("data-antimoderate-idata"), img.getAttribute("data-antimoderate-scale")); 18 | 19 |
20 |
21 | 22 | 23 |

Example 1

24 | 25 | 26 | 27 |
28 | 29 |

Example 2

30 | 31 | 32 | 33 | 34 | 35 | 36 | 44 | 45 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "antimoderate", 3 | "version": "1.0.0", 4 | "description": "The progressive image loading library for great good!", 5 | "main": "antimoderate.min.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/whackashoe/antimoderate.git" 9 | }, 10 | "license": "MIT", 11 | "author": { 12 | "name": "Jett LaRue", 13 | "url": "https://jettlarue.com" 14 | }, 15 | "keywords": [ 16 | "antimoderate", 17 | "image", 18 | "progressive", 19 | "loading" 20 | ] 21 | } 22 | --------------------------------------------------------------------------------