Skip to content

Instantly share code, notes, and snippets.

@gfpacheco
Created August 15, 2015 19:03
Show Gist options
  • Save gfpacheco/eb996194d9faaafd1922 to your computer and use it in GitHub Desktop.
Save gfpacheco/eb996194d9faaafd1922 to your computer and use it in GitHub Desktop.
Picasso blur transformation compatible with older version of Android
package com.gfpacheco;
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.Build;
import android.support.v8.renderscript.Allocation;
import android.support.v8.renderscript.Element;
import android.support.v8.renderscript.RenderScript;
import android.support.v8.renderscript.ScriptIntrinsicBlur;
import com.squareup.picasso.Transformation;
public class BlurTransformation implements Transformation {
private final Context mContext;
private final int mRadius;
public BlurTransformation(Context context, int radius) {
mContext = context;
mRadius = radius;
}
@Override
public Bitmap transform(Bitmap source) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
return blur(source);
} else {
return blur2(source);
}
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
private Bitmap blur(Bitmap original) {
RenderScript rs = RenderScript.create(mContext);
final Allocation input = Allocation.createFromBitmap(rs, original);
final Allocation output = Allocation.createTyped(rs, input.getType());
final ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
script.setRadius((float) mRadius);
script.setInput(input);
script.forEach(output);
output.copyTo(original);
return original;
}
private Bitmap blur2(Bitmap original) {
Bitmap bitmap = original.copy(original.getConfig(), true);
if (mRadius < 1) {
return (null);
}
int w = bitmap.getWidth();
int h = bitmap.getHeight();
int[] pix = new int[w * h];
bitmap.getPixels(pix, 0, w, 0, 0, w, h);
int wm = w - 1;
int hm = h - 1;
int wh = w * h;
int div = mRadius + mRadius + 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 = mRadius + 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 = -mRadius; i <= mRadius; i++) {
p = pix[yi + Math.min(wm, Math.max(i, 0))];
sir = stack[i + mRadius];
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 = mRadius;
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 - mRadius + div;
sir = stack[stackStart % div];
rOutSum -= sir[0];
gOutSum -= sir[1];
bOutSum -= sir[2];
if (y == 0) {
vMin[x] = Math.min(x + mRadius + 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 = -mRadius * w;
for (i = -mRadius; i <= mRadius; i++) {
yi = Math.max(0, yp) + x;
sir = stack[i + mRadius];
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 = mRadius;
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 - mRadius + 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;
}
}
bitmap.setPixels(pix, 0, w, 0, 0, w, h);
return bitmap;
}
@Override
public String key() {
return "blur" + mRadius;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment