Wie kann man mehrere Bilddateien in einem *.tif speichern?
Das Abspeichern mehrerer Bilder in einer einzigen *.tif
-Datei
muss über einen Zwischenschritt erfolgen, bei dem die
Einzeldateien in BufferedImage
-Objeke konvertiert
werden. Im angeführten Beispiel wird ein Array mit den
Dateinamen-Strings dreier *.tif
-Dateien und dem
Speicherpfad an die Methode loadImages()
übergeben. Sie ist für das Laden und die Dekodierung der
Bilddaten zuständig.
In einem zweiten Schritt werden die
erzeugten BufferedImage
-Objekte kodiert und in die
Zieldatei eingelesen.
Laden und Dekodieren der Bilder
In der Methode loadImages()
wird zunächst ein
Array zur späteren Speicherung von BufferedImage
-Objekten
erzeugt. In einer Schleife werden dann die einzelnen Quell-Dateien
in einen FileInputStream
(oder auch FileSeekableStream
)
eingelesen. Zur Weiterverarbeitung müssen die Daten dann
dekodiert werden. Die JAI-Klasse ImageCodec
stellt zur
Erzeugung eines hierzu geeigneten Dekoders eine Reihe
überladener Methoden createImageDecoder()
bereit,
die entsprechende ImageDecoder
-Objekte zum Dekodieren
des Streams erzeugen können, im vorliegenden Fall, indem ihr
ein String des Zieltyps, die gestreamte Quelldatei und ggfs.
Dekodierungs-Parameter in Form eines ImageDecodeParam
-Objektes
übergeben werden.
Der Dekoder erzeugt nun mit seiner Methode
decodeAsRenderedImage()
ein RenderedImage
,
das an den Konstruktor eines NullOpImage
weitergereicht
wird. Zusätzlich werden noch drei weitere Parameter an den
Konstruktor übergeben: das optionale Color-Model in Form eines
ImageLayout
-Objektes, eine ebenfalls optionale Map
mit Konfigurationsvariablen und eine Konstante, die einen Hinweis
auf den Ursprung der Quelldatei gibt und zur Optimierung der
Weiterverarbeitung dient. Das NullOpImage
wird in ein
Objekt der Elternklasse PlanarImage
gecastet und
schließlich von dort in ein BufferedImage
gewandelt, das im o.a. Array gespeichert werden kann.
import java.awt.image.BufferedImage;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import javax.media.jai.NullOpImage;
import javax.media.jai.OpImage;
import javax.media.jai.PlanarImage;
import com.sun.media.jai.codec.ImageCodec;
import com.sun.media.jai.codec.ImageDecoder;
import com.sun.media.jai.codec.ImageEncoder;
import com.sun.media.jai.codec.TIFFEncodeParam;
public class MultipleTiff {
public static void main(String[] args) {
String[] files = { "test1.tif", "test2.tif", "test3.tif" };
MultipleTiff mt = new MultipleTiff();
mt.saveMultipleTiff(mt.loadImages("img/", files), "out/", "out.tif");
}
private BufferedImage[] loadImages(String inputDir, String[] files) {
BufferedImage images[] = new BufferedImage[files.length];
FileInputStream stream = null;
PlanarImage pi;
for (int i = 0; i < files.length; i++) {
try {
stream = new FileInputStream(inputDir + files[i]);
ImageDecoder decoder = ImageCodec.createImageDecoder("tiff",
stream, null);
pi = new NullOpImage(
decoder.decodeAsRenderedImage(), null, null,
OpImage.OP_IO_BOUND);
images[i] = pi.getAsBufferedImage();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
stream.close();
}catch(IOException ioe) {
}
}
}
return images;
}
private void saveMultipleTiff(BufferedImage[] images, String outputDir,
String imageName) {
TIFFEncodeParam params = new TIFFEncodeParam();
OutputStream out = null;
try {
out = new FileOutputStream(outputDir + imageName);
ImageEncoder encoder = ImageCodec.createImageEncoder("tiff", out,
params);
ArrayList<BufferedImage> list = new ArrayList<BufferedImage>();
for (int i = 1; i < images.length; i++) {
list.add(images[i]);
}
params.setExtraImages(list.iterator());
encoder.encode(images[0]);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try{
out.close();
} catch(IOException ioe){}
}
}
}
Kodieren und Ausgabe der Bilder
Der zweite Schritt der Verarbeitung findet in der Methode saveMultipleTiff()
statt.
Hier werden zunächst ein OutputStream
deklariert
und ein Objekt vom Typ TIFFEncodeParam
erzeugt.
Letzteres speichert die Kodierungsparameter, die im Beispiel den
Standardwerten: 'kompressionslose Speicherung' und 'Ablegen der
Bilddaten in Stripes' entsprechen. Nach Erzeugen des Streams mit dem
Zielspeicherort wird ein ImageEncoder
mit Übergabe
des Zieltyps, "tiff", des Streams und der Kodierungsparameter
gebildet.
Zum Speichern mehrerer Bilddateien muss der Methode TIFFEncodeParam#setExtraImages()
ein Iterator übergeben werden, der die Liste durchläuft
und die zusätzlich zu speichernden Bilder erfasst. Das erste
Bild darf hierbei nicht mit erfasst werden, um in der Zieldatei
nicht doppelt zu erscheinen.
Um den Iterator zu erhalten, wird
der Inhalt des Arrays mit den BufferedImages hier in eine ArrayList
überführt und dort die Bilder bis auf das erste
zwischengespeichert. Das erste BufferedImage
wird
dagegen als Parameter der Methode encode()
des
Kodierers übergeben. Sie kodiert das erste Bild und schreibt
das Ergebnis in den OutputStream
, der mit dem ImageEncoder
verbunden ist. Die Reihenfolge an dieser Stelle ist wichtig. Kehrt
man sie um, so wird lediglich das erste Bild in der Zieldatei
gespeichert.
Wenn Ihnen javabeginners.de gefällt, freue ich mich über eine Spende an diese gemeinnützigen Organisationen.