动脑学院 - Java 和 JNI方式处理图片比较

MainAcitivty:
/** 
 * @projectName:JavaNdkComp 
 * @fileName:MainActivity.java 
 * @packageName:club.younge.demo 
 * @date:2016年8月28日下午11:10:29 
 * @copyright (c) 2016, heqy@finansir.nt All Rights Reserved. 
 * 
 */

package club.younge.demo;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Bitmap.Config;
import android.media.Image;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.Toast;
import club.younge.java.JavaImageUtils;
import club.younge.ndk.NdkImageUtils;

/**
 * @className:MainActivity
 * @function: TODO ADD FUNCTION.
 * @reason: TODO ADD REASON.
 * @date: 2016年8月28日 下午11:10:29
 * @author Younge
 * @version
 * @since JDK 1.8
 * @see
 */
public class MainActivity extends Activity {
	private ImageView imageView;
	private Bitmap mBitmap;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		imageView = (ImageView) findViewById(R.id.imageView);
		mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.xy);
	}

	public void srcImage(View view) {
		imageView.setImageBitmap(mBitmap);
	}

	public void javaImage(View view) {
		long start = System.currentTimeMillis();
		Bitmap bitmap = JavaImageUtils.getBitMap(mBitmap);
		imageView.setImageBitmap(bitmap);
		long end = System.currentTimeMillis();
		Toast.makeText(this, "耗时:"+ (end -start) +"ms", Toast.LENGTH_SHORT).show();
	}

	public void ndkImage(View view) {
		int width = mBitmap.getWidth();
		int height = mBitmap.getHeight();
		int[] buffer = new int[width*height];
		mBitmap.getPixels(buffer, 0, width, 0, 0, width, height);
		long start = System.currentTimeMillis();
		int[] result = NdkImageUtils.getImage(buffer, width, height);
		Bitmap bitmap = Bitmap.createBitmap(result, 0, width, width, height, Config.ARGB_8888);
		imageView.setImageBitmap(bitmap);
		long end = System.currentTimeMillis();
		Toast.makeText(this, "耗时:"+ (end -start) +"ms", Toast.LENGTH_SHORT).show();
	}
}

JavaImageUtils:
/** 
 * @projectName:JavaNdkComp 
 * @fileName:JavaImageUtils.java 
 * @packageName:club.younge.java 
 * @date:2016年8月28日下午11:12:57 
 * @copyright (c) 2016, heqy@finansir.nt All Rights Reserved. 
 * 
 */  
  
package club.younge.java;

import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Color;

/** 
 * @className:JavaImageUtils 
 * @function: TODO ADD FUNCTION.  
 * @reason:   TODO ADD REASON. 
 * @date:     2016年8月28日 下午11:12:57
 * @author   Younge 
 * @version   
 * @since    JDK 1.8 
 * @see       
 */
public class JavaImageUtils {
	public static Bitmap getBitMap(Bitmap bitmap){
		if(bitmap == null) return null;
		int width = bitmap.getWidth();
		int height = bitmap.getHeight();
		Bitmap result = Bitmap.createBitmap(width, height, Config.ARGB_8888);
		int color, a, r, g, b, rt, gt, bt;
		float bright = 0.2f;
		float contrast = 0.2f;
		int bri = (int)(256*bright);
		for (int x = 0; x < width; x++) {
			for (int y = 0; y < height; y++) {
				color = bitmap.getPixel(x, y);
				a = Color.alpha(color);
				r = Color.red(color);
				g = Color.green(color);
				b = Color.blue(color);
				//更改亮度,统一增加一个值,变得更白更亮
			    rt = r + bri;
			    gt = g + bri;
			    bt = b + bri;
			    
			    r = rt > 255 ? 255:(rt < 0 ? 0: rt); //事实在目前情况下,不会出现rt小于0的情况,此处这么写是为了统一后边
			    g = gt > 255 ? 255:(gt < 0 ? 0: gt);
			    b = bt > 255 ? 255:(bt < 0 ? 0: bt);
			    
			    //更改对比度, 以128中间值为分界点,白的更白,黑的更黑,增加对比度
			    
			    r = r - 128;
			    g = g - 128;
			    b = b - 128;
			    
			    rt = (int) (r*(1 + contrast)) + 128;
			    gt = (int) (g*(1 + contrast)) + 128;
			    bt = (int) (b*(1 + contrast)) + 128;
			    
			    r = rt > 255 ? 255:(rt < 0 ? 0: rt); 
			    g = gt > 255 ? 255:(gt < 0 ? 0: gt);
			    b = bt > 255 ? 255:(bt < 0 ? 0: bt);
			    
			    color = Color.argb(a, r, g, b);	
			    
			    result.setPixel(x, y, color);
			}
			
		}
		
		return result;
	}
}


NdkImageUtils:
/** 
 * @projectName:JavaNdkComp 
 * @fileName:NdkImageUtils.java 
 * @packageName:club.younge.ndk 
 * @date:2016年8月28日下午11:13:12 
 * @copyright (c) 2016, heqy@finansir.nt All Rights Reserved. 
 * 
 */  
  
package club.younge.ndk;

/** 
 * @className:NdkImageUtils 
 * @function: TODO ADD FUNCTION.  
 * @reason:   TODO ADD REASON. 
 * @date:     2016年8月28日 下午11:13:12
 * @author   Younge 
 * @version   
 * @since    JDK 1.8 
 * @see       
 */
public class NdkImageUtils {
	static{
		System.loadLibrary("Image");
	}
	public static native int[] getImage(int[] buffer, int width, int height);
}

生成的JNI头文件,club_younge_ndk_NdkImageUtils.h:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class club_younge_ndk_NdkImageUtils */

#ifndef _Included_club_younge_ndk_NdkImageUtils
#define _Included_club_younge_ndk_NdkImageUtils
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     club_younge_ndk_NdkImageUtils
 * Method:    getImage
 * Signature: ([III)[I
 */
JNIEXPORT jintArray JNICALL Java_club_younge_ndk_NdkImageUtils_getImage
  (JNIEnv *, jclass, jintArray, jint, jint);

#ifdef __cplusplus
}
#endif
#endif
实现类,编辑实现类时,右键,Android tools -> add Native support, 然后右键Properties -> c/c++ general -> paths and symbols 若为添加包含的头文件路径,需要添加包含的头文件路径,这样在CPP文件中才会出现代码提示,确保不那么容易出现错误。club_younge_ndk_NdkImageUtils.cpp:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <stdlib.h>
#include <jni.h>
#include "club_younge_ndk_NdkImageUtils.h"
/* Header for class club_younge_ndk_NdkImageUtils */


/*
 * Class:     club_younge_ndk_NdkImageUtils
 * Method:    getImage
 * Signature: ([III)[I
 */
JNIEXPORT jintArray JNICALL Java_club_younge_ndk_NdkImageUtils_getImage
  (JNIEnv *env, jclass clazz, jintArray buffer, jint width, jint height){
	jint *buf = (jint*)env->GetIntArrayElements(buffer, 0);
	jsize len = env->GetArrayLength(buffer);
	jint resultBuf[len];
	jintArray result = env->NewIntArray(len);
	int color, a, r, g, b, rt, gt, bt;
	int bright = (int)(0.2f*256);
	float contrast = 0.2f;
	for(int x = 0; x < width; x++){
		for(int y = 0; y < height; y++){
			color = buf[y*width + x];
			a = color  >> 24;
			r = (color >> 16) & 0xFF;
			g = (color >> 8) & 0xFF;
			b = color & 0xFF;

			//改变亮度
			rt = r + bright;
			gt = g + bright;
			bt = b + bright;

			r = rt > 255 ? 255 : rt;
			g = gt > 255 ? 255 : gt;
			b = bt > 255 ? 255 : bt;
			//改变对比度
			r = r - 128;
			g = g - 128;
			b = b - 128;

			rt = (int) (r*(1 + contrast)) + 128;
			gt = (int) (g*(1 + contrast)) + 128;
			bt = (int) (b*(1 + contrast)) + 128;

			r = rt > 255 ? 255 : (rt < 0 ? 0 : rt);
			g = gt > 255 ? 255 : (gt < 0 ? 0 : gt);
			b = bt > 255 ? 255 : (bt < 0 ? 0 : bt);

			color = a << 24 | r << 16 | g << 8 | b;
			resultBuf[y*width + x] = color;
		}
	}

	env->ReleaseIntArrayElements(buffer,buf,0);
	env->SetIntArrayRegion(result, 0, len, resultBuf);

	return result;
}

测试结果:java:1579ms, jni:470ms, 性能提升3倍多一点。若用大图超过1M,JNI调用直接崩溃退出,报Fatal signal 11 (SIGSEGV) at 0x00000000 (code=1)。

Github: 源码

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值