/*
* #%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.lang.reflect.InvocationTargetException;
import loci.common.Region;
import loci.formats.codec.CodecOptions;
import loci.formats.meta.MetadataRetrieve;
/**
* Abstract superclass of writer logic that wraps other writers.
* All methods are simply delegated to the wrapped writer.
*/
public abstract class WriterWrapper implements IFormatWriter {
// -- Fields --
/** FormatWriter used to write the file. */
protected IFormatWriter writer;
// -- Constructors --
/** Constructs a writer wrapper around a new image writer. */
public WriterWrapper() { this(new ImageWriter()); }
/** Constructs a writer wrapper around the given writer. */
public WriterWrapper(IFormatWriter w) {
if (w == null) {
throw new IllegalArgumentException("Format writer cannot be null");
}
writer = w;
}
// -- WriterWrapper API methods --
/** Gets the wrapped writer. */
public IFormatWriter getWriter() { return writer; }
/**
* Unwraps nested wrapped writers until the core writer (i.e., not
* a {@link WriterWrapper} or {@link ImageWriter}) is found.
*/
public IFormatWriter unwrap() throws FormatException, IOException {
return unwrap(null, null);
}
/**
* Unwraps nested wrapped writers until the core writer (i.e., not
* a {@link WriterWrapper} or {@link ImageWriter}) is found.
*
* @param id Id to use as a basis when unwrapping any nested
* {@link ImageWriter}s. If null, the current id is used.
*/
public IFormatWriter unwrap(String id)
throws FormatException, IOException
{
return unwrap(null, id);
}
/**
* Unwraps nested wrapped writers until the given writer class is found.
*
* @param writerClass Class of the desired nested writer. If null, the
* core writer (i.e., deepest wrapped writer) will be returned.
* @param id Id to use as a basis when unwrapping any nested
* {@link ImageWriter}s. If null, the current id is used.
*/
public IFormatWriter unwrap(Class<? extends IFormatWriter> writerClass,
String id) throws FormatException, IOException
{
IFormatWriter w = this;
while (w instanceof WriterWrapper || w instanceof ImageWriter) {
if (writerClass != null && writerClass.isInstance(w)) break;
if (w instanceof ImageWriter) {
ImageWriter iw = (ImageWriter) w;
w = id == null ? iw.getWriter() : iw.getWriter(id);
}
else w = ((WriterWrapper) w).getWriter();
}
if (writerClass != null && !writerClass.isInstance(w)) return null;
return w;
}
/**
* Performs a deep copy of the writer, including nested wrapped writers.
* Most of the writer state is preserved as well, including:<ul>
* <li>{@link #isInterleaved()}</li>
* <li>{@link #getColorModel()}</li>
* <li>{@link #getFramesPerSecond()}</li>
* <li>{@link #getCompression()}</li>
* </ul>
*
* @param imageWriterClass If non-null, any {@link ImageWriter}s in the
* writer stack will be replaced with instances of the given class.
* @throws FormatException If something goes wrong during the duplication.
*/
public WriterWrapper duplicate(
Class<? extends IFormatWriter> imageWriterClass) throws FormatException
{
WriterWrapper wrapperCopy = duplicateRecurse(imageWriterClass);
// sync top-level configuration with original writer
boolean interleaved = isInterleaved();
ColorModel cm = getColorModel();
int rate = getFramesPerSecond();
String compress = getCompression();
wrapperCopy.setInterleaved(interleaved);
wrapperCopy.setColorModel(cm);
wrapperCopy.setFramesPerSecond(rate);
wrapperCopy.setCompression(compress);
return wrapperCopy;
}
// -- IFormatWriter API methods --
@Override
public void changeOutputFile(String id) throws FormatException, IOException {
writer.changeOutputFile(id);
}
@Override
public void saveBytes(int no, byte[] buf) throws FormatException, IOException
{
writer.saveBytes(no, buf);
}
@Override
public void saveBytes(int no, byte[] buf, int x, int y, int w, int h)
throws FormatException, IOException
{
writer.saveBytes(no, buf, x, y, w, h);
}
@Override
public void saveBytes(int no, byte[] buf, Region tile)
throws FormatException, IOException
{
writer.saveBytes(no, buf, tile);
}
@Override
public void savePlane(int no, Object plane)
throws FormatException, IOException
{
writer.savePlane(no, plane);
}
@Override
public void savePlane(int no, Object plane, int x, int y, int w, int h)
throws FormatException, IOException
{
writer.savePlane(no, plane, x, y, w, h);
}
@Override
public void savePlane(int no, Object plane, Region tile)
throws FormatException, IOException
{
writer.savePlane(no, plane, tile);
}
@Override
public void setSeries(int series) throws FormatException {
writer.setSeries(series);
}
@Override
public int getSeries() {
return writer.getSeries();
}
@Override
public void setInterleaved(boolean interleaved) {
writer.setInterleaved(interleaved);
}
@Override
public boolean isInterleaved() {
return writer.isInterleaved();
}
@Override
public void setValidBitsPerPixel(int bits) {
writer.setValidBitsPerPixel(bits);
}
@Override
public boolean canDoStacks() {
return writer.canDoStacks();
}
@Override
public void setMetadataRetrieve(MetadataRetrieve r) {
writer.setMetadataRetrieve(r);
}
@Override
public MetadataRetrieve getMetadataRetrieve() {
return writer.getMetadataRetrieve();
}
@Override
public void setColorModel(ColorModel cm) {
writer.setColorModel(cm);
}
@Override
public ColorModel getColorModel() {
return writer.getColorModel();
}
@Override
public void setFramesPerSecond(int rate) {
writer.setFramesPerSecond(rate);
}
@Override
public int getFramesPerSecond() {
return writer.getFramesPerSecond();
}
@Override
public String[] getCompressionTypes() {
return writer.getCompressionTypes();
}
@Override
public int[] getPixelTypes() {
return writer.getPixelTypes();
}
@Override
public int[] getPixelTypes(String codec) {
return writer.getPixelTypes(codec);
}
@Override
public boolean isSupportedType(int type) {
return writer.isSupportedType(type);
}
@Override
public void setCompression(String compress) throws FormatException {
writer.setCompression(compress);
}
/* @see IFormatWriter#setCodecOptions(CodecOptions) */
@Override
public void setCodecOptions(CodecOptions options) {
writer.setCodecOptions(options);
}
@Override
public String getCompression() {
return writer.getCompression();
}
@Override
public void setWriteSequentially(boolean sequential) {
writer.setWriteSequentially(sequential);
}
// -- IFormatHandler API methods --
@Override
public boolean isThisType(String name) {
return writer.isThisType(name);
}
@Override
public String getFormat() {
return writer.getFormat();
}
@Override
public String[] getSuffixes() {
return writer.getSuffixes();
}
@Override
public Class<?> getNativeDataType() {
return writer.getNativeDataType();
}
@Override
public void setId(String id) throws FormatException, IOException {
writer.setId(id);
}
@Override
public void close() throws IOException {
writer.close();
}
// -- Helper methods --
private WriterWrapper duplicateRecurse(
Class<? extends IFormatWriter> imageWriterClass) throws FormatException
{
IFormatWriter childCopy = null;
if (writer instanceof WriterWrapper) {
// found a nested writer layer; duplicate via recursion
childCopy = ((WriterWrapper) writer).duplicateRecurse(imageWriterClass);
}
else {
Class<? extends IFormatWriter> c = null;
if (writer instanceof ImageWriter) {
// found an image writer; if given, substitute the writer class
c = imageWriterClass == null ? ImageWriter.class : imageWriterClass;
}
else {
// bottom of the writer stack; duplicate the core writer
c = writer.getClass();
}
try {
childCopy = (IFormatWriter) c.newInstance();
}
catch (IllegalAccessException exc) { throw new FormatException(exc); }
catch (InstantiationException exc) { throw new FormatException(exc); }
}
// use crazy reflection to instantiate a writer of the proper type
Class<? extends WriterWrapper> wrapperClass = getClass();
WriterWrapper wrapperCopy = null;
try {
wrapperCopy = wrapperClass.getConstructor(new Class[]
{IFormatWriter.class}).newInstance(new Object[] {childCopy});
}
catch (InstantiationException exc) { throw new FormatException(exc); }
catch (IllegalAccessException exc) { throw new FormatException(exc); }
catch (NoSuchMethodException exc) { throw new FormatException(exc); }
catch (InvocationTargetException exc) { throw new FormatException(exc); }
return wrapperCopy;
}
}