功能实现|java 多张jpg合成tif后避免tif文件过大的方法

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

/** * 合并成一个tif * @param bookFilePaths 要合并的图片集合,字符串为图片的全路径 * @param toPath 目的文件夹路径 * @param distFileName 合成的文件名(带后缀) */ public static void many2one(List 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 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
功能实现|java 多张jpg合成tif后避免tif文件过大的方法
文章图片

这几种可以理解成是合成tif时候的方式
下面是tiff6.0的格式简介
http://www.codeweblog.com/tiff6-0%E6%A0%BC%E5%BC%8F%E7%AE%80%E4%BB%8B/
功能实现|java 多张jpg合成tif后避免tif文件过大的方法
文章图片

这之后的部分很重要,各位可以根据自己的需求选择搭配的属性。这个地方他说的这些属性指的就是tif图片的属性,要在TIFFField这里设置,这也就是我上面提到的第二个类。
https://www.awaresystems.be/imaging/tiff/tifftags/baseline.html
这里面就是可以设置的参数,表中的DEC就是上面代码中的258,262,282,283这些。至于第二、四个参数应该填什么还是要上tiff6.0的格式简介里面去查,查到的类型去这里匹配
功能实现|java 多张jpg合成tif后避免tif文件过大的方法
文章图片

把构造方法的几个参数填上之后,赶紧试一下效果。合成的图片就只有9M多了。但是还有个问题就是等待的时间很长,30张图片要2分钟,这个问题还需要以后有时间解决~
还有一篇文章也有用到,放在下边,自取
【功能实现|java 多张jpg合成tif后避免tif文件过大的方法】http://www.libtiff.org/support.html

    推荐阅读