package com.vansuita.gaussianblur;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.support.annotation.FloatRange;
import android.support.annotation.IntRange;
import android.support.annotation.UiThread;
import android.support.annotation.WorkerThread;
import android.support.v8.renderscript.Allocation;
import android.support.v8.renderscript.RenderScript;
import android.support.v8.renderscript.ScriptIntrinsicBlur;
import android.widget.ImageView;
import java.lang.ref.WeakReference;
/**
* Created by jrvansuita on 09/11/16.
*/
public class GaussianBlur {
public static final int MIN_RADIUS = 0;
public static final int MAX_RADIUS = 25;
public static final int MIN_SIZE = 0;
public static final int MAX_SIZE = 800;
private Context context;
private int radius;
private float size;
private GaussianBlur(Context context) {
this.context = context;
radius(MAX_RADIUS);
size(MAX_SIZE);
}
public static GaussianBlur with(Context context) {
return new GaussianBlur(context);
}
@WorkerThread
public Bitmap render(int res) {
return render(BitmapFactory.decodeResource(context.getResources(), res));
}
@WorkerThread
public Bitmap render(Drawable drawable) {
return render(((BitmapDrawable) drawable).getBitmap());
}
@WorkerThread
public Bitmap render(Bitmap source) {
Bitmap bitmap = source;
RenderScript rs = RenderScript.create(context);
if (getSize() > 0)
bitmap = scaleDown(bitmap);
Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
Allocation inAlloc = Allocation.createFromBitmap(rs, bitmap, Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_GRAPHICS_TEXTURE);
Allocation outAlloc = Allocation.createFromBitmap(rs, output);
ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(rs, inAlloc.getElement()); // Element.U8_4(rs));
script.setRadius(getRadius());
script.setInput(inAlloc);
script.forEach(outAlloc);
outAlloc.copyTo(output);
rs.destroy();
return output;
}
@UiThread
public void put(Drawable drawable, ImageView imageView) {
new BitmapGaussianAsync(imageView).execute(((BitmapDrawable) drawable).getBitmap());
}
@UiThread
public void put(Bitmap bitmap, ImageView imageView) {
new BitmapGaussianAsync(imageView).execute(bitmap);
}
@UiThread
public void put(int res, ImageView imageView) {
new ResourceGaussianAsync(imageView).execute(res);
}
@WorkerThread
public Bitmap scaleDown(int res) {
return scaleDown(BitmapFactory.decodeResource(context.getResources(), res));
}
@WorkerThread
public Bitmap scaleDown(Bitmap input) {
float ratio = Math.min(getSize() / input.getWidth(), getSize() / input.getHeight());
int width = Math.round(ratio * input.getWidth());
int height = Math.round(ratio * input.getHeight());
return Bitmap.createScaledBitmap(input, width, height, true);
}
public int getRadius() {
return radius;
}
/**
* @param radius Set the gaussian blur radius.
*/
public GaussianBlur radius(@IntRange(from = MIN_RADIUS, to = MAX_RADIUS) int radius) {
this.radius = radius;
return this;
}
public float getSize() {
return size;
}
/**
* This method is provided to speed up the process. Once the image will be blurred,
* there's no need to keep the original image size.
* The smaller, the fastest.
* @param maxSize Set an float value to define the image size. Zero, means the image will be keep with original size.
*/
public GaussianBlur size(@FloatRange(from = MIN_SIZE, to = MAX_SIZE) float maxSize) {
this.size = maxSize;
return this;
}
/**
* Async load and apply gaussian blur on an image from resource
*/
class ResourceGaussianAsync extends GaussianAsync<Integer> {
public ResourceGaussianAsync(ImageView imageView) {
super(imageView);
}
@Override
protected Bitmap doInBackground(Integer... params) {
return render(params[0]);
}
}
/**
* Async load and apply gaussian blur on an image from bitmap
*/
class BitmapGaussianAsync extends GaussianAsync<Bitmap> {
public BitmapGaussianAsync(ImageView imageView) {
super(imageView);
}
@Override
protected Bitmap doInBackground(Bitmap... params) {
return render(params[0]);
}
}
/**
* Async base class
*/
abstract class GaussianAsync<T> extends AsyncTask<T, Void, Bitmap> {
private final WeakReference<ImageView> imageViewReference;
public GaussianAsync(ImageView imageView) {
imageViewReference = new WeakReference(imageView);
}
@Override
protected void onPostExecute(Bitmap bitmap) {
if (imageViewReference != null && bitmap != null) {
final ImageView imageView = imageViewReference.get();
if (imageView != null) {
imageView.setImageBitmap(bitmap);
}
}
}
}
}