/* * Copyright (C) 2015 by Array Systems Computing Inc. http://www.array.ca * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 3 of the License, or (at your option) * any later version. * This program 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 General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, see http://www.gnu.org/licenses/ */ package org.esa.s1tbx.io.imageio; import com.bc.ceres.core.ProgressMonitor; import org.esa.snap.core.dataio.AbstractProductWriter; import org.esa.snap.core.dataio.ProductWriterPlugIn; import org.esa.snap.core.datamodel.Band; import org.esa.snap.core.datamodel.MetadataElement; import org.esa.snap.core.datamodel.ProductData; import org.esa.snap.core.datamodel.ProductNode; import org.esa.snap.core.datamodel.VirtualBand; import org.esa.snap.engine_utilities.datamodel.AbstractMetadata; import org.esa.snap.engine_utilities.datamodel.metadata.AbstractMetadataIO; import org.esa.snap.engine_utilities.gpf.ReaderUtils; import javax.imageio.IIOImage; import javax.imageio.ImageIO; import javax.imageio.ImageWriteParam; import javax.imageio.ImageWriter; import javax.imageio.stream.ImageOutputStream; import javax.media.jai.PlanarImage; import javax.media.jai.RasterFactory; import java.awt.*; import java.awt.image.BufferedImage; import java.awt.image.ColorModel; import java.awt.image.DataBuffer; import java.awt.image.DataBufferInt; import java.awt.image.RenderedImage; import java.awt.image.SampleModel; import java.awt.image.WritableRaster; import java.io.File; import java.io.IOException; import java.util.Hashtable; import java.util.Iterator; public class ImageIOWriter extends AbstractProductWriter { private File file; private ImageOutputStream _outputStream; private ImageWriter writer; private String format = ""; private int[] dataArray = null; private int pos = 0; /** * Construct a new instance of a product writer for the given product writer plug-in. * * @param writerPlugIn the given product writer plug-in, must not be <code>null</code> */ public ImageIOWriter(final ProductWriterPlugIn writerPlugIn) { super(writerPlugIn); } /** * Overwrite this method to set the format to write for writers which handle multiple formats. */ public void setFormatName(final String formatName) { format = formatName; } /** * Writes the in-memory representation of a data product. This method was called by <code>writeProductNodes(product, * output)</code> of the AbstractProductWriter. * * @throws IllegalArgumentException if <code>output</code> type is not one of the supported output sources. * @throws java.io.IOException if an I/O error occurs */ @Override protected void writeProductNodesImpl() throws IOException { _outputStream = null; file = ReaderUtils.getFileFromInput(getOutput()); // ensure extension //todo this should not be done here if (!file.getName().toLowerCase().endsWith(format.toLowerCase())) { file = new File(file.getAbsolutePath() + '.' + format.toLowerCase()); } final Iterator<ImageWriter> writerList = ImageIO.getImageWritersBySuffix(format); writer = writerList.next(); if(!file.getParentFile().exists()) { file.getParentFile().mkdirs(); } _outputStream = ImageIO.createImageOutputStream(file); writer.setOutput(_outputStream); final MetadataElement absRoot = AbstractMetadata.getAbstractedMetadata(getSourceProduct()); AbstractMetadataIO.saveExternalMetadata(getSourceProduct(), absRoot, file); setIncrementalMode(false); } /** * {@inheritDoc} */ public void writeBandRasterData(final Band sourceBand, final int sourceOffsetX, final int sourceOffsetY, final int sourceWidth, final int sourceHeight, final ProductData sourceBuffer, ProgressMonitor pm) throws IOException { try { final ImageWriteParam param = writer.getDefaultWriteParam(); final boolean canWriteTiles = param.canWriteTiles(); /* if(canWriteTiles) { param.setTilingMode(ImageWriteParam.MODE_EXPLICIT); //param.setDestinationOffset(new Point(sourceOffsetX, sourceOffsetY)); param.setSourceRegion(new Rectangle(sourceOffsetX, sourceOffsetY, sourceWidth, sourceHeight)); param.setTiling(sourceWidth, sourceHeight, sourceOffsetX, sourceOffsetY); writer.write(null, new IIOImage(sourceBand.getSourceImage(), null, null), param); } else { if(dataArray == null) { dataArray = new int[sourceBand.getRasterWidth() * sourceBand.getRasterHeight()]; } final int num = sourceBuffer.getNumElems(); for(int i=0; i < num; ++i) { dataArray[pos++] = (short)sourceBuffer.getElemIntAt(i); } */ if (sourceHeight == sourceBand.getRasterHeight() || sourceOffsetY == sourceBand.getRasterHeight() - 1) { /* RenderedImage img = createRenderedImage(dataArray, sourceBand.getRasterWidth(), sourceBand.getRasterHeight()); //writer.write(img); //writer.write(null, new IIOImage(img, null, null), param); //ImageIO.write(img, format, file); */ writer.write(null, new IIOImage(sourceBand.getSourceImage(), null, null), param); } // } } catch (Exception e) { throw new IOException(e.getMessage()+ "\nTry using convertDataType to convert to UInt8 or a data type supported by the image format"); } } private static RenderedImage createRenderedImage(final int[] array, final int w, final int h) { // create rendered image with demension being width by height final SampleModel sampleModel = RasterFactory.createBandedSampleModel(DataBuffer.TYPE_INT, w, h, 1); final ColorModel colourModel = PlanarImage.createColorModel(sampleModel); final DataBufferInt dataBuffer = new DataBufferInt(array, array.length); final WritableRaster raster = RasterFactory.createWritableRaster(sampleModel, dataBuffer, new Point(0, 0)); return new BufferedImage(colourModel, raster, false, new Hashtable()); } /** * Deletes the physically representation of the given product from the hard disk. */ public void deleteOutput() { } /** * Writes all data in memory to disk. After a flush operation, the writer can be closed safely * * @throws java.io.IOException on failure */ public void flush() throws IOException { if (_outputStream != null) { _outputStream.flush(); } } /** * Closes all output streams currently open. * * @throws java.io.IOException on failure */ public void close() throws IOException { if (_outputStream != null) { _outputStream.flush(); _outputStream.close(); _outputStream = null; } if (writer != null) { writer.dispose(); } } /** * Returns wether the given product node is to be written. * * @param node the product node * @return <code>true</code> if so */ @Override public boolean shouldWrite(ProductNode node) { return !(node instanceof VirtualBand) && super.shouldWrite(node); } }