2013-07-21 27 views
9

Rozerwałem moje włosy na tym.Dzielenie wielostronicowego obrazu TIFF na pojedyncze obrazy (Java)

Jak podzielić wielostronicowy/wielowarstwowy obraz TIFF na kilka pojedynczych obrazów?

Dostępne jest zdjęcie demonstracyjne here.

(woleliby czystej Javy (czyli non-native) rozwiązanie. Nie ma znaczenia, czy rozwiązanie opiera się na bibliotekach komercyjnych.)

+1

Jeśli pliki TIFF będą spójne i jak próbki, można zrobić szybkie-n-brudne metody, która nie jest trudno napisać. Uogólniona procedura obsługi wszystkich plików TIFF byłaby bardziej skomplikowana. – BitBank

Odpowiedz

19

Można użyć Java Advanced Imaging biblioteka, JAI, aby podzielić TIFF mutlipage, stosując 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); 

Następnie można uzyskać liczbę stron:

nbPages = reader.getNumImages(true); 

i czytania stron Separatly:

reader.read(numPage) 
+2

Właściwie wielką zaletą napisanego przez Ciebie kodu jest to, że nie wymaga on nawet JAI podczas kompilacji, a JAI może być zastąpiony inną wtyczką TIFF w czasie wykonywania. :-) – haraldK

1

użyłem tego próbkę powyżej wtyczki tiff znalazłem nazwie ImageIO-tiff. Zależność

Maven:

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

udało mi się uzyskać buforowane obrazów z zasobu 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); 

Ale potem znalazłem inny projekt o nazwie Apache Commons obrazowania zależność Maven:

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

W jednej linii można uzyskać buforowane obrazy:

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

Następnie napisać przykładowy plik:

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); 
     } 

Właściwie testowania wydajności, apache jest dużo wolniejsza ...

Albo używać starej wersji iText, który jest o wiele szybciej:

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

Szybkie, ale nie oparte na JAVA rozwiązanie to tiffsplit. Jest częścią biblioteki libtiff.

przykładowe polecenie, aby podzielić plik TIFF w sumie to warstwami byłoby:

tiffsplit image.tif

manpage mówi wszystko:

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

Wszystkie proponowane rozwiązania wymagają czytania wielostronicowy obraz strona po stronie i zapisz strony z powrotem do nowych obrazów TIFF. Jeśli nie chcesz zapisywać poszczególnych stron w innym formacie, nie ma sensu dekodować obrazu. Biorąc pod uwagę specjalną strukturę obrazu TIFF, można podzielić wielostronicowy TIFF na pojedyncze obrazy TIFF bez dekodowania.

Narzędzie do regulacji TIFF (część biblioteki o większym obrazie - "icafe" Używam jest napisane od zera z czystą Javą.Może usuwać strony, wstawiać strony, zachowywać określone strony, dzielić strony z wielostronicowego TIFF, jak również . jak scalić wielostronicowych obrazów TIFF w jednym TIFF bez ich dekompresję

Po wypróbowaniu pomocą narzędzia TIFF szczypanie, jestem w stanie podzielić obraz na 3 stronach: page#0, page#1 i page#2

UWAGA1: Oryginalny obraz demo z jakiegoś powodu zawiera "niepoprawny" św ripByteCounts wartość 1, która nie jest faktycznym bajtem potrzebnym dla paska obrazów. Okazuje się, że dane obrazu nie są kompresowane, więc rzeczywiste bajtów dla każdego pasa obrazu może być zorientowali się poprzez inne wartości pól TIFF, takich jak rowsperstrip, samplesperpixel, ImageWidth itp

UWAGA2: Ponieważ w rozdzielenia programów TIFF, wspomniana biblioteka nie musi dekodować i ponownie kodować obrazu. Jest szybki i zachowuje oryginalne kodowanie oraz dodatkowe metadane każdej strony!

0

To jak to zrobiłem z 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(); 
} 

wziąłem część kodu z this blog.

0

Poniższy kod przekonwertuje wiele tif na indywidualne i wygeneruje arkusz Excel z listą zdjęć tiff.

Musisz utworzyć folder o nazwie "FAX" na dysku C i umieścić w nim obrazy TIFF, a następnie uruchomić ten kod. Można znaleźć przekonwertowane obrazy w "C: \ Final_FAX \"

trzeba importować z poniższych słoiki z http://www.java2s.com/Code/JarDownload/sun/

1.sun-as-jsr88-DM-4.0-źródeł

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(); 

    } 
}