package com.glview.stackblur; import java.util.ArrayList; import java.util.concurrent.Callable; import com.glview.blur.Blur; /** * Blur using Java code. * * This is a compromise between Gaussian Blur and Box blur * It creates much better looking blurs than Box Blur, but is * 7x faster than my Gaussian Blur implementation. * I called it Stack Blur because this describes best how this * filter works internally: it creates a kind of moving stack * of colors whilst scanning through the image. Thereby it * just has to add one new block of color to the right side * of the stack and remove the leftmost color. The remaining * colors on the topmost layer of the stack are either added on * or reduced by one, depending on if they are on the right or * on the left side of the stack. * * @author Enrique López Mañas <eenriquelopez@gmail.com> * http://www.neo-tech.es * * Author of the original algorithm: Mario Klingemann <mario.quasimondo.com> * * Based heavily on http://vitiy.info/Code/stackblur.cpp * See http://vitiy.info/stackblur-algorithm-multi-threaded-blur-for-cpp/ * * @copyright: Enrique López Mañas * @license: Apache License 2.0 */ public class NativeBlurProcess implements BlurProcess { @Override public byte[] blur(byte[] original, int w, int h, int stride, float radius) { if (stride < w) stride = w; byte[] currentPixels = original; int cores = EXECUTOR_THREADS; ArrayList<A8BlurTask> horizontal = new ArrayList<A8BlurTask>(cores); ArrayList<A8BlurTask> vertical = new ArrayList<A8BlurTask>(cores); for (int i = 0; i < cores; i++) { horizontal.add(new A8BlurTask(currentPixels, w, h, stride, (int) radius, cores, i, 1)); vertical.add(new A8BlurTask(currentPixels, w, h, stride, (int) radius, cores, i, 2)); } try { EXECUTOR.invokeAll(horizontal); } catch (InterruptedException e) { return null; } try { EXECUTOR.invokeAll(vertical); } catch (InterruptedException e) { return null; } return currentPixels; } @Override public int[] blur(int[] original, int w, int h, int stride, float radius) { int[] currentPixels = new int[w * h]; System.arraycopy(original, 0, currentPixels, 0, currentPixels.length); int cores = EXECUTOR_THREADS; ArrayList<RGBABlurTask> horizontal = new ArrayList<RGBABlurTask>(cores); ArrayList<RGBABlurTask> vertical = new ArrayList<RGBABlurTask>(cores); for (int i = 0; i < cores; i++) { horizontal.add(new RGBABlurTask(currentPixels, w, h, (int) radius, cores, i, 1)); vertical.add(new RGBABlurTask(currentPixels, w, h, (int) radius, cores, i, 2)); } try { EXECUTOR.invokeAll(horizontal); } catch (InterruptedException e) { return null; } try { EXECUTOR.invokeAll(vertical); } catch (InterruptedException e) { return null; } return currentPixels; } private static class RGBABlurTask implements Callable<Void> { private final int[] _src; private final int _w; private final int _h; private final int _radius; private final int _totalCores; private final int _coreIndex; private final int _round; public RGBABlurTask(int[] src, int w, int h, int radius, int totalCores, int coreIndex, int round) { _src = src; _w = w; _h = h; _radius = radius; _totalCores = totalCores; _coreIndex = coreIndex; _round = round; } @Override public Void call() throws Exception { // blurIteration(_src, _w, _h, _radius, _totalCores, _coreIndex, _round); return null; } } private static class A8BlurTask implements Callable<Void> { private final byte[] _src; private final int _w; private final int _h; private final int _stride; private final int _radius; private final int _totalCores; private final int _coreIndex; private final int _round; public A8BlurTask(byte[] src, int w, int h, int stride, int radius, int totalCores, int coreIndex, int round) { _src = src; _w = w; _h = h; _stride = stride; _radius = radius; _totalCores = totalCores; _coreIndex = coreIndex; _round = round; } @Override public Void call() throws Exception { Blur.blur(_src, _w, _h, _stride, _radius, _totalCores, _coreIndex, _round); return null; } } }