2013-07-21 232 views
9

一直在撕掉我的頭髮。將多頁TIFF圖像分割成單獨的圖像(Java)

如何將多頁/多層TIFF圖像拆分爲多個單獨的圖像?

演示圖像可用here

(寧願一個純Java(即非原生)解決方案。如果解決方案依賴於商業庫也無所謂。)

+1

如果您的TIFF文件將是一致的和喜歡的樣品,你可以做一個快速的正骯髒的方法,它並不難寫。廣義程序來處理所有的TIFF格式會比較複雜。 – BitBank

回答

19

可以使用Java高級圖像庫,JAI,分裂一個mutlipage 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) 
+2

其實,你發佈的代碼,一個偉大的事情是,它甚至不需要JAI在編譯的時候,和JAI可以替代在運行時另一TIFF插件。 :-) – haraldK

1

我用上面的這個示例與我發現的名爲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的依賴另一個項目:

<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

快速但非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/ 
1

所有提出的解決方案需要讀取多頁圖像逐頁逐頁寫回新的TIFF圖像。除非您要將單個頁面保存爲不同的圖像格式,否則解碼圖像沒有意義。鑑於TIFF圖像的特殊結構,您可以將多頁TIFF分割爲單個TIFF圖像而無需解碼。

TIFF調整工具(我使用的是一個更大的圖像相關庫 - "icafe"的一部分是從零開始編寫的,它可以從多頁TIFF中刪除頁面,插入頁面,保留特定頁面,拆分頁面如無解壓縮它們合併多頁TIFF圖像轉換成一個TIFF圖像

與TIFF的調整工具嘗試之後,我能夠將圖像分割成3頁:page#0page#1page#2

注1:由於某些原因,原始演示圖像包含「不正確的」St ripByteCounts值1,它不是圖像條所需的實際字節數。事實證明,在圖像數據沒有被壓縮,所以對每個圖像條帶的實際字節可以通過其他TIFF字段值如RowsPerStrip,SamplesPerPixel,ImageWidth等

注2計算出來:在分裂由於TIFF,上面提到的庫不需要對圖像進行解碼和重新編碼。所以速度很快,並且它還保留了每個頁面的原始編碼和附加元數據!

0

這是我如何與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。下面

0

該代碼將轉換多個TIFF成單獨的,併產生一個Excel工作表以TIFF圖像的列表。

您需要在C驅動器中創建一個名爲'FAX'的文件夾,然後放入您的TIFF圖像,然後運行此代碼。您可以找到轉換後的圖像 「C:\ Final_FAX \」

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

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

導入下面的罐子

2 /太陽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(); 

    } 
}