91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Android中JNI處理圖片如何實現黑白濾鏡

發布時間:2021-08-04 14:42:47 來源:億速云 閱讀:160 作者:小新 欄目:移動開發

這篇文章將為大家詳細講解有關Android中JNI處理圖片如何實現黑白濾鏡,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。

準備

新版本的Android Studio在新建工程時,就可以選擇Include C++ support

Android中JNI處理圖片如何實現黑白濾鏡

當我們勾上這個選擇后,Android Studio就會幫我們自動完成,c++開發目錄的創建。

Android中JNI處理圖片如何實現黑白濾鏡

我們先看一下CMakeLists.txt:

# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html

# Sets the minimum version of CMake required to build the native library.

cmake_minimum_required(VERSION 3.4.1)

# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.

add_library( # Sets the name of the library.
       native-lib

       # Sets the library as a shared library.
       SHARED

       # Provides a relative path to your source file(s).
       src/main/cpp/native-lib.cpp )

# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.

find_library( # Sets the name of the path variable.
       log-lib

       # Specifies the name of the NDK library that
       # you want CMake to locate.
       log )

# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.

target_link_libraries( # Specifies the target library.
            native-lib jnigraphics

            # Links the target library to the log library
            # included in the NDK.
            ${log-lib} )

我們可以看到,這個文件中,包含了我們需要使用的cpp庫和cpp文件。由于這一次的例子,我們需要開發Bitmap相關的功能,所以我加入了jnigraphics。

Java

先看代碼:

public class MainActivity extends AppCompatActivity {

  private ImageView mImg1, mImg2;

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

    mImg1 = (ImageView) findViewById(R.id.img_test1_id);
    mImg2 = (ImageView) findViewById(R.id.img_test2_id);
  }


  /**
   * 確定native處理圖片的接口
   * @param bitmap 需要被處理的圖片
   */
  public native void nativeProcessBitmap(Bitmap bitmap);

  /**
   * 引入native庫
   */
  static {
    System.loadLibrary("native-lib");
  }

  /**
   * 點擊開始加載圖片
   * @param view
   */
  public void onLoadClick(View view) {
    Bitmap originalBitmap = loadBitmap();
    mImg1.setImageBitmap(originalBitmap);
    Bitmap resultBitmap = processBitmap(originalBitmap);
    mImg2.setImageBitmap(resultBitmap);
  }

  /**
   * 從assets中加載圖片
   * @return
   */
  private Bitmap loadBitmap() {
    Bitmap bmp = null;
    AssetManager am = getResources().getAssets();
    try {
      InputStream is = am.open("test_img.jpg");
      BitmapFactory.Options options = new BitmapFactory.Options();
      bmp = BitmapFactory.decodeStream(is ,null , options);
      is.close();
    } catch (IOException e) {
      e.printStackTrace();
    }
    return bmp;
  }

  /**
   * 處理圖片,此方法中會調用nativeProcessBitmap
   * @param bitmap
   * @return
   */
  private Bitmap processBitmap(Bitmap bitmap) {
    Bitmap bmp = bitmap.copy(Bitmap.Config.ARGB_8888, true);
    nativeProcessBitmap( bmp);
    return bmp;
  }
}

代碼比較簡單。不作過多的解釋。

與圖片相關的事情只有兩件:

  1. 引入native-lib庫

  2. 確定了native接口:public native void nativeProcessBitmap(Bitmap bitmap);

其他的代碼都是為了demo效果寫的一些業務代碼,不作過多贅述。

C++

由于c++的代碼比較長,我們分段來看。

#include <jni.h>
#include <string>

#include <android/bitmap.h>
#include <android/log.h>

#ifndef eprintf
#define eprintf(...) __android_log_print(ANDROID_LOG_ERROR,"@",__VA_ARGS__)

#endif

這一段主要引入了我們需要的庫并宏定義了eprintf,方便我們打日志并進行調試。

#define MAKE_RGB565(r,g,b) ((((r) >> 3) << 11) | (((g) >> 2) << 5) | ((b) >> 3))
#define MAKE_ARGB(a,r,g,b) ((a&0xff)<<24) | ((r&0xff)<<16) | ((g&0xff)<<8) | (b&0xff)

#define RGB565_R(p) ((((p) & 0xF800) >> 11) << 3)
#define RGB565_G(p) ((((p) & 0x7E0 ) >> 5) << 2)
#define RGB565_B(p) ( ((p) & 0x1F )    << 3)

#define RGB8888_A(p) (p & (0xff<<24) >> 24 )
#define RGB8888_R(p) (p & (0xff<<16) >> 16 )
#define RGB8888_G(p) (p & (0xff<<8) >> 8 )
#define RGB8888_B(p) (p & (0xff) )

這一段定義了RGB565和ARGB8888的讀寫方法。對于RGB565和ARGB8888格式不熟悉的同學,可以參考:

在Android的Bitmap.Config中有四個枚舉類型:ALPHA_8、ARGB_4444、ARGB_8888和RGB_565

下面是這四種類型的詳細解釋:

ALPHA_8:每個像素都需要1(8位)個字節的內存,只存儲位圖的透明度,沒有顏色信息

ARGB_4444:A(Alpha)占4位的精度,R(Red)占4位的精度,G(Green)占4位的精度,B(Blue)占4位的精度,加起來一共是16位的精度,折合是2個字節,也就是一個像素占兩個字節的內存,同時存儲位圖的透明度和顏色信息。不過由于該精度的位圖質量較差,官方不推薦使用

ARGB_8888:這個類型的跟ARGB_4444的原理是一樣的,只是A,R,G,B各占8個位的精度,所以一個像素占4個字節的內存。由于該類型的位圖質量較好,官方特別推薦使用。但是,如果一個480*800的位圖設置了此類型,那個它占用的內存空間是:480*800*4/(1024*1024)=1.5M

RGB_565:同理,R占5位精度,G占6位精度,B占5位精度,一共是16位精度,折合兩個字節。這里注意的時,這個類型存儲的只是顏色信息,沒有透明度信息

值得注意的是雖然RGB565的三色只有5位信息,但其實它們的值是8位,提供的5位信息是高5位的信息。

extern "C"
{

  JNIEXPORT void JNICALL
  Java_com_live_longsiyang_jnibitmapdemo_MainActivity_nativeProcessBitmap(JNIEnv *env,
                                      jobject instance,
                                      jobject bitmap) {

    if (bitmap == NULL) {
      eprintf("bitmap is null\n");
      return;
    }

    AndroidBitmapInfo bitmapInfo;
    memset(&bitmapInfo , 0 , sizeof(bitmapInfo));
    // Need add "jnigraphics" into target_link_libraries in CMakeLists.txt
    AndroidBitmap_getInfo(env , bitmap , &bitmapInfo);

    // Lock the bitmap to get the buffer
    void * pixels = NULL;
    int res = AndroidBitmap_lockPixels(env, bitmap, &pixels);

    // From top to bottom
    int x = 0, y = 0;
    for (y = 0; y < bitmapInfo.height; ++y) {
      // From left to right
      for (x = 0; x < bitmapInfo.width; ++x) {
        int a = 0, r = 0, g = 0, b = 0;
        void *pixel = NULL;
        // Get each pixel by format

        if(bitmapInfo.format == ANDROID_BITMAP_FORMAT_RGBA_8888)
        {
          pixel = ((uint32_t *)pixels) + y * bitmapInfo.width + x;
          int r,g,b;
          uint32_t v = *((uint32_t *)pixel);
          r = RGB8888_R(v);
          g = RGB8888_G(v);
          b = RGB8888_B(v);
          int sum = r+g+b;
          *((uint32_t *)pixel) = MAKE_ARGB(0x1f , sum/3, sum/3, sum/3);
        }
        else if (bitmapInfo.format == ANDROID_BITMAP_FORMAT_RGB_565) {
          pixel = ((uint16_t *)pixels) + y * bitmapInfo.width + x;
          int r,g,b;
          uint16_t v = *((uint16_t *)pixel);
          r = RGB565_R(v);
          g = RGB565_G(v);
          b = RGB565_B(v);
          int sum = r+g+b;
          *((uint16_t *)pixel) = MAKE_RGB565(sum/3, sum/3, sum/3); }
      }
    }

    AndroidBitmap_unlockPixels(env, bitmap);

  }

}

這一段代碼雖然長,但邏輯其實非常簡單。

AndroidBitmapInfo bitmapInfo;
    memset(&bitmapInfo , 0 , sizeof(bitmapInfo));
    // Need add "jnigraphics" into target_link_libraries in CMakeLists.txt
    AndroidBitmap_getInfo(env , bitmap , &bitmapInfo);

我們通過bitmap獲得AndroidBitmapInfo對象。AndroidBitmapInfo為我們提供了Bitmap的所有信息。

然后我們,再調用AndroidBitmap_lockPixels:

void * pixels = NULL;
int res = AndroidBitmap_lockPixels(env, bitmap, &pixels);

獲得bitmap的像素矩陣,并將它存放在&pixels中。

pixels的每一位就包含了一個像素點的顏色信息。因此在RGB565模式下,它就是16位的,在ARGB8888模式下,它就是24位的。最后,我對RGB三色的值取了平均,從而得到一個新的圖片。在這個圖片中,RGB三色的值是相等的。因此,它是一個黑白圖片。

我們在修改圖片的像素值時,圖片其實是被鎖定的,修改完成后,我們需要解鎖:

AndroidBitmap_unlockPixels(env, bitmap);

至此,我們的圖片修改就完成了。最后看一下效果。

Android中JNI處理圖片如何實現黑白濾鏡

關于“Android中JNI處理圖片如何實現黑白濾鏡”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

百色市| 石泉县| 河北区| 武汉市| 罗江县| 汪清县| 买车| 赤峰市| 牟定县| 阳山县| 西丰县| 新源县| 泰顺县| 边坝县| 本溪| 四平市| 泰州市| 华坪县| 丹凤县| 阿勒泰市| 万载县| 郓城县| 胶南市| 汶上县| 平果县| 长沙县| 连江县| 浦东新区| 巴彦县| 滦平县| 平凉市| 澄江县| 东源县| 泸州市| 泗阳县| 塘沽区| 枣阳市| 绥滨县| 正阳县| 清水河县| 吉隆县|