/*
* #%L
* BSD implementations of Bio-Formats readers and writers
* %%
* Copyright (C) 2005 - 2015 Open Microscopy Environment:
* - Board of Regents of the University of Wisconsin-Madison
* - Glencoe Software, Inc.
* - University of Dundee
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
package loci.formats;
import java.awt.image.ColorModel;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import loci.common.Region;
import loci.formats.codec.CodecOptions;
import loci.formats.meta.MetadataRetrieve;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* ImageWriter is the master file format writer for all supported formats.
* It uses one instance of each writer subclass (specified in writers.txt,
* or other class list source) to identify file formats and write data.
*
* @author Curtis Rueden ctrueden at wisc.edu
*/
public class ImageWriter implements IFormatWriter {
// -- Constants --
private static final Logger LOGGER =
LoggerFactory.getLogger(ImageWriter.class);
// -- Static fields --
/** Default list of writer classes, for use with noargs constructor. */
private static ClassList<IFormatWriter> defaultClasses;
// -- Static utility methods --
public static ClassList<IFormatWriter> getDefaultWriterClasses() {
if (defaultClasses == null) {
// load built-in writer classes from writers.txt file
try {
defaultClasses =
new ClassList<IFormatWriter>("writers.txt", IFormatWriter.class);
}
catch (IOException exc) {
defaultClasses = new ClassList<IFormatWriter>(IFormatWriter.class);
LOGGER.info("Could not parse class list; using default classes", exc);
}
}
return defaultClasses;
}
// -- Fields --
/** List of supported file format writers. */
protected IFormatWriter[] writers;
/**
* Valid suffixes for all file format writers.
* Populated the first time getSuffixes() is called.
*/
private String[] suffixes;
/**
* Compression types for all file format writers.
* Populated the first time getCompressionTypes() is called.
*/
protected String[] compressionTypes;
/** Name of current file. */
protected String currentId;
/** Current form index. */
protected int current;
// -- Constructor --
/**
* Constructs a new ImageWriter with the default
* list of writer classes from writers.txt.
*/
public ImageWriter() {
this(getDefaultWriterClasses());
}
/** Constructs a new ImageWriter from the given list of writer classes. */
public ImageWriter(ClassList<IFormatWriter> classList) {
// add writers to the list
List<IFormatWriter> list = new ArrayList<IFormatWriter>();
Class<? extends IFormatWriter>[] c = classList.getClasses();
for (int i=0; i<c.length; i++) {
IFormatWriter writer = null;
try {
writer = c[i].newInstance();
}
catch (IllegalAccessException exc) { }
catch (InstantiationException exc) { }
if (writer == null) {
LOGGER.error("{} cannot be instantiated.", c[i].getName());
continue;
}
list.add(writer);
}
writers = new IFormatWriter[list.size()];
list.toArray(writers);
}
// -- ImageWriter API methods --
/** Gets a string describing the file format for the given file. */
public String getFormat(String id) throws FormatException, IOException {
return getWriter(id).getFormat();
}
/** Gets the writer used to save the given file. */
public IFormatWriter getWriter(String id) throws FormatException {
if (!id.equals(currentId)) {
// initialize file
boolean success = false;
for (int i=0; i<writers.length; i++) {
if (writers[i].isThisType(id)) {
current = i;
currentId = id;
success = true;
break;
}
}
if (!success) {
throw new UnknownFormatException("Unknown file format: " + id);
}
}
return writers[current];
}
/** Gets the writer used to save the current file. */
public IFormatWriter getWriter() {
return writers[current];
}
/** Gets the file format writer instance matching the given class. */
public IFormatWriter getWriter(Class<? extends IFormatWriter> c) {
for (int i=0; i<writers.length; i++) {
if (writers[i].getClass().equals(c)) return writers[i];
}
return null;
}
/** Gets all constituent file format writers. */
public IFormatWriter[] getWriters() {
IFormatWriter[] w = new IFormatWriter[writers.length];
System.arraycopy(writers, 0, w, 0, writers.length);
return w;
}
// -- IFormatWriter API methods --
/* @see IFormatWriter#changeOutputFile(String) */
@Override
public void changeOutputFile(String id) throws FormatException, IOException {
getWriter().changeOutputFile(id);
}
/* @see IFormatWriter#saveBytes(int, byte[]) */
@Override
public void saveBytes(int no, byte[] buf) throws FormatException, IOException
{
getWriter().saveBytes(no, buf);
}
/* @see IFormatWriter#saveBytes(int, byte[], int, int, int, int) */
@Override
public void saveBytes(int no, byte[] buf, int x, int y, int w, int h)
throws FormatException, IOException
{
getWriter().saveBytes(no, buf, x, y, w, h);
}
/* @see IFormatWriter#saveBytes(int, byte[], Region) */
@Override
public void saveBytes(int no, byte[] buf, Region tile)
throws FormatException, IOException
{
getWriter().saveBytes(no, buf, tile);
}
/* @see IFormatWriter#savePlane(int, Object) */
@Override
public void savePlane(int no, Object plane)
throws FormatException, IOException
{
getWriter().savePlane(no, plane);
}
/* @see IFormatWriter#savePlane(int, Object, int, int, int, int) */
@Override
public void savePlane(int no, Object plane, int x, int y, int w, int h)
throws FormatException, IOException
{
getWriter().savePlane(no, plane, x, y, w, h);
}
/* @see IFormatWriter#savePlane(int, Object, Region) */
@Override
public void savePlane(int no, Object plane, Region tile)
throws FormatException, IOException
{
getWriter().savePlane(no, plane, tile);
}
/* @see IFormatWriter#setSeries(int) */
@Override
public void setSeries(int series) throws FormatException {
getWriter().setSeries(series);
}
/* @see IFormatWriter#getSeries() */
@Override
public int getSeries() {
return getWriter().getSeries();
}
/* @see IFormatWriter#setInterleaved(boolean) */
@Override
public void setInterleaved(boolean interleaved) {
for (int i=0; i<writers.length; i++) writers[i].setInterleaved(interleaved);
}
/* @see IFormatWriter#isInterleaved() */
@Override
public boolean isInterleaved() {
// NB: all writers should have the same interleaved status
return writers[0].isInterleaved();
}
/* @see IFormatWriter#setValidBitsPerPixel(int) */
@Override
public void setValidBitsPerPixel(int bits) {
for (IFormatWriter writer : writers) {
writer.setValidBitsPerPixel(bits);
}
}
/* @see IFormatWriter#canDoStacks() */
@Override
public boolean canDoStacks() {
return getWriter().canDoStacks();
}
/* @see IFormatWriter#setMetadataRetrieve(MetadataRetrieve) */
@Override
public void setMetadataRetrieve(MetadataRetrieve r) {
for (int i=0; i<writers.length; i++) writers[i].setMetadataRetrieve(r);
}
/* @see IFormatReader#getMetadataStore() */
@Override
public MetadataRetrieve getMetadataRetrieve() {
return getWriter().getMetadataRetrieve();
}
/* @see IFormatWriter#setColorModel(ColorModel) */
@Override
public void setColorModel(ColorModel cm) {
for (int i=0; i<writers.length; i++) writers[i].setColorModel(cm);
}
/* @see IFormatWriter#getColorModel() */
@Override
public ColorModel getColorModel() {
// NB: all writers should have the same color model
return writers[0].getColorModel();
}
/* @see IFormatWriter#setFramesPerSecond(int) */
@Override
public void setFramesPerSecond(int rate) {
for (int i=0; i<writers.length; i++) writers[i].setFramesPerSecond(rate);
}
/* @see IFormatWriter#getFramesPerSecond() */
@Override
public int getFramesPerSecond() {
// NB: all writers should have the same frames per second
return writers[0].getFramesPerSecond();
}
/* @see IFormatWriter#getCompressionTypes() */
@Override
public String[] getCompressionTypes() {
if (compressionTypes == null) {
HashSet<String> set = new HashSet<String>();
for (int i=0; i<writers.length; i++) {
String[] s = writers[i].getCompressionTypes();
if (s != null) {
for (int j=0; j<s.length; j++) set.add(s[j]);
}
}
compressionTypes = new String[set.size()];
set.toArray(compressionTypes);
Arrays.sort(compressionTypes);
}
return compressionTypes;
}
/* @see IFormatWriter#getPixelTypes() */
@Override
public int[] getPixelTypes() {
return getWriter().getPixelTypes();
}
/* @see IFormatWriter#getPixelTypes(String) */
@Override
public int[] getPixelTypes(String codec) {
return getWriter().getPixelTypes(codec);
}
/* @see IFormatWriter#isSupportedType(int) */
@Override
public boolean isSupportedType(int type) {
return getWriter().isSupportedType(type);
}
/* @see IFormatWriter#setCompression(String) */
@Override
public void setCompression(String compress) throws FormatException {
boolean ok = false;
for (int i=0; i<writers.length; i++) {
String[] s = writers[i].getCompressionTypes();
if (s == null) continue;
for (int j=0; j<s.length; j++) {
if (s[j].equals(compress)) {
// valid compression type for this format
writers[i].setCompression(compress);
ok = true;
}
}
}
if (!ok) throw new FormatException("Invalid compression type: " + compress);
}
/* @see IFormatWriter#getCompression() */
@Override
public String getCompression() {
return getWriter().getCompression();
}
/* @see IFormatWriter#setWriteSequentially(boolean) */
@Override
public void setWriteSequentially(boolean sequential) {
for (IFormatWriter writer : writers) {
writer.setWriteSequentially(sequential);
}
}
/* @see IFormatWriter#setCodecOptions(CodecOptions) */
@Override
public void setCodecOptions(CodecOptions options) {
getWriter().setCodecOptions(options);
}
// -- IFormatHandler API methods --
/* @see IFormatHandler#isThisType(String) */
@Override
public boolean isThisType(String name) {
for (int i=0; i<writers.length; i++) {
if (writers[i].isThisType(name)) return true;
}
return false;
}
/* @see IFormatHandler#getFormat() */
@Override
public String getFormat() { return getWriter().getFormat(); }
/* @see IFormatHandler#getSuffixes() */
@Override
public String[] getSuffixes() {
if (suffixes == null) {
HashSet<String> suffixSet = new HashSet<String>();
for (int i=0; i<writers.length; i++) {
String[] suf = writers[i].getSuffixes();
for (int j=0; j<suf.length; j++) suffixSet.add(suf[j]);
}
suffixes = new String[suffixSet.size()];
suffixSet.toArray(suffixes);
Arrays.sort(suffixes);
}
return suffixes;
}
/* @see IFormatHandler#getNativeDataType() */
@Override
public Class<?> getNativeDataType() {
return getWriter().getNativeDataType();
}
/* @see IFormatHandler#setId(String) */
@Override
public void setId(String id) throws FormatException, IOException {
getWriter(id).setId(id);
}
/* @see IFormatHandler#close() */
@Override
public void close() throws IOException {
getWriter().close();
}
}