项目结构图
结构图
MainActivity
public class MainActivity extends Activity {
static {
System.loadLibrary("jpegbither");
System.loadLibrary("native-lib");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 申请权限
checkPermission(this);
}
private boolean checkPermission(Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && activity.checkSelfPermission(
Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
activity.requestPermissions(new String[]{
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
}, 1);
}
return false;
}
// 按钮点击事件
public void onLoad(View view) {
File input = new File(Environment.getExternalStorageDirectory(), "before.jpg");
Bitmap inputBitmap = BitmapFactory.decodeFile(input.getAbsolutePath());
File output = new File(Environment.getExternalStorageDirectory(), "哈夫曼压缩.jpg");
// 哈夫曼压缩
compress(inputBitmap, output.getAbsolutePath());
// 质量压缩
File output1 = new File(Environment.getExternalStorageDirectory(), "质量压缩.jpg");
compressQuality(inputBitmap, output1);
// 尺寸压缩
File output2= new File(Environment.getExternalStorageDirectory(), "尺寸压缩.jpg");
compressSize(inputBitmap, output2);
}
public native void compress(Bitmap bitmap, String path);
/*
* 质量压缩:设置bitmap options属性,降低图片的质量,不会减少像素
第一个参数:需要压缩的bitmap图片对象,第二个参数:压缩后图片保存的位置
设置options属性值(0-100)来实现压缩
*/
public void compressQuality(Bitmap bmp, File file) {
int options = 10; // 100为不压缩
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// 把压缩后的数据存放到baos中
bmp.compress(Bitmap.CompressFormat.JPEG, options, baos);
try {
FileOutputStream fos = new FileOutputStream(file);
fos.write(baos.toByteArray());
fos.flush();
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/*
* 尺寸压缩:通过缩放图片像素,来减少图片占用内存大小
*/
public void compressSize(Bitmap bmp, File file) {
// 尺寸压缩倍数:值越大,图片尺寸越小
int ratio = 6;
// 压缩Bitmap到对应尺寸
Bitmap result = Bitmap.createBitmap(bmp.getWidth() / ratio, bmp.getHeight() / ratio,
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(result);
Rect rect = new Rect(0, 0, bmp.getWidth() / ratio, bmp.getHeight() / ratio);
canvas.drawBitmap(bmp, null, rect, null);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// 把压缩后的数据存放到baos中
result.compress(Bitmap.CompressFormat.JPEG, 100 ,baos);
try {
FileOutputStream fos = new FileOutputStream(file);
fos.write(baos.toByteArray());
fos.flush();
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
native-lib.cpp
#include <jni.h>
#include <string>
#include <android/bitmap.h>
#include <android/log.h>
#include <malloc.h>
extern "C" {
#include "jpeglib.h"
}
typedef uint8_t BYTE;
void writeImg(BYTE *data, const char *path, int w, int h) {
// jpeg引擎,绕过skia来实现压缩
//信使
struct jpeg_compress_struct jpeg_struct;
// 设置错误处理信息
jpeg_error_mgr err;
jpeg_struct.err = jpeg_std_error(&err);
// 给结构体分配内存
jpeg_create_compress(&jpeg_struct);
FILE *file = fopen(path, "wb");
// 设置输出路径
jpeg_stdio_dest(&jpeg_struct, file);
jpeg_struct.image_width = w;
jpeg_struct.image_height = h;
// 初始化 初始化
jpeg_struct.arith_code = FALSE; // 开启hufuman算法
jpeg_struct.optimize_coding = TRUE;
jpeg_struct.in_color_space = JCS_RGB;
jpeg_struct.input_components = 3;
// 其他的设置默认
jpeg_set_defaults(&jpeg_struct);
jpeg_set_quality(&jpeg_struct, 20, true);
jpeg_start_compress(&jpeg_struct, TRUE);
JSAMPROW row_pointer[1];
// 一行的rgb
int row_stride = w * 3;
while (jpeg_struct.next_scanline < h) {
row_pointer[0] = &data[jpeg_struct.next_scanline * w * 3];
jpeg_write_scanlines(&jpeg_struct, row_pointer, 1);
}
jpeg_finish_compress(&jpeg_struct);
jpeg_destroy_compress(&jpeg_struct);
fclose(file);
}
extern "C" JNIEXPORT void JNICALL
Java_com_zc_pressimage_MainActivity_compress(JNIEnv *env, jobject instance, jobject bitmap, jstring path_) {
const char *path = env->GetStringUTFChars(path_, 0);
AndroidBitmapInfo bitmapInfo;
AndroidBitmap_getInfo(env, bitmap, &bitmapInfo);
BYTE *pixels;
AndroidBitmap_lockPixels(env, bitmap, (void **) &pixels);
int h = bitmapInfo.height;
int w = bitmapInfo.width;
BYTE *data, *tmpData;
data = (BYTE *) malloc(w * h * 3);
tmpData = data;
BYTE r, g, b;
int color;
for (int i = 0; i < h; ++i) {
for (int j = 0; j < w; ++j) {
color = *((int *) pixels);
r = ((color & 0x00FF0000) >> 16);
g = ((color & 0x0000FF00) >> 8);
b = ((color & 0x000000FF));
*data = b;
*(data + 1) = g;
*(data + 2) = r;
data += 3;
pixels += 4;
}
}
AndroidBitmap_unlockPixels(env, bitmap);
writeImg(tmpData, path, w, h);
env->ReleaseStringUTFChars(path_, path);
}