/*
* Geotoolkit.org - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2007-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.plugin;
import java.io.BufferedWriter;
import java.io.IOException;
import java.text.FieldPosition;
import java.text.NumberFormat;
import java.util.Locale;
import javax.imageio.IIOImage;
import javax.imageio.ImageWriter;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.spi.ImageWriterSpi;
import javax.imageio.metadata.IIOMetadata;
import javax.media.jai.iterator.RectIter;
import org.apache.sis.util.CharSequences;
import org.geotoolkit.image.ImageDimension;
import org.geotoolkit.image.io.TextImageWriter;
import org.geotoolkit.resources.Descriptions;
/**
* An image encoder for matrix of floating-point numbers. The sample values are formatted by an
* {@link NumberFormat} instance. Consequently the format is locale-dependent, unless the locale
* is explicitly specified either in the <cite>Service Provider Interface</cite> ({@link Spi#locale})
* or by overriding the {@link #getDataLocale(ImageWriteParam)} method.
* <p>
* This format is typically used for writing one-banded image. However if an image with more than
* one band is to be written, then each band is separated by a blank line in the output stream.
*
* @author Martin Desruisseaux (IRD)
* @version 3.08
*
* @see TextMatrixImageReader
*
* @since 3.08 (derived from 1.2)
* @module
*/
public class TextMatrixImageWriter extends TextImageWriter {
/**
* Amount of spaces to put between columns.
*/
private static final int SEPARATOR_WIDTH = 1;
/**
* Constructs a new image writer.
*
* @param provider The {@link ImageWriterSpi} that is constructing this object, or {@code null}.
*/
protected TextMatrixImageWriter(final Spi provider) {
super(provider);
}
/**
* Appends a complete image stream containing a single image.
*
* @param streamMetadata The stream metadata (ignored in default implementation).
* @param image The image or raster to be written.
* @param parameters The write parameters, or null if the whole image will be written.
* @throws IOException If an error occurred while writing to the stream.
*/
@Override
public void write(final IIOMetadata streamMetadata, final IIOImage image,
final ImageWriteParam parameters) throws IOException
{
processImageStarted();
final BufferedWriter out = getWriter(parameters);
final String lineSeparator = getLineSeparator(parameters);
final NumberFormat format = createNumberFormat(image, parameters);
final FieldPosition pos = getExpectedFractionPosition(format);
final int fractionWidth = pos.getEndIndex() - pos.getBeginIndex();
final int width = pos.getEndIndex() + SEPARATOR_WIDTH;
final StringBuffer buffer = new StringBuffer(width);
final RectIter iterator = createRectIter(image, parameters);
final ImageDimension size = computeSize(image, parameters);
final float progressScale = 100f / size.getNumSampleValues();
int numSampleValues = 0, nextProgress = 0;
boolean moreBands = false;
if (!iterator.finishedBands()) do {
if (moreBands) {
out.write(lineSeparator); // Separate bands by a blank line.
}
if (!iterator.finishedLines()) do {
if (numSampleValues >= nextProgress) {
// Informs about progress only every 2000 numbers.
processImageProgress(progressScale * numSampleValues);
nextProgress = numSampleValues + 2000;
}
if (abortRequested()) {
processWriteAborted();
return;
}
if (!iterator.finishedPixels()) do {
buffer.setLength(0);
String n = format.format(iterator.getSampleDouble(), buffer, pos).toString();
final int fractionOffset = Math.max(0, fractionWidth - (pos.getEndIndex() - pos.getBeginIndex()));
out.append(CharSequences.spaces(width - n.length() - fractionOffset));
out.write(n);
out.append(CharSequences.spaces(fractionOffset));
} while (!iterator.nextPixelDone());
out.write(lineSeparator);
numSampleValues += size.width;
iterator.startPixels();
} while (!iterator.nextLineDone());
iterator.startLines();
moreBands = true;
} while (!iterator.nextBandDone());
out.flush();
processImageComplete();
}
/**
* Service provider interface (SPI) for {@code TextMatrixImageWriter}s. This SPI provides
* necessary implementation for creating default {@link TextMatrixImageWriter} using default
* locale and character set. The default constructor initializes the fields to the values
* listed below:
* <p>
* <table border="1" cellspacing="0">
* <tr bgcolor="lightblue"><th>Field</th><th>Value</th></tr>
* <tr><td> {@link #names} </td><td> {@code "matrix"} </td></tr>
* <tr><td> {@link #MIMETypes} </td><td> {@code "text/plain"}, {@code "text/x-matrix"} </td></tr>
* <tr><td> {@link #pluginClassName} </td><td> {@code "org.geotoolkit.image.io.plugin.TextMatrixImageWriter"} </td></tr>
* <tr><td> {@link #vendorName} </td><td> {@code "Geotoolkit.org"} </td></tr>
* <tr><td> {@link #version} </td><td> Value of {@link org.geotoolkit.util.Version#GEOTOOLKIT} </td></tr>
* <tr><td colspan="2" align="center">See
* {@linkplain org.geotoolkit.image.io.TextImageWriter.Spi super-class javadoc} for remaining fields</td></tr>
* </table>
*
* @author Martin Desruisseaux (IRD, Geomatys)
* @version 3.20
*
* @see TextMatrixImageReader.Spi
*
* @since 3.08 (derived from 2.4)
* @module
*/
public static class Spi extends TextImageWriter.Spi {
/**
* The provider of the corresponding image reader.
*/
private static final String[] READERS = {"org.geotoolkit.image.io.plugin.TextMatrixImageReader$Spi"};
/**
* Constructs a default {@code TextMatrixImageWriter.Spi}. The fields are initialized as
* documented in the <a href="#skip-navbar_top">class javadoc</a>. Subclasses can modify
* those values if desired.
* <p>
* For efficiency reasons, the above fields are initialized to shared arrays. Subclasses
* can assign new arrays, but should not modify the default array content.
*/
public Spi() {
names = TextMatrixImageReader.Spi.NAMES;
MIMETypes = TextMatrixImageReader.Spi.MIME_TYPES;
pluginClassName = "org.geotoolkit.image.io.plugin.TextMatrixImageWriter";
readerSpiNames = READERS;
nativeStreamMetadataFormatName = null; // No stream metadata.
}
/**
* Returns a brief, human-readable description of this service provider
* and its associated implementation. The resulting string should be
* localized for the supplied locale, if possible.
*
* @param locale A Locale for which the return value should be localized.
* @return A String containing a description of this service provider.
*/
@Override
public String getDescription(final Locale locale) {
return Descriptions.getResources(locale).getString(Descriptions.Keys.CodecMatrix);
}
/**
* Checks if the specified image can be encoded in a text file.
* The default implementation returns {@code true} only if the image has only one band.
*
* @since 3.20
*/
@Override
public boolean canEncodeImage(final ImageTypeSpecifier type) {
return type.getNumBands() == 1;
}
/**
* Returns an instance of the {@code ImageWriter} implementation associated
* with this service provider.
*
* @param extension An optional extension object, which may be null.
* @return An image writer instance.
* @throws IOException if the attempt to instantiate the writer fails.
*/
@Override
public ImageWriter createWriterInstance(final Object extension) throws IOException {
return new TextMatrixImageWriter(this);
}
}
}