1/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.rs.image;
18
19import android.app.Activity;
20import android.os.Bundle;
21import android.graphics.BitmapFactory;
22import android.graphics.Bitmap;
23import android.graphics.Canvas;
24import android.renderscript.ScriptC;
25import android.renderscript.RenderScript;
26import android.renderscript.Type;
27import android.renderscript.Allocation;
28import android.renderscript.Element;
29import android.renderscript.Script;
30import android.view.SurfaceView;
31import android.view.SurfaceHolder;
32import android.widget.ImageView;
33import android.widget.SeekBar;
34import android.widget.TextView;
35import android.view.View;
36import android.util.Log;
37import java.lang.Math;
38
39public class ImageProcessingActivity extends Activity
40                                       implements SurfaceHolder.Callback,
41                                       SeekBar.OnSeekBarChangeListener {
42    private final String TAG = "Img";
43    private Bitmap mBitmapIn;
44    private Bitmap mBitmapOut;
45    private ScriptC_threshold mScript;
46    private ScriptC_vertical_blur mScriptVBlur;
47    private ScriptC_horizontal_blur mScriptHBlur;
48    private int mRadius = 0;
49    private SeekBar mRadiusSeekBar;
50
51    private float mInBlack = 0.0f;
52    private SeekBar mInBlackSeekBar;
53    private float mOutBlack = 0.0f;
54    private SeekBar mOutBlackSeekBar;
55    private float mInWhite = 255.0f;
56    private SeekBar mInWhiteSeekBar;
57    private float mOutWhite = 255.0f;
58    private SeekBar mOutWhiteSeekBar;
59    private float mGamma = 1.0f;
60    private SeekBar mGammaSeekBar;
61
62    private float mSaturation = 1.0f;
63    private SeekBar mSaturationSeekBar;
64
65    private TextView mBenchmarkResult;
66
67    @SuppressWarnings({"FieldCanBeLocal"})
68    private RenderScript mRS;
69    @SuppressWarnings({"FieldCanBeLocal"})
70    private Type mPixelType;
71    @SuppressWarnings({"FieldCanBeLocal"})
72    private Allocation mInPixelsAllocation;
73    @SuppressWarnings({"FieldCanBeLocal"})
74    private Allocation mOutPixelsAllocation;
75    @SuppressWarnings({"FieldCanBeLocal"})
76    private Allocation mScratchPixelsAllocation1;
77    private Allocation mScratchPixelsAllocation2;
78
79    private SurfaceView mSurfaceView;
80    private ImageView mDisplayView;
81
82    private boolean mIsProcessing;
83
84    class FilterCallback extends RenderScript.RSMessageHandler {
85        private Runnable mAction = new Runnable() {
86            public void run() {
87
88                synchronized (mDisplayView) {
89                    mIsProcessing = false;
90                }
91
92                mOutPixelsAllocation.copyTo(mBitmapOut);
93                mDisplayView.invalidate();
94            }
95        };
96
97        @Override
98        public void run() {
99            mSurfaceView.removeCallbacks(mAction);
100            mSurfaceView.post(mAction);
101        }
102    }
103
104    int in[];
105    int interm[];
106    int out[];
107    int MAX_RADIUS = 25;
108    // Store our coefficients here
109    float gaussian[];
110
111    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
112        if (fromUser) {
113
114            if (seekBar == mRadiusSeekBar) {
115                float fRadius = progress / 100.0f;
116                fRadius *= (float)(MAX_RADIUS);
117                mRadius = (int)fRadius;
118
119                mScript.set_radius(mRadius);
120            } else if (seekBar == mInBlackSeekBar) {
121                mInBlack = (float)progress;
122                mScriptVBlur.invoke_setLevels(mInBlack, mOutBlack, mInWhite, mOutWhite);
123            } else if (seekBar == mOutBlackSeekBar) {
124                mOutBlack = (float)progress;
125                mScriptVBlur.invoke_setLevels(mInBlack, mOutBlack, mInWhite, mOutWhite);
126            } else if (seekBar == mInWhiteSeekBar) {
127                mInWhite = (float)progress + 127.0f;
128                mScriptVBlur.invoke_setLevels(mInBlack, mOutBlack, mInWhite, mOutWhite);
129            } else if (seekBar == mOutWhiteSeekBar) {
130                mOutWhite = (float)progress + 127.0f;
131                mScriptVBlur.invoke_setLevels(mInBlack, mOutBlack, mInWhite, mOutWhite);
132            } else if (seekBar == mGammaSeekBar) {
133                mGamma = (float)progress/100.0f;
134                mGamma = Math.max(mGamma, 0.1f);
135                mGamma = 1.0f / mGamma;
136                mScriptVBlur.invoke_setGamma(mGamma);
137            } else if (seekBar == mSaturationSeekBar) {
138                mSaturation = (float)progress / 50.0f;
139                mScriptVBlur.invoke_setSaturation(mSaturation);
140            }
141
142            synchronized (mDisplayView) {
143                if (mIsProcessing) {
144                    return;
145                }
146                mIsProcessing = true;
147            }
148
149            mScript.invoke_filter();
150        }
151    }
152
153    public void onStartTrackingTouch(SeekBar seekBar) {
154    }
155
156    public void onStopTrackingTouch(SeekBar seekBar) {
157    }
158
159    @Override
160    protected void onCreate(Bundle savedInstanceState) {
161        super.onCreate(savedInstanceState);
162        setContentView(R.layout.main);
163
164        mBitmapIn = loadBitmap(R.drawable.city);
165        mBitmapOut = loadBitmap(R.drawable.city);
166
167        mSurfaceView = (SurfaceView) findViewById(R.id.surface);
168        mSurfaceView.getHolder().addCallback(this);
169
170        mDisplayView = (ImageView) findViewById(R.id.display);
171        mDisplayView.setImageBitmap(mBitmapOut);
172
173        mRadiusSeekBar = (SeekBar) findViewById(R.id.radius);
174        mRadiusSeekBar.setOnSeekBarChangeListener(this);
175
176        mInBlackSeekBar = (SeekBar)findViewById(R.id.inBlack);
177        mInBlackSeekBar.setOnSeekBarChangeListener(this);
178        mInBlackSeekBar.setMax(128);
179        mInBlackSeekBar.setProgress(0);
180        mOutBlackSeekBar = (SeekBar)findViewById(R.id.outBlack);
181        mOutBlackSeekBar.setOnSeekBarChangeListener(this);
182        mOutBlackSeekBar.setMax(128);
183        mOutBlackSeekBar.setProgress(0);
184
185        mInWhiteSeekBar = (SeekBar)findViewById(R.id.inWhite);
186        mInWhiteSeekBar.setOnSeekBarChangeListener(this);
187        mInWhiteSeekBar.setMax(128);
188        mInWhiteSeekBar.setProgress(128);
189        mOutWhiteSeekBar = (SeekBar)findViewById(R.id.outWhite);
190        mOutWhiteSeekBar.setOnSeekBarChangeListener(this);
191        mOutWhiteSeekBar.setMax(128);
192        mOutWhiteSeekBar.setProgress(128);
193
194        mGammaSeekBar = (SeekBar)findViewById(R.id.inGamma);
195        mGammaSeekBar.setOnSeekBarChangeListener(this);
196        mGammaSeekBar.setMax(150);
197        mGammaSeekBar.setProgress(100);
198
199        mSaturationSeekBar = (SeekBar)findViewById(R.id.inSaturation);
200        mSaturationSeekBar.setOnSeekBarChangeListener(this);
201        mSaturationSeekBar.setProgress(50);
202
203        mBenchmarkResult = (TextView) findViewById(R.id.benchmarkText);
204        mBenchmarkResult.setText("Result: not run");
205    }
206
207    public void surfaceCreated(SurfaceHolder holder) {
208        createScript();
209        mScript.invoke_filter();
210        mOutPixelsAllocation.copyTo(mBitmapOut);
211    }
212
213    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
214    }
215
216    public void surfaceDestroyed(SurfaceHolder holder) {
217    }
218
219    private void createScript() {
220        mRS = RenderScript.create(this);
221        mRS.setMessageHandler(new FilterCallback());
222
223        mInPixelsAllocation = Allocation.createFromBitmap(mRS, mBitmapIn,
224                                                          Allocation.MipmapControl.MIPMAP_NONE,
225                                                          Allocation.USAGE_SCRIPT);
226        mOutPixelsAllocation = Allocation.createFromBitmap(mRS, mBitmapOut,
227                                                           Allocation.MipmapControl.MIPMAP_NONE,
228                                                           Allocation.USAGE_SCRIPT);
229
230        Type.Builder tb = new Type.Builder(mRS, Element.F32_4(mRS));
231        tb.setX(mBitmapIn.getWidth());
232        tb.setY(mBitmapIn.getHeight());
233        mScratchPixelsAllocation1 = Allocation.createTyped(mRS, tb.create());
234        mScratchPixelsAllocation2 = Allocation.createTyped(mRS, tb.create());
235
236        mScriptVBlur = new ScriptC_vertical_blur(mRS, getResources(), R.raw.vertical_blur);
237        mScriptHBlur = new ScriptC_horizontal_blur(mRS, getResources(), R.raw.horizontal_blur);
238
239        mScript = new ScriptC_threshold(mRS, getResources(), R.raw.threshold);
240        mScript.set_width(mBitmapIn.getWidth());
241        mScript.set_height(mBitmapIn.getHeight());
242        mScript.set_radius(mRadius);
243
244        mScriptVBlur.invoke_setLevels(mInBlack, mOutBlack, mInWhite, mOutWhite);
245        mScriptVBlur.invoke_setGamma(mGamma);
246        mScriptVBlur.invoke_setSaturation(mSaturation);
247
248        mScript.bind_InPixel(mInPixelsAllocation);
249        mScript.bind_OutPixel(mOutPixelsAllocation);
250        mScript.bind_ScratchPixel1(mScratchPixelsAllocation1);
251        mScript.bind_ScratchPixel2(mScratchPixelsAllocation2);
252
253        mScript.set_vBlurScript(mScriptVBlur);
254        mScript.set_hBlurScript(mScriptHBlur);
255    }
256
257    private Bitmap loadBitmap(int resource) {
258        final BitmapFactory.Options options = new BitmapFactory.Options();
259        options.inPreferredConfig = Bitmap.Config.ARGB_8888;
260        return copyBitmap(BitmapFactory.decodeResource(getResources(), resource, options));
261    }
262
263    private static Bitmap copyBitmap(Bitmap source) {
264        Bitmap b = Bitmap.createBitmap(source.getWidth(), source.getHeight(), source.getConfig());
265        Canvas c = new Canvas(b);
266        c.drawBitmap(source, 0, 0, null);
267        source.recycle();
268        return b;
269    }
270
271    // button hook
272    public void benchmark(View v) {
273        long t = getBenchmark();
274        //long javaTime = javaFilter();
275        //mBenchmarkResult.setText("RS: " + t + " ms  Java: " + javaTime + " ms");
276        mBenchmarkResult.setText("Result: " + t + " ms");
277    }
278
279    // For benchmark test
280    public long getBenchmark() {
281        Log.v(TAG, "Benchmarking");
282        int oldRadius = mRadius;
283        mRadius = MAX_RADIUS;
284        mScript.set_radius(mRadius);
285
286        mScript.invoke_filter();
287        mRS.finish();
288
289        long t = java.lang.System.currentTimeMillis();
290
291        mScript.invoke_filter();
292        mOutPixelsAllocation.copyTo(mBitmapOut);
293
294        t = java.lang.System.currentTimeMillis() - t;
295        Log.v(TAG, "getBenchmark: Renderscript frame time core ms " + t);
296        mRadius = oldRadius;
297        mScript.set_radius(mRadius);
298
299        mScript.invoke_filter();
300        mOutPixelsAllocation.copyTo(mBitmapOut);
301        return t;
302    }
303}
304