java中png转索引图压缩图片
文章目录
- 背景
- png格式简介
- 图片压缩实操
- 使用OpenViewerFX
- 使用pngquant(JNI调用)
- 在linux下构建
- 在win下构建
- JNI调用
- 关于pngquant的jni动态链接库文件下载
背景
需求是大大的减小彩信图片的体积,可以发送更多数量的彩信图片,图片的内容是报表,颜色单一。最开始把透明色去掉了,位深从32->24,但是最近测试发现彩信图片体积还是太大了,这就需要去学习图片压缩的知识了
png格式简介
PNG格式有8位、24位、32位三种形式,其中8位PNG支持两种不同的透明形式(索引透明和alpha透明),24位PNG不支持透明,32位PNG在24位基础上增加了8位透明通道,因此可展现256级透明程度。位深度越大图片体积越大,能够表示的色彩越丰富。
png有种索引彩色模式,采用8位调色板将RGB彩色图像转换为索引彩色图像。图像中保存的不再是各个像素的彩色信息,而是从图像中挑选出来的具有代表性的颜色编号,每一编号对应一种颜色,图像的数据量也因此减少,这对彩色图像的传播非常有利。
通过索引png,可以大大减小图片体积,如果图片中的颜色种类小于256,那么就可以使用索引格式的PNG,如果图片原本的颜色大于256种,那么可以通过矢量量化的方法来创建一个索引PNG格式(有损压缩)
上面只是一个简单的介绍,如果要深入了解可以看看:
https://www.jianshu.com/p/5ad19825a3d0
https://www.jianshu.com/p/324744087e24
图片压缩实操
我这里的场景非常适合png索引图模式,因为图片内容是表格报表,颜色最多只有4种,远远小于索引图的256色,如果颜色丰富的那种照片之类的还是用jpg压缩吧。。。
这里重点介绍png量化转索引图
看网上框架有:tinypng、pngquant、OpenViewerFX6.6.14等等
根据资料显示,tinypng、pngquant、ImageAlpha、pngnq都是有损压缩,基本采用的都是quantization算法,将32位的PNG图片转换为8位的PNG图片,减少图片的颜色数;pngcrush、optipng、pngout、advpng都是无损压缩,采用的都是基于LZ/Huffman的DEFLATE算法,减少图片IDAT
chunk区域的数据。一般有损压缩的压缩率会大大高于无损压缩。
我这里使用开源的pngquant框架和OpenViewerFX6.6.14来操作
使用OpenViewerFX
<dependency><groupId>org.jpedal</groupId><artifactId>OpenViewerFX</artifactId><version>6.6.14</version>
</dependency>
PngCompressor.compress(inputStream, outputStream);
这个的使用极其方便,就一句,input进output出,就是不像pngquant有很多参数可以选,如果只是简单的压缩,这个就足够了
28k(24位) -> 12.6k(8位),发现已经成功的转为了索引图
使用pngquant(JNI调用)
使用pngquant框架,这是一款比较流行的png压缩开源框架,它是一种有损压缩,并将其转为索引图,这种转换大大减小了文件大小(通常高达70%),并保留了完全的alpha透明度。生成的图像与所有web浏览器和操作系统兼容。
它是c语言写的,这里麻烦一点,需要使用jni的方式调用,这里就当练习下jni使用了
官方参考文档: https://pngquant.org/lib/
首先去https://github.com/ImageOptim/libimagequant下载源码,发现它是基于makefile构建的.
文档说使用make java就可以构建了,dll的话就是make java-dll
本地环境: centOS7.3 64位、win7 64位、jdk1.8、gcc9.3.0、GNU make4.3
在linux下构建
在linux下构建比较简单,直接cd到目录下去make java
遇到的问题有:
1、configure文件格式的问题,把内容复制下来重新copy一份即可
2、bad value错误
make clean
make distclean
./configure --extra-cflags="-fPIC"
make java
带上fPIC再试一次就可以了
编译完成后就有了libimagequant.jnilib文件
当然,在linux上我们需要的是libimagequant.so而不是libimagequant.jnilib(这是macOS上使用的)
Make java的时候输出的最后一个命令,我们copy下来修改一下
gcc -g -fno-math-errno -funroll-loops -fomit-frame-pointer -Wall -std=c99 -I. -O3 -DNDEBUG -DUSE_SSE=1 -msse -mfpmath=sse -Wno-unknown-pragmas -fexcess-precision=fast -fPIC -lm -I'/usr/lib/jvm/java-1.8.0-openjdk/include' -I'/usr/lib/jvm/java-1.8.0-openjdk/include/linux' -I'/usr/lib/jvm/java-1.8.0-openjdk/include/win32' -I'/usr/lib/jvm/java-1.8.0-openjdk/include/darwin' -shared -o libimagequant.so org/pngquant/PngQuant.c libimagequant.a
把目标文件改为.so,重新编译就可以了
在win下构建
在win下构建可以用于本地开发测试,所以我这里打一个dll
Win下使用cygwin就可以使用make命令构建了,当然,用visual studio也可以,还能避免一些坑。。。
Cygwin是一个可原生运行于Windows系统上的POSXI兼容环境,使用它就可以用到常用的ls、pwd、make、gcc等命令,也是推荐的c++开发工具链
遇到的问题有:
1、Configure文件格式不对,这个解决办法跟linux下一样
2、__int64定义错误
这种解决方法是不对滴,为了引出问题还是记录一下过程
发现报错了,因为gnu中没有 __int64,而引用的win版本的jdk又有这个玩意
当时的解决方法是修改jni_md.h的34行,加上#ifdef else语句判断一下当前环境。或者gcc编译参数中加入宏定义-D__int64=’long long’
我直接修改了编译参数,在Makefile里面
java-dll:$(MAKE) CFLAGS="$(CFLAGS) -DIMAGEQUANT_EXPORTS" $(JNIDLL)
$(JNIDLL) $(JNIDLLIMP): $(JAVAHEADERS) $(OBJS) org/pngquant/PngQuant.c$(CC) -D__int64='long long' -fPIC -shared -I. $(JAVAINCLUDE) -o $(JNIDLL) $^ $(LDFLAGS) -Wl,--out-implib,$(JNIDLLIMP),--output-def,$(JNIDLLDEF)
在这两处加上-D__int64=’long long’,给__int64这种类型一个宏定义,编译倒是成功编译了,就是运行时有错误
3、jni运行时error
这一步是在程序运行中报错的,可以先看下面jin的使用再看这步报错
#
# A fatal error has been detected by the Java Runtime Environment:
#
# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x0000000180136797, pid=9848, tid=0x0000000000001c3c
#
# JRE version: Java(TM) SE Runtime Environment (8.0_191-b12) (build 1.8.0_191-b12)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.191-b12 mixed mode windows-amd64 compressed oops)
# Problematic frame:
# C [cygwin1.dll+0xf6797]
……
Stack: [0x0000000002580000,0x0000000002680000], sp=0x000000000267f6a0, free space=1021k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
C [cygwin1.dll+0xf6797]
C [cygwin1.dll+0x9431f]Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
j org.pngquant.PngQuant.liq_attr_create()J+0
j org.pngquant.PngQuant.<init>()V+5
j com.ai.base.tool.pngquant.PngQuantTest.main([Ljava/lang/String;)V+4
v ~StubRoutines::call_stub
在调用create的时候直接error了,说是cygwin1.dll里面报错,这个cygwin1.dll是POSIX系统调用的模拟层,使用cygwin构建的所有程序都依赖了cygwin1.dll,所以这里不是关键。
在看下面,报错是在liq_attr_create方法中,就是编译出来的dll有问题,不能正常运行。
解决方法是:换用MinGW编译器,MinGW相比CygWin/gcc来讲,更加贴近win32。因为它几乎支持所有的Win32API。
直接修改configure文件,大概在17行的位置
# make gcc default compiler unless CC is already set
CC=${CC:-x86_64-w64-mingw32-gcc}
把编译器换成这个,我这里是用的cygwin的组件,如果没有的话,去setup一遍cygwin,把这个组件选择安装上
然后重新编译一次,编译过后体积大了100多k,不过终于能正常运行了
关于编译好的pngquant动态链接库文件,文章最后有下载
JNI调用
Jni这里就不多介绍了
在pngquant源码中,lib\org\pngquant目录下找到java文件
这个makefile脚本会调用javah生成头文件
它长这个样子,可以发现是javah自动生成的,下面的方法名是根据:Java+包名+类名+方法名生成的
所以如果生成好了,在项目中引用时不要修改包名,不然找不到方法
如果遇到找不到方法,那么就确认一下动态链接库的方法名是否正确
通过nm命令查看,它可以列举文件中的符号,当然也可以看到方法名
我这里的包结构是这样的
Win下System.loadLibrary的是imagequant.dll(不带lib前缀),linux下就是libimagequant.so(带lib前缀)
public class PngQuantTest {public static void main(String[] args) {BufferedImage newImg;PngQuant pngQuant = new PngQuant();try {newImg = pngQuant.getRemapped(ImageIO.read(new File("D:\\test\\92.png")));ImageIO.write(newImg, "png", new File("D:\\test\\new_92.png"));} catch (IOException e) {e.printStackTrace();}pngQuant.close();}
}
最后写一个测试方法,运行添加jvm参数: -Djava.library.path=./lib,然后测试成功!
关于jni还有个比jni性能好一点的javacpp有兴趣可以看看
https://github.com/bytedeco/javacpp
关于pngquant的jni动态链接库文件下载
https://download.csdn.net/download/w57685321/12706816
java中png转索引图压缩图片相关推荐
- Java 中调用 Apache API 实现图片文件的 压缩 与 解压 实例
< Java 中调用 Apache API 实现图片文件的 压缩 与 解压 > 为什么不直接使用 Java JDK 中自带的 API 呢?必须使用 Apache API 实现文件的压缩与解 ...
- java中生成pdf,插入图片,页眉、页脚、表格
全栈工程师开发手册 (作者:栾鹏) java教程全解 java中生成pdf,插入图片,页眉.页脚.表格 import com.lowagie.text.*; import com.lowagie.te ...
- 压缩图片大小的java代码_java按比例压缩图片的源代码,用java如何把图片处理到指定大小...
[要分析某个网页中的代码构成,需要某个结点下的内容.用此原始方法可以得到整个网页的源码.其实更简单的方法是使用 WebClient 或 HtmlUtil 等开源方式 .public class Ht ...
- java 使用Thumbnailator 上传图片 并压缩图片大小
http://www.cnblogs.com/miskis/p/5500822.html java 上传图片 并压缩图片大小 Thumbnailator 是一个优秀的图片处理的Google开源Java ...
- java中图片与像素矩阵转换,java - Java中具有矩阵乘法的图片转换不起作用 - 堆栈内存溢出...
我正在用Java实现图片转换. 到目前为止,我已经实现了以下类: 矩阵 (持有一个3x3矩阵,该矩阵将用于与Vector相乘) 向量 (用于与变换矩阵相乘以生成原始图像像素的新位置) PictureT ...
- Java中JFrame窗口添加背景图片
知识储备: 1.JFrame中是有很多层次关系的,具体可以去自己查一下: 主要思路: 1.把图片添加到标签里(把标签的大小设为和图片大小相同),把标签放在分层面板的最底层: 2.把窗口面板设为内容面板 ...
- Java中关于超长字符串压缩,解压缩问题
问题:数据库中varchar类型的长度设置为5000,通过一个富文本编辑器编辑了通知内容,接收到了内容字段长度为8000多,unruly数据库时候,数据库报错(字段太长,显示下标越界异常) 解决办法: ...
- java中如何gzip_Java如何压缩Gzip格式的文件?
在此代码示例中,我们将学习如何使用gzip压缩来压缩文件.从本质上讲,gzip只能压缩一个文件,不能将其用于压缩目录以及该目录中的所有文件. 您将用于以gzip格式压缩文件的类包括GZipOutput ...
- java 中导出word后压缩文件_Java批量导出word压缩后的zip文件案例
一.js代码,由于参数比较大所以利用form表单使用post导出 function export_word(){ var selectedRows = $("#dg").datag ...
最新文章
- JavaScript获取DOM元素位置和尺寸大小
- mysql数据库操作手册
- 吴恩达深度学习 —— 2.11 向量化
- JBox2D手机游戏引擎介绍(附jbox2d官网网址)
- shell脚本工具之awk命令
- ITester软件测试小栈历时9个月文章汇总
- 用iMindMap制作健康生活计划思维导图
- sqlplus 命令导入数据文件
- 录制课程视频用什么软件?微课录屏软件等你来选!
- 宝塔面板的数据库地址配置
- Anycloud平台LOGO生成方法
- python交易是什么意思_Py交易是什么意思?Py交易是什么梗?
- 帕累托图(Pareto Diagram,排列图)
- java天眼培训_Java天眼大型分布式跟踪系统 附带源码_IT教程网
- 单应性矩阵 matlab,单应性矩阵MATLAB程序
- 【从零开始学习 SystemVerilog】11.2、SystemVerilog 断言—— Immediate Assertions(立即断言)
- PortTunnel端口映射后,取外网IP
- ZOJ 2112 Dynamic Rankings(主席树-动态第k大)
- 汇正财经靠谱吗?沪深创集体调整
- Redis入门到精通-Redis安全性