欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-04-14 07:49:44
...

这几天突然有个需求要求把之前的通过扫描仪扫出来的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

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分钟,这个问题还需要以后有时间解决~

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

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