Android NDK使用libjpeg解析JPEG图片,并显示到SurfaceView上

来源:互联网 发布:手机嗅探软件 编辑:程序博客网 时间:2024/06/05 16:14

转载请保留原文链接:http://blog.csdn.net/u010593680/article/details/41776151

SurfaceView大概是谷歌提供给开发者最吸引人的的组件了,原因是SurfaceView的界面刷新允许在非UI线程中更新,正因为此,很多频繁更新界面的应用,如视频播放器、游戏、动画效果总会基于SurfaceView及其子类进行开发。

而最近我正在研究的一个应用是关于处理图片并显示图片的应用,图片实在是内存杀手,而处理图片则运算量非常大,这些都是令人头疼的问题。

分析应用,并选择实现技术

1、处理图片运算量大,为了提高运算效率,选择使用C语言处理图片

2、需要的内存空间较大,为节约内存并提高效率,需要从C语言中读入文件,并及早释放


下面写下展示图片的基本流程

1、用户选择图片

2、获得用户选择的图片的路径

3、调用展示图片的方法(C方法)


第一部分:用户选择图片

Intent intent = new Intent(Intent.ACTION_GET_CONTENT);// ACTION_OPEN_DOCUMENTintent.addCategory(Intent.CATEGORY_OPENABLE);intent.setType("image/jpeg");if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {startActivityForResult(intent, SELECT_PIC_KITKAT);} else {startActivityForResult(intent, SELECT_PIC);}


第二部分获得用户选择的图片的路径

protected void onActivityResult(int requestCode, int resultCode, Intent data) {if (resultCode == RESULT_OK) {if (requestCode == SELECT_PIC) {Uri originalUri = data.getData();String[] proj = { MediaStore.Images.Media.DATA };// 好像是android多媒体数据库的封装接口,具体的看Android文档Cursor cursor = managedQuery(originalUri, proj, null, null,null);// 按我个人理解 这个是获得用户选择的图片的索引值int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);// 将光标移至开头 ,这个很重要,不小心很容易引起越界cursor.moveToFirst();// 最后根据索引值获取图片路径String path = cursor.getString(column_index);Log.v("图片路径: ", path);if (path.endsWith(".jpg")) {isOnActivityResult = true;imgPath = path;}}}};

第三部分:调用展示图片的方法

这个部分需要注意,写在SurfaceHolder的回调方法内,为的是让SurfaceView中的Surface成功建立后,再将Surface传入C代码中进行处理

svShow = (SurfaceView) findViewById(R.id.svShow);svHolder = svShow.getHolder();svHolder.addCallback(new SurfaceHolder.Callback() {public void surfaceChanged(SurfaceHolder holder, int format,int width, int height) {Log.v(TAG, "surfaceChanged format=" + format + ", width="+ width + ", height=" + height);}public void surfaceCreated(SurfaceHolder holder) {Log.v(TAG, "surfaceCreated");if (isOnActivityResult && imgPath != null) {showJPG(holder.getSurface(), imgPath);}}public void surfaceDestroyed(SurfaceHolder holder) {Log.v(TAG, "surfaceDestroyed");}});


实际处理图片并显示图片的代码

JNIEXPORT void JNICALL Java_com_example_photoprocessing_activity_SurfaceProcessingActivity_showJPG(JNIEnv * env, jobject activity, jobject surface, jstring img) {const char * imgChar;jboolean * isCopy;imgChar = env->GetStringUTFChars(img, 0);ANativeWindow_Buffer nwBuffer;LOGI("img path : %s  ",imgChar);LOGI("ANativeWindow_fromSurface ");ANativeWindow * mANativeWindow = ANativeWindow_fromSurface(env, surface);if (mANativeWindow == NULL) {LOGE("ANativeWindow_fromSurface error");return;}LOGI("ANativeWindow_lock ");if (0 != ANativeWindow_lock(mANativeWindow, &nwBuffer, 0)) {LOGE("ANativeWindow_lock error");return;}read_jpeg_file_show(imgChar, nwBuffer);if (nwBuffer.format == WINDOW_FORMAT_RGBA_8888) {LOGI("nwBuffer->format == WINDOW_FORMAT_RGBA_8888 ");}LOGI("ANativeWindow_unlockAndPost ");if (0 != ANativeWindow_unlockAndPost(mANativeWindow)) {LOGE("ANativeWindow_unlockAndPost error");return;}env->ReleaseStringUTFChars(img,imgChar);ANativeWindow_release(mANativeWindow);LOGI("ANativeWindow_release ");return;}
int read_jpeg_file_show(const char *input_filename,ANativeWindow_Buffer& nwBuffer) {struct jpeg_decompress_struct cinfo;struct jpeg_error_mgr jerr;FILE *input_file;JSAMPARRAY buffer;int row_width;unsigned char *buffertmp;cinfo.err = jpeg_std_error(&jerr);if ((input_file = fopen(input_filename, "rb")) == NULL) {fprintf(stderr, "can't open %s\n", input_filename);LOGI("can't open jpg1");return -1;}//初始化信息jpeg_create_decompress(&cinfo);LOGI("初始化信息");/* Specify data source for decompression *///指定图片jpeg_stdio_src(&cinfo, input_file);LOGI("指定图片");/* Read file header, set default decompression parameters */(void) jpeg_read_header(&cinfo, TRUE);LOGI("读取头信息, set default decompression parameters ");/* Start decompressor */(void) jpeg_start_decompress(&cinfo);LOGI("解压");row_width = cinfo.output_width * cinfo.output_components;LOGI("图片的宽:%d 图片的高%d 颜色长度:%d", cinfo.output_width, cinfo.output_height, cinfo.output_components);buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr) &cinfo, JPOOL_IMAGE,row_width, 1);//一行buffertmp = (unsigned char *) malloc(row_width);memset(buffertmp, 0, row_width);LOGI("malloc and memset");//        tmp = output_buffer;/* Process data */int get8h5 = 248, get8h6 = 252;__uint16_t * line = (__uint16_t *) nwBuffer.bits;int wheight = 0;int scalew = 1, scaleh = 1;if (cinfo.output_width > nwBuffer.width) {scalew = cinfo.output_width / nwBuffer.width;}LOGI(" scale of img = %d", scalew);for (int i = 0, choosehNum = 0; i < cinfo.output_height; i++) {//获得一行jpeg_read_scanlines(&cinfo, buffer, 1);buffertmp = *buffer;//根据缩放选取行if (i % scalew == 0 && choosehNum++ < nwBuffer.height) {//LOGI("nwBuffer->format == WINDOW_FORMAT_RGB_565");for (int j = 0, choosewNum = 0; j < cinfo.output_width; j++) {if (j % scalew == 0) {if (nwBuffer.format == WINDOW_FORMAT_RGB_565) {line[choosewNum] = ((__uint16_t ) buffertmp[3 * j + 0]& get8h5) << 8| ((__uint16_t ) (buffertmp[3 * j + 1] & get8h6)<< 3)| ((__uint16_t ) (buffertmp[3 * j + 2] & get8h6)>> 3);choosewNum++;}}}line = line + nwBuffer.stride;}}//                memcpy(tmp, *buffer, row_width);//                tmp += row_width;(void) jpeg_finish_decompress(&cinfo);LOGI("jpeg_finish_decompress !!");jpeg_destroy_decompress(&cinfo);LOGI("jpeg_destroy_decompress !!");/* Close files, if we opened them */fclose(input_file);return 0;}

Demo展示:

点击显示图片,开始选择图片:



选择完后,自动显示:



感谢大家看完本博客!!如有问题可提出讨论~~

由于时间太长,这个demo代码已经找不到了,下篇博客的源码工程即包含本博客所用全部方法,麻烦大家移步了

本博客地址:http://blog.csdn.net/u010593680/article/details/41776151





4 0
原创粉丝点击