/*
* Geotoolkit.org - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2008-2012, Open Source Geospatial Foundation (OSGeo)
* (C) 2009-2012, Geomatys
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.geotoolkit.image.io.mosaic;
import java.io.File;
import java.awt.Color;
import java.awt.image.RenderedImage;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.awt.image.ComponentColorModel;
import javax.imageio.ImageWriteParam;
import org.opengis.coverage.PaletteInterpretation;
import org.geotoolkit.image.ImageWorker;
import static org.apache.sis.util.ArgumentChecks.*;
import org.geotoolkit.image.internal.SimpleBufferedImageOp;
/**
* The parameters for {@link MosaicImageWriter}.
*
* @author Martin Desruisseaux (Geomatys)
* @version 3.01
*
* @since 2.5
* @module
*/
public class MosaicImageWriteParam extends ImageWriteParam {
/**
* The index of the {@linkplain TileManager tile manager} to use in the array returned by
* {@link MosaicImageWriter#getOutput}.
*/
private int outputIndex = 0;
/**
* Controls the way {@link MosaicImageWriter} writes the tiles.
*/
private TileWritingPolicy policy = TileWritingPolicy.DEFAULT;
/**
* An optional operation to apply on source tiles before to create the mosaic.
*/
private BufferedImageOp sourceTileFilter;
/**
* Constructs an empty set of parameters.
*/
public MosaicImageWriteParam() {
}
/**
* Creates a new set of parameters with the same mosaic-specific parameters than the given
* one, and the default value for all other parameters.
* <p>
* This method is not public because for a public API, it would be cleaner to copy all
* parameters (as we usually expect from a copy constructor), while {@link MosaicImageWriter}
* really needs to copy only the mosaic-specific parameters and left the other ones to their
* default value.
*
* @param copy The parameters to copy.
*/
MosaicImageWriteParam(final MosaicImageWriteParam copy) {
outputIndex = copy.outputIndex;
policy = copy.policy;
}
/**
* Returns the index of the image to be written. This is the index of the
* {@linkplain TileManager tile manager} to use in the array returned by
* {@link MosaicImageWriter#getOutput}. The default value is 0.
*
* @return The index of the image to be written.
*/
public int getOutputIndex() {
return outputIndex;
}
/**
* Sets the index of the image to be written. This is the index of the
* {@linkplain TileManager tile manager} to use in the array returned by
* {@link MosaicImageWriter#getOutput}. The default value is 0.
*
* @param index The index of the image to be written.
*/
public void setOutputIndex(final int index) {
ensureBetween("index", 0, Tile.MASK, index);
outputIndex = index;
}
/**
* Returns whatever existing {@linkplain File files} should be skipped or overwritten.
* The default value is {@link TileWritingPolicy#OVERWRITE OVERWRITE}.
*
* @return The policy to apply when writing tiles.
*/
public TileWritingPolicy getTileWritingPolicy() {
return policy;
}
/**
* Sets whatever existing {@linkplain File files} should be skipped. The default behavior
* is to {@linkplain TileWritingPolicy#OVERWRITE overwrite} every files unconditionally.
* Settings the policy to {@link TileWritingPolicy#WRITE_NEWS_ONLY WRITE_NEWS_ONLY} may
* speedup {@link MosaicImageWriter} when the process of writing tiles is started again
* after a previous partial failure, by skipping the tiles that were successfully generated
* in the previous run.
*
* @param policy The policy to apply when writing tiles.
*/
public void setTileWritingPolicy(final TileWritingPolicy policy) {
ensureNonNull("policy", policy);
this.policy = policy;
}
/**
* Returns an optional operation to apply on source tiles before to create the mosaic.
*
* @return The operation to apply on source tiles, or {@code null} if none.
*
* @since 3.00
*/
public BufferedImageOp getSourceTileFilter() {
return sourceTileFilter;
}
/**
* Sets the operation to apply on source tiles before to create the mosaic. If an operation
* is given, then that operation will be applied on every source tiles and the result will
* be saved as RAW images in temporary files. The temporary files will be removed when the
* mosaic creation is finished.
*
* @param filter The operation to apply on source tiles, or {@code null} if none.
*
* @since 3.00
*/
public void setSourceTileFilter(final BufferedImageOp filter) {
sourceTileFilter = filter;
}
/**
* Sets the {@linkplain #setSourceTileFilter source tile filter} to an operation that
* replace the given set of opaque colors by fully transparent pixels. Only the colors
* in the neighbor of the tile borders are replaced, as described in the
* {@link org.geotoolkit.image.jai.SilhouetteMask} operation.
* <p>
* This method is appropriate only for {@linkplain ComponentColorModel component color model}
* in RGB color space. If the source images use a different color model or space, they will be
* converted.
*
* @param colors The border colors to make transparent. The colors are presumed opaque,
* i.e. alpha values are ignored.
*
* @since 3.00
*/
public void setOpaqueBorderFilter(final Color... colors) {
setSourceTileFilter(new BorderFilter(colors));
}
/**
* An operation that replace opaque color by fully transparent pixels.
*
* @author Martin Desruisseaux (Geomatys)
* @version 3.01
*
* @since 3.00
* @module
*/
private static final class BorderFilter extends SimpleBufferedImageOp {
/**
* For cross-version compatibility.
*/
private static final long serialVersionUID = 890880010471839924L;
/**
* The opaque border color to make transparent.
*/
private final Color[] colors;
/**
* Creates a new filter for the given opaque border colors to make transparent.
*/
BorderFilter(final Color[] colors) {
this.colors = colors.clone();
}
/**
* Applies the filter, which replace opaque border colors by fully transparent pixels.
* This operation works only on component color model using RGB color space
*/
@Override
@SuppressWarnings("fallthrough")
public RenderedImage filter(final BufferedImage src) {
final ImageWorker worker = new ImageWorker(src);
worker.setColorSpaceType(PaletteInterpretation.RGB);
worker.setColorModelType(ComponentColorModel.class);
final double[][] RGBs = new double[colors.length][worker.getNumBands()];
for (int i=0; i<RGBs.length; i++) {
final Color color = colors[i];
final double[] RGB = RGBs[i];
switch (RGB.length) {
default: // Fall through in every cases.
case 4: RGB[3] = color.getAlpha();
case 3: RGB[2] = color.getBlue();
case 2: RGB[1] = color.getGreen();
case 1: RGB[0] = color.getRed();
case 0: break;
}
}
worker.maskBackground(RGBs, null);
return worker.getRenderedImage();
}
}
}