Android 加载图片 JNI 读取使用图片

最近在学习ndk加载纹理的例子时,有些收获,写出来与大家共同探讨!
在用ndk开发游戏时,最常见的就是显示图片,在c语言下用opengl贴图,经过实践,已知有4种方法可行!
备注:以下部分内容参考网上代码,具体是哪,忘记了。如有冒犯,敬请谅解!

1. java层生成好纹理,通过jni传递给c层

private Bitmap getBitmap(Context context, int resId) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false;
return BitmapFactory.decodeResource(context.getResources(), resId, options);
}
Bitmap bitmap = getBitmap(context, R.drawable.ic_1);
int[] textures = new int[1];
gl.glGenTextures(1, textures, 0);
//textureId = textures[0];

gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);

gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);

GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
GL0JNILib.setTextures(textures);

把textures[0]传递给c层直接绑定纹理

2. java层生成bitmap的图像数据,传递给c

Bitmap bitmap = getBitmap(context, R.drawable.ic_1);
ByteBuffer fcbuffer = ByteBuffer.allocate(bitmap.getHeight() * bitmap.getWidth() * 4);
bitmap.copyPixelsToBuffer(fcbuffer);
fcbuffer.flip();
Log.d(TAG, "bitmap=" + bitmap + "," + fcbuffer);
byte[] data = fcbuffer.array();

3. java层生成bitmap,传递给c,c层获取图片数据

推荐使用这种方式来实现,在C层处理纹理

Bitmap bitmap = getBitmap(context, R.drawable.ic_1);

c层读取图片数据

GLvoid* getBitmapPixels(JNIEnv* env, jobject bitmap)
{
AndroidBitmapInfo info;

int ret;
GLvoid* pixels;
AndroidBitmap_getInfo(env, bitmap, &info);
if(info.format != ANDROID_BITMAP_FORMAT_RGBA_8888) {
LOGI("Bitmap format is not RGBA_8888!");
return;
}
AndroidBitmap_lockPixels(env, bitmap, &pixels);
// Now you can use the pixel array 'pixels', which is in RGBA format
LOGI("Bitmap format --------------------------");
AndroidBitmap_unlockPixels(env, bitmap);
return pixels;
}

4. 通过libpng,libzip库,在c层直接读取png数据

unsigned char* png_read_zip(const char* filename, int *w, int *h) {
int k; //用于循环
png_bytep * row_pointers;//图片的数据内容
int row,col,pos; //用于改变png像素排列的问题。
unsigned char *rgba;
int width;
int height;
file = zip_fopen(APKArchive, filename, 0);
if (!file) {
LOGI("loadTexture Error opening %s from APK", filename);
return TEXTURE_LOAD_ERROR;
}
//LOGI("loadTexture0");
//header for testing if it is a png
png_byte header[8];
//read the header
zip_fread(file, header, 8);
//test if png
int is_png = !png_sig_cmp(header, 0, 8);
if (!is_png) {
zip_fclose(file);
LOGI("loadTexture Not a png file : %s", filename);
return TEXTURE_LOAD_ERROR;
}

//create png struct
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,
NULL, NULL);
if (!png_ptr) {
zip_fclose(file);
LOGI("loadTexture Unable to create png struct : %s", filename);
return (TEXTURE_LOAD_ERROR);
}

//create png info struct
png_infop info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr) {
png_destroy_read_struct(&png_ptr, (png_infopp) NULL, (png_infopp) NULL);
LOGI("loadTexture Unable to create png info : %s", filename);
zip_fclose(file);
return (TEXTURE_LOAD_ERROR);
}

//create png info struct
png_infop end_info = png_create_info_struct(png_ptr);
if (!end_info) {
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL);
LOGI("loadTexture Unable to create png end info : %s", filename);
zip_fclose(file);
return (TEXTURE_LOAD_ERROR);
}

//png error stuff, not sure libpng man suggests this.
if (setjmp(png_jmpbuf(png_ptr))) {
zip_fclose(file);
LOGI("loadTexture Error during setjmp : %s", filename);
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
return (TEXTURE_LOAD_ERROR);
}

//init png reading
//png_init_io(png_ptr, fp);
png_set_read_fn(png_ptr, NULL, png_zip_read);
//let libpng know you already read the first 8 bytes
png_set_sig_bytes(png_ptr, 8);
// read all the info up to the image data
png_read_info(png_ptr, info_ptr);
//variables to pass to get info
int bit_depth, color_type;
png_uint_32 twidth, theight;
// get info about png
png_get_IHDR(png_ptr, info_ptr, &twidth, &theight, &bit_depth, &color_type,
NULL, NULL, NULL);
//update width and height based on png info
width = twidth;
height = theight;
// Update the png info struct.
png_read_update_info(png_ptr, info_ptr);

//读文件
if (setjmp(png_jmpbuf(png_ptr))){
zip_fclose(file);
return (TEXTURE_LOAD_ERROR);
}
rgba = malloc(width * height * 4);
//使用动态数组 设置长度
row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height);

for (k = 0; k < height; k++)
row_pointers[k] = NULL;

//通过扫描流里面的每一行将得到的数据赋值给动态数组
for (k=0; k
//row_pointers[k] = (png_byte*) malloc(png_get_rowbytes(png_ptr,info_ptr));
row_pointers[k] = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr));
//由于png他的像素是由 左-右-从顶到底 而贴图需要的像素都是从左-右-底到顶的所以在这里需要把像素内容进行一个从新排列
//读图片
png_read_image(png_ptr, row_pointers);

pos = (width * height * 4) - (4 * width);
for( row = 0; row < height; row++)
{
for( col = 0; col < (4 * width); col += 4)
{
rgba[pos++] = row_pointers[row][col]; // red
rgba[pos++] = row_pointers[row][col + 1]; // green
rgba[pos++] = row_pointers[row][col + 2]; // blue
rgba[pos++] = row_pointers[row][col + 3]; // alpha
}
pos=(pos - (width * 4)*2);
}
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);

//LOGI("loadTexture7");
free(row_pointers);

zip_fclose(file);

*w = width;
*h = height;
return rgba;
} 
Android应用开发中,如果需要读取本地文件,可以通过JNI(Java Native Interface)来实现。 JNI是用于在Java代码与本地代码(C/C++)之间进行交互的一种技术。通过JNI,我们可以在Java代码中调用本地代码来访问系统底层资源,例如读取本地文件。 以下是一种实现方式: 1. 创建一个Java类,用于加载本地库文件和声明本地方法。例如: ``` public class NativeFileReader { static { System.loadLibrary("native-library"); } public static native String readFile(String filePath); } ``` 2. 在本地代码中实现读取文件的方法,并将内容转换为字符串返回。例如: ``` #include <jni.h> #include <stdio.h> JNIEXPORT jstring JNICALL Java_com_example_NativeFileReader_readFile(JNIEnv* env, jclass clazz, jstring filePath) { const char* filePathStr = (*env)->GetStringUTFChars(env, filePath, NULL); FILE* file = fopen(filePathStr, "r"); if (file == NULL) { return NULL; } fseek(file, 0, SEEK_END); long fileSize = ftell(file); fseek(file, 0, SEEK_SET); char* buffer = malloc(fileSize + 1); fread(buffer, 1, fileSize, file); buffer[fileSize] = '\0'; fclose(file); (*env)->ReleaseStringUTFChars(env, filePath, filePathStr); jstring result = (*env)->NewStringUTF(env, buffer); free(buffer); return result; } ``` 3. 将本地代码编译为动态库文件,例如libnative-library.so。 4. 将生成的动态库文件放置到项目的jniLibs目录中。 5. 在Java代码中调用NativeFileReader类的readFile方法,传入要读取的文件路径,就可以得到读取到的文件内容。例如: ``` String filePath = "/sdcard/example.txt"; String fileContent = NativeFileReader.readFile(filePath); ``` 这样,就能够通过JNI读取本地文件了。需要注意的是,为了保证文件读取的权限,需要在AndroidManifest.xml文件中添加文件读写权限的声明。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值