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类
这几种可以理解成是合成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分钟,这个问题还需要以后有时间解决~
还有一篇文章也有用到,放在下边,自取