Initial StackBlur port
This commit is contained in:
committed by
Joshua Granick
parent
6dce7ad79a
commit
5d0f446970
@@ -633,9 +633,7 @@ class ImageDataUtil
|
||||
|
||||
// TODO: Faster approach
|
||||
var imagePremultiplied = image.premultiplied;
|
||||
var sourceImagePremultiplied = sourceImage.premultiplied;
|
||||
if (imagePremultiplied) image.premultiplied = false;
|
||||
if (sourceImagePremultiplied) sourceImage.premultiplied = false;
|
||||
|
||||
// TODO: Use ImageDataView
|
||||
|
||||
@@ -645,77 +643,14 @@ class ImageDataUtil
|
||||
|
||||
// }
|
||||
|
||||
var imgB = image.data;
|
||||
var imgA = sourceImage.data;
|
||||
var w = Std.int(sourceRect.width);
|
||||
var h = Std.int(sourceRect.height);
|
||||
var bx = Std.int(blurX);
|
||||
var by = Std.int(blurY);
|
||||
var oX = Std.int(destPoint.x);
|
||||
var oY = Std.int(destPoint.y);
|
||||
|
||||
var n = (quality * 2) - 1;
|
||||
var rng = Math.pow(2, quality) * 0.125;
|
||||
|
||||
var bxs = __getBoxesForGaussianBlur(bx * rng, n);
|
||||
var bys = __getBoxesForGaussianBlur(by * rng, n);
|
||||
var offset:Int = Std.int((w * oY + oX) * 4);
|
||||
|
||||
__boxBlur(imgA, imgB, w, h, (bxs[0] - 1) / 2, (bys[0] - 1) / 2);
|
||||
var bIndex:Int = 1;
|
||||
|
||||
for (i in 0...Std.int(n / 2))
|
||||
{
|
||||
__boxBlur(imgB, imgA, w, h, (bxs[bIndex] - 1) / 2, (bys[bIndex] - 1) / 2);
|
||||
__boxBlur(imgA, imgB, w, h, (bxs[bIndex + 1] - 1) / 2, (bys[bIndex + 1] - 1) / 2);
|
||||
bIndex += 2;
|
||||
}
|
||||
|
||||
var x:Int;
|
||||
var y:Int;
|
||||
|
||||
if (offset != 0 || strength != 1)
|
||||
{
|
||||
if (offset <= 0)
|
||||
{
|
||||
y = 0;
|
||||
while (y < h)
|
||||
{
|
||||
x = 0;
|
||||
while (x < w)
|
||||
{
|
||||
__translatePixel(imgB, sourceImage.rect, image.rect, destPoint, x, y, strength);
|
||||
x += 1;
|
||||
}
|
||||
y += 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
y = h - 1;
|
||||
while (y >= 0)
|
||||
{
|
||||
x = w - 1;
|
||||
while (x >= 0)
|
||||
{
|
||||
__translatePixel(imgB, sourceImage.rect, image.rect, destPoint, x, y, strength);
|
||||
x -= 1;
|
||||
}
|
||||
y -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
StackBlur.blur(image, sourceImage, sourceRect, destPoint, blurX, blurY, quality);
|
||||
|
||||
image.dirty = true;
|
||||
image.version++;
|
||||
sourceImage.dirty = true;
|
||||
sourceImage.version++;
|
||||
|
||||
if (imagePremultiplied) image.premultiplied = true;
|
||||
if (sourceImagePremultiplied) sourceImage.premultiplied = true;
|
||||
|
||||
if (imgB == image.data) return image;
|
||||
return sourceImage;
|
||||
return image;
|
||||
}
|
||||
|
||||
public static function getColorBoundsRect(image:Image, mask:Int, color:Int, findColor:Bool, format:PixelFormat):Rectangle
|
||||
|
||||
195
src/lime/_internal/graphics/StackBlur.hx
Normal file
195
src/lime/_internal/graphics/StackBlur.hx
Normal file
@@ -0,0 +1,195 @@
|
||||
package lime._internal.graphics;
|
||||
|
||||
import lime.graphics.Image;
|
||||
import lime.math.Rectangle;
|
||||
import lime.math.Vector2;
|
||||
|
||||
// Ported from https://github.com/CreateJS/EaselJS/blob/master/src/easeljs/filters/BlurFilter.js
|
||||
class StackBlur
|
||||
{
|
||||
private static var MUL_TABLE:Array<Int> = [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];
|
||||
private static var SHG_TABLE:Array<Int> = [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];
|
||||
|
||||
public static function blur(dest:Image, source:Image, sourceRect:Rectangle, destPoint:Vector2, blurX:Float, blurY:Float, quality:Int)
|
||||
{
|
||||
dest.copyPixels(source, sourceRect, destPoint);
|
||||
__stackBlurCanvasRGBA(dest, Std.int(sourceRect.width), Std.int(sourceRect.height), blurX, blurY, quality);
|
||||
}
|
||||
|
||||
private static function __stackBlurCanvasRGBA(image:Image, width:Int, height:Int, blurX:Float, blurY:Float, quality:Int)
|
||||
{
|
||||
var radiusX = Math.round(blurX) >> 1;
|
||||
var radiusY = Math.round(blurY) >> 1;
|
||||
|
||||
if (radiusX < 0 || radiusY < 0)
|
||||
return;
|
||||
|
||||
var iterations = quality;
|
||||
if (iterations < 1) iterations = 1;
|
||||
if (iterations > 3) iterations = 3;
|
||||
|
||||
var px = image.data;
|
||||
var x:Int=0, y:Int=0, i:Int=0, p:Int=0, yp:Int=0, yi:Int=0, yw:Int=0;
|
||||
var r:Int=0, g:Int=0, b:Int=0, a:Int=0, pr:Int=0, pg:Int=0, pb:Int=0, pa:Int=0;
|
||||
|
||||
var divx = (radiusX + radiusX + 1);
|
||||
var divy = (radiusY + radiusY + 1);
|
||||
var w = width;
|
||||
var h = height;
|
||||
|
||||
var w1 = w - 1;
|
||||
var h1 = h - 1;
|
||||
var rxp1 = radiusX + 1;
|
||||
var ryp1 = radiusY + 1;
|
||||
|
||||
var ssx = new BlurStack();
|
||||
var sx = ssx;
|
||||
for (i in 1...divx)
|
||||
{
|
||||
sx = sx.n = new BlurStack();
|
||||
}
|
||||
sx.n = ssx;
|
||||
|
||||
var ssy = new BlurStack();
|
||||
var sy = ssy;
|
||||
for (i in 1...divy)
|
||||
{
|
||||
sy = sy.n = new BlurStack();
|
||||
}
|
||||
sy.n = ssy;
|
||||
|
||||
var si = null;
|
||||
|
||||
var mtx = MUL_TABLE[radiusX];
|
||||
var stx = SHG_TABLE[radiusX];
|
||||
var mty = MUL_TABLE[radiusY];
|
||||
var sty = SHG_TABLE[radiusY];
|
||||
|
||||
while (iterations > 0)
|
||||
{
|
||||
iterations--;
|
||||
yw = yi = 0;
|
||||
var ms = mtx;
|
||||
var ss = stx;
|
||||
y = h;
|
||||
do
|
||||
{
|
||||
r = rxp1 * (pr = px[yi]);
|
||||
g = rxp1 * (pg = px[yi + 1]);
|
||||
b = rxp1 * (pb = px[yi + 2]);
|
||||
a = rxp1 * (pa = px[yi + 3]);
|
||||
sx = ssx;
|
||||
i = rxp1;
|
||||
do
|
||||
{
|
||||
sx.r = pr;
|
||||
sx.g = pg;
|
||||
sx.b = pb;
|
||||
sx.a = pa;
|
||||
sx = sx.n;
|
||||
} while(--i > -1);
|
||||
|
||||
for (i in 1...rxp1)
|
||||
{
|
||||
p = yi + ((w1 < i ? w1 : i) << 2);
|
||||
r += ( sx.r = px[p]);
|
||||
g += ( sx.g = px[p+1]);
|
||||
b += ( sx.b = px[p+2]);
|
||||
a += ( sx.a = px[p+3]);
|
||||
sx = sx.n;
|
||||
}
|
||||
|
||||
si = ssx;
|
||||
for (x in 0...w)
|
||||
{
|
||||
px[yi++] = (r * ms) >>> ss;
|
||||
px[yi++] = (g * ms) >>> ss;
|
||||
px[yi++] = (b * ms) >>> ss;
|
||||
px[yi++] = (a * ms) >>> ss;
|
||||
p = (yw + ((p = x + radiusX + 1) < w1 ? p : w1)) << 2;
|
||||
r -= si.r - ( si.r = px[p]);
|
||||
g -= si.g - ( si.g = px[p+1]);
|
||||
b -= si.b - ( si.b = px[p+2]);
|
||||
a -= si.a - ( si.a = px[p+3]);
|
||||
si = si.n;
|
||||
}
|
||||
yw += w;
|
||||
} while (--y > -1);
|
||||
|
||||
ms = mty;
|
||||
ss = sty;
|
||||
for (x in 0...w)
|
||||
{
|
||||
yi = x << 2;
|
||||
r = ryp1 * (pr = px[yi]);
|
||||
g = ryp1 * (pg = px[yi + 1]);
|
||||
b = ryp1 * (pb = px[yi + 2]);
|
||||
a = ryp1 * (pa = px[yi + 3]);
|
||||
sy = ssy;
|
||||
for (i in 0...ryp1)
|
||||
{
|
||||
sy.r = pr;
|
||||
sy.g = pg;
|
||||
sy.b = pb;
|
||||
sy.a = pa;
|
||||
sy = sy.n;
|
||||
}
|
||||
yp = w;
|
||||
for(i in 1...(radiusY + 1))
|
||||
{
|
||||
yi = ( yp + x ) << 2;
|
||||
r += ( sy.r = px[yi]);
|
||||
g += ( sy.g = px[yi+1]);
|
||||
b += ( sy.b = px[yi+2]);
|
||||
a += ( sy.a = px[yi+3]);
|
||||
sy = sy.n;
|
||||
if( i < h1 )
|
||||
{
|
||||
yp += w;
|
||||
}
|
||||
}
|
||||
yi = x;
|
||||
si = ssy;
|
||||
for (y in 0...h)
|
||||
{
|
||||
p = yi << 2;
|
||||
px[p+3] = pa = (a * ms) >>> ss;
|
||||
if ( pa > 0 )
|
||||
{
|
||||
px[p] = (r * ms) >>> ss;
|
||||
px[p+1] = (g * ms) >>> ss;
|
||||
px[p+2] = (b * ms) >>> ss;
|
||||
}
|
||||
else
|
||||
{
|
||||
px[p] = px[p+1] = px[p+2] = 0;
|
||||
}
|
||||
p = ( x + (( ( p = y + ryp1) < h1 ? p : h1 ) * w )) << 2;
|
||||
r -= si.r - (si.r = px[p]);
|
||||
g -= si.g - (si.g = px[p+1]);
|
||||
b -= si.b - (si.b = px[p+2]);
|
||||
a -= si.a - (si.a = px[p+3]);
|
||||
si = si.n;
|
||||
yi += w;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class BlurStack
|
||||
{
|
||||
public var r:Int;
|
||||
public var g:Int;
|
||||
public var b:Int;
|
||||
public var a:Int;
|
||||
public var n:BlurStack;
|
||||
public function new()
|
||||
{
|
||||
this.r = 0;
|
||||
this.g = 0;
|
||||
this.b = 0;
|
||||
this.a = 0;
|
||||
this.n = null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user