Android LibJpeg图片压缩

本文介绍了Android中图片压缩的多种方法,包括质量压缩、尺寸压缩、采样率压缩及使用libjpeg库进行压缩的技术细节。通过对不同压缩方法的对比,帮助开发者选择最适合应用场景的压缩方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Android的图片压缩

Android的图片压缩的几种方式:质量压缩,尺寸压缩,采样率压缩,通过NDK调用libjpeg库进行压缩!

质量压缩

通过设置bitmap options属性,降低图片的质量,但是像素不会减少

    public static void compressImageToFile(Bitmap bmp,File file) {
            // 0-100 100为不压缩
            int options = 20;
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            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 static void compressBitmapToFile(Bitmap bmp, File file){
            // 尺寸压缩倍数,值越大,图片尺寸越小
            int ratio = 8;
            // 压缩Bitmap到对应尺寸
            Bitmap result = Bitmap.createBitmap(bmp.getWidth() / ratio, bmp.getHeight() / ratio, 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();
            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();
            }
        }

采样率压缩

通过关键字inJustDecodeBounds 加载bmp,设置bmp的inSampleSize 参数,控制图片采样率进行压缩,这里的decodeFile是使用Android自己的native压缩方法!

 public static void compressBitmap(String filePath, File file){
            // 数值越高,表示图片像素越低
            int inSampleSize = 10;
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = false;
//          options.inJustDecodeBounds = true;//注意,如果为true的时候不会真正加载bmp,只能得到图片的宽高信息。
            //采样率
            options.inSampleSize = inSampleSize;
            Bitmap bitmap = BitmapFactory.decodeFile(filePath, options);

            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100 ,baos);
            try {
                if(file.exists())
                {
                    file.delete();
                }
                else {
                    file.createNewFile();
                }
                FileOutputStream fos = new FileOutputStream(file);
                fos.write(baos.toByteArray());
                fos.flush();
                fos.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

LIBJPEG进行压缩

Libjpeg是95年开源的一个图片处理库,基于C语言的!
我们通常会有一个一个疑问:为什么同样大小的照片,IPHONE拍出来的照片会比Android的要清晰,以前一直搞不明白,通过网上查阅资料终于明白其历史来源!原因是:google犯的一个”错误”!

其实IPHONE与Android的图片压缩都是使用图片压缩都是基于LibJPE库,只是google思前想后最终将libjpeg库的一个参数arith_code(是否使用哈夫曼编码)设置为false,采用了定长编码压缩,这样就导致图片会比IOS端大一些!google这样做是基于哈夫曼编码相对会耗性能,以前我们的手机设备cpu内存比较吃紧,所以遗弃了哈夫曼编码算法!但是现在对于我们的手机设备来说,cpu已经大大的解放,在损耗一丢丢的性能而去追求良好体验的代价是不大的!
所以说,任何事情存在都是有其历史原因的,存在即合理~!
使用Libjpeg

Libjpeg是C语言写的,需要交叉编译so或者.a到Android平台使用.下面是使用步骤!

1.下载源码

    https://ijg.org

2.编译链接库

将下载好了源代码传到linux,进行编译!步骤:
    修改文件可执行权限
    ./configure 检查环境
    编写脚本:
        1 #!/bin/bash
        2 export NDK=/usr/temptest/ndk/android-ndk-r10e
        3 export CPU=arm
        4 export PREFIX=$(pwd)/android2/$CPU
        7 ./configure --prefix=$PREFIX
        8 --enable-static \
        9 --disable-shared                                                                                                                                                                           
        10 make clean
        11 make
        12 make install
    执行脚本,半分钟就可以完成,可以看到so .a文件!

3.使用Libjpeg库
NDK环境相关的这里就不讲了,大家可以看我的其他博客有写!下面写NDK调用:

1.将android的bitmap解码,并转换成RGB数据,去除alpha
2.JPEG对象分配空间以及初始化
3.指定压缩数据源
4.获取文件信息
5.为压缩文件设置参数,比如图像大小、类型、颜色空间
6.开始压缩
jpeg_start_compress()
7.压缩结束
jpeg_finish_compress()
8.释放资源
void Java_test_jpeg_JPEGUtil_compress(JNIEnv* env,jclass thiz, jobject bitmapcolor, int w, int h, int quality,jstring fileNameStr) {
    BYTE *pixelscolor;
    //1.锁定画布,将bitmap里面的所有像素信息读取出来,并转换成RGB数据,保存到二维byte数组(pixelscolor)里面
    AndroidBitmap_lockPixels(env,bitmapcolor,(void**)&pixelscolor);

    //2.解析每一个像素点里面的rgb值(去掉alpha值),保存到一维数组data里面
    BYTE *data;
    BYTE r,g,b;
    data = (BYTE*)malloc(w*h*3);//每一个像素都有三个信息RGB
    BYTE *tmpdata;
    //临时保存data的首地址
    tmpdata = data;
    int i=0,j=0;
    int color;
    for (i = 0; i < h; ++i) {
        for (j = 0; j < w; ++j) {
            //解决掉alpha
            //获取二维数组的每一个像素信息首地址
            color = *((int *)pixelscolor);//通过地址取值
            //0~255:
//          a = ((color & 0xFF000000) >> 24);
            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就是取下一个像素点
            pixelscolor += 4;
        }
    }
    //处理bitmap图形信息方法2 解锁
    AndroidBitmap_unlockPixels(env,bitmapcolor);
    generateJPEG(tmpdata,w,h,quality,fileName,optimize);
}

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

    //jpeg的结构体,保存的比如宽、高、位深、图片格式等信息
    struct jpeg_compress_struct jcs;

    //当读完整个文件的时候就会回调my_error_exit这个退出方法。setjmp是一个系统级函数,是一个回调。
    struct my_error_mgr jem;
    jcs.err = jpeg_std_error(&jem.pub);
    jem.pub.error_exit = my_error_exit;
    if (setjmp(jem.setjmp_buffer)) {
        return ;
    }

    //初始化jsc结构体
    jpeg_create_compress(&jcs);
    //打开输出文件 wb:可写byte
    FILE* f = fopen(outfilename, "wb");
    if (f == NULL) {
        return ;
    }
    //设置结构体的文件路径
    jpeg_stdio_dest(&jcs, f);
    jcs.image_width = w;//设置宽高
    jcs.image_height = h;

    //看源码注释,设置哈夫曼编码:/* TRUE=arithmetic coding, FALSE=Huffman */
    jcs.arith_code = false;
    /* 颜色的组成 rgb
    jcs.input_components = 3;
    //设置结构体的颜色空间为rgb
    jcs.in_color_space = JCS_RGB;
    //设置默认参数
    jpeg_set_defaults(&jcs);
    //是否采用哈弗曼表数据计算 品质相差5-10倍
    jcs.optimize_coding = optimize;
    //设置质量
    jpeg_set_quality(&jcs, quality, true);
    //开始压缩,第二个参数表示是否写入全部像素
    jpeg_start_compress(&jcs, TRUE);

    JSAMPROW row_pointer[1];
    int row_stride;
    //一行的rgb数量
    row_stride = jcs.image_width * 3;
    while (jcs.next_scanline < jcs.image_height) {
        //得到一行的首地址
        row_pointer[0] = &data[jcs.next_scanline * row_stride];

        //此方法会将jcs.next_scanline加1
        //row_pointer就是一行的首地址
        //1表示写入的行数
        jpeg_write_scanlines(&jcs, row_pointer, 1);
    }
    //结束
    jpeg_finish_compress(&jcs);
    jpeg_destroy_compress(&jcs);//销毁回收内存
    fclose(f);
}

几种压缩方法对比

对比几种压缩算法,通过比较,在图片大小以及图片清晰度进行对比,Libjpeg效果更佳!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值