/* * Geotoolkit - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 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.coverage.wkb; import java.awt.geom.AffineTransform; import java.awt.image.DataBuffer; import java.awt.image.Raster; import java.awt.image.RenderedImage; import java.awt.image.SampleModel; import java.io.ByteArrayOutputStream; import java.io.DataOutput; import java.io.DataOutputStream; import java.io.IOException; import java.io.OutputStream; import org.geotoolkit.coverage.grid.GridCoverage2D; import org.geotoolkit.io.LEDataOutputStream; import org.geotoolkit.referencing.IdentifiedObjects; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.opengis.referencing.operation.MathTransform2D; import org.opengis.util.FactoryException; /** * WKB Raster Writer, used in postGIS 2 but can be used elsewhere. * * @author Johann Sorel (Geomatys) */ public class WKBRasterWriter { public WKBRasterWriter() { } /** * Reset values before new write call. */ public void reset(){ } /** * Encode given coverage in Postgis WKB. * * @param coverage : grid coverage 2d , not null * @return byte[] encoded image * @throws IOException */ public byte[] write(final GridCoverage2D coverage) throws IOException, FactoryException { final ByteArrayOutputStream out = new ByteArrayOutputStream(); write(coverage, out); return out.toByteArray(); } /** * Encode given coverage in Postgis WKB. * * @param coverage : grid coverage 2d , not null * @param stream : output stream to write in * @throws IOException */ public void write(final GridCoverage2D coverage, final OutputStream stream) throws IOException, FactoryException { write(coverage, stream, true); } /** * Encode given coverage in Postgis WKB. * * @param coverage : grid coverage 2d , not null * @param stream : output stream to write in * @param littleEndian : wanted value encoding * @throws IOException */ public void write(final GridCoverage2D coverage, final OutputStream stream, final boolean littleEndian) throws IOException, FactoryException { final CoordinateReferenceSystem crs = coverage.getCoordinateReferenceSystem2D(); final Integer srid = IdentifiedObjects.lookupEpsgCode(crs, true); if(srid == null){ throw new IOException("CoordinateReferenceSystem does not have an EPSG code."); } final MathTransform2D gridToCRS = coverage.getGridGeometry().getGridToCRS2D(); if(!(gridToCRS instanceof AffineTransform)){ throw new IOException("Coverage GridToCRS transform is not affine."); } final RenderedImage image = coverage.getRenderedImage(); write(image, (AffineTransform)gridToCRS, srid, stream); } /** * Encode given image in Postgis WKB. * * @param image : image , not null * @param gridToCRS : image grid to crs, can be null * @param srid : image srid * @return byte[] encoded image * @throws IOException */ public byte[] write(final RenderedImage image, final AffineTransform gridToCRS, final int srid) throws IOException { final ByteArrayOutputStream out = new ByteArrayOutputStream(); write(image, gridToCRS, srid, out); return out.toByteArray(); } /** * Encode given image in Postgis WKB. * * @param image : image , not null * @param gridToCRS : image grid to crs, can be null * @param srid : image srid * @return byte[] encoded image * @throws IOException */ public byte[] write(final Raster image, final AffineTransform gridToCRS, final int srid) throws IOException { final ByteArrayOutputStream out = new ByteArrayOutputStream(); write(image, gridToCRS, srid, out); return out.toByteArray(); } /** * Encode given image in Postgis WKB. * * @param image : image , not null * @param gridToCRS : image grid to crs, can be null * @param srid : image srid * @param stream : output stream to write in * @throws IOException */ public void write(final RenderedImage image, AffineTransform gridToCRS, final int srid, final OutputStream stream) throws IOException { write(image.getData(), gridToCRS, srid, stream, true); } /** * Encode given image in Postgis WKB. * * @param image : image , not null * @param gridToCRS : image grid to crs, can be null * @param srid : image srid * @param stream : output stream to write in * @throws IOException */ public void write(final Raster image, AffineTransform gridToCRS, final int srid, final OutputStream stream) throws IOException { write(image, gridToCRS, srid, stream, true); } /** * Encode given image in Postgis WKB. * * @param image : image , not null * @param gridToCRS : image grid to crs, can be null * @param srid : image srid * @param stream : output stream to write in * @param littleEndian : wanted value encoding * @throws IOException */ public void write(final Raster image, AffineTransform gridToCRS, final int srid, final OutputStream stream, final boolean littleEndian) throws IOException { if(gridToCRS == null){ gridToCRS = new AffineTransform(); } final DataOutput ds; if(littleEndian){ ds = new LEDataOutputStream(stream); }else{ ds = new DataOutputStream(stream); } final SampleModel sm = image.getSampleModel(); final Raster raster = image; final int nbBand = sm.getNumBands(); final int width = image.getWidth(); final int height = image.getHeight(); int databufferType = sm.getDataType(); if(databufferType == DataBuffer.TYPE_INT){ //special case, most image compression bands on single int when it would be byte if(sm.getSampleSize()[0] <= 8){ databufferType = DataBuffer.TYPE_BYTE; } } final int pixelType = WKBRasterConstants.getPixelType(databufferType); final int bytePerpixel = WKBRasterConstants.getNbBytePerPixel(pixelType); //endianess ds.write( littleEndian ? 1 : 0 ); //version, 0 for now ds.writeShort(0); //number of bands ds.writeShort(nbBand); //grid to crs ds.writeDouble(gridToCRS.getScaleX()); ds.writeDouble(gridToCRS.getScaleY()); ds.writeDouble(gridToCRS.getTranslateX()); ds.writeDouble(gridToCRS.getTranslateY()); ds.writeDouble(gridToCRS.getShearX()); ds.writeDouble(gridToCRS.getShearY()); //write srid ds.writeInt(srid); //width and height ds.writeShort(width); ds.writeShort(height); //write each band for(int b=0;b<nbBand;b++){ // band description final byte flags = (byte) pixelType; // OffDatabase = false // TODO HasNodata : we don't have informations for no data // this would requiere a SampleDimension object // IsNodata = false // Reserved = false ds.write(flags); // TODO no data value ds.write(new byte[bytePerpixel]); //write values for(int y=raster.getMinY(),maxy=raster.getMinY()+height;y<maxy;y++){ for(int x=raster.getMinX(),maxx=raster.getMinX()+width;x<maxx;x++){ switch(databufferType){ case DataBuffer.TYPE_BYTE : ds.writeByte( (byte)raster.getSample(x, y, b)); break; case DataBuffer.TYPE_SHORT : ds.writeShort( (short)raster.getSample(x, y, b)); break; case DataBuffer.TYPE_USHORT : ds.writeShort( (short)raster.getSample(x, y, b)); break; case DataBuffer.TYPE_INT : ds.writeInt( raster.getSample(x, y, b)); break; case DataBuffer.TYPE_FLOAT : ds.writeFloat( raster.getSampleFloat(x, y, b)); break; case DataBuffer.TYPE_DOUBLE : ds.writeDouble( raster.getSampleDouble(x, y, b)); break; } } } } } }