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文件过大的方法_第1张图片

这几种可以理解成是合成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的格式简介里面去查,查到的类型去这里匹配

java 多张jpg合成tif后避免tif文件过大的方法_第2张图片

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

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

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

你可能感兴趣的:(功能实现,Java)