I'm looking to add a blur animation to an ImageView
, but with a set duration. So, for example I want an image to blur out over time.
I already have the method to blur the image, but what I need is to make it go from blur to none blur over, say, 2 seconds.
Can anybody help me out?
EDIT: This is the method I currently have to blur the image.
public Bitmap blur(Bitmap sentBitmap, int radius) {
// Stack Blur Algorithm by Mario Klingemann <mario@quasimondo.com>
Bitmap bitmap = sentBitmap.copy(sentBitmap.getConfig(), true);
if (radius < 1) {
return (null);
}
int w = bitmap.getWidth();
int h = bitmap.getHeight();
int[] pix = new int[w * h];
Log.e("pix", w + " " + h + " " + pix.length);
bitmap.getPixels(pix, 0, w, 0, 0, w, h);
int wm = w - 1;
int hm = h - 1;
int wh = w * h;
int div = radius + radius + 1;
int r[] = new int[wh];
int g[] = new int[wh];
int b[] = new int[wh];
int rsum, gsum, bsum, x, y, i, p, yp, yi, yw;
int vmin[] = new int[Math.max(w, h)];
int divsum = (div + 1) >> 1;
divsum *= divsum;
int dv[] = new int[256 * divsum];
for (i = 0; i < 256 * divsum; i++) {
dv[i] = (i / divsum);
}
yw = yi = 0;
int[][] stack = new int[div][3];
int stackpointer;
int stackstart;
int[] sir;
int rbs;
int r1 = radius + 1;
int routsum, goutsum, boutsum;
int rinsum, ginsum, binsum;
for (y = 0; y < h; y++) {
rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
for (i = -radius; i <= radius; i++) {
p = pix[yi + Math.min(wm, Math.max(i, 0))];
sir = stack[i + radius];
sir[0] = (p & 0xff0000) >> 16;
sir[1] = (p & 0x00ff00) >> 8;
sir[2] = (p & 0x0000ff);
rbs = r1 - Math.abs(i);
rsum += sir[0] * rbs;
gsum += sir[1] * rbs;
bsum += sir[2] * rbs;
if (i > 0) {
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
} else {
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
}
}
stackpointer = radius;
for (x = 0; x < w; x++) {
r[yi] = dv[rsum];
g[yi] = dv[gsum];
b[yi] = dv[bsum];
rsum -= routsum;
gsum -= goutsum;
bsum -= boutsum;
stackstart = stackpointer - radius + div;
sir = stack[stackstart % div];
routsum -= sir[0];
goutsum -= sir[1];
boutsum -= sir[2];
if (y == 0) {
vmin[x] = Math.min(x + radius + 1, wm);
}
p = pix[yw + vmin[x]];
sir[0] = (p & 0xff0000) >> 16;
sir[1] = (p & 0x00ff00) >> 8;
sir[2] = (p & 0x0000ff);
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
rsum += rinsum;
gsum += ginsum;
bsum += binsum;
stackpointer = (stackpointer + 1) % div;
sir = stack[(stackpointer) % div];
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
rinsum -= sir[0];
ginsum -= sir[1];
binsum -= sir[2];
yi++;
}
yw += w;
}
for (x = 0; x < w; x++) {
rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
yp = -radius * w;
for (i = -radius; i <= radius; i++) {
yi = Math.max(0, yp) + x;
sir = stack[i + radius];
sir[0] = r[yi];
sir[1] = g[yi];
sir[2] = b[yi];
rbs = r1 - Math.abs(i);
rsum += r[yi] * rbs;
gsum += g[yi] * rbs;
bsum += b[yi] * rbs;
if (i > 0) {
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
} else {
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
}
if (i < hm) {
yp += w;
}
}
yi = x;
stackpointer = radius;
for (y = 0; y < h; y++) {
// Preserve alpha channel: ( 0xff000000 & pix[yi] )
pix[yi] = ( 0xff000000 & pix[yi] ) | ( dv[rsum] << 16 ) | ( dv[gsum] << 8 ) | dv[bsum];
rsum -= routsum;
gsum -= goutsum;
bsum -= boutsum;
stackstart = stackpointer - radius + div;
sir = stack[stackstart % div];
routsum -= sir[0];
goutsum -= sir[1];
boutsum -= sir[2];
if (x == 0) {
vmin[y] = Math.min(y + r1, hm) * w;
}
p = x + vmin[y];
sir[0] = r[p];
sir[1] = g[p];
sir[2] = b[p];
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
rsum += rinsum;
gsum += ginsum;
bsum += binsum;
stackpointer = (stackpointer + 1) % div;
sir = stack[stackpointer];
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
rinsum -= sir[0];
ginsum -= sir[1];
binsum -= sir[2];
yi += w;
}
}
Log.e("pix", w + " " + h + " " + pix.length);
bitmap.setPixels(pix, 0, w, 0, 0, w, h);
return (bitmap);
}
Blur effects are always difficult on Android. Essentially you have to decide between looks and performance. The better the blur looks the longer it takes, and if the blurring itself is not instantaneous then you cannot really animate the blur.
You original blurring algorithm produces really good results, but because of that it is also very slow making a blur animation impossible. Just to demonstrate what it would take to effectively blur this image I have created a simple blur animation by scaling the bitmap down:
This works quite well (even though there is still some lag), but the results cannot be compared with your blur algorithm, it just looks terrible:
So you see, it is very difficult to combine performance and good looks when it comes to blurring an image, but there are some options first and foremost
RenderScript
.RenderScript
is very fast and has a built in gaussian blur filter. I have never used it, but from what I hear it might be the solution to your problem.You can also try to load already scaled down versions of an image, this would produce the same effect as in the gif above, but would be even faster. The drawback is that using this in an
Animation
is again problematic, but if you just need a blurred image and you don't really care about quality then you should go for this option.You can find more information about
RenderScript
and other fast blur options in this answerI won't prolong my answer too much with code because honestly I don't have it, but I'll try to point out the key things you must consider and a few useful links.
first, the approach:
blur as fast as possible:
your algorithm looks really nice and I believe it does give a good effect, but the reality is that it's running in Java VM in a single thread. You will for absolutely sure have much better performance using RenderScript. That's because RenderScript auto-scales the rendering process to multi-processor and to the GPU.
the base code for it is below, taken directly from android-developers.blogspot.com:
cache the blurred results:
That's because Blur takes time. There will also be a lot of memory implications on that and you must watch it carefully. You certainly won't be able to do it very well in a scrolling list that is recycling views and stuff. A tip maybe is to use
Picasso
library (LINK) for that and also handle your threading. Something like this:cross-fade:
here is where you'll balance between performance and great looks. The reality is that a real animation is impossible without actually render every frame for every step, but with a cross-fade between a few key-frames you can achieve great results.
How many key-frames you'll use will depend on the performance you want, the amount of free memory on the device, etc.
If you're fine with just 2 key-frames (1 not blurred and 1 totally blurred) you can probably apply a TransitionDrawable to it. If you want a finer looking effect, you'll have to create a series of cross-fade transitions or probably create your own custom drawable.
for just 2 key-frames you can see an example on the Yahoo Weather app, if you would like to see an example with a few key-frames you want to check Muzei live wallpaper.
very useful links*
On the following link you'll see a nice discussion by Muzei creator (Roman Nurik, which is also one of the engineers at Google working for the Android) on how he achieved the key-frames, why that's the only way to do it and why, although more complex code, it creates at the end a much prettier result: (short version) https://plus.google.com/+RomanNurik/posts/2sTQ1X2Cb2Z (complete version) https://medium.com/@romannurik/serendipitous-ideas-3a1721a6f716
This link is the source code for Muzei live-wallpaper where you can check how he calculates the key-frames and animates the wallpaper: https://github.com/romannurik/muzei
Good luck and happy coding!
I'm a little bit late to the party, but if I unstderstand you correctly you want to "fade in the blur" so it increases cnstantly?
You can achive this effect by stacking two ImageViews on top of each other. The lower one shows the untouched image, the upper one a blured one which is pre-rendered. The upper one must be invisible (alpha=0f). Next you fade in the upper ImageView and fade out the lower ImageView. This will given you the desired effect. You can customize the effect by playing with the timings and transperancies.
Good luck :)
The blurring itself takes a lot of time, even on new devices. Animating the blur would be even worse. RenderScript wouldn't help much either. Your best bet is to cross-fade between a blurred and non-blurred images:
Note: The crossfade code was taken from: Source (animates on click)
Another way I can think of of doing this, is to use JQuery and animate the blur inside of a WebView.
// these are blurring methods