| /* |
| * 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); |
| } |
| } |
| } |
| } |