diff options
Diffstat (limited to 'src/com/android/gallery3d/ui/BoxBlurFilter.java')
-rw-r--r-- | src/com/android/gallery3d/ui/BoxBlurFilter.java | 100 |
1 files changed, 100 insertions, 0 deletions
diff --git a/src/com/android/gallery3d/ui/BoxBlurFilter.java b/src/com/android/gallery3d/ui/BoxBlurFilter.java new file mode 100644 index 000000000..0497a61fa --- /dev/null +++ b/src/com/android/gallery3d/ui/BoxBlurFilter.java @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +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); + } + } + } +} |