一、环境

Android Studio 4.0.1

NDK R15c

so包是2.0.6生成的 libturbojpeg.so

二、准备

1、编写native方法并用javah命令生成头文件

object ImageUtil {

private external fun compressBitmap(bitmap: Bitmap, quality: Int, fileName: String): Int

fun compressImage(bitmap: Bitmap, quality: Int, fileName: String) {

compressBitmap(bitmap, quality, fileName)

}

init {

System.loadLibrary("turbojpeg");

System.loadLibrary("compress");

}

fun decodeFile(filePath: String): Bitmap {

var finalWidth = 800

var opstions = BitmapFactory.Options()

//不加在图片到内存,只拿宽高

opstions.inJustDecodeBounds = true

BitmapFactory.decodeFile(filePath, opstions)

var bitmapWidth = opstions.outWidth

var inSampleSize = 1

if (bitmapWidth > finalWidth) {

inSampleSize = bitmapWidth / finalWidth

}

opstions.inSampleSize = inSampleSize

opstions.inJustDecodeBounds = false

return BitmapFactory.decodeFile(filePath, opstions)

}

}

注意:如果javah提示 无法确定Bitmap的签名,则指定对应的android.jar即可

F:\Android\workspace\ImageSelector\app\src\main\java>javah -classpath

F:\Android\android-sdk\platforms\android-28\android.jar; com.xf.imageselector.utils.Test

2、引入头文件,并解决头文件中的报错,一般都是因为关联文件目录不对,头文件则从编译的源码中提取需要什么头文件

则引入对应的头文件

3、引入so文件,编写CMakeList.txt

注意:so一定要是对应架构下的,不然可能报错找不到jpeg_**的方法错误,

例如undefined reference to 'jpeg_destroy_decompress'

4、编写CMakeList文件,我的文件和app目录平级,所以导入文件目录可能有不一致

cmake_minimum_required(VERSION 3.4.1)

add_library(compress

SHARED

src/main/cpp/compress_image.cpp)

find_library(log-lib log)

add_library(libjpeg

SHARED

IMPORTED)

set_target_properties(libjpeg

PROPERTIES

IMPORTED_LOCATION

${CMAKE_CURRENT_SOURCE_DIR}/src/main/jniLibs/armeabi/libjpeg.so)

include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src/main/cpp/jpeg)

target_link_libraries(compress

libjpeg

jnigraphics

${log-lib})

注意:如果你的目录写正确了,你按着ctrl鼠标可以点过去。一定要导入头文件,不然可能报找不到jpeg方法

5、gradle文件配置

defaultConfig {

applicationId "com.xf.imageselector"

minSdkVersion 21

targetSdkVersion 29

versionCode 1

versionName "1.0"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

externalNativeBuild {

cmake {

cppFlags "-fexceptions", "-frtti"//-std=c++11

abiFilters "armeabi"

}

}

ndk {

abiFilters 'armeabi'

}

}

三、编写文件

#include

#include

#include "com_xf_imageselector_utils_ImageUtil.h"

#include

#include

#include

#include

#include

#include

#include

#include

#include

//log打印

#define LOG_TAG "wxf"

#define LOGW(...) __android_log_write(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__)

#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)

#define true 1

#define false 0

//把头文件用c包裹起来,允许混合编译,不然会报错

extern "C" {

#include "jpeg/jpeglib.h"

#include "jpeg/jconfig.h"

#include "jpeg/jconfigint.h"

#include "jpeg/jerror.h"

#include "jpeg/jmorecfg.h"

}

typedef uint8_t BYTE;

char *error;

struct my_error_mgr {

struct jpeg_error_mgr pub;

jmp_buf setjmp_buffer;

};

typedef struct my_error_mgr *my_error_ptr;

METHODDEF(void)

my_error_exit(j_common_ptr cinfo) {

my_error_ptr myerr = (my_error_ptr) cinfo->err;

(*cinfo->err->output_message)(cinfo);

error = (char *) myerr->pub.jpeg_message_table[myerr->pub.msg_code];

LOGI("jpeg_message_table[%d]:%s", myerr->pub.msg_code,

myerr->pub.jpeg_message_table[myerr->pub.msg_code]);

longjmp(myerr->setjmp_buffer, 1);

}

int

generateJPEG(BYTE *data, int w, int h, int quality, const char *outfileName, jboolean optimize) {

//结构体相当于java的类

struct jpeg_compress_struct jcs;

// 当读完整个文件的时候回回调

struct my_error_mgr jem;

jcs.err = jpeg_std_error(&jem.pub);

jem.pub.error_exit = my_error_exit;

//setjmp是一个系统级函数,是一个回调

if (setjmp(jem.setjmp_buffer)) {

return 0;

}

//初始化jsc结构体

jpeg_create_compress(&jcs);

//打开输出文件 wb可写 rb可读

FILE *f = fopen(outfileName, "wb");

if (f == NULL) {

return 0;

}

//设置结构体的文件路径,以及宽高

jpeg_stdio_dest(&jcs, f);

jcs.image_width = w;

jcs.image_height = h;

// TRUE=arithmetic coding, FALSE=Huffman

jcs.arith_code = false;

int nComponent = 3;

// 颜色的组成rgb,三个 of color components in input image

jcs.input_components = nComponent;

// 设置颜色空间为rgb

jcs.in_color_space = JCS_RGB;

jpeg_set_defaults(&jcs);

// 是否采用哈夫曼

jcs.optimize_coding = optimize;

//设置质量

jpeg_set_quality(&jcs, quality, true);

// 开始压缩

jpeg_start_compress(&jcs, TRUE);

JSAMPROW row_pointer[1];

int row_stride;

row_stride = jcs.image_width * nComponent;

while (jcs.next_scanline < jcs.image_height) {

//得到一行的首地址

row_pointer[0] = &data[jcs.next_scanline * row_stride];

jpeg_write_scanlines(&jcs, row_pointer, 1);

}

// 压缩结束

jpeg_finish_compress(&jcs);

// 销毁回收内存

jpeg_destroy_compress(&jcs);

// 关闭文件

fclose(f);

return 1;

}

extern "C" jint Java_com_xf_imageselector_utils_ImageUtil_compressBitmap

(JNIEnv *env,

jobject thiz, jobject bitmap, jint quality, jstring fileNameStr) {

//解析RGB

//1.1获取bitmap信息,w、h,format Android的Native要有了解

AndroidBitmapInfo info;

// java你调用完方法,往往返回的是对象,而c是参数

AndroidBitmap_getInfo(env, bitmap, &info);

// 从地址获取值

int bitmap_height = info.height;

int bitmap_width = info.width;

int bitmap_format = info.format;

if (bitmap_format != ANDROID_BITMAP_FORMAT_RGBA_8888) {

//argb

return -1;

}

LOGI("bitmap_height = %d,bitmap_width = %d,", bitmap_height, bitmap_width);

//1.2 把bitmap解析到数组中,数组保存的是rgb->YCbCr

//1.2.1 锁定画布

BYTE *pixel_color;

AndroidBitmap_lockPixels(env, bitmap, (void **) &pixel_color);

// 1.2.2解析数据,定义一些变量

BYTE *data;

BYTE r, g, b;

//申请一块内存=宽*高*3

data = (BYTE *) malloc(bitmap_width * bitmap_height * 3);

// 数组指针指向的是数组首地址,因为这块内存需要释放,所以先保存一下

BYTE *tempData;

tempData = data;

//一个一个像素保存到data

int i = 0;

int j = 0;

int color;

for (int i = 0; i < bitmap_height; ++i) {

for (int j = 0; j < bitmap_width; ++j) {

//获取二维数组的每一个像素信息的首地址

color = *((int *) pixel_color);

// 取出RGB

r = ((color & 0x00FF0000) >> 16);

g = ((color & 0x0000FF00) >> 8);

b = (color & 0x000000FF);

//保存到data中

*data = b;

*(data + 1) = g;

*(data + 2) = r;

data = data + 3;

// 一个像素点包括argb四个值,每+4下就是取下一个像素点

pixel_color += 4;

}

}

//1.2.3解锁画布

AndroidBitmap_unlockPixels(env, bitmap);

// 1.2.4 还差一个参数,jstring-》char*

char *file_name = (char *) env->GetStringUTFChars(fileNameStr, NULL);

LOGI("file_name = %s", file_name);

// 2、调用第三方提供好的方法,赋值

int result = generateJPEG(tempData, bitmap_width, bitmap_height, quality, file_name, true);

// 3、回收内存

free(tempData);

env->ReleaseStringUTFChars(fileNameStr, file_name);

// 释放bitmap,调用bitmap的Recycler

//3.2获取对象的class

jclass obj_clazz = env->GetObjectClass(bitmap);

// 3.3 通过class获取方法的id

jmethodID method_id = env->GetMethodID(obj_clazz, "recycle", "()V");

//3.4调用方法释放bitmap

env->CallVoidMethod(bitmap, method_id);

LOGI("result = %d", result);

// 4、返回结果

if (result == 0) {

return -1;

}

return 1;

}

注意:头文件不需做任何改动,直接引入就好

四、测试,生成的so在build的cmake文件夹下可以找到

源图片1.13M压缩完只有300k左右,我的压缩比是95,图片也没有失真

我的项目源码我会放在资源中,名字turbolibjpeg

我尝试用过 libturbojpeg.so,并引入了turbojpeg.h,但还是找不到jpeg的方法,所以之能引入libjpeg.so

本文地址:https://blog.csdn.net/wanxiaofan/article/details/107961108

android使用的图片压缩格式,Android 之使用libjpeg压缩图片相关推荐

  1. android根据拍摄url获取格式,Android如何通过URI获取文件路径示例代码

    前言 最近在工作的过程中,遇到不同 Android 版本下 URI 采用不同方式来获取文件路径的问题. 因为需求的原因,要求拍照上传或者从相册中选择图片上传,而且图片是需要经过压缩的,大小不能超过2M ...

  2. Android开发文件上传格式,(android开发)使用okhttp上传文件

    开发android手机客户端,常常会需要上传文件到服务器,比如:你手机里的照片. 使用okhttp会是一个很好的选择.它使用很简单,而且运行效率也很高. 首先,在 app/build.gradle 的 ...

  3. Android中下载进度条格式,Android开发如何实现文件下载进度条

    释放双眼,带上耳机,听听看~! 今天和小编狗在这里学习下载进度的实现吧,这段代码是网上找的,自己做了些小改,通过模拟器测试.文件下载进度条控制(就是为了高清壁纸加个进度条),自己研究了好久,但是进度条 ...

  4. 如何压缩图片jpg格式?一分钟学会jpg图片压缩

    现在技术越来越发达,jpg图片质量也越来越高,质量越高占用的内存越多,储存起来非常的不方便.很多小伙伴就会用jpg图片压缩器去缩小图片kb,这里推荐一种可以无损压缩jpg图片的方法,一起来看看jpg压 ...

  5. android获得手机的时间格式,Android获取手机通讯录并按照时间电话类型分类处理...

    本文用到的RecyclerView标题悬浮,参考连接 先看看图片详情: device-2017-01-08-113015.png device-2017-01-08-113047.png 获取通讯录之 ...

  6. android 将文字转换为拼音格式,android中将汉字转为拼音

    汉字转拼音,汉字转拼音首字母~ 下面的方法是在做项目的时候,从网上查了好久才得到的~虽然不是自己写的,但是也改的差不多了~放在这里供大家参考哈 http://download.csdn.net/det ...

  7. 【Android 安装包优化】7z 文件压缩格式 ( 7z 格式简介 | 7z 命令使用说明 )

    文章目录 一.7z 文件压缩格式简介 二.7z 命令使用说明 1.压缩命令 2.解压命令 三.7z 命令示例 1.配置 7z 命令环境变量 2.压缩 3.解压缩 四.参考资料 一.7z 文件压缩格式简 ...

  8. Unity中图片压缩格式

    图片格式 1.不同格式的本质区别在于压缩算法不一样,导致图片加载到内存中占用的内存空间大小不一样. 2.常用图片格式有Png,Jpg,Tga,Psd等.平时主要用Png,Jpg. 3.Jpg是有损压缩 ...

  9. android 车载app怎么开发,Android开发智能车载App(1)---android控件及属性介绍

    1.展示文本控件 TextView 属性名称 描述 android:text 设置显示文本. android:textSize 设置文字大小,推荐度量单位"sp",如"1 ...

最新文章

  1. Django的下载与基本命令
  2. linux路由命令大全,常用Linux路由命令
  3. OpenCASCADE:使用DRAW绘图
  4. VTK:PolyData之ReverseSense
  5. C语言矩阵N*N旋转的算法(附完整源码)
  6. Tomcat配置和Web应用程序开发
  7. javafor循环打印图案_C程序使用循环打印盒子图案
  8. Tensorflow2.0数据和部署(四)——Tensorflow高级模型部署
  9. java day53【 Mybatis框架概述 、 Mybatis 框架快速入门、自定义 Mybatis 框架 】
  10. 推荐两个非常不错的公众号
  11. CUDA memory
  12. win10怎样获得计算机管理员权限,详解Win10获取管理员权限的具体方法
  13. 了不起的 Java VM-Java 虚拟机初探
  14. cd linux自带系统安装,大神示范win7系统将CDLinux装入硬盘的法子
  15. jupyter notebook 更改工作环境和浏览器
  16. android logo颜色渐变,华为悄然更新品牌Logo:无渐变色,更加扁平化
  17. vmware各个版本 安装 mac osx 10.11终级权威教程,踩了所有坑
  18. 油猴安装、编写及添加脚本 笔记
  19. 分享150个PHP源码,总有一款适合您
  20. java gzip 压缩解压工具类

热门文章

  1. 将窗体显示在 PageControl 上。
  2. tcp连接的三次握手
  3. 清除webbrowser cookie/session的6种方法
  4. Quartz.NET
  5. intellij idea 部署项目的时候 图中application context 写不写有什么关系?有什么作用?...
  6. Druid 配置_配置WebStatFilter
  7. 重构学习1-重命名方法、类、参数等
  8. 如何计算两个日期之间相差的天数?
  9. Postman Could not get any response
  10. postman模拟post请求的四种请求体