Suppose I manually created pixel values for more than 4 bands and I want to store them in a tiff file.
Those bands can be for R, G, B, temperature (values of temperature are not in the range of 0 to 255 thus I am using int instead of byte for pexils), etc. i.e. any information that can be taken from the satellite
Now I want to save those pixels to a tiff file. In java there is a BufferedImage class which has many types like: TYPE_4BYTE_ABGR, TYPE_BYTE_GRAY, etc. However none of them for multi bands more than 4 bands. There is TYPE_CUSTOM but when specifying it and trying to save the data to a Tiff file it gives you an exception because it is not supported for write operation (only for read operation i.e. it can read the file and set the type to TYPE_CUSTOM if it didn't understand the type but it can not write the file in a not understood type).
The below code worked for 3 bands even not properly (it doesn't show colored image and it looked like a distorted image with missing lines) but for more than 4 bands how can I do that?
ImageOutputStream ios = ImageIO.createImageOutputStream(os);
Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("tiff");
ImageWriter writer = writers.next();
writer.setOutput(ios);
int index = 0;
int[] pixels = new int[width*height*numberOfBands];
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
for (int k = 0; k < numberOfBands; k++) {
pixels[index++] = //any values;
}
}
}
DataBuffer dataBuffer = new DataBufferInt(pixels, pixels.length);
// Create Raster
WritableRaster writableRaster = Raster.createBandedRaster
(dataBuffer, width, height,
width, // scanlineStride
new int[numberOfBands], // bankIndices,
new int[numberOfBands], // bandOffsets,
null); // location
// Create the image
BufferedImage bufferedImage = new BufferedImage
(width, height, BufferedImage.TYPE_BYTE_RGB);
bufferedImage.setData(writableRaster);
IIOImage iioImage = new IIOImage(bufferedImage, null, null);
ImageWriteParam param = writer.getDefaultWriteParam();
writer.write(null, iioImage, param);
I am using GeoTools by the way
Edited: According to @iant I changed the code but it is giving blank transparent background only, even I kept the same number of bands i.e. 3 bands. @iant Could you check the code below.
package examples;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.IOException;
import javax.media.jai.RasterFactory;
import org.geotools.coverage.CoverageFactoryFinder;
import org.geotools.coverage.grid.GridCoordinates2D;
import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.coverage.grid.GridCoverageFactory;
import org.geotools.coverage.grid.GridEnvelope2D;
import org.geotools.coverage.grid.GridGeometry2D;
import org.geotools.coverage.grid.io.AbstractGridFormat;
import org.geotools.coverage.grid.io.OverviewPolicy;
import org.geotools.gce.geotiff.GeoTiffFormat;
import org.geotools.gce.geotiff.GeoTiffReader;
import org.opengis.coverage.grid.GridCoverageWriter;
import org.opengis.parameter.GeneralParameterValue;
import org.opengis.parameter.ParameterValue;
public class CreateTiffImageTest2 {
public static void main(String[] args) throws IOException {
File file = new File("/home/mosab/Desktop/input/tif.tif");
ParameterValue<OverviewPolicy> policy = AbstractGridFormat.OVERVIEW_POLICY.createValue();
policy.setValue(OverviewPolicy.IGNORE);
ParameterValue<String> gridsize = AbstractGridFormat.SUGGESTED_TILE_SIZE.createValue();
ParameterValue<Boolean> useJaiRead = AbstractGridFormat.USE_JAI_IMAGEREAD.createValue();
useJaiRead.setValue(true);
GeoTiffReader geoTiffReader = new GeoTiffReader(file);
GridCoverage2D cov = geoTiffReader.read(new GeneralParameterValue[] { policy, gridsize, useJaiRead });
GridGeometry2D geometry = cov.getGridGeometry();
GridEnvelope2D gridEnvelope = geometry.getGridRange2D();
int w = (int) gridEnvelope.getWidth();
int h = (int) gridEnvelope.getHeight();
WritableRaster writableRaster = RasterFactory.createBandedRaster(java.awt.image.DataBuffer.TYPE_DOUBLE, w, h, 3,
null);
double[] data = new double[3];
double[] dest = new double[3];
for (int i = 0; i < w; i++) {
for (int j = 0; j < h; j++) {
GridCoordinates2D coord = new GridCoordinates2D(i, j);
cov.evaluate(coord, dest);
data[0] = dest[0];
data[1] = dest[1];
data[2] = dest[2];
writableRaster.setPixel(i, j, data);
}
float perc = 100.0f * i / w;
if (i % 100 == 0) {
System.out.println("done " + perc);
}
}
// Wrap the raster as a Coverage
GridCoverageFactory factory = CoverageFactoryFinder.getGridCoverageFactory(null);
GridCoverage2D gc = factory.create("name", writableRaster, cov.getEnvelope());
File out = new File("/home/mosab/Desktop/input/tifgen.tif");
GeoTiffFormat format = new GeoTiffFormat();
GridCoverageWriter writer = format.getWriter(out);
try {
writer.write(gc, null);
writer.dispose();
} catch (IllegalArgumentException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Update 2:
import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.media.jai.RasterFactory;
import org.geotools.coverage.CoverageFactoryFinder;
import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.coverage.grid.GridCoverageFactory;
import org.geotools.coverage.grid.io.AbstractGridFormat;
import org.geotools.coverage.grid.io.GridFormatFinder;
import org.geotools.factory.Hints;
import org.geotools.gce.geotiff.GeoTiffFormat;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.referencing.CRS;
import org.opengis.coverage.grid.GridCoverageWriter;
import org.opengis.geometry.MismatchedDimensionException;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.NoSuchAuthorityCodeException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
public class Test2 {
public static void print(Object o) {
System.out.println(o);
}
public static void main(String[] args)
throws MismatchedDimensionException, NoSuchAuthorityCodeException, FactoryException, IOException {
File out = new File("/home/mosab/Desktop/input/1.tif");
BufferedImage img = ImageIO.read(out);
// ColorModel colorModel = img.getColorModel(
WritableRaster raster = img.getRaster();
int w = img.getWidth();
int h = img.getHeight();
print("width = " + w);
print("heigh = " + h);
int numBands = raster.getNumBands();
WritableRaster writableRaster = RasterFactory.createBandedRaster(java.awt.image.DataBuffer.TYPE_INT, w, h, 3,
null);
//as I said pixels are created manually but I used here pixels from an image to check the approach
int[] data = new int[3];
for (int i = 0; i < w; i++) {
for (int j = 0; j < h; j++) {
for (int k = 0; k < numBands; k++) {
data[k] = raster.getSample(i, j, k);
}
writableRaster.setPixel(i, j, data);
}
}
GridCoverageFactory factory = CoverageFactoryFinder.getGridCoverageFactory(null);
CoordinateReferenceSystem crs = CRS.decode("EPSG:27700");
int llx = 500000;
int lly = 105000;
ReferencedEnvelope referencedEnvelope = new ReferencedEnvelope(llx, llx + (w * 10), lly, lly + (h * 10), crs);
GridCoverage2D gc = factory.create("name", writableRaster, referencedEnvelope);
AbstractGridFormat format = GridFormatFinder.findFormat(out);
Hints hints = null;
if (format instanceof GeoTiffFormat) {
hints = new Hints(Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER, Boolean.TRUE);
}
File out1 = new File("/home/mosab/Desktop/input/tifgen.tif");
GridCoverageWriter writer = format.getWriter(out1);
try {
writer.write(gc, null);
writer.dispose();
} catch (IllegalArgumentException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Notice: I used int type and an array of size 3 because the original image has RGB bands.