web-dev-qa-db-ja.com

複数ページのTIFF画像を個々の画像に分割する(Java)

これで私の髪を引き裂いてきました。

マルチページ/マルチレイヤーTIFF画像をいくつかの個別の画像に分割するにはどうすればよいですか?

利用可能なデモ画像 ここ

(純粋なJava(つまり、非ネイティブ)ソリューションを好むでしょう。ソリューションが商用ライブラリに依存しているかどうかは関係ありません。)

12
aioobe

Java Advanced Imagingライブラリ [〜#〜] jai [〜#〜] を使用して、複数ページを分割できますTIFF、ImageReaderを使用して:

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)
22
Thire

上記のサンプルを、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);

しかし、その後、Mavenの依存関係をイメージングするApachecommonsと呼ばれる別のプロジェクトを見つけました。

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

1行で、バッファリングされた画像を取得できます。

 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
shane lee

高速ですが非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/
2
CousinCocaine

これは私が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();
}

このブログ からコードに参加しました。

1
Stephan Berg

提案されたすべてのソリューションでは、複数ページの画像をページごとに読み取り、ページを新しいTIFF画像に書き戻す必要があります。個々のページを異なる画像形式で保存する場合を除いて、画像をデコードしても意味がありません。 TIFF画像の特別な構造を考えると、デコードせずに複数ページのTIFFを単一のTIFF画像に分割できます。

TIFF調整ツール(より大きな画像関連ライブラリの一部 "icafe" 私が使用しているのは純粋なJavaでゼロから書かれています。ページの削除、ページの挿入、特定のページの保持、ページの分割が可能です。複数ページのTIFF、および複数ページのTIFF画像を解凍せずに1つのTIFF画像にマージします。

TIFF調整ツールを試した後、画像を3つのページに分割することができます: page#page#1 、および page#2

注1:何らかの理由で、元のデモ画像に「誤った」StripByteCounts値1が含まれていますが、これは画像ストリップに必要な実際のバイト数ではありません。画像データは圧縮されていないことが判明したため、各画像ストリップの実際のバイト数は、RowsPerStrip、SamplesPerPixel、ImageWidthなどの他のTIFFフィールド値から把握できます。

注2:TIFFを分割する場合、上記のライブラリは画像をデコードして再エンコードする必要がないためです。そのため、高速で、各ページの元のエンコーディングと追加のメタデータも保持されます。

1
dragon66

圧縮を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();
  }
}
0
Potter Sukeep

以下のコードは、複数のtiffを個人のものに変換し、tiff画像のリストを含むExcelシートを生成します。

Cドライブに「FAX」という名前のフォルダーを作成し、その中にTIFFイメージを配置してから、このコードを実行する必要があります。変換された画像は「C:\ Final_FAX\"」にあります。

以下のjarファイルを 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();

    }
}
0
Nandan A