2012年3月4日 星期日

Android 開發筆記 - 實作 Mono 照片特效 @ Ubuntu 10.04

tw.study.rs_screenout


之前接觸 Renderscript - HelloCompute 時,第一次了解 Mono 特效是怎樣做的。這次則是要來筆記純用 Java 和 NDK 作的方式。


環境概述(以 Renderscript - HelloCompute 架構為例):


private Bitmap mBitmapIn;
private Bitmap mBitmapOut;


private Bitmap loadBitmap(int resource) {
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inPreferredConfig = Bitmap.Config.ARGB_8888;
        return BitmapFactory.decodeResource(getResources(), resource, options);
}


protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);


        ...
        mBitmapIn = loadBitmap(R.drawable.data); // R.drawable.data 是一張圖片
        mBitmapOut = Bitmap.createBitmap(mBitmapIn.getWidth(), mBitmapIn.getHeight(), mBitmapIn.getConfig()); // 空資料,大小跟 mBitmapIn 一樣
        ...

        // doMonoByJava(); // use Java only
        // doMonoByNDK(); // use NDK
        // createScript();     // use Renderscript
        ...
}


純 Java 版:


private void doMonoByJava() {
        final float gMonoMult[] = {0.299f, 0.587f, 0.114f};
        int imageHeight = mBitmapIn.getHeight();
        int imageWidth = mBitmapIn.getWidth();

        /* only assign, 速度慢
        for( int i=0 ;i<imageWidth; ++i )
                for( int j=0;j<imageHeight; ++j)
                        mBitmapOut.setPixel(i, j, mBitmapIn.getPixel(i, j));
        */

        /* only assign, 速度快
        int[] pixels = new int[imageWidth*imageHeight];
        mBitmapIn.getPixels(pixels,0,imageWidth,0,0,imageWidth,imageHeight);
        mBitmapOut.setPixels(pixels, 0, imageWidth, 0, 0, imageWidth, imageHeight);
        */


        int[] pixels = new int[imageWidth*imageHeight];
        mBitmapIn.getPixels(pixels,0,imageWidth,0,0,imageWidth,imageHeight);
        for( int i=0 ; i<imageHeight*imageWidth ; ++i ) {
                int R = (pixels[i] >> 16) & 0xff; 
                int G = (pixels[i] >> 8) & 0xff;
                int B = pixels[i] & 0xff;

                int m = (int)((float)R*gMonoMult[0] + (float)G*gMonoMult[1] + (float)B*gMonoMult[2] );
                R = m;
                G = m;
                B = m;


                pixels[i] = 0xff000000 | (R << 16) | (G << 8) | B;
        }
        mBitmapOut.setPixels(pixels, 0, imageWidth, 0, 0, imageWidth, imageHeight);
}


使用 NDK 版:


HelloCompute.java:


package com.example.android.rs.hellocompute;

public class HelloCompute extends Activity {
        ...
        static {
                System.loadLibrary("my-jni");
        }
        public native void doByNDK( int [] pixels, int size);

        private void doMonoByNDK() {
                int imageHeight = mBitmapIn.getHeight();
                int imageWidth = mBitmapIn.getWidth();
                int size = imageWidth*imageHeight;
                int[] pixels = new int[size];
                mBitmapIn.getPixels(pixels,0,imageWidth,0,0,imageWidth,imageHeight);
                doByNDK(pixels,size);
                mBitmapOut.setPixels(pixels, 0, imageWidth, 0, 0, imageWidth, imageHeight);
        }
        ...
}


my-jni.c:


#include <jni.h>
void Java_com_example_android_rs_hellocompute_HelloCompute_doByNDK( JNIEnv* env, jobject thiz, jintArray pixels, jint size) {
        float gMonoMult[] = {0.299f, 0.587f, 0.114f};
        int i, R, G, B, m;


        jboolean isCopy = JNI_FALSE;
        jint *jpixels = (*env)->GetIntArrayElements(env, pixels, &isCopy);


        for(i=0 ; i<size ; ++i ) {
                R = (jpixels[i] >> 16) & 0xff; //bitwise shifting
                G = (jpixels[i] >> 8) & 0xff;
                B = jpixels[i] & 0xff;
                m = (int)((float)R*gMonoMult[0] + (float)G*gMonoMult[1] + (float)B*gMonoMult[2] );
                R = m;
                G = m;
                B = m;
                jpixels[i] = 0xff000000 | (R << 16) | (G << 8) | B;
        }
}


若要計算效率,可以再用這段程式碼:


Long timeCost = System.currentTimeMillis();

// do something ...

timeCost = System.currentTimeMillis() - timeCost;
System.out.println("Cost:"+timeCost);


沒有留言:

張貼留言