Please note that the contents of this offline web site may be out of date. To access the most recent documentation visit the online version .
Note that links that point to online resources are green in color and will open in a new window.
We would love it if you could give us feedback about this material by filling this form (You have to be online to fill it)
RenderScriptIntrinsic / src / com.example.android.renderscriptintrinsic /

MainActivity.java

       
        1
       
       
        /*
       
       
        2
       
       
        * Copyright (C) 2014 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
       
       
       
       
        17
       
       
        package com.example.android.renderscriptintrinsic;
       
       
        18
       
       
       
       
        19
       
       
        import android.app.Activity;
       
       
        20
       
       
        import android.graphics.Bitmap;
       
       
        21
       
       
        import android.graphics.BitmapFactory;
       
       
        22
       
       
        import android.os.AsyncTask;
       
       
        23
       
       
        import android.os.Bundle;
       
       
        24
       
       
        import android.widget.CompoundButton;
       
       
        25
       
       
        import android.widget.CompoundButton.OnCheckedChangeListener;
       
       
        26
       
       
        import android.widget.ImageView;
       
       
        27
       
       
        import android.widget.RadioButton;
       
       
        28
       
       
        import android.widget.SeekBar;
       
       
        29
       
       
        import android.widget.SeekBar.OnSeekBarChangeListener;
       
       
        30
       
       
        import android.support.v8.renderscript.*;
       
       
        31
       
       
       
       
        32
       
       
        public class MainActivity extends Activity {
       
       
        33
       
       
        /* Number of bitmaps that is used for renderScript thread and UI thread synchronization.
       
       
        34
       
       
        Ideally, this can be reduced to 2, however in some devices, 2 buffers still showing tierings on UI.
       
       
        35
       
       
        Investigating a root cause.
       
       
        36
       
       
        */
       
       
        37
       
       
        private final int NUM_BITMAPS = 3;
       
       
        38
       
       
        private int mCurrentBitmap = 0;
       
       
        39
       
       
        private Bitmap mBitmapIn;
       
       
        40
       
       
        private Bitmap[] mBitmapsOut;
       
       
        41
       
       
        private ImageView mImageView;
       
       
        42
       
       
       
       
        43
       
       
        private RenderScript mRS;
       
       
        44
       
       
        private Allocation mInAllocation;
       
       
        45
       
       
        private Allocation[] mOutAllocations;
       
       
        46
       
       
       
       
        47
       
       
        private ScriptIntrinsicBlur mScriptBlur;
       
       
        48
       
       
        private ScriptIntrinsicConvolve5x5 mScriptConvolve;
       
       
        49
       
       
        private ScriptIntrinsicColorMatrix mScriptMatrix;
       
       
        50
       
       
       
       
        51
       
       
        private final int MODE_BLUR = 0;
       
       
        52
       
       
        private final int MODE_CONVOLVE = 1;
       
       
        53
       
       
        private final int MODE_COLORMATRIX = 2;
       
       
        54
       
       
       
       
        55
       
       
        private int mFilterMode = MODE_BLUR;
       
       
        56
       
       
       
       
        57
       
       
        private RenderScriptTask mLatestTask = null;
       
       
        58
       
       
       
       
        59
       
       
        @Override
       
       
        60
       
       
        protected void onCreate(Bundle savedInstanceState) {
       
       
        61
       
       
        super.onCreate(savedInstanceState);
       
       
        62
       
       
       
       
        63
       
       
        setContentView(R.layout.main_layout);
       
       
        64
       
       
       
       
        65
       
       
        /*
       
       
        66
       
       
        * Initialize UI
       
       
        67
       
       
        */
       
       
        68
       
       
       
       
        69
       
       
        //Set up main image view
       
       
        70
       
       
        mBitmapIn = loadBitmap(R.drawable.data);
       
       
        71
       
       
        mBitmapsOut = new Bitmap[NUM_BITMAPS];
       
       
        72
       
       
        for (int i = 0; i < NUM_BITMAPS; ++i) {
       
       
        73
       
       
        mBitmapsOut[i] = Bitmap.createBitmap(mBitmapIn.getWidth(),
       
       
        74
       
       
        mBitmapIn.getHeight(), mBitmapIn.getConfig());
       
       
        75
       
       
        }
       
       
        76
       
       
       
       
        77
       
       
        mImageView = (ImageView) findViewById(R.id.imageView);
       
       
        78
       
       
        mImageView.setImageBitmap(mBitmapsOut[mCurrentBitmap]);
       
       
        79
       
       
        mCurrentBitmap += (mCurrentBitmap + 1) % NUM_BITMAPS;
       
       
        80
       
       
       
       
        81
       
       
        //Set up seekbar
       
       
        82
       
       
        final SeekBar seekbar = (SeekBar) findViewById(R.id.seekBar1);
       
       
        83
       
       
        seekbar.setProgress(50);
       
       
        84
       
       
        seekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
       
       
        85
       
       
        public void onProgressChanged(SeekBar seekBar, int progress,
       
       
        86
       
       
        boolean fromUser) {
       
       
        87
       
       
        updateImage(progress);
       
       
        88
       
       
        }
       
       
        89
       
       
       
       
        90
       
       
        @Override
       
       
        91
       
       
        public void onStartTrackingTouch(SeekBar seekBar) {
       
       
        92
       
       
        }
       
       
        93
       
       
       
       
        94
       
       
        @Override
       
       
        95
       
       
        public void onStopTrackingTouch(SeekBar seekBar) {
       
       
        96
       
       
        }
       
       
        97
       
       
        });
       
       
        98
       
       
       
       
        99
       
       
        //Setup effect selector
       
       
        100
       
       
        RadioButton radio0 = (RadioButton) findViewById(R.id.radio0);
       
       
        101
       
       
        radio0.setOnCheckedChangeListener(new OnCheckedChangeListener() {
       
       
        102
       
       
       
       
        103
       
       
        @Override
       
       
        104
       
       
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
       
       
        105
       
       
        if (isChecked) {
       
       
        106
       
       
        mFilterMode = MODE_BLUR;
       
       
        107
       
       
        updateImage(seekbar.getProgress());
       
       
        108
       
       
        }
       
       
        109
       
       
        }
       
       
        110
       
       
        });
       
       
        111
       
       
        RadioButton radio1 = (RadioButton) findViewById(R.id.radio1);
       
       
        112
       
       
        radio1.setOnCheckedChangeListener(new OnCheckedChangeListener() {
       
       
        113
       
       
       
       
        114
       
       
        @Override
       
       
        115
       
       
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
       
       
        116
       
       
        if (isChecked) {
       
       
        117
       
       
        mFilterMode = MODE_CONVOLVE;
       
       
        118
       
       
        updateImage(seekbar.getProgress());
       
       
        119
       
       
        }
       
       
        120
       
       
        }
       
       
        121
       
       
        });
       
       
        122
       
       
        RadioButton radio2 = (RadioButton) findViewById(R.id.radio2);
       
       
        123
       
       
        radio2.setOnCheckedChangeListener(new OnCheckedChangeListener() {
       
       
        124
       
       
       
       
        125
       
       
        @Override
       
       
        126
       
       
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
       
       
        127
       
       
        if (isChecked) {
       
       
        128
       
       
        mFilterMode = MODE_COLORMATRIX;
       
       
        129
       
       
        updateImage(seekbar.getProgress());
       
       
        130
       
       
        }
       
       
        131
       
       
        }
       
       
        132
       
       
        });
       
       
        133
       
       
       
       
        134
       
       
        /*
       
       
        135
       
       
        * Create renderScript
       
       
        136
       
       
        */
       
       
        137
       
       
        createScript();
       
       
        138
       
       
       
       
        139
       
       
        /*
       
       
        140
       
       
        * Create thumbnails
       
       
        141
       
       
        */
       
       
        142
       
       
        createThumbnail();
       
       
        143
       
       
       
       
        144
       
       
       
       
        145
       
       
        /*
       
       
        146
       
       
        * Invoke renderScript kernel and update imageView
       
       
        147
       
       
        */
       
       
        148
       
       
        mFilterMode = MODE_BLUR;
       
       
        149
       
       
        updateImage(50);
       
       
        150
       
       
        }
       
       
        151
       
       
       
       
        152
       
       
        private void createScript() {
       
       
        153
       
       
        mRS = RenderScript.create(this);
       
       
        154
       
       
       
       
        155
       
       
        mInAllocation = Allocation.createFromBitmap(mRS, mBitmapIn);
       
       
        156
       
       
       
       
        157
       
       
        mOutAllocations = new Allocation[NUM_BITMAPS];
       
       
        158
       
       
        for (int i = 0; i < NUM_BITMAPS; ++i) {
       
       
        159
       
       
        mOutAllocations[i] = Allocation.createFromBitmap(mRS, mBitmapsOut[i]);
       
       
        160
       
       
        }
       
       
        161
       
       
       
       
        162
       
       
        /*
       
       
        163
       
       
        Create intrinsics.
       
       
        164
       
       
        RenderScript has built-in features such as blur, convolve filter etc.
       
       
        165
       
       
        These intrinsics are handy for specific operations without writing RenderScript kernel.
       
       
        166
       
       
        In the sample, it's creating blur, convolve and matrix intrinsics.
       
       
        167
       
       
        */
       
       
        168
       
       
       
       
        169
       
       
        mScriptBlur = ScriptIntrinsicBlur.create(mRS, Element.U8_4(mRS));
       
       
        170
       
       
        mScriptConvolve = ScriptIntrinsicConvolve5x5.create(mRS,
       
       
        171
       
       
        Element.U8_4(mRS));
       
       
        172
       
       
        mScriptMatrix = ScriptIntrinsicColorMatrix.create(mRS,
       
       
        173
       
       
        Element.U8_4(mRS));
       
       
        174
       
       
        }
       
       
        175
       
       
       
       
        176
       
       
        private void performFilter(Allocation inAllocation,
       
       
        177
       
       
        Allocation outAllocation, Bitmap bitmapOut, float value) {
       
       
        178
       
       
        switch (mFilterMode) {
       
       
        179
       
       
        case MODE_BLUR:
       
       
        180
       
       
        /*
       
       
        181
       
       
        * Set blur kernel size
       
       
        182
       
       
        */
       
       
        183
       
       
        mScriptBlur.setRadius(value);
       
       
        184
       
       
       
       
        185
       
       
        /*
       
       
        186
       
       
        * Invoke filter kernel
       
       
        187
       
       
        */
       
       
        188
       
       
        mScriptBlur.setInput(inAllocation);
       
       
        189
       
       
        mScriptBlur.forEach(outAllocation);
       
       
        190
       
       
        break;
       
       
        191
       
       
        case MODE_CONVOLVE: {
       
       
        192
       
       
        float f1 = value;
       
       
        193
       
       
        float f2 = 1.0f - f1;
       
       
        194
       
       
       
       
        195
       
       
        // Emboss filter kernel
       
       
        196
       
       
        float coefficients[] = {-f1 * 2, 0, -f1, 0, 0, 0, -f2 * 2, -f2, 0,
       
       
        197
       
       
        0, -f1, -f2, 1, f2, f1, 0, 0, f2, f2 * 2, 0, 0, 0, f1, 0,
       
       
        198
       
       
        f1 * 2,};
       
       
        199
       
       
        /*
       
       
        200
       
       
        * Set kernel parameter
       
       
        201
       
       
        */
       
       
        202
       
       
        mScriptConvolve.setCoefficients(coefficients);
       
       
        203
       
       
       
       
        204
       
       
        /*
       
       
        205
       
       
        * Invoke filter kernel
       
       
        206
       
       
        */
       
       
        207
       
       
        mScriptConvolve.setInput(inAllocation);
       
       
        208
       
       
        mScriptConvolve.forEach(outAllocation);
       
       
        209
       
       
        break;
       
       
        210
       
       
        }
       
       
        211
       
       
        case MODE_COLORMATRIX: {
       
       
        212
       
       
        /*
       
       
        213
       
       
        * Set HUE rotation matrix
       
       
        214
       
       
        * The matrix below performs a combined operation of,
       
       
        215
       
       
        * RGB->HSV transform * HUE rotation * HSV->RGB transform
       
       
        216
       
       
        */
       
       
        217
       
       
        float cos = (float) Math.cos((double) value);
       
       
        218
       
       
        float sin = (float) Math.sin((double) value);
       
       
        219
       
       
        Matrix3f mat = new Matrix3f();
       
       
        220
       
       
        mat.set(0, 0, (float) (.299 + .701 * cos + .168 * sin));
       
       
        221
       
       
        mat.set(1, 0, (float) (.587 - .587 * cos + .330 * sin));
       
       
        222
       
       
        mat.set(2, 0, (float) (.114 - .114 * cos - .497 * sin));
       
       
        223
       
       
        mat.set(0, 1, (float) (.299 - .299 * cos - .328 * sin));
       
       
        224
       
       
        mat.set(1, 1, (float) (.587 + .413 * cos + .035 * sin));
       
       
        225
       
       
        mat.set(2, 1, (float) (.114 - .114 * cos + .292 * sin));
       
       
        226
       
       
        mat.set(0, 2, (float) (.299 - .3 * cos + 1.25 * sin));
       
       
        227
       
       
        mat.set(1, 2, (float) (.587 - .588 * cos - 1.05 * sin));
       
       
        228
       
       
        mat.set(2, 2, (float) (.114 + .886 * cos - .203 * sin));
       
       
        229
       
       
        mScriptMatrix.setColorMatrix(mat);
       
       
        230
       
       
       
       
        231
       
       
        /*
       
       
        232
       
       
        * Invoke filter kernel
       
       
        233
       
       
        */
       
       
        234
       
       
        mScriptMatrix.forEach(inAllocation, outAllocation);
       
       
        235
       
       
        }
       
       
        236
       
       
        break;
       
       
        237
       
       
        }
       
       
        238
       
       
       
       
        239
       
       
        /*
       
       
        240
       
       
        * Copy to bitmap and invalidate image view
       
       
        241
       
       
        */
       
       
        242
       
       
        outAllocation.copyTo(bitmapOut);
       
       
        243
       
       
        }
       
       
        244
       
       
       
       
        245
       
       
        /*
       
       
        246
       
       
        Convert seekBar progress parameter (0-100 in range) to parameter for each intrinsic filter.
       
       
        247
       
       
        (e.g. 1.0-25.0 in Blur filter)
       
       
        248
       
       
        */
       
       
        249
       
       
        private float getFilterParameter(int i) {
       
       
        250
       
       
        float f = 0.f;
       
       
        251
       
       
        switch (mFilterMode) {
       
       
        252
       
       
        case MODE_BLUR: {
       
       
        253
       
       
        final float max = 25.0f;
       
       
        254
       
       
        final float min = 1.f;
       
       
        255
       
       
        f = (float) ((max - min) * (i / 100.0) + min);
       
       
        256
       
       
        }
       
       
        257
       
       
        break;
       
       
        258
       
       
        case MODE_CONVOLVE: {
       
       
        259
       
       
        final float max = 2.f;
       
       
        260
       
       
        final float min = 0.f;
       
       
        261
       
       
        f = (float) ((max - min) * (i / 100.0) + min);
       
       
        262
       
       
        }
       
       
        263
       
       
        break;
       
       
        264
       
       
        case MODE_COLORMATRIX: {
       
       
        265
       
       
        final float max = (float) Math.PI;
       
       
        266
       
       
        final float min = (float) -Math.PI;
       
       
        267
       
       
        f = (float) ((max - min) * (i / 100.0) + min);
       
       
        268
       
       
        }
       
       
        269
       
       
        break;
       
       
        270
       
       
        }
       
       
        271
       
       
        return f;
       
       
        272
       
       
       
       
        273
       
       
        }
       
       
        274
       
       
       
       
        275
       
       
        /*
       
       
        276
       
       
        * In the AsyncTask, it invokes RenderScript intrinsics to do a filtering.
       
       
        277
       
       
        * After the filtering is done, an operation blocks at Allication.copyTo() in AsyncTask thread.
       
       
        278
       
       
        * Once all operation is finished at onPostExecute() in UI thread, it can invalidate and update ImageView UI.
       
       
        279
       
       
        */
       
       
        280
       
       
        private class RenderScriptTask extends AsyncTask<Float, Integer, Integer> {
       
       
        281
       
       
        Boolean issued = false;
       
       
        282
       
       
       
       
        283
       
       
        protected Integer doInBackground(Float... values) {
       
       
        284
       
       
        int index = -1;
       
       
        285
       
       
        if (isCancelled() == false) {
       
       
        286
       
       
        issued = true;
       
       
        287
       
       
        index = mCurrentBitmap;
       
       
        288
       
       
       
       
        289
       
       
        performFilter(mInAllocation, mOutAllocations[index], mBitmapsOut[index], values[0]);
       
       
        290
       
       
        mCurrentBitmap = (mCurrentBitmap + 1) % NUM_BITMAPS;
       
       
        291
       
       
        }
       
       
        292
       
       
        return index;
       
       
        293
       
       
        }
       
       
        294
       
       
       
       
        295
       
       
        void updateView(Integer result) {
       
       
        296
       
       
        if (result != -1) {
       
       
        297
       
       
        // Request UI update
       
       
        298
       
       
        mImageView.setImageBitmap(mBitmapsOut[result]);
       
       
        299
       
       
        mImageView.invalidate();
       
       
        300
       
       
        }
       
       
        301
       
       
        }
       
       
        302
       
       
       
       
        303
       
       
        protected void onPostExecute(Integer result) {
       
       
        304
       
       
        updateView(result);
       
       
        305
       
       
        }
       
       
        306
       
       
       
       
        307
       
       
        protected void onCancelled(Integer result) {
       
       
        308
       
       
        if (issued) {
       
       
        309
       
       
        updateView(result);
       
       
        310
       
       
        }
       
       
        311
       
       
        }
       
       
        312
       
       
        }
       
       
        313
       
       
       
       
        314
       
       
        /*
       
       
        315
       
       
        Invoke AsynchTask and cancel previous task.
       
       
        316
       
       
        When AsyncTasks are piled up (typically in slow device with heavy kernel),
       
       
        317
       
       
        Only the latest (and already started) task invokes RenderScript operation.
       
       
        318
       
       
        */
       
       
        319
       
       
        private void updateImage(int progress) {
       
       
        320
       
       
        float f = getFilterParameter(progress);
       
       
        321
       
       
       
       
        322
       
       
        if (mLatestTask != null)
       
       
        323
       
       
        mLatestTask.cancel(false);
       
       
        324
       
       
        mLatestTask = new RenderScriptTask();
       
       
        325
       
       
       
       
        326
       
       
        mLatestTask.execute(f);
       
       
        327
       
       
        }
       
       
        328
       
       
       
       
        329
       
       
        /*
       
       
        330
       
       
        Helper to load Bitmap from resource
       
       
        331
       
       
        */
       
       
        332
       
       
        private Bitmap loadBitmap(int resource) {
       
       
        333
       
       
        final BitmapFactory.Options options = new BitmapFactory.Options();
       
       
        334
       
       
        options.inPreferredConfig = Bitmap.Config.ARGB_8888;
       
       
        335
       
       
        return BitmapFactory.decodeResource(getResources(), resource, options);
       
       
        336
       
       
        }
       
       
        337
       
       
       
       
        338
       
       
        /*
       
       
        339
       
       
        Create thumbNail for UI. It invokes RenderScript kernel synchronously in UI-thread,
       
       
        340
       
       
        which is OK for small thumbnail (but not ideal).
       
       
        341
       
       
        */
       
       
        342
       
       
        private void createThumbnail() {
       
       
        343
       
       
        int width = 72;
       
       
        344
       
       
        int height = 96;
       
       
        345
       
       
        float scale = getResources().getDisplayMetrics().density;
       
       
        346
       
       
        int pixelsWidth = (int) (width * scale + 0.5f);
       
       
        347
       
       
        int pixelsHeight = (int) (height * scale + 0.5f);
       
       
        348
       
       
       
       
        349
       
       
        //Temporary image
       
       
        350
       
       
        Bitmap tempBitmap = Bitmap.createScaledBitmap(mBitmapIn, pixelsWidth, pixelsHeight, false);
       
       
        351
       
       
        Allocation inAllocation = Allocation.createFromBitmap(mRS, tempBitmap);
       
       
        352
       
       
       
       
        353
       
       
        //Create thumbnail with each RS intrinsic and set it to radio buttons
       
       
        354
       
       
        int[] modes = {MODE_BLUR, MODE_CONVOLVE, MODE_COLORMATRIX};
       
       
        355
       
       
        int[] ids = {R.id.radio0, R.id.radio1, R.id.radio2};
       
       
        356
       
       
        int[] parameter = {50, 100, 25};
       
       
        357
       
       
        for (int mode : modes) {
       
       
        358
       
       
        mFilterMode = mode;
       
       
        359
       
       
        float f = getFilterParameter(parameter[mode]);
       
       
        360
       
       
       
       
        361
       
       
        Bitmap destBitpmap = Bitmap.createBitmap(tempBitmap.getWidth(),
       
       
        362
       
       
        tempBitmap.getHeight(), tempBitmap.getConfig());
       
       
        363
       
       
        Allocation outAllocation = Allocation.createFromBitmap(mRS, destBitpmap);
       
       
        364
       
       
        performFilter(inAllocation, outAllocation, destBitpmap, f);
       
       
        365
       
       
       
       
        366
       
       
        ThumbnailRadioButton button = (ThumbnailRadioButton) findViewById(ids[mode]);
       
       
        367
       
       
        button.setThumbnail(destBitpmap);
       
       
        368
       
       
        }
       
       
        369
       
       
        }
       
       
        370
       
       
        }