您好,欢迎来到源码搜藏网!分享精神,快乐你我!
[加入VIP] 设为首页 | 收藏本站 | 网站地图 | Sitemap | TAG标签
  • 首 页
  • 在线工具
  • jquery手册
  • 当前位置:首页 > 安卓源码 > 技术博客 >

    Android开发中对图片优化之质量压缩,尺寸压缩,采样率压缩,Lib

    时间:2018-02-01 17:45 来源:互联网 作者:源码搜藏 浏览:收藏 挑错 推荐 打印

    效果演示 质量压缩 质量压缩:根据传递进去的质量大小,采用系统自带的压缩算法,将图片压缩成JPEG格式 /** * 质量压缩 * * @param bitmap * @param quality * @param file */ public static void compressQuality (Bitmap bitmap, int quality, File file)

    效果演示

    Android开发中对图片优化之质量压缩,尺寸压缩,采样率压缩,Lib

    质量压缩

    质量压缩:根据传递进去的质量大小,采用系统自带的压缩算法,将图片压缩成JPEG格式

    /**
     * 质量压缩
     *
     * @param bitmap
     * @param quality
     * @param file
     */
    public static void compressQuality(Bitmap bitmap, int quality, File file) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.JPEG, quality, baos);
        try {
            FileOutputStream fos = new FileOutputStream(file);
            fos.write(baos.toByteArray());
            fos.flush();
            fos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    尺寸压缩

    尺寸压缩:根据图片的缩放比例进行等比大小的缩小尺寸,从而达到压缩的效果

    /**
     * 尺寸压缩
     *
     * @param bitmap
     * @param file
     */
    public static void compressSize(Bitmap bitmap, File file) {
        int ratio = 8;//尺寸压缩比例
        Bitmap result = Bitmap.createBitmap(bitmap.getWidth() / ratio, bitmap.getHeight() / ratio, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(result);
        Rect rect = new Rect(0, 0, bitmap.getWidth() / ratio, bitmap.getHeight() / ratio);
        canvas.drawBitmap(bitmap, null, rect, null);
    
        compressQuality(result, 100, file);
    }

    采样率压缩

    采样率压缩:根据图片的采样率大小进行压缩

    /**
     * 采样率压缩
     *
     * @param filePath
     * @param file
     */
    public static void compressSample(String filePath, File file) {
        int inSampleSize = 8;//采样率设置
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = false;
        options.inSampleSize = inSampleSize;
        Bitmap bitmap = BitmapFactory.decodeFile(filePath, options);
    
        compressQuality(bitmap, 100, file);
    }

    libjpeg的压缩

    libjpeg的压缩:通过NDK调用的libjpeg库进行压缩,保留原有的像素,清晰度高

    一,编译的libjpeg

    1,从Github上可以下载已经写好编译脚本的项目:https : //github.com/Zelex/libjpeg-turbo-android,并将其上传到Linux服务器的某个目录

    Android开发中对图片优化之质量压缩,尺寸压缩,采样率压缩,Lib

    2,授予整个目录权限

    chmod 777 -R libjpeg-turbo-android-master

    3,进入的libjpeg目录,使用下面指令进行编译,前提是你的服务器已经搭建了NDK-构建和配置了环境变量

    ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=./Android.mk APP_ABI=armeabi-v7a obj/local/armeabi-v7a/libjpeg.a LOCAL_ARM_MODE=arm LOCAL_ARM_NEON=true ARCH_ARM_HAVE_NEON=true

    4,接着编译成功后,会在obj / local目录下生成我们需要的libjpeg.a

    Android开发中对图片优化之质量压缩,尺寸压缩,采样率压缩,Lib

    二,创建工程

    1,创建一个新的项目,勾选包含C ++,勾选C ++ 11和C ++的依赖库

    Android开发中对图片优化之质量压缩,尺寸压缩,采样率压缩,Lib

    2,将生成的libjpeg.a和头文件导入到我们的项目中

    Android开发中对图片优化之质量压缩,尺寸压缩,采样率压缩,Lib

    3,配置gradle这个

    android {
        compileSdkVersion 25
        buildToolsVersion "25.0.3"
        defaultConfig {
            applicationId "com.handsome.bitmapcompress"
            minSdkVersion 16
            targetSdkVersion 25
            versionCode 1
            versionName "1.0"
            testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
            externalNativeBuild {
                cmake {
                    cppFlags "-std=c++11 -frtti -fexceptions"
                    //支持的CPU类型
                    abiFilters "armeabi", "armeabi-v7a"
                }
            }
        }
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            }
        }
        //修改Libs库的路径
        sourceSets.main {
            jniLibs.srcDirs = ['libs']
            jni.srcDirs = []
        }
        externalNativeBuild {
            cmake {
                path "CMakeLists.txt"
            }
        }
    }

    4,配置的CMake

    cmake_minimum_required(VERSION 3.4.1)
    
    include_directories(./libs/jpeg)
    link_directories(./libs/${ANDROID_ABI})
    
    find_library(log-lib
                 log)
    find_library(android-lib
                 android)
    find_library(bitmap-lib
                 jnigraphics)
    
    
    add_library( # Sets the name of the library.
                 native-lib
    
                 # Sets the library as a shared library.
                 SHARED
    
                 # Provides a relative path to your source file(s).
                 src/main/cpp/native-lib.cpp )
    
    target_link_libraries( native-lib
                           ${log-lib}
                           ${android-lib}
                           ${bitmap-lib}
                           jpeg )

    5,声明权限

    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

    三,使用的libjpeg

    1,启动选择文件的意图

    /**
     * 选择文件
     */
    public void selectFile() {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
            startActivityForResult(new Intent(Intent.ACTION_GET_CONTENT).setType("image/*"), REQUEST_PICK_IMAGE);
        } else {
            Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
            intent.addCategory(Intent.CATEGORY_OPENABLE);
            intent.setType("image/*");
            startActivityForResult(intent, REQUEST_KITKAT_PICK_IMAGE);
        }
    }

    2,对返回的结果进行压缩

    /**
     * 返回结果
     *
     * @param requestCode
     * @param resultCode
     * @param data
     */
    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == RESULT_OK) {
            switch (requestCode) {
                case REQUEST_PICK_IMAGE:
                    if (data != null) {
                        Uri uri = data.getData();
                        compressImage(uri);
                    }
                    break;
                case REQUEST_KITKAT_PICK_IMAGE:
                    if (data != null) {
                        Uri uri = ensureUriPermission(this, data);
                        compressImage(uri);
                    }
                    break;
            }
        }
    }
    
    /**
     * 压缩图片
     * 注意:记得手动开启权限
     *
     * @param uri
     */
    public void compressImage(Uri uri) {
        try {
            File saveFile = new File(getExternalCacheDir(), "NDK压缩.jpg");
            Bitmap bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), uri);
            int code = CompressUtils.compressBitmap(bitmap, 20, saveFile.getAbsolutePath().getBytes(), true);
    
            File saveFile1 = new File(getExternalCacheDir(), "质量压缩.jpg");
            CompressUtils.compressQuality(bitmap, 20, saveFile1);
    
            File saveFile2 = new File(getExternalCacheDir(), "尺寸压缩.jpg");
            CompressUtils.compressSize(bitmap, saveFile2);
    
            //采样率比较特殊,需要传递文件的目录,这里采用直接指定目录的文件
            File saveFile3 = new File(getExternalCacheDir(), "采样率压缩.jpg");
            File LocalFile = new File("/storage/emulated/0/DCIM/Camera/IMG_20171216_171956.jpg");
            if (LocalFile.exists()) {
                CompressUtils.compressSample(LocalFile.getAbsolutePath(), saveFile3);
            }
    
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    3,加载本地库和声明的libjpeg压缩方法

    public class CompressUtils {
    
        static {
            System.loadLibrary("native-lib");
        }
    
        public static native int compressBitmap(Bitmap bitmap, int quality, byte[] fileNameBytes,
                                                    boolean optimize);
    }

    4,编写的libjpeg的本地文件

    • 提取图片的ARGB通量的RGB通量
    • 采用的libjpeg的API进行压缩
    • 将数据写入到文件中
    #include <jni.h>
    #include <string>
    #include <android/bitmap.h>
    #include <android/log.h>
    #include <setjmp.h>
    
    extern "C" {
    #include "jpeglib.h"
    #include "cdjpeg.h"
    }
    
    #define LOG_TAG "jni"
    #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
    
    typedef uint8_t BYTE;
    
    typedef struct my_error_mgr *my_error_ptr;
    struct my_error_mgr {
        struct jpeg_error_mgr pub;
        jmp_buf setjmp_buffer;
    };
    
    METHODDEF(void)
    my_error_exit(j_common_ptr cinfo) {
        my_error_ptr myerr = (my_error_ptr) cinfo->err;
        (*cinfo->err->output_message)(cinfo);
        LOGE("jpeg_message_table[%d]:%s", myerr->pub.msg_code,
             myerr->pub.jpeg_message_table[myerr->pub.msg_code]);
        longjmp(myerr->setjmp_buffer, 1);
    }
    
    /**
     * 采用Libjpeg压缩
     * @param data
     * @param w
     * @param h
     * @param quality
     * @param outfilename
     * @param optimize
     * @return
     */
    int generateJPEG(BYTE *data, int w, int h, int quality,
                     const char *outfilename, jboolean optimize) {
    
        //jpeg的结构体,保存的比如宽、高、位深、图片格式等信息
        struct jpeg_compress_struct jcs;
        //当读完整个文件的时候就会回调my_error_exit
        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 0;
        }
        //初始化jsc结构体
        jpeg_create_compress(&jcs);
        //打开输出文件
        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
        if (optimize) {
            jcs.arith_code = false;
        } else {
            jcs.arith_code = true;
        }
        //颜色通道数量
        int nComponent = 3;
        jcs.input_components = nComponent;
        //设置结构体的颜色空间为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 * nComponent;
        //一行一行遍历
        while (jcs.next_scanline < jcs.image_height) {
            //得到一行的首地址
            row_pointer[0] = &data[jcs.next_scanline * row_stride];
            //此方法会将jcs.next_scanline加1
            jpeg_write_scanlines(&jcs, row_pointer, 1);//row_pointer就是一行的首地址,1:写入的行数
        }
        jpeg_finish_compress(&jcs);
        jpeg_destroy_compress(&jcs);
        fclose(f);
        return 1;
    }
    
    /**
     * byte数组转C的字符串
     */
    char *jstrinTostring(JNIEnv *env, jbyteArray barr) {
        char *rtn = NULL;
        jsize alen = env->GetArrayLength(barr);
        jbyte *ba = env->GetByteArrayElements(barr, 0);
        if (alen > 0) {
            rtn = (char *) malloc(alen + 1);
            memcpy(rtn, ba, alen);
            rtn[alen] = 0;
        }
        env->ReleaseByteArrayElements(barr, ba, 0);
        return rtn;
    }
    
    extern "C"
    JNIEXPORT jint JNICALL
    Java_com_handsome_bitmapcompress_CompressUtils_compressBitmap(JNIEnv *env, jclass type,
                                                                  jobject bitmap,
                                                                  jint quality,
                                                                  jbyteArray fileNameBytes_,
                                                                  jboolean optimize) {
        //获取Bitmap信息
        AndroidBitmapInfo android_bitmap_info;
        AndroidBitmap_getInfo(env, bitmap, &android_bitmap_info);
        //获取bitmap的 宽,高,format
        int w = android_bitmap_info.width;
        int h = android_bitmap_info.height;
        int format = android_bitmap_info.format;
    
        if (format != ANDROID_BITMAP_FORMAT_RGBA_8888) {
            return -1;
        }
    
        //存储ARGB所有像素点
        BYTE *pixelsColor;
        //1、读取Bitmap所有像素信息
        AndroidBitmap_lockPixels(env, bitmap, (void **) &pixelsColor);
        //2、解析每个像素,去除A通量,取出RGB通量
        int i = 0, j = 0;
        BYTE a, r, g, b;
        //存储RGB所有像素点
        BYTE *data;
        data = (BYTE *) malloc(w * h * 3);
        //存储RGB首地址
        BYTE *tempData = data;
    
        int color;
        for (i = 0; i < h; ++i) {
            for (j = 0; j < w; ++j) {
                //将8位通道转成32位通道
                color = *((int *) pixelsColor);
                //取值
                a = ((color & 0xFF000000) >> 24);
                r = ((color & 0x00FF0000) >> 16);
                g = ((color & 0x0000FF00) >> 8);
                b = ((color & 0x000000FF));
                //赋值
                *data = b;
                *(data + 1) = g;
                *(data + 2) = r;
                //指针往后移
                data += 3;
                pixelsColor += 4;
            }
        }
    
        //3、读取像素点完毕
        AndroidBitmap_unlockPixels(env, bitmap);
        char *fileName = jstrinTostring(env, fileNameBytes_);
        //4、采用Libjpeg进行压缩
        int resultCode = generateJPEG(tempData, w, h, quality, fileName, optimize);
        if (resultCode == 0) {
            return 0;
        }
        return 1;
    }
    Android开发中对图片优化之质量压缩,尺寸压缩,采样率压缩,Lib转载http://www.codesocang.com/appboke/38422.html
    标签:网站源码