java 多张jpg合成tif后避免tif文件过大的方法

2023-12-22 05:58

本文主要是介绍java 多张jpg合成tif后避免tif文件过大的方法,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

这几天突然有个需求要求把之前的通过扫描仪扫出来的jpg图片给合成一个tif文件,乍一看这个需求还是没啥问题的,于是乎直接上网找一个方法下来就好啦,百度“多张jpg合成tif”得到如下方法:

	/*** 合并成一个tif* @param bookFilePaths 要合并的图片集合,字符串为图片的全路径* @param toPath 目的文件夹路径* @param distFileName 合成的文件名(带后缀)*/public static void many2one(List<String> bookFilePaths, String toPath, String distFileName) {if (bookFilePaths != null && bookFilePaths.size() > 0) {File[] files = new File[bookFilePaths.size()];for (int i = 0; i < bookFilePaths.size(); i++) {files[i] = new File(bookFilePaths.get(i));}if (files != null && files.length > 0) {try {ArrayList pages = new ArrayList(files.length - 1);FileSeekableStream[] stream = new FileSeekableStream[files.length];for (int i = 0; i < files.length; i++) {stream[i] = new FileSeekableStream(files[i].getPath());}ParameterBlock pb = (new ParameterBlock());PlanarImage firstPage = JAI.create("stream", stream[0]);for (int i = 1; i < files.length; i++) {PlanarImage page = JAI.create("stream", stream[i]);pages.add(page);}TIFFEncodeParam param = new TIFFEncodeParam();File f = new File(toPath);if (!f.exists()) {f.mkdirs();}OutputStream os = new FileOutputStream(toPath + File.separator + distFileName);ImageEncoder enc = ImageCodec.createImageEncoder("tiff", os, param);param.setExtraImages(pages.iterator());enc.encode(firstPage);for (int i = 0; i < files.length; i++) {stream[i].close();if (files[i].isFile() && files[i].exists()) {files[i].delete();}}os.close();} catch (IOException e) {e.printStackTrace();}}}}

参数意义明确,感觉胜利就在眼前,迅速把图片放上去试一下,结果发现30张300K左右的jpg图片合成完之后却有340M!这个是肯定不接受的。上网找了一个软件来合成这30张jpg大小为9M,与30张的大小之和基本一致。

想了以下几个办法解决:

1.直接压缩340M的tif

2.先压缩jpg再合成tif

3.先把30张jpg转为pdf再转tif

4.重新review方法找原因

第一种方法压缩之后离要求的大小还是相差很大;第二种先压缩再合成也是这样,而且还改变了原jpg的dpi,这种方案也是不行;第三种方案,pdf转tif有问题,不是对于中文pdf支持有问题就是转不出多页tif,也pass;最后一种方案,好好研究了一下TIFFEncodeParam,TIFFField这两个类,先贴成功之后的代码

	public static void many2one(List<String> bookFilePaths, String toPath, String distFileName) {if (bookFilePaths != null && bookFilePaths.size() > 0) {File[] files = new File[bookFilePaths.size()];for (int i = 0; i < bookFilePaths.size(); i++) {files[i] = new File(bookFilePaths.get(i));}if (files != null && files.length > 0) {try {ArrayList pages = new ArrayList(files.length - 1);FileSeekableStream[] stream = new FileSeekableStream[files.length];for (int i = 0; i < files.length; i++) {stream[i] = new FileSeekableStream(files[i].getCanonicalPath());}ParameterBlock pb = (new ParameterBlock());PlanarImage firstPage = JAI.create("stream", stream[0]);for (int i = 1; i < files.length; i++) {PlanarImage page = JAI.create("stream", stream[i]);pages.add(page);}TIFFEncodeParam param = new TIFFEncodeParam();param.setCompression(TIFFEncodeParam.COMPRESSION_JPEG_TTN2);
//					param.setCompression(TIFFEncodeParam.COMPRESSION_DEFLATE);
//					param.setDeflateLevel(9);
//					param.setWriteTiled(true);
//					param.setReverseFillOrder(true);TIFFField[] extras = new TIFFField[4];extras[0] = new TIFFField(262, TIFFField.TIFF_SHORT, 1, (Object) new short[] { 6 });extras[1] = new TIFFField(282, TIFFTag.TIFF_RATIONAL, 1, (Object) new long[][]{{(long) 200, 1}, {0, 0}});  extras[2] = new TIFFField(283, TIFFTag.TIFF_RATIONAL, 1, (Object) new long[][]{{(long) 200, 1}, {0, 0}});extras[3] = new TIFFField(258, TIFFField.TIFF_SHORT, 1, (Object) new char[] { 8 });param.setExtraFields(extras);param.setExtraImages(pages.iterator());File f = new File(toPath);if (!f.exists()) {f.mkdirs();}OutputStream os = new FileOutputStream(toPath + File.separator + distFileName);ImageEncoder enc = ImageCodec.createImageEncoder("tiff", os, param);enc.encode(firstPage);os.close();System.out.println("over");} catch (IOException e) {e.printStackTrace();}}}}

TIFFEncodeParam类

https://docs.oracle.com/cd/E17802_01/products/products/java-media/jai/forDevelopers/jai-apidocs/com/sun/media/jai/codec/TIFFEncodeParam.html#COMPRESSION_DEFLATE

这几种可以理解成是合成tif时候的方式

下面是tiff6.0的格式简介

http://www.codeweblog.com/tiff6-0%E6%A0%BC%E5%BC%8F%E7%AE%80%E4%BB%8B/

这之后的部分很重要,各位可以根据自己的需求选择搭配的属性。这个地方他说的这些属性指的就是tif图片的属性,要在TIFFField这里设置,这也就是我上面提到的第二个类。

https://www.awaresystems.be/imaging/tiff/tifftags/baseline.html

这里面就是可以设置的参数,表中的DEC就是上面代码中的258,262,282,283这些。至于第二、四个参数应该填什么还是要上tiff6.0的格式简介里面去查,查到的类型去这里匹配

把构造方法的几个参数填上之后,赶紧试一下效果。合成的图片就只有9M多了。但是还有个问题就是等待的时间很长,30张图片要2分钟,这个问题还需要以后有时间解决~

还有一篇文章也有用到,放在下边,自取

http://www.libtiff.org/support.html

这篇关于java 多张jpg合成tif后避免tif文件过大的方法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/522793

相关文章

Spring Boot集成/输出/日志级别控制/持久化开发实践

《SpringBoot集成/输出/日志级别控制/持久化开发实践》SpringBoot默认集成Logback,支持灵活日志级别配置(INFO/DEBUG等),输出包含时间戳、级别、类名等信息,并可通过... 目录一、日志概述1.1、Spring Boot日志简介1.2、日志框架与默认配置1.3、日志的核心作用

破茧 JDBC:MyBatis 在 Spring Boot 中的轻量实践指南

《破茧JDBC:MyBatis在SpringBoot中的轻量实践指南》MyBatis是持久层框架,简化JDBC开发,通过接口+XML/注解实现数据访问,动态代理生成实现类,支持增删改查及参数... 目录一、什么是 MyBATis二、 MyBatis 入门2.1、创建项目2.2、配置数据库连接字符串2.3、入

Springboot项目启动失败提示找不到dao类的解决

《Springboot项目启动失败提示找不到dao类的解决》SpringBoot启动失败,因ProductServiceImpl未正确注入ProductDao,原因:Dao未注册为Bean,解决:在启... 目录错误描述原因解决方法总结***************************APPLICA编

深度解析Spring Security 中的 SecurityFilterChain核心功能

《深度解析SpringSecurity中的SecurityFilterChain核心功能》SecurityFilterChain通过组件化配置、类型安全路径匹配、多链协同三大特性,重构了Spri... 目录Spring Security 中的SecurityFilterChain深度解析一、Security

Python安装Pandas库的两种方法

《Python安装Pandas库的两种方法》本文介绍了三种安装PythonPandas库的方法,通过cmd命令行安装并解决版本冲突,手动下载whl文件安装,更换国内镜像源加速下载,最后建议用pipli... 目录方法一:cmd命令行执行pip install pandas方法二:找到pandas下载库,然后

SpringBoot多环境配置数据读取方式

《SpringBoot多环境配置数据读取方式》SpringBoot通过环境隔离机制,支持properties/yaml/yml多格式配置,结合@Value、Environment和@Configura... 目录一、多环境配置的核心思路二、3种配置文件格式详解2.1 properties格式(传统格式)1.

Apache Ignite 与 Spring Boot 集成详细指南

《ApacheIgnite与SpringBoot集成详细指南》ApacheIgnite官方指南详解如何通过SpringBootStarter扩展实现自动配置,支持厚/轻客户端模式,简化Ign... 目录 一、背景:为什么需要这个集成? 二、两种集成方式(对应两种客户端模型) 三、方式一:自动配置 Thick

Spring WebClient从入门到精通

《SpringWebClient从入门到精通》本文详解SpringWebClient非阻塞响应式特性及优势,涵盖核心API、实战应用与性能优化,对比RestTemplate,为微服务通信提供高效解决... 目录一、WebClient 概述1.1 为什么选择 WebClient?1.2 WebClient 与

Java.lang.InterruptedException被中止异常的原因及解决方案

《Java.lang.InterruptedException被中止异常的原因及解决方案》Java.lang.InterruptedException是线程被中断时抛出的异常,用于协作停止执行,常见于... 目录报错问题报错原因解决方法Java.lang.InterruptedException 是 Jav

深入浅出SpringBoot WebSocket构建实时应用全面指南

《深入浅出SpringBootWebSocket构建实时应用全面指南》WebSocket是一种在单个TCP连接上进行全双工通信的协议,这篇文章主要为大家详细介绍了SpringBoot如何集成WebS... 目录前言为什么需要 WebSocketWebSocket 是什么Spring Boot 如何简化 We