blob: a256ea9e20594ddf7efffeee72a1352c378a866a [file] [log] [blame]
package com.android.gallery3d.ui;
import android.graphics.Bitmap;
public class BoxBlurFilter {
private static final int RED_MASK = 0xff0000;
private static final int RED_MASK_SHIFT = 16;
private static final int GREEN_MASK = 0x00ff00;
private static final int GREEN_MASK_SHIFT = 8;
private static final int BLUE_MASK = 0x0000ff;
private static final int RADIUS = 4;
private static final int KERNEL_SIZE = RADIUS * 2 + 1;
private static final int NUM_COLORS = 256;
private static final int[] KERNEL_NORM = new int[KERNEL_SIZE * NUM_COLORS];
public static final int MODE_REPEAT = 1;
public static final int MODE_CLAMP = 2;
static {
int index = 0;
// Build a lookup table from summed to normalized kernel values.
// The formula: KERNAL_NORM[value] = value / KERNEL_SIZE
for (int i = 0; i < NUM_COLORS; ++i) {
for (int j = 0; j < KERNEL_SIZE; ++j) {
KERNEL_NORM[index++] = i;
}
}
}
private BoxBlurFilter() {
}
private static int sample(int x, int width, int mode) {
if (x >= 0 && x < width) return x;
return mode == MODE_REPEAT
? x < 0 ? x + width : x - width
: x < 0 ? 0 : width - 1;
}
public static void apply(
Bitmap bitmap, int horizontalMode, int verticalMode) {
int width = bitmap.getWidth();
int height = bitmap.getHeight();
int data[] = new int[width * height];
bitmap.getPixels(data, 0, width, 0, 0, width, height);
int temp[] = new int[width * height];
applyOneDimension(data, temp, width, height, horizontalMode);
applyOneDimension(temp, data, height, width, verticalMode);
bitmap.setPixels(data, 0, width, 0, 0, width, height);
}
private static void applyOneDimension(
int[] in, int[] out, int width, int height, int mode) {
for (int y = 0, read = 0; y < height; ++y, read += width) {
// Evaluate the kernel for the first pixel in the row.
int red = 0;
int green = 0;
int blue = 0;
for (int i = -RADIUS; i <= RADIUS; ++i) {
int argb = in[read + sample(i, width, mode)];
red += (argb & RED_MASK) >> RED_MASK_SHIFT;
green += (argb & GREEN_MASK) >> GREEN_MASK_SHIFT;
blue += argb & BLUE_MASK;
}
for (int x = 0, write = y; x < width; ++x, write += height) {
// Output the current pixel.
out[write] = 0xFF000000
| (KERNEL_NORM[red] << RED_MASK_SHIFT)
| (KERNEL_NORM[green] << GREEN_MASK_SHIFT)
| KERNEL_NORM[blue];
// Slide to the next pixel, adding the new rightmost pixel and
// subtracting the former leftmost.
int prev = in[read + sample(x - RADIUS, width, mode)];
int next = in[read + sample(x + RADIUS + 1, width, mode)];
red += ((next & RED_MASK) - (prev & RED_MASK)) >> RED_MASK_SHIFT;
green += ((next & GREEN_MASK) - (prev & GREEN_MASK)) >> GREEN_MASK_SHIFT;
blue += (next & BLUE_MASK) - (prev & BLUE_MASK);
}
}
}
}