zoukankan      html  css  js  c++  java
  • 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-r10eplatformsandroid-21arch-armusrincludeandroid里面

    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:	estNdkBitmapappsrcmaincpp/native-lib.cpp:52: undefined reference to `AndroidBitmap_getInfo'
      E:	estNdkBitmapappsrcmaincpp/native-lib.cpp:53: undefined reference to `AndroidBitmap_getInfo'
      E:	estNdkBitmapappsrcmaincpp/native-lib.cpp:59: undefined reference to `AndroidBitmap_lockPixels'
      E:	estNdkBitmapappsrcmaincpp/native-lib.cpp:64: undefined reference to `AndroidBitmap_lockPixels'
      E:	estNdkBitmapappsrcmaincpp/native-lib.cpp:86: undefined reference to `AndroidBitmap_unlockPixels'
      E:	estNdkBitmapappsrcmaincpp/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} )
  • 相关阅读:
    docker下安装mysql数据库
    asp.net core3.0 mvc 用 autofac
    遍历Map的方式
    JAVA 每次从List中取出100条记录
    JAVA 必须掌握技能(三)-Java 基础知识
    JAVA 必须掌握技能-Java 知识结构图
    JAVA 必须掌握技能(二)-Java IO流学习之输入输出流
    JAVA 必须掌握技能(一)-集合类型那么多,如何选择使用List, Set, Map?
    JavaScript 开发必须掌握技能(四)- 更好的使用jQuery attr方法
    JavaScript 开发必须掌握技能(三)- 更好的使用for循环方法
  • 原文地址:https://www.cnblogs.com/mingfeng002/p/6542652.html
Copyright © 2011-2022 走看看