これで私の髪を引き裂いてきました。
マルチページ/マルチレイヤーTIFF画像をいくつかの個別の画像に分割するにはどうすればよいですか?
利用可能なデモ画像 ここ 。
(純粋なJava(つまり、非ネイティブ)ソリューションを好むでしょう。ソリューションが商用ライブラリに依存しているかどうかは関係ありません。)
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)
上記のサンプルを、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;
}
高速ですが非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/
これは私が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();
}
このブログ からコードに参加しました。
提案されたすべてのソリューションでは、複数ページの画像をページごとに読み取り、ページを新しい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を分割する場合、上記のライブラリは画像をデコードして再エンコードする必要がないためです。そのため、高速で、各ページの元のエンコーディングと追加のメタデータも保持されます。
圧縮を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();
}
}
以下のコードは、複数の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();
}
}