将多页TIFF图像拆分为单个图像(Java)

在这一个上撕裂了我的头发。

如何将多页/多层TIFF图像分割成多个单独的图像?

这里有演示图片。

(更喜欢纯Java(即非本地)解决方案。如果解决方案依赖于商业库,则无关紧要。)

您可以使用Java高级映像库JAI通过使用ImageReader来分割多个TIFF:

ImageInputStream is = ImageIO.createImageInputStream(new File(pathToImage)); if (is == null || is.length() == 0){ // handle error } Iterator iterator = ImageIO.getImageReaders(is); if (iterator == null || !iterator.hasNext()) { throw new IOException("Image file format not supported by ImageIO: " + pathToImage); } // We are just looking for the first reader compatible: ImageReader reader = (ImageReader) iterator.next(); iterator = null; reader.setInput(is); 

然后你可以得到页数:

 nbPages = reader.getNumImages(true); 

并分别阅读页面:

 reader.read(numPage) 

快速但非JAVA解决方案是tiffsplit 。 它是libtiff库的一部分。

在所有层中拆分tiff文件的示例命令是:

tiffsplit image.tif

该联机帮助页说明了一切:

 NAME tiffsplit - split a multi-image TIFF into single-image TIFF files SYNOPSIS tiffsplit src.tif [ prefix ] DESCRIPTION tiffsplit takes a multi-directory (page) TIFF file and creates one or more single-directory (page) TIFF files from it. The output files are given names created by concatenating a prefix, a lexically ordered suffix in the range [aaa-zzz], the suffix .tif (eg xaaa.tif, xaab.tif, xzzz.tif). If a prefix is not specified on the command line, the default prefix of x is used. OPTIONS None. BUGS Only a select set of ''known tags'' is copied when splitting. SEE ALSO tiffcp(1), tiffinfo(1), libtiff(3TIFF) Libtiff library home page: http://www.remotesensing.org/libtiff/ 

我在上面使用了一个名为imageio-tiff的tiff插件。

Maven依赖:

  com.tomgibara.imageio imageio-tiff 1.0  

我能够从tiff资源中获取缓冲的图像:

  Resource img3 = new ClassPathResource(TIFF4); ImageInputStream is = ImageIO.createImageInputStream(img3.getInputStream()); Iterator iterator = ImageIO.getImageReaders(is); if (iterator == null || !iterator.hasNext()) { throw new IOException("Image file format not supported by ImageIO: "); } // We are just looking for the first reader compatible: ImageReader reader = (ImageReader) iterator.next(); iterator = null; reader.setInput(is); int nbPages = reader.getNumImages(true); LOGGER.info("No. of pages for tiff file is {}", nbPages); BufferedImage image1 = reader.read(0); BufferedImage image2 = reader.read(1); BufferedImage image3 = reader.read(2); 

但后来我发现另一个名为apache commons的项目成像Maven依赖:

  org.apache.commons commons-imaging 1.0-SNAPSHOT  

在一行中,您可以获得缓冲的图像:

  List bufferedImages = Imaging.getAllBufferedImages(img3.getInputStream(), TIFF4); LOGGER.info("No. of pages for tiff file is {} using apache commons imaging", bufferedImages.size()); 

然后写入文件样本:

  final Map params = new HashMap(); // set optional parameters if you like params.put(ImagingConstants.PARAM_KEY_COMPRESSION, new Integer(TiffConstants.TIFF_COMPRESSION_CCITT_GROUP_4)); int i = 0; for (Iterator iterator1 = bufferedImages.iterator(); iterator1.hasNext(); i++) { BufferedImage bufferedImage = iterator1.next(); LOGGER.info("Image type {}", bufferedImage.getType()); File outFile = new File("C:\\tmp" + File.separator + "shane" + i + ".tiff"); Imaging.writeImage(bufferedImage, outFile, ImageFormats.TIFF, params); } 

实际上测试性能,apache很慢……

或者使用旧版iText,这个版本更快:

 private ByteArrayOutputStream convertTiffToPdf(InputStream imageStream) throws IOException, DocumentException { Image image; ByteArrayOutputStream out = new ByteArrayOutputStream(); Document document = new Document(); PdfWriter writer = PdfWriter.getInstance(document, out); writer.setStrictImageSequence(true); document.open(); RandomAccessFileOrArray ra = new RandomAccessFileOrArray(imageStream); int pages = TiffImage.getNumberOfPages(ra); for (int i = 1; i <= pages; i++) { image = TiffImage.getTiffImage(ra, i); image.setAbsolutePosition(0, 0); image.scaleToFit(PageSize.A4.getWidth(), PageSize.A4.getHeight()); document.setPageSize(PageSize.A4); document.newPage(); document.add(image); } document.close(); out.flush(); return out; } 

这就是我用ImageIO做的事情:

 public List extractImages(InputStream fileInput) throws Exception { List extractedImages = new ArrayList(); try (ImageInputStream iis = ImageIO.createImageInputStream(fileInput)) { ImageReader reader = getTiffImageReader(); reader.setInput(iis); int pages = reader.getNumImages(true); for (int imageIndex = 0; imageIndex < pages; imageIndex++) { BufferedImage bufferedImage = reader.read(imageIndex); extractedImages.add(bufferedImage); } } return extractedImages; } private ImageReader getTiffImageReader() { Iterator imageReaders = ImageIO.getImageReadersByFormatName("TIFF"); if (!imageReaders.hasNext()) { throw new UnsupportedOperationException("No TIFF Reader found!"); } return imageReaders.next(); } 

我从这个博客中获取了部分代码。

所有提出的解决方案都需要逐页读取多页图像并将页面写回新的TIFF图像。 除非您想将各个页面保存为不同的图像格式,否则解码图像毫无意义。 鉴于TIFF图像的特殊结构,您可以将多页TIFF分割为单个TIFF图像而无需解码。

TIFF调整工具(一个较大的图像相关库的一部分 – 我使用的“icafe”是从头开始用纯Java编写的。它可以删除页面,插入页面,保留某些页面,从多页TIFF拆分页面以及合并将TIFF图像多重化为一个TIFF图像而不对其进行解压缩。

尝试使用TIFF调整工具后,我可以将图像分成3页: 第0 页 , 第1 页和第2页

注1:原始演示图像由于某种原因包含“不正确”的StripByteCounts值1,它不是图像条带所需的实际字节数。 事实certificate,图像数据没有被压缩,因此每个图像条的实际字节可以通过其他TIFF字段值(如RowsPerStrip,SamplesPerPixel,ImageWidth等)计算出来。

注2:由于分割TIFF,上面提到的库不需要解码和重新编码图像。 所以它很快,它还保留了每个页面的原始编码和附加元数据!

下面的代码将多个tiff转换为个体,并生成带有tiff图像列表的Excel工作表。

您需要在C驱动器中创建一个名为“FAX”的文件夹,并将TIFF图像放入其中,然后运行此代码。 您可以在“C:\ Final_FAX \”中找到转换后的图像

需要从http://www.java2s.com/Code/JarDownload/sun/导入以下jar子

1.sun-AS-JSR88-DM-4.0-源

2./sun-jai_codec

3.sun-jai_core

 import java.awt.AWTException; import java.awt.Robot; import java.awt.image.RenderedImage; import java.awt.image.renderable.ParameterBlock; import java.io.File; import java.io.IOException; import javax.media.jai.JAI; import javax.media.jai.RenderedOp; import com.sun.media.jai.codec.FileSeekableStream; import com.sun.media.jai.codec.ImageCodec; import com.sun.media.jai.codec.ImageDecoder; import com.sun.media.jai.codec.TIFFEncodeParam; import java.io.*; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import javax.swing.JOptionPane; import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.usermodel.Row; public class TIFF_Sepreator { File folder = new File("C:/FAX/"); public static void infoBox(String infoMessage, String titleBar) { JOptionPane.showMessageDialog(null, infoMessage, "InfoBox: " + titleBar, JOptionPane.INFORMATION_MESSAGE); } public void splitting() throws IOException, AWTException { boolean FinalFAXFolder = (new File("C:/Final_FAX")).mkdirs(); // int ListOfFiles = new File("C:/Final_FAX/").listFiles().length; // System.out.println(ListOfFiles); File[] listOfFiles = folder.listFiles(); String dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss").format(Calendar.getInstance().getTime()); try{ if (listOfFiles.length > 0) { for(int file=0; file files = new ArrayList(Arrays.asList(folder.listFiles())); try { String filename = "C:/Final_FAX/List_Of_Fax_Files.xls" ; HSSFWorkbook workbook = new HSSFWorkbook(); HSSFSheet sheet = workbook.createSheet("FirstSheet"); for (int file=0; file 

它可以将压缩设置为default param.setCompression(32946);

 public static void doitJAI(String mutitiff) throws IOException { FileSeekableStream ss = new FileSeekableStream(mutitiff); ImageDecoder dec = ImageCodec.createImageDecoder("tiff", ss, null); int count = dec.getNumPages(); TIFFEncodeParam param = new TIFFEncodeParam(); param.setCompression(32946); param.setLittleEndian(false); // Intel System.out.println("This TIF has " + count + " image(s)"); for (int i = 0; i < count; i++) { RenderedImage page = dec.decodeAsRenderedImage(i); File f = new File("D:/PSN/SCB/SCAN/bin/Debug/Temps/test/single_" + i + ".tif"); System.out.println("Saving " + f.getCanonicalPath()); ParameterBlock pb = new ParameterBlock(); pb.addSource(page); pb.add(f.toString()); pb.add("tiff"); pb.add(param); RenderedOp r = JAI.create("filestore",pb); r.dispose(); } }