{"id":19462977,"url":"https://github.com/yangkun19921001/libjpeg_sample","last_synced_at":"2026-03-27T02:42:23.127Z","repository":{"id":107684400,"uuid":"187463847","full_name":"yangkun19921001/LIBJPEG_SAMPLE","owner":"yangkun19921001","description":" Android libjpeg 图片压缩，哈夫曼算法图片压缩","archived":false,"fork":false,"pushed_at":"2019-05-21T02:47:30.000Z","size":550,"stargazers_count":36,"open_issues_count":2,"forks_count":14,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-25T08:43:12.735Z","etag":null,"topics":["android"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yangkun19921001.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2019-05-19T10:41:59.000Z","updated_at":"2023-10-10T06:07:32.000Z","dependencies_parsed_at":"2023-06-08T18:45:28.041Z","dependency_job_id":null,"html_url":"https://github.com/yangkun19921001/LIBJPEG_SAMPLE","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/yangkun19921001/LIBJPEG_SAMPLE","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yangkun19921001%2FLIBJPEG_SAMPLE","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yangkun19921001%2FLIBJPEG_SAMPLE/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yangkun19921001%2FLIBJPEG_SAMPLE/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yangkun19921001%2FLIBJPEG_SAMPLE/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yangkun19921001","download_url":"https://codeload.github.com/yangkun19921001/LIBJPEG_SAMPLE/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yangkun19921001%2FLIBJPEG_SAMPLE/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31011523,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-27T02:33:22.146Z","status":"ssl_error","status_checked_at":"2026-03-27T02:33:21.763Z","response_time":164,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android"],"created_at":"2024-11-10T18:07:26.146Z","updated_at":"2026-03-27T02:42:23.117Z","avatar_url":"https://github.com/yangkun19921001.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"## [或者更多信息请移步我的博客](https://juejin.im/post/5ce15d0ce51d45106e5e6dac)\n## 使用方式\n\n1. 在 project/build.gradle 上添加以下代码\n\n   ```java\n   allprojects {\n   \t\trepositories {\n   \t\t\t...\n   \t\t\tmaven { url 'https://jitpack.io' }\n   \t\t}\n   \t}\n   ```\n\n   \n\n2. 在 app/build.gradle 添加依赖\n\n   ```java\n   dependencies {\n           implementation 'com.github.yangkun19921001:LIBJPEG_SAMPLE:v1.0.1'\n   }\n   ```\n\n   \n\n3. 压缩使用\n\n   ```java\n   //bitmap        : 需要压缩的 bitmap\n   //q             : 压缩质量 建议 30 - 50\n   //outputFilePath: 压缩之后存储的图片地址\n   JpegUtils.native_Compress(Bitmap bitmap,int q,String outputFilePath);\n   ```\n\n   \n\n## JEPG 是什么?\n\n相信有一部分使用 iPhone 手机用微信发送图片的时候，明明图片大小只有 1M ，但清晰度比 Android 手机 5 M 图片大小的还要清晰，那么这是为什么呢 ？。\n\n当时谷歌开发 Android 的时候，考虑了大部分手机的配置并没有那么高，所以对图片处理使用的是 Skia。当然这个库的底层还是用的 jpeg 图片压缩处理。但是为了能够适配低端的手机（这里的低端是指以前的硬件配置不高的手机，CPU 和内存在手机上都非常吃紧，性能差），由于哈夫曼算法比较吃 CPU 并且编解码慢，被迫用了其他的算法。所以 Skia 在进行图片处理在低版本中并没有开启哈弗曼算法。\n\n那么，JEPG 到底是什么？JEPG (全称是 Joint Photographic Experts Group) 是一种常见的一种图像格式，为什么我在这里会提到 JEPG 呢？是因为开源了一个 C/C++ 库底层是基于哈夫曼算法对图片的压缩 (libjpeg)，下面我们就来着重了解下 libjpeg 这个库\n\n### libjpeg 简介\n\nlibjpeg-turbo 是一个 JPEG 图像编解码器，它使用 SIMD 指令（MMX，SSE2，AVX2，NEON，AltiVec）来加速 x86，x86-64，ARM 和 PowerPC 系统上的基线 JPEG 压缩和解压缩，以及渐进式JPEG 压缩 x86 和 x86-64 系统。在这样的系统上，libjpeg-turbo 的速度通常是 libjpeg 的 2 - 6 倍，其他条件相同。在其他类型的系统上，凭借其高度优化的霍夫曼编码例程，libjpeg-turbo 仍然可以大大超过 libjpeg。在许多情况下，libjpeg-turbo 的性能可与专有的高速 JPEG 编解码器相媲美。 libjpeg-turbo 实现了传统的 libjpeg API 以及功能较弱但更直接的 TurboJPEG API 。 libjpeg-turbo 还具有色彩空间扩展，允许它从/解压缩到32位和大端像素缓冲区（RGBX，XBGR等），以及功能齐全的 Java 接口。 libjpeg-turbo 最初基于 libjpeg / SIMD，这是由 Miyasaka Masaru 开发的 libjpeg v6b 的 MMX 加速衍生物。 TigerVNC 和 VirtualGL 项目在 2009 年对编解码器进行了大量增强，并且在2010年初，libjpeg-turbo 分拆成一个独立项目，目标是为更广泛的用户提供高速 JPEG压缩/解压缩技术。开发人员。\n\n现在我们大概了解到了 libjpeg 是一个对图像编解码库，现在我们需要准备环境去编译 libjpeg。\n\n## 编译准备工作\n\n**系统:**      [Ubuntu 18.04](\u003chttp://www.ubuntu.org.cn/download\u003e)  [也可以使用我下载好的 提取码：biyt](https://pan.baidu.com/s/1PkcNn2Oh_fp698zdCuuyow)\n\n**libjpeg:**  [libjepg 2.0.2](https://github.com/libjpeg-turbo/libjpeg-turbo/archive/2.0.2.tar.gz)\n\n**cmake**: [cmake-3.14.4-Linux-x86_64.tar.gz](https://github.com/Kitware/CMake/releases/download/v3.14.4/cmake-3.14.4.tar.gz)\n\n**ndk:**      [android-ndk-r17c](https://dl.google.com/android/repository/android-ndk-r17c-linux-x86_64.zip)\n\n**开始发车准备编译**\n\n1. ubuntu 中下载 [libjpeg](\u003chttps://github.com/libjpeg-turbo/libjpeg-turbo\u003e)\n\n   1. wget https://github.com/libjpeg-turbo/libjpeg-turbo/archive/2.0.2.tar.gz\n\n   2. 解压  tar xvf 2.0.2.tar.gz\n\n   3. [编译参考])(\u003chttps://github.com/libjpeg-turbo/libjpeg-turbo/blob/master/BUILDING.md\u003e)\n\n      \n\n2. ubuntu 中安装 cmake\n\n   1. 删除原来的 apt-get autoremove cmake\n\n   2. wget https://github.com/Kitware/CMake/releases/download/v3.14.4/cmake-3.14.4.tar.gz\n\n   3. 解压 tar zxvf cmake-3.14.3.tar.gz\n\n   4. 创建软连接\n\n      1. mv cmake-3.14.3-Linux-x86_64 /opt/cmake-3.14.3\n      2. ln -sf /opt/cmake-3.14.3/bin/*  /usr/bin/\n\n      输入 cmake -- version 如果有这样的显示代表安装成功\n\n      ![](https://user-gold-cdn.xitu.io/2019/5/19/16ad056da20c96b0?w=732\u0026h=160\u0026f=jpeg\u0026s=39209)\n\n      \n\n3. 进入到 libjpeg 目录，生成 shell 脚本\n\n   1. vim build.sh 新建一个文件\n\n      ```java\n      # lib-name\n      MY_LIBS_NAME=libjpeg-turbo_2.0.2\n      # 源码目录\n      MY_SOURCE_DIR=/home/yangkun/libjpeg-turbo-2.0.2\n      MY_BUILD_DIR=yangkun\n      \n      # android-cmake\n      CMAKE_PATH=/opt/cmake-3.14.4/bin\n      \n      export PATH=${CMAKE_PATH}/bin:$PATH\n      \n      NDK_PATH=/home/yangkun//android-ndk-r17c\n      BUILD_PLATFORM=linux-x86_64\n      TOOLCHAIN_VERSION=4.9\n      ANDROID_VERSION=24\n      \n      ANDROID_ARMV5_CFLAGS=\"-march=armv5te\"\n      ANDROID_ARMV7_CFLAGS=\"-march=armv7-a -mfloat-abi=softfp -mfpu=neon\"  # -mfpu=vfpv3-d16  -fexceptions -frtti\n      ANDROID_ARMV8_CFLAGS=\"-march=armv8-a\"  \t# -mfloat-abi=softfp -mfpu=neon -fexceptions -frtti\n      ANDROID_X86_CFLAGS=\"-march=i386 -mtune=intel -mssse3 -mfpmath=sse -m32\"\n      ANDROID_X86_64_CFLAGS=\"-march=x86-64 -msse4.2 -mpopcnt -m64 -mtune=intel\"\n      \n      # params($1:arch,$2:arch_abi,$3:host,$4:compiler,$5:cflags,$6:processor)\n      build_bin() {\n      \n          echo \"-------------------star build $2-------------------------\"\n      \n          ARCH=$1                # arm arm64 x86 x86_64\n          ANDROID_ARCH_ABI=$2    # armeabi armeabi-v7a x86 mips\n          # 最终编译的安装目录\n          PREFIX=$(pwd)/dist/${MY_LIBS_NAME}/${ANDROID_ARCH_ABI}/\n          HOST=$3\n          COMPILER=$4\n          PROCESSOR=$6\n          SYSROOT=${NDK_PATH}/platforms/android-${ANDROID_VERSION}/arch-${ARCH}\n          CFALGS=\"$5\"\n          TOOLCHAIN=${NDK_PATH}/toolchains/${HOST}-${TOOLCHAIN_VERSION}/prebuilt/${BUILD_PLATFORM}\n          \n          # build 中间件\n          BUILD_DIR=./${MY_BUILD_DIR}/${ANDROID_ARCH_ABI}\n      \n          export CFLAGS=\"$5 -Os -D__ANDROID_API__=${ANDROID_VERSION} --sysroot=${SYSROOT} \\\n                         -isystem ${NDK_PATH}/sysroot/usr/include \\\n                         -isystem ${NDK_PATH}/sysroot/usr/include/${HOST} \"\n          export LDFLAGS=-pie\n      \n          echo \"path==\u003e$PATH\"\n          echo \"build_dir==\u003e$BUILD_DIR\"\n          echo \"ARCH==\u003e$ARCH\"\n          echo \"ANDROID_ARCH_ABI==\u003e$ANDROID_ARCH_ABI\"\n          echo \"HOST==\u003e$HOST\"\n          echo \"CFALGS==\u003e$CFALGS\"\n          echo \"COMPILER==\u003e$COMPILER-gcc\"\n          echo \"PROCESSOR==\u003e$PROCESSOR\"\n      \n          mkdir -p ${BUILD_DIR}   #创建当前arch_abi的编译目录,比如:binary/armeabi-v7a\n          cd ${BUILD_DIR}         #此处 进了当前arch_abi的2级编译目录\n      \n      #运行时创建临时编译链文件toolchain.cmake\n      cat \u003etoolchain.cmake \u003c\u003c EOF \n      set(CMAKE_SYSTEM_NAME Linux)\n      set(CMAKE_SYSTEM_PROCESSOR $6)\n      set(CMAKE_C_COMPILER ${TOOLCHAIN}/bin/${COMPILER}-gcc)\n      set(CMAKE_FIND_ROOT_PATH ${TOOLCHAIN}/${COMPILER})\n      EOF\n      \n          cmake -G\"Unix Makefiles\" \\\n                -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake \\\n                -DCMAKE_POSITION_INDEPENDENT_CODE=1 \\\n                -DCMAKE_INSTALL_PREFIX=${PREFIX} \\\n                -DWITH_JPEG8=1 \\\n                ${MY_SOURCE_DIR}\n      \n          make clean\n          make\n          make install\n      \n          #从当前arch_abi编译目录跳出，对应上面的cd ${BUILD_DIR},以便function多次执行\n          cd ../../\n      \n          echo \"-------------------$2 build end-------------------------\"\n      }\n      \n      # build armeabi\n      build_bin arm armeabi arm-linux-androideabi arm-linux-androideabi \"$ANDROID_ARMV5_CFLAGS\" arm\n      \n      #build armeabi-v7a\n      build_bin arm armeabi-v7a arm-linux-androideabi arm-linux-androideabi \"$ANDROID_ARMV7_CFLAGS\" arm\n      \n      #build arm64-v8a\n      build_bin arm64 arm64-v8a aarch64-linux-android aarch64-linux-android \"$ANDROID_ARMV8_CFLAGS\" aarch64\n      \n      #build x86\n      build_bin x86 x86 x86 i686-linux-android \"$ANDROID_X86_CFLAGS\" i386\n      \n      #build x86_64\n      build_bin x86_64 x86_64 x86_64 x86_64-linux-android \"$ANDROID_X86_64_CFLAGS\" x86_64\n      ```\n\n   2. 如果编译遇见 权限问题\n\n      ![](https://user-gold-cdn.xitu.io/2019/5/19/16ad0568e451867d?w=816\u0026h=673\u0026f=jpeg\u0026s=216141)\n\n      给它一个 可执行文件的权限 chmod +x build.sh\n\n   3. 继续执行\n\n      ![](https://user-gold-cdn.xitu.io/2019/5/19/16ad0565d2e01fea)\n\n   4. 编译完成\n\n      ![](https://user-gold-cdn.xitu.io/2019/5/19/16ad055fc25cbb9b?w=800\u0026h=600\u0026f=jpeg\u0026s=210778)\n\n      这里我们发现 已经有我们需要的 静态库 .a 和 动态库 .so\n\n   5. 在 AndroidStudio 中创建一个简单的项目 用于测试是否压缩成功\n\n      1. 结构目录\n\n      ![](https://user-gold-cdn.xitu.io/2019/5/19/16ad0578463b6131?w=829\u0026h=866\u0026f=jpeg\u0026s=83392)\n\n      标红的都是重要的文件，include 头文件和 libs/armeabi-v7a 是我们刚刚编译出来的文件\n\n      下面我们就来运行一下看看压缩效果\n\n      2. 压缩主要代码\n\n         **jni 代码**\n\n         ```c++\n         #include \u003cjni.h\u003e\n         #include \u003cstring\u003e\n         #include \"../include/jpeglib.h\"\n         #include \u003cmalloc.h\u003e\n         #include \u003candroid/bitmap.h\u003e\n         \n         \n         void write_JPEG_file(uint8_t *data, int w, int h, jint q, const char *path) {\n         //    3.1、创建jpeg压缩对象\n             jpeg_compress_struct jcs;\n             //错误回调\n             jpeg_error_mgr error;\n             jcs.err = jpeg_std_error(\u0026error);\n             //创建压缩对象\n             jpeg_create_compress(\u0026jcs);\n         //    3.2、指定存储文件  write binary\n             FILE *f = fopen(path, \"wb\");\n             jpeg_stdio_dest(\u0026jcs, f);\n         //    3.3、设置压缩参数\n             jcs.image_width = w;\n             jcs.image_height = h;\n             //bgr\n             jcs.input_components = 3;\n             jcs.in_color_space = JCS_RGB;\n             jpeg_set_defaults(\u0026jcs);\n             //开启哈夫曼功能\n             jcs.optimize_coding = true;\n             jpeg_set_quality(\u0026jcs, q, 1);\n         //    3.4、开始压缩\n             jpeg_start_compress(\u0026jcs, 1);\n         //    3.5、循环写入每一行数据\n             int row_stride = w * 3;//一行的字节数\n             JSAMPROW row[1];\n             while (jcs.next_scanline \u003c jcs.image_height) {\n                 //取一行数据\n                 uint8_t *pixels = data + jcs.next_scanline * row_stride;\n                 row[0] = pixels;\n                 jpeg_write_scanlines(\u0026jcs, row, 1);\n             }\n         //    3.6、压缩完成\n             jpeg_finish_compress(\u0026jcs);\n         //    3.7、释放jpeg对象\n             fclose(f);\n             jpeg_destroy_compress(\u0026jcs);\n         }\n         \n         \n         extern \"C\"\n         JNIEXPORT void JNICALL\n         Java_com_yk_libjpeg_1sample_libjpeg_JpegUtils_native_1Compress__Landroid_graphics_Bitmap_2ILjava_lang_String_2(\n                 JNIEnv *env, jclass type, jobject bitmap, jint q, jstring path_) {\n             const char *path = env-\u003eGetStringUTFChars(path_, 0);\n             //从bitmap获取argb数据\n             AndroidBitmapInfo info;//info=new 对象();\n             //获取里面的信息\n             AndroidBitmap_getInfo(env, bitmap, \u0026info);//  void method(list)\n             //得到图片中的像素信息\n             uint8_t *pixels;//uint8_t char    java   byte     *pixels可以当byte[]\n             AndroidBitmap_lockPixels(env, bitmap, (void **) \u0026pixels);\n             //jpeg argb中去掉他的a ===\u003ergb\n             int w = info.width;\n             int h = info.height;\n             int color;\n             //开一块内存用来存入rgb信息\n             uint8_t *data = (uint8_t *) malloc(w * h * 3);//data中可以存放图片的所有内容\n             uint8_t *temp = data;\n             uint8_t r, g, b;//byte\n             //循环取图片的每一个像素\n             for (int i = 0; i \u003c h; i++) {\n                 for (int j = 0; j \u003c w; j++) {\n                     color = *(int *) pixels;//0-3字节  color4 个字节  一个点\n                     //取出rgb\n                     r = (color \u003e\u003e 16) \u0026 0xFF;//    #00rrggbb  16  0000rr   8  00rrgg\n                     g = (color \u003e\u003e 8) \u0026 0xFF;\n                     b = color \u0026 0xFF;\n                     //存放，以前的主流格式jpeg    bgr\n                     *data = b;\n                     *(data + 1) = g;\n                     *(data + 2) = r;\n                     data += 3;\n                     //指针跳过4个字节\n                     pixels += 4;\n                 }\n             }\n             //把得到的新的图片的信息存入一个新文件 中\n             write_JPEG_file(temp, w, h, q, path);\n         \n             //释放内存\n             free(temp);\n             AndroidBitmap_unlockPixels(env, bitmap);\n             env-\u003eReleaseStringUTFChars(path_, path);\n         }\n         ```\n\n         **调用代码**\n\n         ```java\n         public class JpegUtils {\n             static {\n                 System.loadLibrary(\"jpeg-yk\");\n             }\n         \n             /**\n              * A native method that is implemented by the 'native-lib' native library,\n              * which is packaged with this application.\n              */\n             public native  static void native_Compress(Bitmap bitmap, int q, String path);\n         \n         }\n         ```\n\n## 效果\n\n1. 开始压缩\n\n   ```java\n       public void click(View view) {\n           File input = new File(Environment.getExternalStorageDirectory(), \"/girl.jpg\");\n           ImageView preImg = findViewById(R.id.pre);\n           mNextImg = findViewById(R.id.next);\n           inputBitmap = BitmapFactory.decodeFile(input.getAbsolutePath());\n           preImg.setImageBitmap(inputBitmap);\n          JpegUtils .native_Compress(inputBitmap, 10, Environment.getExternalStorageDirectory() + \"/girl4.jpg\");\n           Toast.makeText(this, \"执行完成\", Toast.LENGTH_SHORT).show();\n           String filePath = Environment.getExternalStorageDirectory() + \"/girl4.jpg\";\n           mNextImg.setImageBitmap(BitmapFactory.decodeFile(filePath));\n       }\n   ```\n\n2. 动画效果\n\n   ![](https://user-gold-cdn.xitu.io/2019/5/19/16ad0559370744f9?w=365\u0026h=740\u0026f=gif\u0026s=2617424)\n\n   **压缩效果:** 压缩质量在 10 的时候用压缩出来的质量也还是挺好了，只有周围有点点模糊，但是建议压缩质量在 30 -50 之间。\n\n   **压缩率:** 大约压缩后的图片大小是原图的缩小 6 倍的样子。\n\n\n\n## 资料\n\n### [更多代码信息请移步 GitHub](\u003chttps://github.com/yangkun19921001/LIBJPEG_SAMPLE\u003e)\n\n### [提供 libjpeg 编译脚本](\u003chttps://github.com/yangkun19921001/LIBJPEG_SAMPLE/blob/master/jpeg_build.sh\u003e)\n\n### [libjpeg 编译的源码和动态/静态库 在 dist 目录 提取码：b0cs](https://pan.baidu.com/s/1WshwS4GjYl3bbzXD4RX_pg )\n\n## 计划(也有可能由于工作任务，滞后)\n\n\n**图片优化计划出三篇文章** \n1. libjpeg 编译及使用 \n2. 长图巨图优化 \n3. bitmap 内存管理 三级缓存\n\n\n\n\n\n\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyangkun19921001%2Flibjpeg_sample","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyangkun19921001%2Flibjpeg_sample","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyangkun19921001%2Flibjpeg_sample/lists"}