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

时间:2013-07-21 07:31:37

标签: java tiff

一直在撕裂我的头发。

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

可用的演示图像here

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

7 个答案:

答案 0 :(得分:20)

您可以使用 Java Advanced Imaging JAI,通过使用ImageReader来分割多个TIFF:

ImageInputStream is = ImageIO.createImageInputStream(new File(pathToImage));
if (is == null || is.length() == 0){
  // handle error
}
Iterator<ImageReader> 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)

答案 1 :(得分:2)

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

Maven依赖:

<dependency>
        <groupId>com.tomgibara.imageio</groupId>
        <artifactId>imageio-tiff</artifactId>
        <version>1.0</version>
        </dependency>

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

   Resource img3 = new ClassPathResource(TIFF4);
            ImageInputStream is = ImageIO.createImageInputStream(img3.getInputStream());

            Iterator<ImageReader> 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 imaging的项目 Maven依赖:

<dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-imaging</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

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

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

然后写入文件样本:

 final Map<String, Object> params = new HashMap<String, Object>();
        // 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<BufferedImage> 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;
}

答案 2 :(得分:2)

快速但非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 (e.g.  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/

答案 3 :(得分:1)

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

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

尝试使用TIFF调整工具后,我可以将图像拆分为3页:page#0page#1page#2

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

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

答案 4 :(得分:1)

这就是我使用ImageIO的方式:

public List<BufferedImage> extractImages(InputStream fileInput) throws Exception {
    List<BufferedImage> extractedImages = new ArrayList<BufferedImage>();

    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<ImageReader> imageReaders = ImageIO.getImageReadersByFormatName("TIFF");
    if (!imageReaders.hasNext()) {
        throw new UnsupportedOperationException("No TIFF Reader found!");
    }
    return imageReaders.next();
}

我从this blog获取了部分代码。

答案 5 :(得分:0)

下面的代码会将多个tiff转换为单个tiff,并生成一张带有tiff图像列表的Excel表格。

您需要创建一个名为&#39; FAX&#39;的文件夹。在C盘中将TIFF图像放入其中,然后运行此代码。您可以在&#34; C:\ Final_FAX \&#34;

中找到转换后的图像

需要从http://www.java2s.com/Code/JarDownload/sun/

导入以下广告罐

1.sun-as-jsr88-dm-4.0-sources

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<listOfFiles.length; file++)
            {
            System.out.println(listOfFiles[file]);
            FileSeekableStream ss = new FileSeekableStream(listOfFiles[file]);
            ImageDecoder dec = ImageCodec.createImageDecoder("tiff", ss, null);
            int count = dec.getNumPages();
            TIFFEncodeParam param = new TIFFEncodeParam();
            param.setCompression(TIFFEncodeParam.COMPRESSION_GROUP4);
            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("C:\\Final_FAX\\"+dateFormat+ file +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();
                }
            }
            TIFF_Sepreator.infoBox("Find your splitted TIFF images in location 'C:/Final_FAX/' " , "Done :)");
            WriteListOFFilesIntoExcel();
        }  

        else
        {
            TIFF_Sepreator.infoBox("No files was found in location 'C:/FAX/' " , "Empty folder");
            System.out.println("No files found");
        }
    } 

   catch(Exception e)

        {
            TIFF_Sepreator.infoBox("Unabe to run due to this  error: " +e , "Error");
            System.out.println("Error: "+e);
        }
    }

public void WriteListOFFilesIntoExcel(){

    File[] listOfFiles = folder.listFiles();
    ArrayList<File> files = new ArrayList<File>(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<listOfFiles.length; file++) {
        System.out.println(listOfFiles[file]);
           Row r = sheet.createRow(file);
           r.createCell(0).setCellValue(files.get(file).toString());
        }

    FileOutputStream fileOut = new FileOutputStream(filename);
    workbook.write(fileOut);
    fileOut.close();
    System.out.println("Your excel file has been generated!");

    }
 catch(Exception ex){
        TIFF_Sepreator.infoBox("Unabe to run due to this  error: " +ex , "Error");
        System.out.println("Error: "+ex);   
 }
}
    public static void main(String[] args) throws IOException, AWTException {
         new TIFF_Sepreator().splitting();

    }
}

答案 6 :(得分:0)

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

&#13;
&#13;
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();
  }
}
&#13;
&#13;
&#13;