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

将多页TIFF图像拆分为单个图像(Java),java,tiff,Java,Tiff,我一直在扯我的头发 如何将多页/多层TIFF图像分割为多个单独的图像 演示图像可用 (更喜欢纯Java(即非本机)解决方案。该解决方案是否依赖于商业库无关紧要。)您可以使用Java Advanced Imaging库,通过使用ImageReader拆分多页TIFF: ImageInputStream is = ImageIO.createImageInputStream(new File(pathToImage)); if (is == null || is.length() == 0){

我一直在扯我的头发

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

演示图像可用


(更喜欢纯Java(即非本机)解决方案。该解决方案是否依赖于商业库无关紧要。)

您可以使用Java Advanced Imaging库,通过使用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);
并分别阅读以下页面:

reader.read(numPage)

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

Maven依赖项:

<dependency>
        <groupId>com.tomgibara.imageio</groupId>
        <artifactId>imageio-tiff</artifactId>
        <version>1.0</version>
        </dependency>
<dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-imaging</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

com.tomgibara.imageio
图像tiff
1
我能够从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);
Resource img3=新类路径资源(TIFF4);
ImageInputStream=ImageIO.CreateMageInputStream(img3.getInputStream());
迭代器迭代器=ImageIO.getImageReaders(is);
if(iterator==null | |!iterator.hasNext()){
抛出新IOException(“ImageIO不支持图像文件格式:”);
}
//我们正在寻找第一个兼容的读卡器:
ImageReader=(ImageReader)迭代器。下一步();
迭代器=null;
reader.setInput(is);
int nbPages=reader.getNumImages(true);
info(“tiff文件的页数为{}”,nbPages);
BuffereImage image1=reader.read(0);
BuffereImage image2=读取器.read(1);
BuffereImage image3=读取器.read(2);
但后来我发现了另一个叫做ApacheCommonsImaging的项目 Maven依赖项:

<dependency>
        <groupId>com.tomgibara.imageio</groupId>
        <artifactId>imageio-tiff</artifactId>
        <version>1.0</version>
        </dependency>
<dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-imaging</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

org.apache.commons
公共图像
1.0-快照
在一行中,您可以获得缓冲图像:

 List<BufferedImage> bufferedImages = Imaging.getAllBufferedImages(img3.getInputStream(), TIFF4);
        LOGGER.info("No. of pages for tiff file is {} using apache commons imaging", bufferedImages.size());
List bufferedImages=Imaging.getAllBufferedImages(img3.getInputStream(),TIFF4);
info(“使用apache commons imaging时tiff文件的页数为{}”,buffereImage.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);
        }
final Map params=new HashMap();
//如果愿意,可以设置可选参数
参数put(ImagingConstants.PARAM_KEY_COMPRESSION,新整数(TiffConstants.TIFF_COMPRESSION_CCITT_GROUP_4));
int i=0;
for(迭代器迭代器1=BuffereImage.Iterator();迭代器1.hasNext();i++){
BuffereImage BuffereImage=iterator1.next();
info(“图像类型{}”,buffereImage.getType());
File outFile=新文件(“C:\\tmp”+File.separator+“shane”+i+“.tiff”);
Imaging.writeImage(BuffereImage、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;
}
private ByteArrayOutputStream converttifptodf(InputStream imageStream)引发IOException、DocumentException{
图像;
ByteArrayOutputStream out=新建ByteArrayOutputStream();
文档=新文档();
PdfWriter writer=PdfWriter.getInstance(文档,输出);
writer.setStritimagesequence(true);
document.open();
RandomAccessFileOrArray ra=新的RandomAccessFileOrArray(imageStream);
int pages=TiffImage.getNumberOfPages(ra);

对于(inti=1;i一个快速但非JAVA的解决方案是
tiffsplit
。它是libtiff库的一部分

在tiff文件的所有层中拆分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/

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

TIFF调整工具(我正在使用的一个更大的图像相关库的一部分)是用纯Java从头开始编写的。它可以删除页面、插入页面、保留某些页面、从多页TIFF中拆分页面,以及将多页TIFF图像合并到一个TIFF图像中而无需解压缩

尝试使用TIFF调整工具后,我可以将图像分割为3页:,和

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


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

这就是我使用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();
}
public List extractImages(InputStream fileInput)引发异常{
List extractedimage=new ArrayList();
try(ImageInputStream iis=ImageIO.createImageInputStream(fileInput)){
ImageReader=getTiffImageReader();
reader.setInput(iis);
int pages=reader.getNumImages(true);
对于(int-imageIndex=0;imageIndex

我从中获取了部分代码。

下面的代码将多个tiff转换为单个tiff,并生成包含tiff图像列表的Excel表格

你需要