【Androidメモリ最適化】Androidエンジニアリングでlibjpeg-turbo圧縮画像を使用(JNIよりBitmapを転送|ビットマップ情報取得|画像データ取得|画像データフィルタリング|リソース解放)
26144 ワード
文書ディレクトリ一、Bitmap画像データ処理 二、Java層BitmapオブジェクトからJNI層bitmapオブジェクトへの変換 三、bitmap中の画像データ を取得する四、bitmap中の画像データ(RGBデータを取得するAチャネルデータを除く) をフィルタリングする.五、解放資源 六、Bitmap画像データ処理 前回ブログ【Androidメモリ最適化】libjpeg-turbo関数ライブラリクロスコンパイルと使用(クロスコンパイルスクリプト作成|関数ライブラリヘッダファイルコピー|構築スクリプト構成|Android Studioテスト関数ライブラリ)のlibjpeg-turbo関数ライブラリをクロスコンパイルし、対応するヘッダファイルと静的ライブラリをAndroid Studioプロジェクトにコピーし、CMakeListを構成した.txt構築スクリプト、build.gradle構築スクリプトは、このブログでコードの作成を開始します.
一、Bitmap画像データ処理
Bitmap画像データ処理:
①Bitmap画像オブジェクトを取得する:JavaがJNI層に渡すのはjobjectオブジェクトであり、これをJNI中のbitmapオブジェクトに変換する必要がある;
②データ抽出:bitmap画像からRGB画素値、すなわちALPHAチャネル(透明度)を除いたデータを抽出する.
③libjpeg-turboを用いてピクチャを圧縮する:libjpeg-turbo関数ライブラリを呼び出し、上記抽出したピクチャRGB画素データを圧縮する;
④リリースリソース:画像圧縮完了後、関連リソースをリリースする;
二、Java層BitmapオブジェクトからJNI層bitmapオブジェクトへ
1.Bitmap情報:AndroidBitmapInfo構造体には、画像幅、画像高さ、画素フォーマットなどの情報が封入されている.
2.Bitmap情報を取得:bitmapを呼び出す.hのAndroid Bitmap_getInfoメソッドは、jbitmapから対応する情報を取得することができる.
3.コード例:
三、bitmapの画像データを取得する
Android Bitmapを呼び出すlockPixelsメソッドは、JavaのBitmapオブジェクトからデータのヘッダアドレスを取得できます.この関数に2 Dポインタが入力され、この2 Dポインタパラメータは戻り値として使用され、この2 Dポインタが最終的に指すメモリは画像データメモリである.
1. AndroidBitmap_lockPixels関数の役割:指定されたJava Bitmapオブジェクトから、対応するピクセルデータアドレスを取得します.ロックは画素データメモリがロック解除方法を呼び出し、関連データを消去するまで固定されていることを保証することができる.この方法はAndroid Bitmap_とunlockPixelsメソッドはペアで使用され、その後addrPtrアドレスは使用されるべきではありません.実行に成功すると、*addrPtrは画像画素データの先頭アドレスを指し、方法が失敗した場合、この2次元ポインタは無効なポインタである.
2. AndroidBitmap_lockPixels関数のプロトタイプ:
①JNIEnv*envパラメータ:注意ここではJNIEnv*envパラメータを使用しています.メインスレッド呼び出しは直接使用できます.サブスレッド呼び出しの場合、JavaVM呼び出しAttachCurrentThreadメソッドを使用してJNIEnvポインタを入力する必要があります.その後、このJNIEnvはスレッド対応のJNI環境で、使用が終わったらバインドを解除します.
参考【Android NDK開発】JNIスレッド(JNIスレッド作成|スレッド実行関数|非JNIメソッド取得JNIEnvとJavaオブジェクト|スレッド取得JNIEnv|グローバル変数設定)ブログ;
②jobject jbitmapパラメータ:JavaのBitmapオブジェクト;
③void**addrPtrパラメータ:二次元ポインタ、実行成功後に画像の画素データの先頭アドレスを指し、同時に戻り値として使用し、ユーザーが画素データを呼び出すことができるようにする.
3.コード例:
四、bitmap中の画像データをフィルタリングする(RGBデータを取得してAチャネルデータを取り除く)
1.データフィルタ需要:以前に画像データを取得し、addrPtrポインタに保存した.
2.2つのメモリ:uint 8_t*addrPtrポインタが指すメモリはソースデータ、uint 8_t*dataポインタが指すデータはターゲットデータであり、最終的に圧縮するデータはdataターゲットデータである.
3.画素フォーマット:ソースデータに格納されているBGRA画素フォーマットのデータであり、ターゲットデータに格納されているのはBGR画素フォーマットのデータである.
4.画素データの循環:循環を開き、各画素点を直接循環し、画素点の保存形式がBGRAであることに注意し、その後、データを別のメモリに保存し、保存順序はBGRである.注意ループのたびに、対応するポインタを移動する必要があります.
五、資源の解放
前にjpegフォーマットの画像を圧縮するステップがありました.このプロセスは複雑で、ブログの説明を開きます.この章は圧縮が終わった後のメモリの解放操作を説明します.
1.ピクセルデータのロック/ロック解除:Android Bitmap_UnlockPixelsメソッドとAndroid Bitmap_lockPixelsメソッドはペアで使用され、Bitmapオブジェクトのデータが不要になったことを示します.
2.圧縮データの解放:圧縮するJPEGピクチャRGBデータを格納しているメモリを解放し、この時点で既に圧縮済みで、前に申請したメモリをすべて解放することができる.注意前に申請したdataポインタは、データをコピーする過程で、このポインタを移動して、dataポインタを解放することができなくて、前のdataメモリ申請後のバックアップポインタしか解放できなくて、さもなくばエラーを報告します;
3.文字列の解放:env->GetStringUTFcharsが作成した文字列はローカル参照で、ここでは解放する必要があります.メモリをタイムリーに回収するのは良い習慣です.
六、Bitmap画像データ処理
GitHubプロジェクトアドレス:han 1202012/PictureCompression
libjpeg-turbo圧縮JPEGコード例:
一、Bitmap画像データ処理
Bitmap画像データ処理:
①Bitmap画像オブジェクトを取得する:JavaがJNI層に渡すのはjobjectオブジェクトであり、これをJNI中のbitmapオブジェクトに変換する必要がある;
②データ抽出:bitmap画像からRGB画素値、すなわちALPHAチャネル(透明度)を除いたデータを抽出する.
③libjpeg-turboを用いてピクチャを圧縮する:libjpeg-turbo関数ライブラリを呼び出し、上記抽出したピクチャRGB画素データを圧縮する;
④リリースリソース:画像圧縮完了後、関連リソースをリリースする;
二、Java層BitmapオブジェクトからJNI層bitmapオブジェクトへ
1.Bitmap情報:AndroidBitmapInfo構造体には、画像幅、画像高さ、画素フォーマットなどの情報が封入されている.
/** Bitmap info, see AndroidBitmap_getInfo(). */
typedef struct {
/** . */
uint32_t width;
/** . */
uint32_t height;
/** . */
uint32_t stride;
/** . See {@link AndroidBitmapFormat} */
int32_t format;
/** . */
uint32_t flags; // 0 for now
} AndroidBitmapInfo;
2.Bitmap情報を取得:bitmapを呼び出す.hのAndroid Bitmap_getInfoメソッドは、jbitmapから対応する情報を取得することができる.
int AndroidBitmap_getInfo(JNIEnv* env, jobject jbitmap,
AndroidBitmapInfo* info);
3.コード例:
// ,
// bitmap.h
AndroidBitmapInfo info;
// bitmap AndroidBitmapInfo
AndroidBitmap_getInfo(env, jbitmap, &info);
三、bitmapの画像データを取得する
Android Bitmapを呼び出すlockPixelsメソッドは、JavaのBitmapオブジェクトからデータのヘッダアドレスを取得できます.この関数に2 Dポインタが入力され、この2 Dポインタパラメータは戻り値として使用され、この2 Dポインタが最終的に指すメモリは画像データメモリである.
1. AndroidBitmap_lockPixels関数の役割:指定されたJava Bitmapオブジェクトから、対応するピクセルデータアドレスを取得します.ロックは画素データメモリがロック解除方法を呼び出し、関連データを消去するまで固定されていることを保証することができる.この方法はAndroid Bitmap_とunlockPixelsメソッドはペアで使用され、その後addrPtrアドレスは使用されるべきではありません.実行に成功すると、*addrPtrは画像画素データの先頭アドレスを指し、方法が失敗した場合、この2次元ポインタは無効なポインタである.
2. AndroidBitmap_lockPixels関数のプロトタイプ:
①JNIEnv*envパラメータ:注意ここではJNIEnv*envパラメータを使用しています.メインスレッド呼び出しは直接使用できます.サブスレッド呼び出しの場合、JavaVM呼び出しAttachCurrentThreadメソッドを使用してJNIEnvポインタを入力する必要があります.その後、このJNIEnvはスレッド対応のJNI環境で、使用が終わったらバインドを解除します.
参考【Android NDK開発】JNIスレッド(JNIスレッド作成|スレッド実行関数|非JNIメソッド取得JNIEnvとJavaオブジェクト|スレッド取得JNIEnv|グローバル変数設定)ブログ;
②jobject jbitmapパラメータ:JavaのBitmapオブジェクト;
③void**addrPtrパラメータ:二次元ポインタ、実行成功後に画像の画素データの先頭アドレスを指し、同時に戻り値として使用し、ユーザーが画素データを呼び出すことができるようにする.
int AndroidBitmap_lockPixels(JNIEnv* env, jobject jbitmap, void** addrPtr);
3.コード例:
// unsigned char, Java byte
// byte ,
//
uint8_t *addrPtr;
// , ARGB
AndroidBitmap_lockPixels(env, jbitmap, (void **) &addrPtr);
四、bitmap中の画像データをフィルタリングする(RGBデータを取得してAチャネルデータを取り除く)
1.データフィルタ需要:以前に画像データを取得し、addrPtrポインタに保存した.
2.2つのメモリ:uint 8_t*addrPtrポインタが指すメモリはソースデータ、uint 8_t*dataポインタが指すデータはターゲットデータであり、最終的に圧縮するデータはdataターゲットデータである.
3.画素フォーマット:ソースデータに格納されているBGRA画素フォーマットのデータであり、ターゲットデータに格納されているのはBGR画素フォーマットのデータである.
4.画素データの循環:循環を開き、各画素点を直接循環し、画素点の保存形式がBGRAであることに注意し、その後、データを別のメモリに保存し、保存順序はBGRである.注意ループのたびに、対応するポインタを移動する必要があります.
// JPEG , , RGB
//
//
int width = info.width;
//
int height = info.height;
// RGB
uint8_t* data = (uint8_t *) malloc(width * height * 3);
// data , ,
uint8_t* temp = data;
// JPEG RGB ,
uint8_t red, green, blue;
// Bitmap addrPtr BGRA , data BGR
for(int i = 0; i < height; i++){
for (int j = 0; j < width; ++j) {
// i j
// Bitmap BGRA
blue = *( addrPtr );
green = *( addrPtr + 1 );
red = *( addrPtr + 2 );
// libturbojpeg JPEG BGR
*data = blue;
*( data + 1 ) = green;
*( data + 2 ) = red;
// data
data += 3;
// addrPtr ,
addrPtr +=4;
}
}// , JPEG , data
五、資源の解放
前にjpegフォーマットの画像を圧縮するステップがありました.このプロセスは複雑で、ブログの説明を開きます.この章は圧縮が終わった後のメモリの解放操作を説明します.
1.ピクセルデータのロック/ロック解除:Android Bitmap_UnlockPixelsメソッドとAndroid Bitmap_lockPixelsメソッドはペアで使用され、Bitmapオブジェクトのデータが不要になったことを示します.
2.圧縮データの解放:圧縮するJPEGピクチャRGBデータを格納しているメモリを解放し、この時点で既に圧縮済みで、前に申請したメモリをすべて解放することができる.注意前に申請したdataポインタは、データをコピーする過程で、このポインタを移動して、dataポインタを解放することができなくて、前のdataメモリ申請後のバックアップポインタしか解放できなくて、さもなくばエラーを報告します;
3.文字列の解放:env->GetStringUTFcharsが作成した文字列はローカル参照で、ここでは解放する必要があります.メモリをタイムリーに回収するのは良い習慣です.
//
AndroidBitmap_unlockPixels(env,jbitmap);
// temp , data ,
free(temp);
// , , GC ,
env->ReleaseStringUTFChars(path, filePath);
六、Bitmap画像データ処理
GitHubプロジェクトアドレス:han 1202012/PictureCompression
libjpeg-turbo圧縮JPEGコード例:
#include
#include
#include
#include
#include
#include
#include
#include
//
void compressJpegFile(uint8_t *data, int imageWidth, int imageHeight,
jint compressQuality, const char *filename);
extern "C" JNIEXPORT jstring JNICALL
Java_kim_hsl_pc_MainActivity_stringFromJNI(
JNIEnv* env,
jobject /* this */) {
std::string hello = "Hello from C++";
// libturbojpeg.a
jpeg_compress_struct jcs;
__android_log_print(ANDROID_LOG_INFO, "JPEG", "jpeg_compress_struct jcs = %d", jcs.image_width);
hello = hello + " , jpeg_compress_struct jcs = " + std::to_string(jcs.image_width);
return env->NewStringUTF(hello.c_str());
}
/**
*
*/
extern "C"
JNIEXPORT void JNICALL
Java_kim_hsl_pc_MainActivity_native_1pictureCompress(JNIEnv *env, jobject thiz,
jobject jbitmap,
jint quality, jstring path) {
// Java C ,
const char *filePath = env->GetStringUTFChars(path, 0);
// ,
// bitmap.h
AndroidBitmapInfo info;
// bitmap AndroidBitmapInfo
AndroidBitmap_getInfo(env, jbitmap, &info);
// unsigned char, Java byte
// byte ,
//
uint8_t *addrPtr;
// , ARGB
AndroidBitmap_lockPixels(env, jbitmap, (void **) &addrPtr);
// JPEG , , RGB
//
//
int width = info.width;
//
int height = info.height;
//rgb
uint8_t* data = (uint8_t *) malloc(width * height * 3);
// data , ,
uint8_t* temp = data;
// JPEG RGB ,
uint8_t red, green, blue;
// Bitmap addrPtr BGRA , data BGR
for(int i = 0; i < height; i++){
for (int j = 0; j < width; ++j) {
// Bitmap BGRA
blue = *( addrPtr );
green = *( addrPtr + 1 );
red = *( addrPtr + 2 );
// libturbojpeg JPEG BGR
*data = blue;
*( data + 1 ) = green;
*( data + 2 ) = red;
// data
data += 3;
// addrPtr ,
addrPtr +=4;
}
}// , JPEG , data
// data JPEG
compressJpegFile(temp, width, height, quality, filePath);
//
AndroidBitmap_unlockPixels(env,jbitmap);
// temp , data ,
free(temp);
// , , GC ,
env->ReleaseStringUTFChars(path, filePath);
}