├── zorrosvg ├── .htaccess ├── img │ ├── example.png │ ├── zorrosvg.jpg │ ├── transparentpattern.gif │ ├── transparentpattern.png │ ├── zorro.svg │ ├── example2.svg │ ├── zorro2.svg │ ├── example4.svg │ ├── example1.svg │ └── example3.svg ├── README.md ├── index.html └── js │ └── zorrosvgmaskmaker.js ├── blur ├── stackblur.pdf ├── IntegralImage.js ├── FastBlur.js ├── StackBoxBlur.js ├── StackBlur.js └── CompoundBlur.js └── README.md /zorrosvg/.htaccess: -------------------------------------------------------------------------------- 1 | AddType image/svg+xml .svg .svgz -------------------------------------------------------------------------------- /blur/stackblur.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Quasimondo/QuasimondoJS/HEAD/blur/stackblur.pdf -------------------------------------------------------------------------------- /zorrosvg/img/example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Quasimondo/QuasimondoJS/HEAD/zorrosvg/img/example.png -------------------------------------------------------------------------------- /zorrosvg/img/zorrosvg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Quasimondo/QuasimondoJS/HEAD/zorrosvg/img/zorrosvg.jpg -------------------------------------------------------------------------------- /zorrosvg/img/transparentpattern.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Quasimondo/QuasimondoJS/HEAD/zorrosvg/img/transparentpattern.gif -------------------------------------------------------------------------------- /zorrosvg/img/transparentpattern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Quasimondo/QuasimondoJS/HEAD/zorrosvg/img/transparentpattern.png -------------------------------------------------------------------------------- /zorrosvg/README.md: -------------------------------------------------------------------------------- 1 | ZorroSVG 2 | ============ 3 | 4 | The source code for: http://quasimondo.com/ZorroSVG/ 5 | 6 | This is not cleaned up or documented at all, but if you are interested in making a standalone version 7 | or your own flavour of it, you'll find all of the required code inside of js/zorrosvgmaskmaker.js 8 | 9 | I've not added all the jQuery/foundation etc. code to the repository - I mean it's shameful enough that 10 | I used jQuery for the UI in the first place ;-) 11 | 12 | Please let me know whenever you make improvements to the code or port it. 13 | 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | QuasimondoJS 2 | ============ 3 | 4 | A collection of more or less useful Javascript utils and snippets 5 | 6 | 7 | 8 | ZorroSVG - Put a Mask on it. 9 | 10 | Converts transparent PNGs to SVGs and can shrink file sizes considerably. 11 | http://quasimondo.com/ZorroSVG/ 12 | 13 | 14 | 15 | Various Blurs: 16 | 17 | Stack Blur (best quality/speed ratio): 18 | http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html 19 | 20 | An explanation how the Stackblur Algorithm works can be found here: 21 | https://github.com/Quasimondo/QuasimondoJS/blob/master/blur/stackblur.pdf?raw=true 22 | 23 | Compound Blur with variable radii: 24 | http://www.quasimondo.com/CompoundBlurForCanvas/CompoundBlurDemo.html 25 | 26 | Superfast Blur (fastest, but not so beautiful): 27 | http://www.quasimondo.com/BoxBlurForCanvas/FastBlurDemo.html 28 | 29 | Stack Box Blur (another fast variant): 30 | http://www.quasimondo.com/BoxBlurForCanvas/FastBlur2Demo.html 31 | 32 | Integral Image Blur (and another fast variant): 33 | http://www.quasimondo.com/IntegralImageForCanvas/IntegralImageBlurDemo.html 34 | 35 | -------------------------------------------------------------------------------- /zorrosvg/img/zorro.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | ]> 9 | 100 | -------------------------------------------------------------------------------- /zorrosvg/img/example2.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /blur/IntegralImage.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Integral Image 4 | 5 | Version: 0.4 6 | Author: Mario Klingemann 7 | Contact: mario@quasimondo.com 8 | Website: http://www.quasimondo.com/IntegralImageForCanvas 9 | Twitter: @quasimondo 10 | 11 | In case you find this class useful - especially in commercial projects - 12 | I am not totally unhappy for a small donation to my PayPal account 13 | mario@quasimondo.de 14 | 15 | 16 | Copyright (c) 2011 Mario Klingemann 17 | 18 | Permission is hereby granted, free of charge, to any person 19 | obtaining a copy of this software and associated documentation 20 | files (the "Software"), to deal in the Software without 21 | restriction, including without limitation the rights to use, 22 | copy, modify, merge, publish, distribute, sublicense, and/or sell 23 | copies of the Software, and to permit persons to whom the 24 | Software is furnished to do so, subject to the following 25 | conditions: 26 | 27 | The above copyright notice and this permission notice shall be 28 | included in all copies or substantial portions of the Software. 29 | 30 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 31 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 32 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 33 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 34 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 35 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 36 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 37 | OTHER DEALINGS IN THE SOFTWARE. 38 | */ 39 | 40 | function integralBlurImage( imageID, canvasID, radius, blurAlphaChannel, iterations ) 41 | { 42 | 43 | var img = document.getElementById( imageID ); 44 | var w = img.naturalWidth; 45 | var h = img.naturalHeight; 46 | 47 | var canvas = document.getElementById( canvasID ); 48 | 49 | canvas.style.width = w + "px"; 50 | canvas.style.height = h + "px"; 51 | canvas.width = w; 52 | canvas.height = h; 53 | 54 | var context = canvas.getContext("2d"); 55 | context.clearRect( 0, 0, w, h ); 56 | context.drawImage( img, 0, 0 ); 57 | 58 | if ( isNaN(radius) || radius < 1 ) return; 59 | 60 | if ( blurAlphaChannel ) 61 | { 62 | integralBlurCanvasRGBA( canvasID, 0, 0, w, h, radius, iterations ); 63 | } else { 64 | integralBlurCanvasRGB( canvasID, 0, 0, w, h, radius, iterations ); 65 | } 66 | } 67 | 68 | function integralBlurCanvasRGB( id, top_x, top_y, width, height, radius, iterations ) 69 | { 70 | 71 | var ii = integralImageFromCanvasRGB( id, 0, 0, width, height ); 72 | if ( ii == null ) return; 73 | var imageData = ii.imageData; 74 | var pixels = imageData.pixels; 75 | var context = ii.context; 76 | blurIntegralImageRGB( ii, radius ); 77 | 78 | while ( --iterations > 0 ) 79 | { 80 | ii = calculateIntegralImageRGB( pixels, width, height ); 81 | ii.imageData = imageData; 82 | ii.context = context; 83 | blurIntegralImageRGB( ii, radius ); 84 | } 85 | 86 | context.putImageData( imageData, top_x, top_y ); 87 | 88 | } 89 | 90 | 91 | function integralBlurCanvasRGBA( id, top_x, top_y, width, height, radius, iterations ) 92 | { 93 | 94 | var ii = integralImageFromCanvasRGBA( id, 0, 0, width, height ); 95 | if ( ii == null ) return; 96 | var imageData = ii.imageData; 97 | var pixels = ii.pixels; 98 | var context = ii.context; 99 | blurIntegralImageRGBA( ii, radius ); 100 | 101 | while ( --iterations > 0 ) 102 | { 103 | ii = calculateIntegralImageRGBA( pixels, width, height ); 104 | ii.imageData = imageData; 105 | ii.context = context; 106 | blurIntegralImageRGBA( ii, radius ); 107 | } 108 | 109 | context.putImageData( imageData, top_x, top_y ); 110 | 111 | } 112 | 113 | function updateCanvas( integralImage ) 114 | { 115 | integralImage.context.putImageData( integralImage.imageData, 0, 0 ); 116 | } 117 | 118 | function blurIntegralImageRGBA( integralImage, radius ) 119 | { 120 | var dx1,dx2,dy1,dy2,dy,idx1,idx2,idx3,idx4,area; 121 | 122 | var ii = integralImage; 123 | var width = ii.width; 124 | var height = ii.height; 125 | var pixels = ii.pixels; 126 | var i1 = 0; 127 | var i2 = 0; 128 | var r = ii.r; 129 | var g = ii.g; 130 | var b = ii.b; 131 | var a = ii.a; 132 | var pa; 133 | var iw = width + 1; 134 | 135 | for ( var y = 0; y < height; y++ ) 136 | { 137 | dy1 = ( y < radius ? -y : -radius ); 138 | dy2 = ( y >= height - radius ? height - y : radius ); 139 | dy = dy2 - dy1; 140 | dy1 *= iw; 141 | dy2 *= iw; 142 | for ( var x = 0; x < width; x++ ) 143 | { 144 | dx1 = ( x < radius ? -x : -radius ); 145 | dx2 = ( x >= width - radius ? width - x : radius ); 146 | area = 1 / ((dx2 - dx1) * dy); 147 | 148 | dx1 += i1; 149 | dx2 += i1; 150 | 151 | idx1 = dx1+dy1; 152 | idx2 = dx2+dy2; 153 | idx3 = dx1+dy2; 154 | idx4 = dx2+dy1; 155 | 156 | pa = (( a[idx1] + a[idx2] - a[idx3] - a[idx4] ) * area ) | 0; 157 | if ( pa > 0 ) 158 | { 159 | pa = 255 / pa; 160 | pixels[i2++] = (( r[idx1] + r[idx2] - r[idx3] - r[idx4] ) * area * pa) | 0; 161 | pixels[i2++] = (( g[idx1] + g[idx2] - g[idx3] - g[idx4] ) * area * pa) | 0; 162 | pixels[i2++] = (( b[idx1] + b[idx2] - b[idx3] - b[idx4] ) * area * pa) | 0; 163 | pixels[i2++] = pa; 164 | } else { 165 | pixels[i2++] = pixels[i2++] = pixels[i2++] = pixels[i2++] = 0; 166 | } 167 | i1++; 168 | } 169 | i1++; 170 | } 171 | } 172 | 173 | 174 | 175 | function blurIntegralImageRGB( integralImage, radius ) 176 | { 177 | var dx1,dx2,dy1,dy2,dy,idx1,idx2,idx3,idx4,area; 178 | 179 | var ii = integralImage; 180 | var width = ii.width; 181 | var height = ii.height; 182 | var pixels = ii.pixels; 183 | var i1 = 0; 184 | var i2 = 0; 185 | var r = ii.r; 186 | var g = ii.g; 187 | var b = ii.b; 188 | var iw = width + 1; 189 | 190 | for ( var y = 0; y < height; y++ ) { 191 | dy1 = ( y < radius ? -y : -radius ); 192 | dy2 = ( y >= height - radius ? height - y -1 : radius ); 193 | dy = dy2 - dy1; 194 | dy1 *= iw; 195 | dy2 *= iw; 196 | 197 | for ( var x = 0; x < width; x++ ) { 198 | dx1 = ( x < radius ? -x : -radius ); 199 | dx2 = ( x >= width - radius ? width - x - 1: radius ); 200 | 201 | area = 1 / ((dx2 - dx1) * dy); 202 | 203 | dx1 += i1; 204 | dx2 += i1; 205 | 206 | idx1 = dx1+dy1; 207 | idx2 = dx2+dy2; 208 | idx3 = dx1+dy2; 209 | idx4 = dx2+dy1; 210 | 211 | pixels[i2++] = (( r[idx1] + r[idx2] - r[idx3] - r[idx4] ) * area ) | 0; 212 | pixels[i2++] = (( g[idx1] + g[idx2] - g[idx3] - g[idx4] ) * area ) | 0; 213 | pixels[i2++] = (( b[idx1] + b[idx2] - b[idx3] - b[idx4] ) * area ) | 0; 214 | i2++ 215 | i1++; 216 | } 217 | i1++; 218 | } 219 | 220 | } 221 | 222 | function integralImageFromImage( imageID, canvasID, includeAlphaChannel ) 223 | { 224 | 225 | var img = document.getElementById( imageID ); 226 | var w = img.naturalWidth; 227 | var h = img.naturalHeight; 228 | 229 | var canvas = document.getElementById( canvasID ); 230 | 231 | canvas.style.width = w + "px"; 232 | canvas.style.height = h + "px"; 233 | canvas.width = w; 234 | canvas.height = h; 235 | 236 | var context = canvas.getContext("2d"); 237 | context.clearRect( 0, 0, w, h ); 238 | context.drawImage( img, 0, 0 ); 239 | 240 | if ( includeAlphaChannel ) 241 | { 242 | return integralImageFromCanvasRGBA( canvasID, 0, 0, w, h ); 243 | } else { 244 | return integralImageFromCanvasRGB( canvasID, 0, 0, w, h ); 245 | } 246 | } 247 | 248 | function integralImageFromCanvasRGB( id, top_x, top_y, width, height ) 249 | { 250 | var pixelData = getCanvasPixels( id, top_x, top_y, width, height ); 251 | if ( pixelData == null ) return; 252 | 253 | var ii = calculateIntegralImageRGB( pixelData.pixels, width, height ); 254 | ii.context = pixelData.context; 255 | ii.imageData = pixelData.imageData; 256 | return ii; 257 | } 258 | 259 | function integralImageFromCanvasRGBA( id, top_x, top_y, width, height ) 260 | { 261 | var pixelData = getCanvasPixels( id, top_x, top_y, width, height ); 262 | if ( pixelData == null ) return; 263 | 264 | var ii = calculateIntegralImageRGBA( pixelData.pixels, width, height ); 265 | ii.context = pixelData.context; 266 | ii.imageData = pixelData.imageData; 267 | return ii; 268 | } 269 | 270 | function getCanvasPixels( canvasID, top_x, top_y, width, height ) 271 | { 272 | var result = { id:canvasID, top_x:top_x, top_y:top_y, width:width, height:height }; 273 | result.canvas = document.getElementById( canvasID ); 274 | result.context = result.canvas.getContext("2d"); 275 | 276 | try { 277 | result.imageData = result.context.getImageData( top_x, top_y, width, height ); 278 | } catch(e) { 279 | //throw new Error("unable to access image data: " + e); 280 | return null; 281 | } 282 | result.pixels = result.imageData.data; 283 | return result; 284 | } 285 | 286 | function calculateIntegralImageRGB( pixels, width, height ) 287 | { 288 | var r = []; 289 | var g = []; 290 | var b = []; 291 | 292 | var i = 0; 293 | var j = 0; 294 | for ( y=0; y < height; y++ ) 295 | { 296 | rsum = pixels[i++]; 297 | gsum = pixels[i++]; 298 | bsum = pixels[i++]; 299 | i++; 300 | for ( x = 0; x < width; x++ ) 301 | { 302 | r[j] = rsum; 303 | g[j] = gsum; 304 | b[j++] = bsum; 305 | 306 | rsum += pixels[i++]; 307 | gsum += pixels[i++]; 308 | bsum += pixels[i++]; 309 | i++; 310 | } 311 | 312 | r[j] = rsum; 313 | g[j] = gsum; 314 | b[j++] = bsum; 315 | i-=4; 316 | } 317 | 318 | var j1 = width + 1; 319 | var w1 = j1; 320 | var k = j1 * ( height + 1 ); 321 | var j2 = j1 - w1; 322 | while ( j1 < k ) 323 | { 324 | r[j1] += r[j2]; 325 | g[j1] += g[j2]; 326 | b[j1] += b[j2]; 327 | j1++,j2++; 328 | } 329 | 330 | return { r:r, g:g, b:b, width:width, height:height, pixels:pixels }; 331 | 332 | } 333 | 334 | function calculateIntegralImageRGBA( pixels, width, height ) 335 | { 336 | 337 | var r = []; 338 | var g = []; 339 | var b = []; 340 | var a = []; 341 | var i = 0; 342 | var j = 0; 343 | 344 | for ( y=0; y < height; y++ ) 345 | { 346 | rsum = pixels[i++]; 347 | gsum = pixels[i++]; 348 | bsum = pixels[i++]; 349 | asum = pixels[i++]; 350 | 351 | for ( x = 0; x < width; x++ ) 352 | { 353 | r[j] = rsum; 354 | g[j] = gsum; 355 | b[j] = bsum; 356 | a[j++] = asum; 357 | 358 | rsum += pixels[i++]; 359 | gsum += pixels[i++]; 360 | bsum += pixels[i++]; 361 | asum += pixels[i++]; 362 | } 363 | 364 | r[j] = rsum; 365 | g[j] = gsum; 366 | b[j] = bsum; 367 | a[j++] = asum; 368 | i-=4; 369 | } 370 | 371 | var j1 = width + 1; 372 | var w1 = j1; 373 | var k = j1 * ( height + 1 ); 374 | var j2 = j1 - w1; 375 | while ( j1 < k ) 376 | { 377 | r[j1] += r[j2]; 378 | g[j1] += g[j2]; 379 | b[j1] += b[j2]; 380 | a[j1] += a[j2]; 381 | j1++, j2++; 382 | } 383 | 384 | return { r:r, g:g, b:b, a:a, width:width, height:height, pixels:pixels }; 385 | } 386 | 387 | 388 | 389 | -------------------------------------------------------------------------------- /zorrosvg/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 | 7 |The transparency of PNGs for the file size of JPEGs
40 |Drag a transparent PNG or GIF from your desktop onto this page or use the file picker 54 | and see how many kB ZorroSVG can save you.
55 | 56 |
65 | Images created with ZorroSVG can be used like any other image. Simply embed the transparent bitmap in your html like this:
80 |<img src="yourImage.svg" />If you want to be on the safe side you can add a fallback which will display the old png in case the browser does not support SVG. Your html tag would look like this:
82 |<img src="yourImage.svg" onerror="this.src='yourOriginal.png'"/>And if you really care about users that still use mobile-Safari on iOS 7 you will have to use an object tag instead of the img tag:
84 |<object data="yourImage.svg" type="image/svg+xml"/>ZorroSVG has some minor pitfalls you should be a aware of: 93 |
AddType image/svg+xml .svg .svgz97 |
v1.0 121 |
v1.1 126 |
v1.2 131 |
Transparent PNGs are great, but they come at a price: file size. Wouldn't it be nice if there were transparent JPEGs instead? Unfortunately there is no such thing, but ZorroSVG gives you the power of transparent PNGs for the size of a JPEG.
143 |It achieves this by converting your PNG to an SVG which uses the compositing capabilites of SVG to create a masked bitmap on-the-fly using JPEGs for both the image and its mask - achieving most of the time a much better compression than PNG. Since all the compositing and masking happens inside the SVG there is no JavaScript required. And it will work on any current browser.
144 |The SVGs created by ZorroSVG can be used like any other image by simply using the <img> tag to embed it into your page.
145 |The tool on this page helps you to convert your current PNGs to the ZorroSVG image format. Give it a try!
146 |Original PNG: "+ Math.round( sourceFileSize / 1024)+"kB"+ 380 | " - ZorroSVG: "+ Math.round(size1 / 1024)+"kB, that's "+ 381 | ""+ Math.round(size1 / sourceFileSize * 100)+"% of the original size
"+ 382 | (size1 > sourceFileSize ? "In this case, you rather shouldn't, but if you insist you still can":"")+ 383 | ""; 384 | 385 | var a = document.getElementById("singlesvg"); 386 | a.onclick = download; 387 | a.href = "#"; 388 | 389 | document.getElementById("originalSize").innerHTML = "Original Transparent PNG: "+Math.round( sourceFileSize / 1024)+"kB"; 390 | document.getElementById("zorroSize").innerHTML = "ZorroSVG: "+Math.round(size1 / 1024)+"kB (live rendered)"; 391 | 392 | } 393 | 394 | function download(e) { 395 | e.preventDefault(); 396 | var blob = new Blob([rawSVG], {type: "image/svg+xml"}); 397 | saveAs(blob, currentFileName+".svg"); 398 | } 399 | 400 | function maskedImageToSVG(quality, embedded) { 401 | 402 | var svg = document.createElementNS("http://www.w3.org/2000/svg","svg"); 403 | svg.setAttribute('xmlns',"http://www.w3.org/2000/svg" ); 404 | svg.setAttribute('width', currentMaskCanvas.width); 405 | svg.setAttribute('height', currentMaskCanvas.height*0.5); 406 | svg.setAttribute('viewBox', "0 0 "+currentMaskCanvas.width+" "+(currentMaskCanvas.height*0.5)); 407 | 408 | svg.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:xlink", "http://www.w3.org/1999/xlink"); 409 | 410 | 411 | var defs = document.createElementNS("http://www.w3.org/2000/svg", 'defs'); 412 | svg.appendChild(defs); 413 | 414 | var filter = document.createElementNS("http://www.w3.org/2000/svg", 'filter'); 415 | filter.setAttribute("id","a"); 416 | defs.appendChild(filter); 417 | 418 | var feOffset = document.createElementNS("http://www.w3.org/2000/svg", 'feOffset'); 419 | feOffset.setAttribute("dy",-currentMaskCanvas.height*0.5); 420 | feOffset.setAttribute("in","SourceGraphic" ); 421 | feOffset.setAttribute("result","b"); 422 | filter.appendChild(feOffset); 423 | 424 | var feColorMatrix = document.createElementNS("http://www.w3.org/2000/svg", 'feColorMatrix'); 425 | feColorMatrix.setAttribute("in","b" ); 426 | feColorMatrix.setAttribute("result","b"); 427 | feColorMatrix.setAttribute("type","matrix"); 428 | feColorMatrix.setAttribute("values","0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0"); 429 | filter.appendChild(feColorMatrix); 430 | 431 | var feComposite = document.createElementNS("http://www.w3.org/2000/svg", 'feComposite'); 432 | feComposite.setAttribute("in","SourceGraphic" ); 433 | feComposite.setAttribute("in2","b" ); 434 | feComposite.setAttribute("operator","in" ); 435 | filter.appendChild(feComposite); 436 | 437 | var image = document.createElementNS("http://www.w3.org/2000/svg", 'image'); 438 | image.setAttribute("width","100%"); 439 | image.setAttribute("height","200%"); 440 | 441 | if ( embedded ) 442 | image.setAttributeNS("http://www.w3.org/1999/xlink", "A:href",currentMaskCanvas.toDataURL("image/jpeg", quality)); 443 | else 444 | image.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:href",currentFileName+".jpg"); 445 | 446 | image.setAttribute("filter","url(#a)"); 447 | svg.appendChild(image); 448 | return svg; 449 | } 450 | 451 | -------------------------------------------------------------------------------- /zorrosvg/img/zorro2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 157 | -------------------------------------------------------------------------------- /blur/StackBoxBlur.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | StackBoxBlur - a fast almost Box Blur For Canvas 4 | 5 | Version: 0.3 6 | Author: Mario Klingemann 7 | Contact: mario@quasimondo.com 8 | Website: http://www.quasimondo.com/ 9 | Twitter: @quasimondo 10 | 11 | In case you find this class useful - especially in commercial projects - 12 | I am not totally unhappy for a small donation to my PayPal account 13 | mario@quasimondo.de 14 | 15 | Copyright (c) 2010 Mario Klingemann 16 | 17 | Permission is hereby granted, free of charge, to any person 18 | obtaining a copy of this software and associated documentation 19 | files (the "Software"), to deal in the Software without 20 | restriction, including without limitation the rights to use, 21 | copy, modify, merge, publish, distribute, sublicense, and/or sell 22 | copies of the Software, and to permit persons to whom the 23 | Software is furnished to do so, subject to the following 24 | conditions: 25 | 26 | The above copyright notice and this permission notice shall be 27 | included in all copies or substantial portions of the Software. 28 | 29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 30 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 31 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 32 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 33 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 34 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 35 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 36 | OTHER DEALINGS IN THE SOFTWARE. 37 | */ 38 | /* 39 | var mul_table = [ 1,57,41,21,203,34,97,73,227,91,149,62,105,45,39,137,241,107,3,173,39,71,65,238,219,101,187,87,81,151,141,133,249,117,221,209,197,187,177,169,5,153,73,139,133,127,243,233,223,107,103,99,191,23,177,171,165,159,77,149,9,139,135,131,253,245,119,231,224,109,211,103,25,195,189,23,45,175,171,83,81,79,155,151,147,9,141,137,67,131,129,251,123,30,235,115,113,221,217,53,13,51,50,49,193,189,185,91,179,175,43,169,83,163,5,79,155,19,75,147,145,143,35,69,17,67,33,65,255,251,247,243,239,59,29,229,113,111,219,27,213,105,207,51,201,199,49,193,191,47,93,183,181,179,11,87,43,85,167,165,163,161,159,157,155,77,19,75,37,73,145,143,141,35,138,137,135,67,33,131,129,255,63,250,247,61,121,239,237,117,29,229,227,225,111,55,109,216,213,211,209,207,205,203,201,199,197,195,193,48,190,47,93,185,183,181,179,178,176,175,173,171,85,21,167,165,41,163,161,5,79,157,78,154,153,19,75,149,74,147,73,144,143,71,141,140,139,137,17,135,134,133,66,131,65,129,1]; 40 | 41 | 42 | var shg_table = [0,9,10,10,14,12,14,14,16,15,16,15,16,15,15,17,18,17,12,18,16,17,17,19,19,18,19,18,18,19,19,19,20,19,20,20,20,20,20,20,15,20,19,20,20,20,21,21,21,20,20,20,21,18,21,21,21,21,20,21,17,21,21,21,22,22,21,22,22,21,22,21,19,22,22,19,20,22,22,21,21,21,22,22,22,18,22,22,21,22,22,23,22,20,23,22,22,23,23,21,19,21,21,21,23,23,23,22,23,23,21,23,22,23,18,22,23,20,22,23,23,23,21,22,20,22,21,22,24,24,24,24,24,22,21,24,23,23,24,21,24,23,24,22,24,24,22,24,24,22,23,24,24,24,20,23,22,23,24,24,24,24,24,24,24,23,21,23,22,23,24,24,24,22,24,24,24,23,22,24,24,25,23,25,25,23,24,25,25,24,22,25,25,25,24,23,24,25,25,25,25,25,25,25,25,25,25,25,25,23,25,23,24,25,25,25,25,25,25,25,25,25,24,22,25,25,23,25,25,20,24,25,24,25,25,22,24,25,24,25,24,25,25,24,25,25,25,25,22,25,25,25,24,25,24,25,18]; 43 | */ 44 | 45 | var mul_table = [ 1,171,205,293,57,373,79,137,241,27,391,357,41,19,283,265,497,469,443,421,25,191,365,349,335,161,155,149,9,278,269,261,505,245,475,231,449,437,213,415,405,395,193,377,369,361,353,345,169,331,325,319,313,307,301,37,145,285,281,69,271,267,263,259,509,501,493,243,479,118,465,459,113,446,55,435,429,423,209,413,51,403,199,393,97,3,379,375,371,367,363,359,355,351,347,43,85,337,333,165,327,323,5,317,157,311,77,305,303,75,297,294,73,289,287,71,141,279,277,275,68,135,67,133,33,262,260,129,511,507,503,499,495,491,61,121,481,477,237,235,467,232,115,457,227,451,7,445,221,439,218,433,215,427,425,211,419,417,207,411,409,203,202,401,399,396,197,49,389,387,385,383,95,189,47,187,93,185,23,183,91,181,45,179,89,177,11,175,87,173,345,343,341,339,337,21,167,83,331,329,327,163,81,323,321,319,159,79,315,313,39,155,309,307,153,305,303,151,75,299,149,37,295,147,73,291,145,289,287,143,285,71,141,281,35,279,139,69,275,137,273,17,271,135,269,267,133,265,33,263,131,261,130,259,129,257,1]; 46 | 47 | 48 | var shg_table = [0,9,10,11,9,12,10,11,12,9,13,13,10,9,13,13,14,14,14,14,10,13,14,14,14,13,13,13,9,14,14,14,15,14,15,14,15,15,14,15,15,15,14,15,15,15,15,15,14,15,15,15,15,15,15,12,14,15,15,13,15,15,15,15,16,16,16,15,16,14,16,16,14,16,13,16,16,16,15,16,13,16,15,16,14,9,16,16,16,16,16,16,16,16,16,13,14,16,16,15,16,16,10,16,15,16,14,16,16,14,16,16,14,16,16,14,15,16,16,16,14,15,14,15,13,16,16,15,17,17,17,17,17,17,14,15,17,17,16,16,17,16,15,17,16,17,11,17,16,17,16,17,16,17,17,16,17,17,16,17,17,16,16,17,17,17,16,14,17,17,17,17,15,16,14,16,15,16,13,16,15,16,14,16,15,16,12,16,15,16,17,17,17,17,17,13,16,15,17,17,17,16,15,17,17,17,16,15,17,17,14,16,17,17,16,17,17,16,15,17,16,14,17,16,15,17,16,17,17,16,17,15,16,17,14,17,16,15,17,16,17,13,17,16,17,17,16,17,14,17,16,17,16,17,16,17,9 49 | ]; 50 | 51 | function stackBoxBlurImage( imageID, canvasID, radius, blurAlphaChannel, iterations ) 52 | { 53 | 54 | var img = document.getElementById( imageID ); 55 | var w = img.naturalWidth; 56 | var h = img.naturalHeight; 57 | 58 | var canvas = document.getElementById( canvasID ); 59 | 60 | canvas.style.width = w + "px"; 61 | canvas.style.height = h + "px"; 62 | canvas.width = w; 63 | canvas.height = h; 64 | 65 | var context = canvas.getContext("2d"); 66 | context.clearRect( 0, 0, w, h ); 67 | context.drawImage( img, 0, 0 ); 68 | 69 | if ( isNaN(radius) || radius < 1 ) return; 70 | 71 | if ( blurAlphaChannel ) 72 | stackBoxBlurCanvasRGBA( canvasID, 0, 0, w, h, radius, iterations ); 73 | else 74 | stackBoxBlurCanvasRGB( canvasID, 0, 0, w, h, radius, iterations ); 75 | } 76 | 77 | 78 | function stackBoxBlurCanvasRGBA( id, top_x, top_y, width, height, radius, iterations ) 79 | { 80 | if ( isNaN(radius) || radius < 1 ) return; 81 | radius |= 0; 82 | 83 | if ( isNaN(iterations) ) iterations = 1; 84 | iterations |= 0; 85 | if ( iterations > 3 ) iterations = 3; 86 | if ( iterations < 1 ) iterations = 1; 87 | 88 | var canvas = document.getElementById( id ); 89 | var context = canvas.getContext("2d"); 90 | var imageData; 91 | 92 | try { 93 | try { 94 | imageData = context.getImageData( top_x, top_y, width, height ); 95 | } catch(e) { 96 | 97 | // NOTE: this part is supposedly only needed if you want to work with local files 98 | // so it might be okay to remove the whole try/catch block and just use 99 | // imageData = context.getImageData( top_x, top_y, width, height ); 100 | try { 101 | netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead"); 102 | imageData = context.getImageData( top_x, top_y, width, height ); 103 | } catch(e) { 104 | alert("Cannot access local image"); 105 | throw new Error("unable to access local image data: " + e); 106 | return; 107 | } 108 | } 109 | } catch(e) { 110 | alert("Cannot access image"); 111 | throw new Error("unable to access image data: " + e); 112 | } 113 | 114 | var pixels = imageData.data; 115 | 116 | var x, y, i, p, yp, yi, yw, r_sum, g_sum, b_sum, a_sum, 117 | r_out_sum, g_out_sum, b_out_sum, a_out_sum, 118 | r_in_sum, g_in_sum, b_in_sum, a_in_sum, 119 | pr, pg, pb, pa, rbs; 120 | 121 | var div = radius + radius + 1; 122 | var w4 = width << 2; 123 | var widthMinus1 = width - 1; 124 | var heightMinus1 = height - 1; 125 | var radiusPlus1 = radius + 1; 126 | 127 | var stackStart = new BlurStack(); 128 | 129 | var stack = stackStart; 130 | for ( i = 1; i < div; i++ ) 131 | { 132 | stack = stack.next = new BlurStack(); 133 | if ( i == radiusPlus1 ) var stackEnd = stack; 134 | } 135 | stack.next = stackStart; 136 | var stackIn = null; 137 | 138 | 139 | 140 | var mul_sum = mul_table[radius]; 141 | var shg_sum = shg_table[radius]; 142 | while ( iterations-- > 0 ) { 143 | yw = yi = 0; 144 | for ( y = height; --y > -1; ) 145 | { 146 | r_sum = radiusPlus1 * ( pr = pixels[yi] ); 147 | g_sum = radiusPlus1 * ( pg = pixels[yi+1] ); 148 | b_sum = radiusPlus1 * ( pb = pixels[yi+2] ); 149 | a_sum = radiusPlus1 * ( pa = pixels[yi+3] ); 150 | 151 | stack = stackStart; 152 | 153 | for( i = radiusPlus1; --i > -1; ) 154 | { 155 | stack.r = pr; 156 | stack.g = pg; 157 | stack.b = pb; 158 | stack.a = pa; 159 | stack = stack.next; 160 | } 161 | 162 | for( i = 1; i < radiusPlus1; i++ ) 163 | { 164 | p = yi + (( widthMinus1 < i ? widthMinus1 : i ) << 2 ); 165 | r_sum += ( stack.r = pixels[p]); 166 | g_sum += ( stack.g = pixels[p+1]); 167 | b_sum += ( stack.b = pixels[p+2]); 168 | a_sum += ( stack.a = pixels[p+3]); 169 | 170 | stack = stack.next; 171 | } 172 | 173 | stackIn = stackStart; 174 | for ( x = 0; x < width; x++ ) 175 | { 176 | pixels[yi++] = (r_sum * mul_sum) >>> shg_sum; 177 | pixels[yi++] = (g_sum * mul_sum) >>> shg_sum; 178 | pixels[yi++] = (b_sum * mul_sum) >>> shg_sum; 179 | pixels[yi++] = (a_sum * mul_sum) >>> shg_sum; 180 | 181 | p = ( yw + ( ( p = x + radius + 1 ) < widthMinus1 ? p : widthMinus1 ) ) << 2; 182 | 183 | r_sum -= stackIn.r - ( stackIn.r = pixels[p]); 184 | g_sum -= stackIn.g - ( stackIn.g = pixels[p+1]); 185 | b_sum -= stackIn.b - ( stackIn.b = pixels[p+2]); 186 | a_sum -= stackIn.a - ( stackIn.a = pixels[p+3]); 187 | 188 | stackIn = stackIn.next; 189 | 190 | } 191 | yw += width; 192 | } 193 | 194 | 195 | for ( x = 0; x < width; x++ ) 196 | { 197 | yi = x << 2; 198 | 199 | r_sum = radiusPlus1 * ( pr = pixels[yi]); 200 | g_sum = radiusPlus1 * ( pg = pixels[yi+1]); 201 | b_sum = radiusPlus1 * ( pb = pixels[yi+2]); 202 | a_sum = radiusPlus1 * ( pa = pixels[yi+3]); 203 | 204 | stack = stackStart; 205 | 206 | for( i = 0; i < radiusPlus1; i++ ) 207 | { 208 | stack.r = pr; 209 | stack.g = pg; 210 | stack.b = pb; 211 | stack.a = pa; 212 | stack = stack.next; 213 | } 214 | 215 | yp = width; 216 | 217 | for( i = 1; i <= radius; i++ ) 218 | { 219 | yi = ( yp + x ) << 2; 220 | 221 | r_sum += ( stack.r = pixels[yi]); 222 | g_sum += ( stack.g = pixels[yi+1]); 223 | b_sum += ( stack.b = pixels[yi+2]); 224 | a_sum += ( stack.a = pixels[yi+3]); 225 | 226 | stack = stack.next; 227 | 228 | if( i < heightMinus1 ) 229 | { 230 | yp += width; 231 | } 232 | } 233 | 234 | yi = x; 235 | stackIn = stackStart; 236 | for ( y = 0; y < height; y++ ) 237 | { 238 | p = yi << 2; 239 | pixels[p+3] = pa =(a_sum * mul_sum) >>> shg_sum; 240 | if ( pa > 0 ) 241 | { 242 | pa = 255 / pa; 243 | pixels[p] = ((r_sum * mul_sum) >>> shg_sum ) * pa; 244 | pixels[p+1] = ((g_sum * mul_sum) >>> shg_sum ) * pa; 245 | pixels[p+2] = ((b_sum * mul_sum) >>> shg_sum ) * pa; 246 | } else { 247 | pixels[p] = pixels[p+1] = pixels[p+2] = 0 248 | } 249 | 250 | p = ( x + (( ( p = y + radiusPlus1) < heightMinus1 ? p : heightMinus1 ) * width )) << 2; 251 | 252 | r_sum -= stackIn.r - ( stackIn.r = pixels[p]); 253 | g_sum -= stackIn.g - ( stackIn.g = pixels[p+1]); 254 | b_sum -= stackIn.b - ( stackIn.b = pixels[p+2]); 255 | a_sum -= stackIn.a - ( stackIn.a = pixels[p+3]); 256 | 257 | stackIn = stackIn.next; 258 | 259 | yi += width; 260 | } 261 | } 262 | } 263 | context.putImageData( imageData, top_x, top_y ); 264 | 265 | } 266 | 267 | 268 | function stackBoxBlurCanvasRGB( id, top_x, top_y, width, height, radius, iterations ) 269 | { 270 | if ( isNaN(radius) || radius < 1 ) return; 271 | radius |= 0; 272 | 273 | if ( isNaN(iterations) ) iterations = 1; 274 | iterations |= 0; 275 | if ( iterations > 3 ) iterations = 3; 276 | if ( iterations < 1 ) iterations = 1; 277 | 278 | var canvas = document.getElementById( id ); 279 | var context = canvas.getContext("2d"); 280 | var imageData; 281 | 282 | try { 283 | try { 284 | imageData = context.getImageData( top_x, top_y, width, height ); 285 | } catch(e) { 286 | 287 | // NOTE: this part is supposedly only needed if you want to work with local files 288 | // so it might be okay to remove the whole try/catch block and just use 289 | // imageData = context.getImageData( top_x, top_y, width, height ); 290 | try { 291 | netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead"); 292 | imageData = context.getImageData( top_x, top_y, width, height ); 293 | } catch(e) { 294 | alert("Cannot access local image"); 295 | throw new Error("unable to access local image data: " + e); 296 | return; 297 | } 298 | } 299 | } catch(e) { 300 | alert("Cannot access image"); 301 | throw new Error("unable to access image data: " + e); 302 | } 303 | 304 | var pixels = imageData.data; 305 | 306 | var x, y, i, p, yp, yi, yw, r_sum, g_sum, b_sum, 307 | r_out_sum, g_out_sum, b_out_sum, 308 | r_in_sum, g_in_sum, b_in_sum, 309 | pr, pg, pb, rbs; 310 | 311 | var div = radius + radius + 1; 312 | var w4 = width << 2; 313 | var widthMinus1 = width - 1; 314 | var heightMinus1 = height - 1; 315 | var radiusPlus1 = radius + 1; 316 | 317 | var stackStart = new BlurStack(); 318 | var stack = stackStart; 319 | for ( i = 1; i < div; i++ ) 320 | { 321 | stack = stack.next = new BlurStack(); 322 | if ( i == radiusPlus1 ) var stackEnd = stack; 323 | } 324 | stack.next = stackStart; 325 | var stackIn = null; 326 | 327 | 328 | 329 | var mul_sum = mul_table[radius]; 330 | var shg_sum = shg_table[radius]; 331 | 332 | while ( iterations-- > 0 ) { 333 | yw = yi = 0; 334 | 335 | for ( y = height; --y >-1; ) 336 | { 337 | r_sum = radiusPlus1 * ( pr = pixels[yi] ); 338 | g_sum = radiusPlus1 * ( pg = pixels[yi+1] ); 339 | b_sum = radiusPlus1 * ( pb = pixels[yi+2] ); 340 | 341 | stack = stackStart; 342 | 343 | for( i = radiusPlus1; --i > -1; ) 344 | { 345 | stack.r = pr; 346 | stack.g = pg; 347 | stack.b = pb; 348 | stack = stack.next; 349 | } 350 | 351 | for( i = 1; i < radiusPlus1; i++ ) 352 | { 353 | p = yi + (( widthMinus1 < i ? widthMinus1 : i ) << 2 ); 354 | r_sum += ( stack.r = pixels[p++]); 355 | g_sum += ( stack.g = pixels[p++]); 356 | b_sum += ( stack.b = pixels[p]); 357 | 358 | stack = stack.next; 359 | } 360 | 361 | stackIn = stackStart; 362 | for ( x = 0; x < width; x++ ) 363 | { 364 | pixels[yi++] = (r_sum * mul_sum) >>> shg_sum; 365 | pixels[yi++] = (g_sum * mul_sum) >>> shg_sum; 366 | pixels[yi++] = (b_sum * mul_sum) >>> shg_sum; 367 | yi++; 368 | 369 | p = ( yw + ( ( p = x + radius + 1 ) < widthMinus1 ? p : widthMinus1 ) ) << 2; 370 | 371 | r_sum -= stackIn.r - ( stackIn.r = pixels[p++]); 372 | g_sum -= stackIn.g - ( stackIn.g = pixels[p++]); 373 | b_sum -= stackIn.b - ( stackIn.b = pixels[p]); 374 | 375 | stackIn = stackIn.next; 376 | } 377 | yw += width; 378 | } 379 | 380 | 381 | for ( x = 0; x < width; x++ ) 382 | { 383 | yi = x << 2; 384 | 385 | r_sum = radiusPlus1 * ( pr = pixels[yi++]); 386 | g_sum = radiusPlus1 * ( pg = pixels[yi++]); 387 | b_sum = radiusPlus1 * ( pb = pixels[yi]); 388 | 389 | stack = stackStart; 390 | 391 | for( i = 0; i < radiusPlus1; i++ ) 392 | { 393 | stack.r = pr; 394 | stack.g = pg; 395 | stack.b = pb; 396 | stack = stack.next; 397 | } 398 | 399 | yp = width; 400 | 401 | for( i = 1; i <= radius; i++ ) 402 | { 403 | yi = ( yp + x ) << 2; 404 | 405 | r_sum += ( stack.r = pixels[yi++]); 406 | g_sum += ( stack.g = pixels[yi++]); 407 | b_sum += ( stack.b = pixels[yi]); 408 | 409 | stack = stack.next; 410 | 411 | if ( i < heightMinus1 ) yp += width; 412 | } 413 | 414 | yi = x; 415 | stackIn = stackStart; 416 | for ( y = 0; y < height; y++ ) 417 | { 418 | p = yi << 2; 419 | pixels[p] = (r_sum * mul_sum) >>> shg_sum; 420 | pixels[p+1] = (g_sum * mul_sum) >>> shg_sum; 421 | pixels[p+2] = (b_sum * mul_sum) >>> shg_sum; 422 | 423 | p = ( x + (( ( p = y + radiusPlus1) < heightMinus1 ? p : heightMinus1 ) * width )) << 2; 424 | 425 | r_sum -= stackIn.r - ( stackIn.r = pixels[p]); 426 | g_sum -= stackIn.g - ( stackIn.g = pixels[p+1]); 427 | b_sum -= stackIn.b - ( stackIn.b = pixels[p+2]); 428 | 429 | stackIn = stackIn.next; 430 | 431 | yi += width; 432 | } 433 | } 434 | } 435 | context.putImageData( imageData, top_x, top_y ); 436 | 437 | } 438 | 439 | function BlurStack() 440 | { 441 | this.r = 0; 442 | this.g = 0; 443 | this.b = 0; 444 | this.a = 0; 445 | this.next = null; 446 | } 447 | 448 | -------------------------------------------------------------------------------- /zorrosvg/img/example4.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /blur/StackBlur.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | StackBlur - a fast almost Gaussian Blur For Canvas 4 | 5 | Version: 0.6 6 | Author: Mario Klingemann 7 | Contact: mario@quasimondo.com 8 | Website: http://www.quasimondo.com/StackBlurForCanvas 9 | Twitter: @quasimondo 10 | 11 | In case you find this class useful - especially in commercial projects - 12 | I am not totally unhappy for a small donation to my PayPal account 13 | mario@quasimondo.de 14 | 15 | Or support me on flattr: 16 | https://flattr.com/thing/72791/StackBlur-a-fast-almost-Gaussian-Blur-Effect-for-CanvasJavascript 17 | 18 | Copyright (c) 2010 Mario Klingemann 19 | 20 | Permission is hereby granted, free of charge, to any person 21 | obtaining a copy of this software and associated documentation 22 | files (the "Software"), to deal in the Software without 23 | restriction, including without limitation the rights to use, 24 | copy, modify, merge, publish, distribute, sublicense, and/or sell 25 | copies of the Software, and to permit persons to whom the 26 | Software is furnished to do so, subject to the following 27 | conditions: 28 | 29 | The above copyright notice and this permission notice shall be 30 | included in all copies or substantial portions of the Software. 31 | 32 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 33 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 34 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 35 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 36 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 37 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 38 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 39 | OTHER DEALINGS IN THE SOFTWARE. 40 | */ 41 | 42 | var mul_table = [ 43 | 512,512,456,512,328,456,335,512,405,328,271,456,388,335,292,512, 44 | 454,405,364,328,298,271,496,456,420,388,360,335,312,292,273,512, 45 | 482,454,428,405,383,364,345,328,312,298,284,271,259,496,475,456, 46 | 437,420,404,388,374,360,347,335,323,312,302,292,282,273,265,512, 47 | 497,482,468,454,441,428,417,405,394,383,373,364,354,345,337,328, 48 | 320,312,305,298,291,284,278,271,265,259,507,496,485,475,465,456, 49 | 446,437,428,420,412,404,396,388,381,374,367,360,354,347,341,335, 50 | 329,323,318,312,307,302,297,292,287,282,278,273,269,265,261,512, 51 | 505,497,489,482,475,468,461,454,447,441,435,428,422,417,411,405, 52 | 399,394,389,383,378,373,368,364,359,354,350,345,341,337,332,328, 53 | 324,320,316,312,309,305,301,298,294,291,287,284,281,278,274,271, 54 | 268,265,262,259,257,507,501,496,491,485,480,475,470,465,460,456, 55 | 451,446,442,437,433,428,424,420,416,412,408,404,400,396,392,388, 56 | 385,381,377,374,370,367,363,360,357,354,350,347,344,341,338,335, 57 | 332,329,326,323,320,318,315,312,310,307,304,302,299,297,294,292, 58 | 289,287,285,282,280,278,275,273,271,269,267,265,263,261,259]; 59 | 60 | 61 | var shg_table = [ 62 | 9, 11, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17, 63 | 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 64 | 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 65 | 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 66 | 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 67 | 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 68 | 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 69 | 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 70 | 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 71 | 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 72 | 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 73 | 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 74 | 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 75 | 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 76 | 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 77 | 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24 ]; 78 | 79 | function stackBlurImage( imageIDOrElement, canvasIDOrElement, radius, blurAlphaChannel ) 80 | { 81 | 82 | var img = stackBlurGetElement( imageIDOrElement ); 83 | var w = img.naturalWidth; 84 | var h = img.naturalHeight; 85 | 86 | var canvas = stackBlurGetElement( canvasIDOrElement ); 87 | 88 | canvas.style.width = w + "px"; 89 | canvas.style.height = h + "px"; 90 | canvas.width = w; 91 | canvas.height = h; 92 | 93 | var context = canvas.getContext("2d"); 94 | context.clearRect( 0, 0, w, h ); 95 | context.drawImage( img, 0, 0 ); 96 | 97 | if ( isNaN(radius) || radius < 1 ) return; 98 | 99 | if ( blurAlphaChannel ) 100 | stackBlurCanvasRGBA( canvasIDOrElement, 0, 0, w, h, radius ); 101 | else 102 | stackBlurCanvasRGB( canvasIDOrElement, 0, 0, w, h, radius ); 103 | } 104 | 105 | 106 | function stackBlurCanvasRGBA( canvasIDOrElement, top_x, top_y, width, height, radius ) 107 | { 108 | var canvas = stackBlurGetElement( canvasIDOrElement ); 109 | var context = canvas.getContext("2d"); 110 | var imageData; 111 | 112 | try { 113 | try { 114 | imageData = context.getImageData( top_x, top_y, width, height ); 115 | } catch(e) { 116 | 117 | // NOTE: this part is supposedly only needed if you want to work with local files 118 | // so it might be okay to remove the whole try/catch block and just use 119 | // imageData = context.getImageData( top_x, top_y, width, height ); 120 | try { 121 | netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead"); 122 | imageData = context.getImageData( top_x, top_y, width, height ); 123 | } catch(e) { 124 | alert("Cannot access local image"); 125 | throw new Error("unable to access local image data: " + e); 126 | return; 127 | } 128 | } 129 | } catch(e) { 130 | alert("Cannot access image"); 131 | throw new Error("unable to access image data: " + e); 132 | } 133 | 134 | imageData = stackBlurImageDataRGBA( imageData, radius ); 135 | context.putImageData( imageData, top_x, top_y ); 136 | } 137 | 138 | 139 | function stackBlurImageDataRGBA( imageData, radius ) 140 | { 141 | if ( isNaN(radius) || radius < 1 ) return; 142 | radius |= 0; 143 | 144 | var pixels = imageData.data; 145 | var width = imageData.width; 146 | var height = imageData.height; 147 | 148 | var x, y, i, p, yp, yi, yw, r_sum, g_sum, b_sum, a_sum, 149 | r_out_sum, g_out_sum, b_out_sum, a_out_sum, 150 | r_in_sum, g_in_sum, b_in_sum, a_in_sum, 151 | pr, pg, pb, pa, rbs; 152 | 153 | var div = radius + radius + 1; 154 | var w4 = width << 2; 155 | var widthMinus1 = width - 1; 156 | var heightMinus1 = height - 1; 157 | var radiusPlus1 = radius + 1; 158 | var sumFactor = radiusPlus1 * ( radiusPlus1 + 1 ) / 2; 159 | 160 | var stackStart = new BlurStack(); 161 | var stack = stackStart; 162 | for ( i = 1; i < div; i++ ) 163 | { 164 | stack = stack.next = new BlurStack(); 165 | if ( i == radiusPlus1 ) var stackEnd = stack; 166 | } 167 | stack.next = stackStart; 168 | var stackIn = null; 169 | var stackOut = null; 170 | 171 | yw = yi = 0; 172 | 173 | var mul_sum = mul_table[radius]; 174 | var shg_sum = shg_table[radius]; 175 | 176 | for ( y = 0; y < height; y++ ) 177 | { 178 | r_in_sum = g_in_sum = b_in_sum = a_in_sum = r_sum = g_sum = b_sum = a_sum = 0; 179 | 180 | r_out_sum = radiusPlus1 * ( pr = pixels[yi] ); 181 | g_out_sum = radiusPlus1 * ( pg = pixels[yi+1] ); 182 | b_out_sum = radiusPlus1 * ( pb = pixels[yi+2] ); 183 | a_out_sum = radiusPlus1 * ( pa = pixels[yi+3] ); 184 | 185 | r_sum += sumFactor * pr; 186 | g_sum += sumFactor * pg; 187 | b_sum += sumFactor * pb; 188 | a_sum += sumFactor * pa; 189 | 190 | stack = stackStart; 191 | 192 | for( i = 0; i < radiusPlus1; i++ ) 193 | { 194 | stack.r = pr; 195 | stack.g = pg; 196 | stack.b = pb; 197 | stack.a = pa; 198 | stack = stack.next; 199 | } 200 | 201 | for( i = 1; i < radiusPlus1; i++ ) 202 | { 203 | p = yi + (( widthMinus1 < i ? widthMinus1 : i ) << 2 ); 204 | r_sum += ( stack.r = ( pr = pixels[p])) * ( rbs = radiusPlus1 - i ); 205 | g_sum += ( stack.g = ( pg = pixels[p+1])) * rbs; 206 | b_sum += ( stack.b = ( pb = pixels[p+2])) * rbs; 207 | a_sum += ( stack.a = ( pa = pixels[p+3])) * rbs; 208 | 209 | r_in_sum += pr; 210 | g_in_sum += pg; 211 | b_in_sum += pb; 212 | a_in_sum += pa; 213 | 214 | stack = stack.next; 215 | } 216 | 217 | 218 | stackIn = stackStart; 219 | stackOut = stackEnd; 220 | for ( x = 0; x < width; x++ ) 221 | { 222 | pixels[yi] = (r_sum * mul_sum) >> shg_sum; 223 | pixels[yi+1] = (g_sum * mul_sum) >> shg_sum; 224 | pixels[yi+2] = (b_sum * mul_sum) >> shg_sum; 225 | pixels[yi+3] = (a_sum * mul_sum) >> shg_sum; 226 | 227 | r_sum -= r_out_sum; 228 | g_sum -= g_out_sum; 229 | b_sum -= b_out_sum; 230 | a_sum -= a_out_sum; 231 | 232 | r_out_sum -= stackIn.r; 233 | g_out_sum -= stackIn.g; 234 | b_out_sum -= stackIn.b; 235 | a_out_sum -= stackIn.a; 236 | 237 | p = ( yw + ( ( p = x + radius + 1 ) < widthMinus1 ? p : widthMinus1 ) ) << 2; 238 | 239 | r_in_sum += ( stackIn.r = pixels[p]); 240 | g_in_sum += ( stackIn.g = pixels[p+1]); 241 | b_in_sum += ( stackIn.b = pixels[p+2]); 242 | a_in_sum += ( stackIn.a = pixels[p+3]); 243 | 244 | r_sum += r_in_sum; 245 | g_sum += g_in_sum; 246 | b_sum += b_in_sum; 247 | a_sum += a_in_sum; 248 | 249 | stackIn = stackIn.next; 250 | 251 | r_out_sum += ( pr = stackOut.r ); 252 | g_out_sum += ( pg = stackOut.g ); 253 | b_out_sum += ( pb = stackOut.b ); 254 | a_out_sum += ( pa = stackOut.a ); 255 | 256 | r_in_sum -= pr; 257 | g_in_sum -= pg; 258 | b_in_sum -= pb; 259 | a_in_sum -= pa; 260 | 261 | stackOut = stackOut.next; 262 | 263 | yi += 4; 264 | } 265 | yw += width; 266 | } 267 | 268 | 269 | for ( x = 0; x < width; x++ ) 270 | { 271 | g_in_sum = b_in_sum = a_in_sum = r_in_sum = g_sum = b_sum = a_sum = r_sum = 0; 272 | 273 | yi = x << 2; 274 | r_out_sum = radiusPlus1 * ( pr = pixels[yi]); 275 | g_out_sum = radiusPlus1 * ( pg = pixels[yi+1]); 276 | b_out_sum = radiusPlus1 * ( pb = pixels[yi+2]); 277 | a_out_sum = radiusPlus1 * ( pa = pixels[yi+3]); 278 | 279 | r_sum += sumFactor * pr; 280 | g_sum += sumFactor * pg; 281 | b_sum += sumFactor * pb; 282 | a_sum += sumFactor * pa; 283 | 284 | stack = stackStart; 285 | 286 | for( i = 0; i < radiusPlus1; i++ ) 287 | { 288 | stack.r = pr; 289 | stack.g = pg; 290 | stack.b = pb; 291 | stack.a = pa; 292 | stack = stack.next; 293 | } 294 | 295 | yp = width; 296 | 297 | for( i = 1; i <= radius; i++ ) 298 | { 299 | yi = ( yp + x ) << 2; 300 | 301 | r_sum += ( stack.r = ( pr = pixels[yi])) * ( rbs = radiusPlus1 - i ); 302 | g_sum += ( stack.g = ( pg = pixels[yi+1])) * rbs; 303 | b_sum += ( stack.b = ( pb = pixels[yi+2])) * rbs; 304 | a_sum += ( stack.a = ( pa = pixels[yi+3])) * rbs; 305 | 306 | r_in_sum += pr; 307 | g_in_sum += pg; 308 | b_in_sum += pb; 309 | a_in_sum += pa; 310 | 311 | stack = stack.next; 312 | 313 | if( i < heightMinus1 ) 314 | { 315 | yp += width; 316 | } 317 | } 318 | 319 | yi = x; 320 | stackIn = stackStart; 321 | stackOut = stackEnd; 322 | for ( y = 0; y < height; y++ ) 323 | { 324 | p = yi << 2; 325 | pixels[p+3] = pa = (a_sum * mul_sum) >> shg_sum; 326 | if ( pa > 0 ) 327 | { 328 | pa = 255 / pa; 329 | pixels[p] = ((r_sum * mul_sum) >> shg_sum ) * pa; 330 | pixels[p+1] = ((g_sum * mul_sum) >> shg_sum ) * pa; 331 | pixels[p+2] = ((b_sum * mul_sum) >> shg_sum ) * pa; 332 | } else { 333 | pixels[p] = pixels[p+1] = pixels[p+2] = 0; 334 | } 335 | 336 | r_sum -= r_out_sum; 337 | g_sum -= g_out_sum; 338 | b_sum -= b_out_sum; 339 | a_sum -= a_out_sum; 340 | 341 | r_out_sum -= stackIn.r; 342 | g_out_sum -= stackIn.g; 343 | b_out_sum -= stackIn.b; 344 | a_out_sum -= stackIn.a; 345 | 346 | p = ( x + (( ( p = y + radiusPlus1) < heightMinus1 ? p : heightMinus1 ) * width )) << 2; 347 | 348 | r_sum += ( r_in_sum += ( stackIn.r = pixels[p])); 349 | g_sum += ( g_in_sum += ( stackIn.g = pixels[p+1])); 350 | b_sum += ( b_in_sum += ( stackIn.b = pixels[p+2])); 351 | a_sum += ( a_in_sum += ( stackIn.a = pixels[p+3])); 352 | 353 | stackIn = stackIn.next; 354 | 355 | r_out_sum += ( pr = stackOut.r ); 356 | g_out_sum += ( pg = stackOut.g ); 357 | b_out_sum += ( pb = stackOut.b ); 358 | a_out_sum += ( pa = stackOut.a ); 359 | 360 | r_in_sum -= pr; 361 | g_in_sum -= pg; 362 | b_in_sum -= pb; 363 | a_in_sum -= pa; 364 | 365 | stackOut = stackOut.next; 366 | 367 | yi += width; 368 | } 369 | } 370 | 371 | return imageData; 372 | 373 | } 374 | 375 | 376 | function stackBlurCanvasRGB( canvasIDOrElement, top_x, top_y, width, height, radius ) 377 | { 378 | if ( isNaN(radius) || radius < 1 ) return; 379 | radius |= 0; 380 | 381 | var canvas = stackBlurGetElement( canvasIDOrElement ); 382 | var context = canvas.getContext("2d"); 383 | var imageData; 384 | 385 | try { 386 | try { 387 | imageData = context.getImageData( top_x, top_y, width, height ); 388 | } catch(e) { 389 | 390 | // NOTE: this part is supposedly only needed if you want to work with local files 391 | // so it might be okay to remove the whole try/catch block and just use 392 | // imageData = context.getImageData( top_x, top_y, width, height ); 393 | try { 394 | netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead"); 395 | imageData = context.getImageData( top_x, top_y, width, height ); 396 | } catch(e) { 397 | alert("Cannot access local image"); 398 | throw new Error("unable to access local image data: " + e); 399 | return; 400 | } 401 | } 402 | } catch(e) { 403 | alert("Cannot access image"); 404 | throw new Error("unable to access image data: " + e); 405 | } 406 | 407 | var pixels = imageData.data; 408 | 409 | var x, y, i, p, yp, yi, yw, r_sum, g_sum, b_sum, 410 | r_out_sum, g_out_sum, b_out_sum, 411 | r_in_sum, g_in_sum, b_in_sum, 412 | pr, pg, pb, rbs; 413 | 414 | var div = radius + radius + 1; 415 | var w4 = width << 2; 416 | var widthMinus1 = width - 1; 417 | var heightMinus1 = height - 1; 418 | var radiusPlus1 = radius + 1; 419 | var sumFactor = radiusPlus1 * ( radiusPlus1 + 1 ) / 2; 420 | 421 | var stackStart = new BlurStack(); 422 | var stack = stackStart; 423 | for ( i = 1; i < div; i++ ) 424 | { 425 | stack = stack.next = new BlurStack(); 426 | if ( i == radiusPlus1 ) var stackEnd = stack; 427 | } 428 | stack.next = stackStart; 429 | var stackIn = null; 430 | var stackOut = null; 431 | 432 | yw = yi = 0; 433 | 434 | var mul_sum = mul_table[radius]; 435 | var shg_sum = shg_table[radius]; 436 | 437 | for ( y = 0; y < height; y++ ) 438 | { 439 | r_in_sum = g_in_sum = b_in_sum = r_sum = g_sum = b_sum = 0; 440 | 441 | r_out_sum = radiusPlus1 * ( pr = pixels[yi] ); 442 | g_out_sum = radiusPlus1 * ( pg = pixels[yi+1] ); 443 | b_out_sum = radiusPlus1 * ( pb = pixels[yi+2] ); 444 | 445 | r_sum += sumFactor * pr; 446 | g_sum += sumFactor * pg; 447 | b_sum += sumFactor * pb; 448 | 449 | stack = stackStart; 450 | 451 | for( i = 0; i < radiusPlus1; i++ ) 452 | { 453 | stack.r = pr; 454 | stack.g = pg; 455 | stack.b = pb; 456 | stack = stack.next; 457 | } 458 | 459 | for( i = 1; i < radiusPlus1; i++ ) 460 | { 461 | p = yi + (( widthMinus1 < i ? widthMinus1 : i ) << 2 ); 462 | r_sum += ( stack.r = ( pr = pixels[p])) * ( rbs = radiusPlus1 - i ); 463 | g_sum += ( stack.g = ( pg = pixels[p+1])) * rbs; 464 | b_sum += ( stack.b = ( pb = pixels[p+2])) * rbs; 465 | 466 | r_in_sum += pr; 467 | g_in_sum += pg; 468 | b_in_sum += pb; 469 | 470 | stack = stack.next; 471 | } 472 | 473 | 474 | stackIn = stackStart; 475 | stackOut = stackEnd; 476 | for ( x = 0; x < width; x++ ) 477 | { 478 | pixels[yi] = (r_sum * mul_sum) >> shg_sum; 479 | pixels[yi+1] = (g_sum * mul_sum) >> shg_sum; 480 | pixels[yi+2] = (b_sum * mul_sum) >> shg_sum; 481 | 482 | r_sum -= r_out_sum; 483 | g_sum -= g_out_sum; 484 | b_sum -= b_out_sum; 485 | 486 | r_out_sum -= stackIn.r; 487 | g_out_sum -= stackIn.g; 488 | b_out_sum -= stackIn.b; 489 | 490 | p = ( yw + ( ( p = x + radius + 1 ) < widthMinus1 ? p : widthMinus1 ) ) << 2; 491 | 492 | r_in_sum += ( stackIn.r = pixels[p]); 493 | g_in_sum += ( stackIn.g = pixels[p+1]); 494 | b_in_sum += ( stackIn.b = pixels[p+2]); 495 | 496 | r_sum += r_in_sum; 497 | g_sum += g_in_sum; 498 | b_sum += b_in_sum; 499 | 500 | stackIn = stackIn.next; 501 | 502 | r_out_sum += ( pr = stackOut.r ); 503 | g_out_sum += ( pg = stackOut.g ); 504 | b_out_sum += ( pb = stackOut.b ); 505 | 506 | r_in_sum -= pr; 507 | g_in_sum -= pg; 508 | b_in_sum -= pb; 509 | 510 | stackOut = stackOut.next; 511 | 512 | yi += 4; 513 | } 514 | yw += width; 515 | } 516 | 517 | 518 | for ( x = 0; x < width; x++ ) 519 | { 520 | g_in_sum = b_in_sum = r_in_sum = g_sum = b_sum = r_sum = 0; 521 | 522 | yi = x << 2; 523 | r_out_sum = radiusPlus1 * ( pr = pixels[yi]); 524 | g_out_sum = radiusPlus1 * ( pg = pixels[yi+1]); 525 | b_out_sum = radiusPlus1 * ( pb = pixels[yi+2]); 526 | 527 | r_sum += sumFactor * pr; 528 | g_sum += sumFactor * pg; 529 | b_sum += sumFactor * pb; 530 | 531 | stack = stackStart; 532 | 533 | for( i = 0; i < radiusPlus1; i++ ) 534 | { 535 | stack.r = pr; 536 | stack.g = pg; 537 | stack.b = pb; 538 | stack = stack.next; 539 | } 540 | 541 | yp = width; 542 | 543 | for( i = 1; i <= radius; i++ ) 544 | { 545 | yi = ( yp + x ) << 2; 546 | 547 | r_sum += ( stack.r = ( pr = pixels[yi])) * ( rbs = radiusPlus1 - i ); 548 | g_sum += ( stack.g = ( pg = pixels[yi+1])) * rbs; 549 | b_sum += ( stack.b = ( pb = pixels[yi+2])) * rbs; 550 | 551 | r_in_sum += pr; 552 | g_in_sum += pg; 553 | b_in_sum += pb; 554 | 555 | stack = stack.next; 556 | 557 | if( i < heightMinus1 ) 558 | { 559 | yp += width; 560 | } 561 | } 562 | 563 | yi = x; 564 | stackIn = stackStart; 565 | stackOut = stackEnd; 566 | for ( y = 0; y < height; y++ ) 567 | { 568 | p = yi << 2; 569 | pixels[p] = (r_sum * mul_sum) >> shg_sum; 570 | pixels[p+1] = (g_sum * mul_sum) >> shg_sum; 571 | pixels[p+2] = (b_sum * mul_sum) >> shg_sum; 572 | 573 | r_sum -= r_out_sum; 574 | g_sum -= g_out_sum; 575 | b_sum -= b_out_sum; 576 | 577 | r_out_sum -= stackIn.r; 578 | g_out_sum -= stackIn.g; 579 | b_out_sum -= stackIn.b; 580 | 581 | p = ( x + (( ( p = y + radiusPlus1) < heightMinus1 ? p : heightMinus1 ) * width )) << 2; 582 | 583 | r_sum += ( r_in_sum += ( stackIn.r = pixels[p])); 584 | g_sum += ( g_in_sum += ( stackIn.g = pixels[p+1])); 585 | b_sum += ( b_in_sum += ( stackIn.b = pixels[p+2])); 586 | 587 | stackIn = stackIn.next; 588 | 589 | r_out_sum += ( pr = stackOut.r ); 590 | g_out_sum += ( pg = stackOut.g ); 591 | b_out_sum += ( pb = stackOut.b ); 592 | 593 | r_in_sum -= pr; 594 | g_in_sum -= pg; 595 | b_in_sum -= pb; 596 | 597 | stackOut = stackOut.next; 598 | 599 | yi += width; 600 | } 601 | } 602 | 603 | context.putImageData( imageData, top_x, top_y ); 604 | 605 | } 606 | 607 | function BlurStack() 608 | { 609 | this.r = 0; 610 | this.g = 0; 611 | this.b = 0; 612 | this.a = 0; 613 | this.next = null; 614 | } 615 | 616 | function stackBlurGetElement( elementOrID ) 617 | { 618 | if ( elementOrID.nodeType == 1 ) 619 | return elementOrID; 620 | 621 | return document.getElementById( elementOrID ); 622 | } 623 | -------------------------------------------------------------------------------- /zorrosvg/img/example1.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /blur/CompoundBlur.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | CompoundBlur - Blurring with varying radii for Canvas 4 | 5 | Version: 0.1 6 | Author: Mario Klingemann 7 | Contact: mario@quasimondo.com 8 | Website: http://www.quasimondo.com/StackBlurForCanvas 9 | Twitter: @quasimondo 10 | 11 | In case you find this class useful - especially in commercial projects - 12 | I am not totally unhappy for a small donation to my PayPal account 13 | mario@quasimondo.de 14 | 15 | Copyright (c) 2011 Mario Klingemann 16 | 17 | Permission is hereby granted, free of charge, to any person 18 | obtaining a copy of this software and associated documentation 19 | files (the "Software"), to deal in the Software without 20 | restriction, including without limitation the rights to use, 21 | copy, modify, merge, publish, distribute, sublicense, and/or sell 22 | copies of the Software, and to permit persons to whom the 23 | Software is furnished to do so, subject to the following 24 | conditions: 25 | 26 | The above copyright notice and this permission notice shall be 27 | included in all copies or substantial portions of the Software. 28 | 29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 30 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 31 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 32 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 33 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 34 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 35 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 36 | OTHER DEALINGS IN THE SOFTWARE. 37 | */ 38 | 39 | var mul_table = [ 40 | 512,512,456,512,328,456,335,512,405,328,271,456,388,335,292,512, 41 | 454,405,364,328,298,271,496,456,420,388,360,335,312,292,273,512, 42 | 482,454,428,405,383,364,345,328,312,298,284,271,259,496,475,456, 43 | 437,420,404,388,374,360,347,335,323,312,302,292,282,273,265,512, 44 | 497,482,468,454,441,428,417,405,394,383,373,364,354,345,337,328, 45 | 320,312,305,298,291,284,278,271,265,259,507,496,485,475,465,456, 46 | 446,437,428,420,412,404,396,388,381,374,367,360,354,347,341,335, 47 | 329,323,318,312,307,302,297,292,287,282,278,273,269,265,261,512, 48 | 505,497,489,482,475,468,461,454,447,441,435,428,422,417,411,405, 49 | 399,394,389,383,378,373,368,364,359,354,350,345,341,337,332,328, 50 | 324,320,316,312,309,305,301,298,294,291,287,284,281,278,274,271, 51 | 268,265,262,259,257,507,501,496,491,485,480,475,470,465,460,456, 52 | 451,446,442,437,433,428,424,420,416,412,408,404,400,396,392,388, 53 | 385,381,377,374,370,367,363,360,357,354,350,347,344,341,338,335, 54 | 332,329,326,323,320,318,315,312,310,307,304,302,299,297,294,292, 55 | 289,287,285,282,280,278,275,273,271,269,267,265,263,261,259]; 56 | 57 | 58 | var shg_table = [ 59 | 9, 11, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17, 60 | 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 61 | 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 62 | 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 63 | 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 64 | 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 65 | 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 66 | 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 67 | 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 68 | 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 69 | 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 70 | 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 71 | 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 72 | 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 73 | 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 74 | 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24 ]; 75 | 76 | 77 | function compoundBlurImage( imageID, canvasID, radiusData, minRadius, increaseFactor, blurLevels, blurAlphaChannel ) 78 | { 79 | 80 | var img = document.getElementById( imageID ); 81 | var w = img.naturalWidth; 82 | var h = img.naturalHeight; 83 | 84 | var canvas = document.getElementById( canvasID ); 85 | 86 | canvas.style.width = w + "px"; 87 | canvas.style.height = h + "px"; 88 | canvas.width = w; 89 | canvas.height = h; 90 | 91 | var context = canvas.getContext("2d"); 92 | context.clearRect( 0, 0, w, h ); 93 | context.drawImage( img, 0, 0 ); 94 | 95 | if ( isNaN(minRadius) || minRadius <= 0 || isNaN(increaseFactor) || increaseFactor == 0 ) return; 96 | 97 | if ( blurAlphaChannel ) 98 | compundBlurCanvasRGBA( canvasID, 0, 0, w, h, radiusData, minRadius, increaseFactor, blurLevels ); 99 | else 100 | compundBlurCanvasRGB( canvasID, 0, 0, w, h, radiusData, minRadius, increaseFactor, blurLevels ); 101 | } 102 | 103 | function getLinearGradientMap( width, height, centerX, centerY, angle, length, mirrored ) 104 | { 105 | var cnv = document.createElement('canvas'); 106 | cnv.width = width; 107 | cnv.height = height; 108 | 109 | var x1 = centerX + Math.cos( angle ) * length * 0.5; 110 | var y1 = centerY + Math.sin( angle ) * length * 0.5; 111 | 112 | var x2 = centerX - Math.cos( angle ) * length * 0.5; 113 | var y2 = centerY - Math.sin( angle ) * length * 0.5; 114 | 115 | var context = cnv.getContext("2d"); 116 | var gradient = context.createLinearGradient(x1, y1, x2, y2); 117 | if ( !mirrored ) 118 | { 119 | gradient.addColorStop(0, "white"); 120 | gradient.addColorStop(1, "black"); 121 | } else { 122 | gradient.addColorStop(0, "white"); 123 | gradient.addColorStop(0.5, "black"); 124 | gradient.addColorStop(1, "white"); 125 | } 126 | context.fillStyle = gradient; 127 | context.fillRect(0, 0, width, height ); 128 | return context.getImageData( 0, 0, width, height ); 129 | } 130 | 131 | function getRadialGradientMap( width, height, centerX, centerY, radius1, radius2 ) 132 | { 133 | var cnv = document.createElement('canvas'); 134 | cnv.width = width; 135 | cnv.height = height; 136 | 137 | 138 | var context = cnv.getContext("2d"); 139 | var gradient = context.createRadialGradient(centerX, centerY, radius1, centerX, centerY, radius2); 140 | 141 | gradient.addColorStop(1, "white"); 142 | gradient.addColorStop(0, "black"); 143 | 144 | context.fillStyle = gradient; 145 | context.fillRect(0, 0, width, height ); 146 | return context.getImageData( 0, 0, width, height ); 147 | } 148 | 149 | function compundBlurCanvasRGB( id, top_x, top_y, width, height, radiusData, minRadius, increaseFactor, blurLevels ) 150 | { 151 | if ( isNaN(minRadius) || minRadius <= 0 || isNaN(increaseFactor) || increaseFactor == 0 ) return; 152 | 153 | var canvas = document.getElementById( id ); 154 | var context = canvas.getContext("2d"); 155 | var imageData; 156 | 157 | try { 158 | try { 159 | imageData = context.getImageData( top_x, top_y, width, height ); 160 | } catch(e) { 161 | 162 | // NOTE: this part is supposedly only needed if you want to work with local files 163 | // so it might be okay to remove the whole try/catch block and just use 164 | // imageData = context.getImageData( top_x, top_y, width, height ); 165 | try { 166 | netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead"); 167 | imageData = context.getImageData( top_x, top_y, width, height ); 168 | } catch(e) { 169 | alert("Cannot access local image"); 170 | throw new Error("unable to access local image data: " + e); 171 | return; 172 | } 173 | } 174 | } catch(e) { 175 | alert("Cannot access image"); 176 | throw new Error("unable to access image data: " + e); 177 | } 178 | 179 | renderCompundBlurRGB( imageData, radiusData, width, height, minRadius, increaseFactor, blurLevels ); 180 | context.putImageData( imageData, top_x, top_y ); 181 | } 182 | 183 | function compundBlurCanvasRGBA( id, top_x, top_y, width, height, radiusData, minRadius, increaseFactor, blurLevels ) 184 | { 185 | if ( isNaN(minRadius) || minRadius <= 0 || isNaN(increaseFactor) || increaseFactor == 0 ) return; 186 | 187 | var canvas = document.getElementById( id ); 188 | var context = canvas.getContext("2d"); 189 | var imageData; 190 | 191 | try { 192 | try { 193 | imageData = context.getImageData( top_x, top_y, width, height ); 194 | } catch(e) { 195 | 196 | // NOTE: this part is supposedly only needed if you want to work with local files 197 | // so it might be okay to remove the whole try/catch block and just use 198 | // imageData = context.getImageData( top_x, top_y, width, height ); 199 | try { 200 | netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead"); 201 | imageData = context.getImageData( top_x, top_y, width, height ); 202 | } catch(e) { 203 | alert("Cannot access local image"); 204 | throw new Error("unable to access local image data: " + e); 205 | return; 206 | } 207 | } 208 | } catch(e) { 209 | alert("Cannot access image"); 210 | throw new Error("unable to access image data: " + e); 211 | } 212 | 213 | renderCompundBlurRGBA( imageData, radiusData, width, height, minRadius, increaseFactor, blurLevels ); 214 | context.putImageData( imageData, top_x, top_y ); 215 | } 216 | 217 | function renderCompundBlurRGB( imageData, radiusData, width, height, radius, increaseFactor, blurLevels ) 218 | { 219 | var x, y, i, p, yp, yi, yw, r_sum, g_sum, b_sum, 220 | r_out_sum, g_out_sum, b_out_sum, 221 | r_in_sum, g_in_sum, b_in_sum, 222 | pr, pg, pb, rbs; 223 | 224 | var imagePixels = imageData.data; 225 | var radiusPixels = radiusData.data; 226 | 227 | var wh = width * height; 228 | var wh4 = wh << 2; 229 | var pixels = []; 230 | 231 | for ( var i = 0; i < wh4; i++ ) 232 | { 233 | pixels[i] = imagePixels[i]; 234 | } 235 | 236 | var currentIndex = 0; 237 | var steps = blurLevels; 238 | blurLevels -= 1; 239 | 240 | while ( steps-- >= 0 ) 241 | { 242 | var iradius = ( radius + 0.5 ) | 0; 243 | if ( iradius == 0 ) continue; 244 | if ( iradius > 256 ) iradius = 256; 245 | 246 | var div = iradius + iradius + 1; 247 | var w4 = width << 2; 248 | var widthMinus1 = width - 1; 249 | var heightMinus1 = height - 1; 250 | var radiusPlus1 = iradius + 1; 251 | var sumFactor = radiusPlus1 * ( radiusPlus1 + 1 ) / 2; 252 | 253 | var stackStart = new BlurStack(); 254 | var stack = stackStart; 255 | for ( i = 1; i < div; i++ ) 256 | { 257 | stack = stack.next = new BlurStack(); 258 | if ( i == radiusPlus1 ) var stackEnd = stack; 259 | } 260 | stack.next = stackStart; 261 | var stackIn = null; 262 | var stackOut = null; 263 | 264 | yw = yi = 0; 265 | 266 | var mul_sum = mul_table[iradius]; 267 | var shg_sum = shg_table[iradius]; 268 | 269 | for ( y = 0; y < height; y++ ) 270 | { 271 | r_in_sum = g_in_sum = b_in_sum = r_sum = g_sum = b_sum = 0; 272 | 273 | r_out_sum = radiusPlus1 * ( pr = pixels[yi] ); 274 | g_out_sum = radiusPlus1 * ( pg = pixels[yi+1] ); 275 | b_out_sum = radiusPlus1 * ( pb = pixels[yi+2] ); 276 | 277 | r_sum += sumFactor * pr; 278 | g_sum += sumFactor * pg; 279 | b_sum += sumFactor * pb; 280 | 281 | stack = stackStart; 282 | 283 | for( i = 0; i < radiusPlus1; i++ ) 284 | { 285 | stack.r = pr; 286 | stack.g = pg; 287 | stack.b = pb; 288 | stack = stack.next; 289 | } 290 | 291 | for( i = 1; i < radiusPlus1; i++ ) 292 | { 293 | p = yi + (( widthMinus1 < i ? widthMinus1 : i ) << 2 ); 294 | r_sum += ( stack.r = ( pr = pixels[p])) * ( rbs = radiusPlus1 - i ); 295 | g_sum += ( stack.g = ( pg = pixels[p+1])) * rbs; 296 | b_sum += ( stack.b = ( pb = pixels[p+2])) * rbs; 297 | 298 | r_in_sum += pr; 299 | g_in_sum += pg; 300 | b_in_sum += pb; 301 | 302 | stack = stack.next; 303 | } 304 | 305 | 306 | stackIn = stackStart; 307 | stackOut = stackEnd; 308 | for ( x = 0; x < width; x++ ) 309 | { 310 | pixels[yi] = (r_sum * mul_sum) >> shg_sum; 311 | pixels[yi+1] = (g_sum * mul_sum) >> shg_sum; 312 | pixels[yi+2] = (b_sum * mul_sum) >> shg_sum; 313 | 314 | r_sum -= r_out_sum; 315 | g_sum -= g_out_sum; 316 | b_sum -= b_out_sum; 317 | 318 | r_out_sum -= stackIn.r; 319 | g_out_sum -= stackIn.g; 320 | b_out_sum -= stackIn.b; 321 | 322 | p = ( yw + ( ( p = x + radiusPlus1 ) < widthMinus1 ? p : widthMinus1 ) ) << 2; 323 | 324 | r_in_sum += ( stackIn.r = pixels[p]); 325 | g_in_sum += ( stackIn.g = pixels[p+1]); 326 | b_in_sum += ( stackIn.b = pixels[p+2]); 327 | 328 | r_sum += r_in_sum; 329 | g_sum += g_in_sum; 330 | b_sum += b_in_sum; 331 | 332 | stackIn = stackIn.next; 333 | 334 | r_out_sum += ( pr = stackOut.r ); 335 | g_out_sum += ( pg = stackOut.g ); 336 | b_out_sum += ( pb = stackOut.b ); 337 | 338 | r_in_sum -= pr; 339 | g_in_sum -= pg; 340 | b_in_sum -= pb; 341 | 342 | stackOut = stackOut.next; 343 | 344 | yi += 4; 345 | } 346 | yw += width; 347 | } 348 | 349 | 350 | for ( x = 0; x < width; x++ ) 351 | { 352 | g_in_sum = b_in_sum = r_in_sum = g_sum = b_sum = r_sum = 0; 353 | 354 | yi = x << 2; 355 | r_out_sum = radiusPlus1 * ( pr = pixels[yi]); 356 | g_out_sum = radiusPlus1 * ( pg = pixels[yi+1]); 357 | b_out_sum = radiusPlus1 * ( pb = pixels[yi+2]); 358 | 359 | r_sum += sumFactor * pr; 360 | g_sum += sumFactor * pg; 361 | b_sum += sumFactor * pb; 362 | 363 | stack = stackStart; 364 | 365 | for( i = 0; i < radiusPlus1; i++ ) 366 | { 367 | stack.r = pr; 368 | stack.g = pg; 369 | stack.b = pb; 370 | stack = stack.next; 371 | } 372 | 373 | yp = width; 374 | 375 | for( i = 1; i < radiusPlus1; i++ ) 376 | { 377 | yi = ( yp + x ) << 2; 378 | 379 | r_sum += ( stack.r = ( pr = pixels[yi])) * ( rbs = radiusPlus1 - i ); 380 | g_sum += ( stack.g = ( pg = pixels[yi+1])) * rbs; 381 | b_sum += ( stack.b = ( pb = pixels[yi+2])) * rbs; 382 | 383 | r_in_sum += pr; 384 | g_in_sum += pg; 385 | b_in_sum += pb; 386 | 387 | stack = stack.next; 388 | 389 | if( i < heightMinus1 ) 390 | { 391 | yp += width; 392 | } 393 | } 394 | 395 | yi = x; 396 | stackIn = stackStart; 397 | stackOut = stackEnd; 398 | for ( y = 0; y < height; y++ ) 399 | { 400 | p = yi << 2; 401 | pixels[p] = (r_sum * mul_sum) >> shg_sum; 402 | pixels[p+1] = (g_sum * mul_sum) >> shg_sum; 403 | pixels[p+2] = (b_sum * mul_sum) >> shg_sum; 404 | 405 | r_sum -= r_out_sum; 406 | g_sum -= g_out_sum; 407 | b_sum -= b_out_sum; 408 | 409 | r_out_sum -= stackIn.r; 410 | g_out_sum -= stackIn.g; 411 | b_out_sum -= stackIn.b; 412 | 413 | p = ( x + (( ( p = y + radiusPlus1) < heightMinus1 ? p : heightMinus1 ) * width )) << 2; 414 | 415 | r_sum += ( r_in_sum += ( stackIn.r = pixels[p])); 416 | g_sum += ( g_in_sum += ( stackIn.g = pixels[p+1])); 417 | b_sum += ( b_in_sum += ( stackIn.b = pixels[p+2])); 418 | 419 | stackIn = stackIn.next; 420 | 421 | r_out_sum += ( pr = stackOut.r ); 422 | g_out_sum += ( pg = stackOut.g ); 423 | b_out_sum += ( pb = stackOut.b ); 424 | 425 | r_in_sum -= pr; 426 | g_in_sum -= pg; 427 | b_in_sum -= pb; 428 | 429 | stackOut = stackOut.next; 430 | 431 | yi += width; 432 | } 433 | } 434 | 435 | radius *= increaseFactor; 436 | 437 | for ( i = wh; --i > -1 ; ) 438 | { 439 | var idx = i << 2; 440 | var lookupValue = (radiusPixels[idx+2] & 0xff) / 255.0 * blurLevels; 441 | var index = lookupValue | 0; 442 | 443 | if ( index == currentIndex ) 444 | { 445 | var blend = 256.0 * ( lookupValue - (lookupValue | 0 )); 446 | var iblend = 256 - blend; 447 | 448 | imagePixels[idx] = ( imagePixels[idx] * iblend + pixels[idx] * blend ) >> 8; 449 | imagePixels[idx+1] = ( imagePixels[idx+1] * iblend + pixels[idx+1] * blend) >> 8; 450 | imagePixels[idx+2] = ( imagePixels[idx+2] * iblend + pixels[idx+2] * blend) >> 8; 451 | 452 | } else if ( index == currentIndex + 1 ) 453 | { 454 | imagePixels[idx] = pixels[idx]; 455 | imagePixels[idx+1] = pixels[idx+1]; 456 | imagePixels[idx+2] = pixels[idx+2]; 457 | 458 | } 459 | } 460 | currentIndex++; 461 | } 462 | } 463 | 464 | function renderCompundBlurRGBA( imageData, radiusData, width, height, radius, increaseFactor, blurLevels ) 465 | { 466 | var x, y, i, p, yp, yi, yw, r_sum, g_sum, b_sum, a_sum, 467 | r_out_sum, g_out_sum, b_out_sum, a_out_sum, 468 | r_in_sum, g_in_sum, b_in_sum, a_in_sum, 469 | pa, pr, pg, pb, rbs; 470 | 471 | var imagePixels = imageData.data; 472 | var radiusPixels = radiusData.data; 473 | 474 | var wh = width * height; 475 | var wh4 = wh << 2; 476 | var pixels = []; 477 | 478 | for ( var i = 0; i < wh4; i++ ) 479 | { 480 | pixels[i] = imagePixels[i]; 481 | } 482 | 483 | var currentIndex = 0; 484 | var steps = blurLevels; 485 | blurLevels -= 1; 486 | 487 | while ( steps-- >= 0 ) 488 | { 489 | var iradius = ( radius + 0.5 ) | 0; 490 | if ( iradius == 0 ) continue; 491 | if ( iradius > 256 ) iradius = 256; 492 | 493 | var div = iradius + iradius + 1; 494 | var w4 = width << 2; 495 | var widthMinus1 = width - 1; 496 | var heightMinus1 = height - 1; 497 | var radiusPlus1 = iradius + 1; 498 | var sumFactor = radiusPlus1 * ( radiusPlus1 + 1 ) / 2; 499 | 500 | var stackStart = new BlurStack(); 501 | var stack = stackStart; 502 | for ( i = 1; i < div; i++ ) 503 | { 504 | stack = stack.next = new BlurStack(); 505 | if ( i == radiusPlus1 ) var stackEnd = stack; 506 | } 507 | stack.next = stackStart; 508 | var stackIn = null; 509 | var stackOut = null; 510 | 511 | yw = yi = 0; 512 | 513 | var mul_sum = mul_table[iradius]; 514 | var shg_sum = shg_table[iradius]; 515 | 516 | for ( y = 0; y < height; y++ ) 517 | { 518 | r_in_sum = g_in_sum = b_in_sum = a_in_sum = r_sum = g_sum = b_sum = a_sum = 0; 519 | 520 | r_out_sum = radiusPlus1 * ( pr = pixels[yi] ); 521 | g_out_sum = radiusPlus1 * ( pg = pixels[yi+1] ); 522 | b_out_sum = radiusPlus1 * ( pb = pixels[yi+2] ); 523 | a_out_sum = radiusPlus1 * ( pa = pixels[yi+3] ); 524 | 525 | r_sum += sumFactor * pr; 526 | g_sum += sumFactor * pg; 527 | b_sum += sumFactor * pb; 528 | a_sum += sumFactor * pa; 529 | 530 | stack = stackStart; 531 | 532 | for( i = 0; i < radiusPlus1; i++ ) 533 | { 534 | stack.r = pr; 535 | stack.g = pg; 536 | stack.b = pb; 537 | stack.a = pa; 538 | stack = stack.next; 539 | } 540 | 541 | for( i = 1; i < radiusPlus1; i++ ) 542 | { 543 | p = yi + (( widthMinus1 < i ? widthMinus1 : i ) << 2 ); 544 | r_sum += ( stack.r = ( pr = pixels[p])) * ( rbs = radiusPlus1 - i ); 545 | g_sum += ( stack.g = ( pg = pixels[p+1])) * rbs; 546 | b_sum += ( stack.b = ( pb = pixels[p+2])) * rbs; 547 | a_sum += ( stack.a = ( pa = pixels[p+3])) * rbs; 548 | 549 | r_in_sum += pr; 550 | g_in_sum += pg; 551 | b_in_sum += pb; 552 | a_in_sum += pa; 553 | 554 | stack = stack.next; 555 | } 556 | 557 | 558 | stackIn = stackStart; 559 | stackOut = stackEnd; 560 | for ( x = 0; x < width; x++ ) 561 | { 562 | pixels[yi+3] = pa = (a_sum * mul_sum) >> shg_sum; 563 | if ( pa != 0 ) 564 | { 565 | pa = 255 / pa; 566 | pixels[yi] = ((r_sum * mul_sum) >> shg_sum) * pa; 567 | pixels[yi+1] = ((g_sum * mul_sum) >> shg_sum) * pa; 568 | pixels[yi+2] = ((b_sum * mul_sum) >> shg_sum) * pa; 569 | } else { 570 | pixels[yi] = pixels[yi+1] = pixels[yi+2] = 0; 571 | } 572 | 573 | r_sum -= r_out_sum; 574 | g_sum -= g_out_sum; 575 | b_sum -= b_out_sum; 576 | a_sum -= a_out_sum; 577 | 578 | r_out_sum -= stackIn.r; 579 | g_out_sum -= stackIn.g; 580 | b_out_sum -= stackIn.b; 581 | a_out_sum -= stackIn.a; 582 | 583 | p = ( yw + ( ( p = x + radiusPlus1 ) < widthMinus1 ? p : widthMinus1 ) ) << 2; 584 | 585 | r_in_sum += ( stackIn.r = pixels[p]); 586 | g_in_sum += ( stackIn.g = pixels[p+1]); 587 | b_in_sum += ( stackIn.b = pixels[p+2]); 588 | a_in_sum += ( stackIn.a = pixels[p+3]); 589 | 590 | r_sum += r_in_sum; 591 | g_sum += g_in_sum; 592 | b_sum += b_in_sum; 593 | a_sum += a_in_sum; 594 | 595 | stackIn = stackIn.next; 596 | 597 | r_out_sum += ( pr = stackOut.r ); 598 | g_out_sum += ( pg = stackOut.g ); 599 | b_out_sum += ( pb = stackOut.b ); 600 | a_out_sum += ( pa = stackOut.a ); 601 | 602 | r_in_sum -= pr; 603 | g_in_sum -= pg; 604 | b_in_sum -= pb; 605 | a_in_sum -= pa; 606 | 607 | stackOut = stackOut.next; 608 | 609 | yi += 4; 610 | } 611 | yw += width; 612 | } 613 | 614 | 615 | for ( x = 0; x < width; x++ ) 616 | { 617 | g_in_sum = b_in_sum = a_in_sum = r_in_sum = g_sum = b_sum = a_sum = r_sum = 0; 618 | 619 | yi = x << 2; 620 | r_out_sum = radiusPlus1 * ( pr = pixels[yi]); 621 | g_out_sum = radiusPlus1 * ( pg = pixels[yi+1]); 622 | b_out_sum = radiusPlus1 * ( pb = pixels[yi+2]); 623 | a_out_sum = radiusPlus1 * ( pa = pixels[yi+3]); 624 | 625 | r_sum += sumFactor * pr; 626 | g_sum += sumFactor * pg; 627 | b_sum += sumFactor * pb; 628 | a_sum += sumFactor * pa; 629 | 630 | stack = stackStart; 631 | 632 | for( i = 0; i < radiusPlus1; i++ ) 633 | { 634 | stack.r = pr; 635 | stack.g = pg; 636 | stack.b = pb; 637 | stack.a = pa; 638 | stack = stack.next; 639 | } 640 | 641 | yp = width; 642 | 643 | for( i = 1; i < radiusPlus1; i++ ) 644 | { 645 | yi = ( yp + x ) << 2; 646 | 647 | r_sum += ( stack.r = ( pr = pixels[yi])) * ( rbs = radiusPlus1 - i ); 648 | g_sum += ( stack.g = ( pg = pixels[yi+1])) * rbs; 649 | b_sum += ( stack.b = ( pb = pixels[yi+2])) * rbs; 650 | a_sum += ( stack.a = ( pa = pixels[yi+3])) * rbs; 651 | 652 | r_in_sum += pr; 653 | g_in_sum += pg; 654 | b_in_sum += pb; 655 | a_in_sum += pa; 656 | 657 | stack = stack.next; 658 | 659 | if( i < heightMinus1 ) 660 | { 661 | yp += width; 662 | } 663 | } 664 | 665 | yi = x; 666 | stackIn = stackStart; 667 | stackOut = stackEnd; 668 | for ( y = 0; y < height; y++ ) 669 | { 670 | p = yi << 2; 671 | pixels[p+3] = pa = (a_sum * mul_sum) >> shg_sum; 672 | if ( pa > 0 ) 673 | { 674 | pa = 255 / pa; 675 | pixels[p] = ((r_sum * mul_sum) >> shg_sum ) * pa; 676 | pixels[p+1] = ((g_sum * mul_sum) >> shg_sum ) * pa; 677 | pixels[p+2] = ((b_sum * mul_sum) >> shg_sum ) * pa; 678 | } else { 679 | pixels[p] = pixels[p+1] = pixels[p+2] = 0; 680 | } 681 | 682 | r_sum -= r_out_sum; 683 | g_sum -= g_out_sum; 684 | b_sum -= b_out_sum; 685 | a_sum -= a_out_sum; 686 | 687 | r_out_sum -= stackIn.r; 688 | g_out_sum -= stackIn.g; 689 | b_out_sum -= stackIn.b; 690 | a_out_sum -= stackIn.a; 691 | 692 | p = ( x + (( ( p = y + radiusPlus1) < heightMinus1 ? p : heightMinus1 ) * width )) << 2; 693 | 694 | r_sum += ( r_in_sum += ( stackIn.r = pixels[p])); 695 | g_sum += ( g_in_sum += ( stackIn.g = pixels[p+1])); 696 | b_sum += ( b_in_sum += ( stackIn.b = pixels[p+2])); 697 | a_sum += ( a_in_sum += ( stackIn.a = pixels[p+3])); 698 | 699 | stackIn = stackIn.next; 700 | 701 | r_out_sum += ( pr = stackOut.r ); 702 | g_out_sum += ( pg = stackOut.g ); 703 | b_out_sum += ( pb = stackOut.b ); 704 | a_out_sum += ( pa = stackOut.a ); 705 | 706 | r_in_sum -= pr; 707 | g_in_sum -= pg; 708 | b_in_sum -= pb; 709 | a_in_sum -= pa; 710 | 711 | stackOut = stackOut.next; 712 | 713 | yi += width; 714 | } 715 | } 716 | 717 | radius *= increaseFactor; 718 | 719 | for ( i = wh; --i > -1 ; ) 720 | { 721 | var idx = i << 2; 722 | var lookupValue = (radiusPixels[idx+2] & 0xff) / 255.0 * blurLevels; 723 | var index = lookupValue | 0; 724 | 725 | if ( index == currentIndex ) 726 | { 727 | var blend = 256.0 * ( lookupValue - (lookupValue | 0 )); 728 | var iblend = 256 - blend; 729 | 730 | imagePixels[idx] = (imagePixels[idx] * iblend + pixels[idx] * blend) >> 8; 731 | imagePixels[idx+1] = (imagePixels[idx+1] * iblend + pixels[idx+1] * blend) >> 8; 732 | imagePixels[idx+2] = (imagePixels[idx+2] * iblend + pixels[idx+2] * blend) >> 8; 733 | imagePixels[idx+3] = (imagePixels[idx+3] * iblend + pixels[idx+3] * blend) >> 8; 734 | 735 | } else if ( index == currentIndex + 1 ) 736 | { 737 | imagePixels[idx] = pixels[idx]; 738 | imagePixels[idx+1] = pixels[idx+1]; 739 | imagePixels[idx+2] = pixels[idx+2]; 740 | imagePixels[idx+3] = pixels[idx+3]; 741 | } 742 | } 743 | currentIndex++; 744 | } 745 | } 746 | 747 | function BlurStack() 748 | { 749 | this.r = 0; 750 | this.g = 0; 751 | this.b = 0; 752 | this.a = 0; 753 | this.next = null; 754 | } -------------------------------------------------------------------------------- /zorrosvg/img/example3.svg: -------------------------------------------------------------------------------- 1 | --------------------------------------------------------------------------------