Android NDK開發 圖片處理(五)


做過Java的同學可能經常會遇到一些關於圖片處理的

例如類似QQ離線頭像顯示灰的。最快的算法是用colorMatrix來實現。這里通過Java調用JNI來處理每一個像素來實現。

  1. 對每一個像素點取出RGB每個通道的值R,G,B
  2. cololr=(R+G+B)/3;這個值是需要修改的值
  3. 將原來GRB的通道全設置成color的值

 

首先先看用Java怎么實現這個功能 

 public Bitmap convertGrayImg(int resID)
    {
        Bitmap img1=((BitmapDrawable) getResources().getDrawable(resID)).getBitmap();

        int w=img1.getWidth(),h=img1.getHeight();
        int[] pix = new int[w * h];
        img1.getPixels(pix, 0, w, 0, 0, w, h);

        int alpha=0xFF<<24;
        for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {
                // 獲得像素的顏色
                int color = pix[w * i + j];
                int red = ((color & 0x00FF0000) >> 16);
                int green = ((color & 0x0000FF00) >> 8);
                int blue = color & 0x000000FF;
                color = (red + green + blue)/3;
                color = alpha | (color << 16) | (color << 8) | color;
                pix[w * i + j] = color;
            }
        }
        Bitmap result=Bitmap.createBitmap(w, h, Config.RGB_565);
        result.setPixels(pix, 0, w, 0, 0,w, h);
        return result;
    }

 

 

下面是JNI來處理 

c++代碼如下

#include <jni.h>
#include <string>
extern "C"{
jintArray JNICALL
        Java_com_tmf_test_ndk_bitmap_MainActivity_getImgToGray(JNIEnv *env, jobject instance,
                                                               jintArray data_, jint w, jint h);
}

JNIEXPORT jintArray JNICALL
Java_com_tmf_test_ndk_bitmap_MainActivity_getImgToGray(JNIEnv *env, jobject instance,
                                                       jintArray data_, jint w, jint h) {
    jint *data;
    data = env->GetIntArrayElements(data_, NULL);
    if (data == NULL) {
        return 0; /* exception occurred */
    }
    int alpha = 0xFF << 24;
    for (int i = 0; i < h; i++) {
        for (int j = 0; j < w; j++) {
            // 獲得像素的顏色
            int color = data[w * i + j];
            int red = ((color & 0x00FF0000) >> 16);
            int green = ((color & 0x0000FF00) >> 8);
            int blue = color & 0x000000FF;
            color = (red + green + blue) / 3;
            color = alpha | (color << 16) | (color << 8) | color;
            data[w * i + j] = color;
        }
    }
    int size=w * h;
    jintArray result = env->NewIntArray(size);
    env->SetIntArrayRegion(result, 0, size, data);
    env->ReleaseIntArrayElements(data_, data, 0);
    return result;
}

activity實現如下

package com.tmf.test.ndk.bitmap;

import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ImageView;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("native-lib");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Example of a call to a native method
        ImageView tv = (ImageView) findViewById(R.id.image);
        tv.setImageBitmap(getJniBitmap());
    }

    public Bitmap  getJniBitmap(){
        Bitmap bitmap=((BitmapDrawable) getResources().getDrawable(R.mipmap.timg)).getBitmap();
        int w=bitmap.getWidth(),h=bitmap.getHeight();
        int[] pix = new int[w * h];
        bitmap.getPixels(pix, 0, w, 0, 0, w, h);
        //通過ImgToGray.so把彩色像素轉為灰度像素
        int[] resultInt=getImgToGray(pix, w, h);
        Bitmap resultImg=Bitmap.createBitmap(w, h, Bitmap.Config.RGB_565);
        resultImg.setPixels(resultInt, 0, w, 0, 0,w, h);
        return resultImg;
    }


    public native int[] getImgToGray(int[] data,int w,int h);

    private int[] bitmapToArray(int resID)
    {
        Bitmap bitmap=((BitmapDrawable) getResources().getDrawable(resID)).getBitmap();
        int w=bitmap.getWidth(),h=bitmap.getHeight();
        int[] pix = new int[w * h];
        bitmap.getPixels(pix, 0, w, 0, 0, w, h);
      return pix;
    }
   
}

效果如下

 

 

 bitmap.h

目錄android-ndk-r10e\platforms\android-21\arch-arm\usr\include\android里面

 

bitmap.h頭文件中的內容並不多,主要有這些部分組成:

  • 結果狀態定義。
  • 位圖格式枚舉。
  • 位圖信息結構體。
  • 位圖操作函數聲明。

 

define ANDROID_BITMAP_RESULT_SUCCESS            0
#define ANDROID_BITMAP_RESULT_BAD_PARAMETER     -1
#define ANDROID_BITMAP_RESULT_JNI_EXCEPTION     -2
#define ANDROID_BITMAP_RESULT_ALLOCATION_FAILED -3

/* Backward compatibility: this macro used to be misspelled. */
#define ANDROID_BITMAP_RESUT_SUCCESS ANDROID_BITMAP_RESULT_SUCCESS

這里定義了對Bitmap進行操作時的結果,分別對應成功,錯誤的參數,JNI異常,內存分配錯誤,至於最后一個,這是個梗。Google工程師在定義NDK的時候寫錯一個單詞,居然沒有檢查就發布了,然后就233333333了。看來IDE的拼寫檢查對自己人也有好處。

位圖格式枚舉

enum AndroidBitmapFormat {
    ANDROID_BITMAP_FORMAT_NONE      = 0,
    ANDROID_BITMAP_FORMAT_RGBA_8888 = 1,
    ANDROID_BITMAP_FORMAT_RGB_565   = 4,
    ANDROID_BITMAP_FORMAT_RGBA_4444 = 7,
    ANDROID_BITMAP_FORMAT_A_8       = 8,
};

一般而言,常見的位圖格式有RGB_565 、RGBA_8888、 ARGB_8888、 RGBA_4444、 ARGB_4444、 ALPHA_8 

位圖信息結構體

typedef struct {
    uint32_t    width;
    uint32_t    height;
    uint32_t    stride;
    int32_t     format;
    uint32_t    flags;      // 0 for now
} AndroidBitmapInfo;

 

width表示圖片的寬度(列數),height表示圖片的高度(行數),stride為行跨度,具體含義后面會進行介紹。最后一個參數已經被棄用,其值始終為0。

 

位圖操作函數聲明

int AndroidBitmap_getInfo(JNIEnv* env, jobject jbitmap,
                          AndroidBitmapInfo* info);

int AndroidBitmap_lockPixels(JNIEnv* env, jobject jbitmap, void** addrPtr);

int AndroidBitmap_unlockPixels(JNIEnv* env, jobject jbitmap);
  • AndroidBitmap_getInfo:獲取當前位圖信息。
  • AndroidBitmap_lockPixels:鎖定當前位圖像素,在鎖定期間該Bitmap對象不會被回收,使用完成之后必須調用AndroidBitmap_unlockPixels函數來解除對像素的鎖定。
  • AndroidBitmap_unlockPixels:解除像素鎖定。

 

JNIEXPORT jboolean JNICALL
Java_com_tmf_test_ndk_bitmap_MainActivity_getImgToGray1(JNIEnv *env, jclass type, jobject jsrcBitmap,
                                                        jobject desBitmap) {
    AndroidBitmapInfo srcInfo, dstInfo;
    if (ANDROID_BITMAP_RESULT_SUCCESS != AndroidBitmap_getInfo(env, jsrcBitmap, &srcInfo)
        || ANDROID_BITMAP_RESULT_SUCCESS != AndroidBitmap_getInfo(env, desBitmap, &dstInfo)) {
        LOGE("get bitmap info failed");
        return false;
    }

    void *srcBuf, *dstBuf;
    if (ANDROID_BITMAP_RESULT_SUCCESS != AndroidBitmap_lockPixels(env, jsrcBitmap, &srcBuf)) {
        LOGE("lock src bitmap failed");
        return false;
    }

    if (ANDROID_BITMAP_RESULT_SUCCESS != AndroidBitmap_lockPixels(env, desBitmap, &dstBuf)) {
        LOGE("lock dst bitmap failed");
        return false;
    }

    int w = srcInfo.width;
    int h = srcInfo.height;
    int32_t *srcPixs = (int32_t *) srcBuf;
    int32_t *desPixs = (int32_t *) dstBuf;
    int alpha = 0xFF << 24;
    for (int i = 0; i < h; i++) {
        for (int j = 0; j < w; j++) {
            // 獲得像素的顏色
            int color = srcPixs[w * i + j];
            int red = ((color & 0x00FF0000) >> 16);
            int green = ((color & 0x0000FF00) >> 8);
            int blue = color & 0x000000FF;
            color = (red + green + blue) / 3;
            color = alpha | (color << 16) | (color << 8) | color;
            desPixs[w * i + j] = color;
        }
    }
    AndroidBitmap_unlockPixels(env, jsrcBitmap);
    AndroidBitmap_unlockPixels(env, desBitmap);
    return true;
}

Java層代碼

public  native boolean getImgToGray1(Bitmap src,Bitmap des);

效果和上面都一樣的,只是這個直接在底層處理bitmap對象

 

如果有以下異常

  E:\test\NdkBitmap\app\src\main\cpp/native-lib.cpp:52: undefined reference to `AndroidBitmap_getInfo'
  E:\test\NdkBitmap\app\src\main\cpp/native-lib.cpp:53: undefined reference to `AndroidBitmap_getInfo'
  E:\test\NdkBitmap\app\src\main\cpp/native-lib.cpp:59: undefined reference to `AndroidBitmap_lockPixels'
  E:\test\NdkBitmap\app\src\main\cpp/native-lib.cpp:64: undefined reference to `AndroidBitmap_lockPixels'
  E:\test\NdkBitmap\app\src\main\cpp/native-lib.cpp:86: undefined reference to `AndroidBitmap_unlockPixels'
  E:\test\NdkBitmap\app\src\main\cpp/native-lib.cpp:87: undefined reference to `AndroidBitmap_unlockPixels'

我用的是Android studio自帶的cmake打包的,需要在

在CMakeLists.txt 添加 -ljnigraphics

target_link_libraries( # Specifies the target library.
                       native-lib
                       -ljnigraphics
                       # Links the target library to the log library
                       # included in the NDK.
                       ${log-lib} )

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM