protected double[] getMinMax(BufferWrapper elevations, double missingDataSignal) { double min = Double.MAX_VALUE; double max = -Double.MAX_VALUE; for (int i = 0; i < elevations.length(); i++) { double value = elevations.getDouble(i); if (value != missingDataSignal) { min = Math.min(min, elevations.getDouble(i)); max = Math.max(max, elevations.getDouble(i)); } } if (min < minElevationClamp) min = minElevationClamp; if (max > maxElevationClamp) max = maxElevationClamp; /*if (min == Double.MAX_VALUE || max == -Double.MAX_VALUE) { Logging.logger().warning("No elevations found in tile"); }*/ return new double[] {min, max}; }
public void writeRaster(BufferWrapperRaster raster) throws IOException, IllegalArgumentException { if (raster == null) { String msg = Logging.getMessage("nullValue.RasterIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } if (0 == raster.getWidth() || 0 == raster.getHeight()) { String msg = Logging.getMessage("generic.InvalidImageSize", raster.getWidth(), raster.getHeight()); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } this.validateParameters(raster, raster.getWidth(), raster.getHeight()); int bitsPerSample, samplesPerPixel, sampleFormat, photometric, numBands; if (AVKey.ELEVATION.equals(raster.getValue(AVKey.PIXEL_FORMAT))) { if (AVKey.FLOAT32.equals(raster.getValue(AVKey.DATA_TYPE))) { numBands = 1; samplesPerPixel = Tiff.SamplesPerPixel.MONOCHROME; sampleFormat = Tiff.SampleFormat.IEEEFLOAT; photometric = Tiff.Photometric.Grayscale_BlackIsZero; bitsPerSample = Tiff.BitsPerSample.ELEVATIONS_FLOAT32; } else if (AVKey.INT16.equals(raster.getValue(AVKey.DATA_TYPE))) { numBands = 1; samplesPerPixel = Tiff.SamplesPerPixel.MONOCHROME; sampleFormat = Tiff.SampleFormat.SIGNED; photometric = Tiff.Photometric.Grayscale_BlackIsZero; bitsPerSample = Tiff.BitsPerSample.ELEVATIONS_INT16; } else { String msg = Logging.getMessage("GeotiffWriter.UnsupportedType", raster.getValue(AVKey.DATA_TYPE)); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } } else if (AVKey.IMAGE.equals(raster.getValue(AVKey.PIXEL_FORMAT))) { if (AVKey.INT8.equals(raster.getValue(AVKey.DATA_TYPE))) { numBands = 1; samplesPerPixel = Tiff.SamplesPerPixel.MONOCHROME; sampleFormat = Tiff.SampleFormat.UNSIGNED; photometric = Tiff.Photometric.Grayscale_BlackIsZero; bitsPerSample = Tiff.BitsPerSample.MONOCHROME_UINT8; } else if (AVKey.INT16.equals(raster.getValue(AVKey.DATA_TYPE))) { numBands = 1; samplesPerPixel = Tiff.SamplesPerPixel.MONOCHROME; sampleFormat = Tiff.SampleFormat.UNSIGNED; photometric = Tiff.Photometric.Grayscale_BlackIsZero; bitsPerSample = Tiff.BitsPerSample.MONOCHROME_UINT16; } else if (AVKey.INT32.equals(raster.getValue(AVKey.DATA_TYPE))) { numBands = 3; // TODO check ALPHA / Transparency samplesPerPixel = Tiff.SamplesPerPixel.RGB; sampleFormat = Tiff.SampleFormat.UNSIGNED; photometric = Tiff.Photometric.Color_RGB; bitsPerSample = Tiff.BitsPerSample.RGB; } else { String msg = Logging.getMessage("GeotiffWriter.UnsupportedType", raster.getValue(AVKey.DATA_TYPE)); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } } else { String msg = Logging.getMessage("GeotiffWriter.UnsupportedType", raster.getValue(AVKey.PIXEL_FORMAT)); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } int bytesPerSample = numBands * bitsPerSample / Byte.SIZE; this.writeTiffHeader(); // write the image data... int numRows = raster.getHeight(); int numCols = raster.getWidth(); int[] stripCounts = new int[numRows]; int[] stripOffsets = new int[numRows]; BufferWrapper srcBuffer = raster.getBuffer(); ByteBuffer dataBuff = ByteBuffer.allocateDirect(numCols * bytesPerSample); switch (bitsPerSample) { // case Tiff.BitsPerSample.MONOCHROME_BYTE: case Tiff.BitsPerSample.MONOCHROME_UINT8: { for (int y = 0; y < numRows; y++) { stripOffsets[y] = (int) this.theChannel.position(); stripCounts[y] = numCols * bytesPerSample; dataBuff.clear(); for (int x = 0; x < numCols * numBands; x++) { dataBuff.put(srcBuffer.getByte(x + y * numCols)); } dataBuff.flip(); this.theChannel.write(dataBuff); } } break; // case Tiff.BitsPerSample.MONOCHROME_UINT16: case Tiff.BitsPerSample.ELEVATIONS_INT16: { for (int y = 0; y < numRows; y++) { stripOffsets[y] = (int) this.theChannel.position(); stripCounts[y] = numCols * bytesPerSample; dataBuff.clear(); for (int x = 0; x < numCols * numBands; x++) { dataBuff.putShort(srcBuffer.getShort(x + y * numCols)); } dataBuff.flip(); this.theChannel.write(dataBuff); } } break; case Tiff.BitsPerSample.ELEVATIONS_FLOAT32: { for (int y = 0; y < numRows; y++) { stripOffsets[y] = (int) this.theChannel.position(); stripCounts[y] = numCols * bytesPerSample; dataBuff.clear(); for (int x = 0; x < numCols * numBands; x++) { dataBuff.putFloat(srcBuffer.getFloat(x + y * numCols)); } dataBuff.flip(); this.theChannel.write(dataBuff); } } break; case Tiff.BitsPerSample.RGB: { for (int y = 0; y < numRows; y++) { stripOffsets[y] = (int) this.theChannel.position(); stripCounts[y] = numCols * bytesPerSample; dataBuff.clear(); for (int x = 0; x < numCols; x++) { int color = srcBuffer.getInt(x + y * numCols); byte red = (byte) (0xFF & (color >> 16)); byte green = (byte) (0xFF & (color >> 8)); byte blue = (byte) (0xFF & color); // dataBuff.put(0xFF & (color >> 24)); // alpha dataBuff.put(red).put(green).put(blue); } dataBuff.flip(); this.theChannel.write(dataBuff); } } break; } // write out values for the tiff tags and build up the IFD. These are supposed to be sorted; for // now // do this manually here. ArrayList<TiffIFDEntry> ifds = new ArrayList<TiffIFDEntry>(10); ifds.add(new TiffIFDEntry(Tiff.Tag.IMAGE_WIDTH, Tiff.Type.LONG, 1, numCols)); ifds.add(new TiffIFDEntry(Tiff.Tag.IMAGE_LENGTH, Tiff.Type.LONG, 1, numRows)); long offset = this.theChannel.position(); if (Tiff.BitsPerSample.RGB == bitsPerSample) { short[] bps = new short[numBands]; for (int i = 0; i < numBands; i++) { bps[i] = Tiff.BitsPerSample.MONOCHROME_BYTE; } this.theChannel.write(ByteBuffer.wrap(this.getBytes(bps))); ifds.add(new TiffIFDEntry(Tiff.Tag.BITS_PER_SAMPLE, Tiff.Type.SHORT, numBands, offset)); } else ifds.add(new TiffIFDEntry(Tiff.Tag.BITS_PER_SAMPLE, Tiff.Type.SHORT, 1, bitsPerSample)); ifds.add(new TiffIFDEntry(Tiff.Tag.COMPRESSION, Tiff.Type.LONG, 1, Tiff.Compression.NONE)); ifds.add(new TiffIFDEntry(Tiff.Tag.PHOTO_INTERPRETATION, Tiff.Type.SHORT, 1, photometric)); ifds.add(new TiffIFDEntry(Tiff.Tag.SAMPLES_PER_PIXEL, Tiff.Type.SHORT, 1, samplesPerPixel)); ifds.add(new TiffIFDEntry(Tiff.Tag.ORIENTATION, Tiff.Type.SHORT, 1, Tiff.Orientation.DEFAULT)); ifds.add( new TiffIFDEntry( Tiff.Tag.PLANAR_CONFIGURATION, Tiff.Type.SHORT, 1, Tiff.PlanarConfiguration.CHUNKY)); ifds.add(new TiffIFDEntry(Tiff.Tag.SAMPLE_FORMAT, Tiff.Type.SHORT, 1, sampleFormat)); offset = this.theChannel.position(); dataBuff = ByteBuffer.allocateDirect(stripOffsets.length * INTEGER_SIZEOF); for (int stripOffset : stripOffsets) { dataBuff.putInt(stripOffset); } dataBuff.flip(); this.theChannel.write(dataBuff); ifds.add(new TiffIFDEntry(Tiff.Tag.STRIP_OFFSETS, Tiff.Type.LONG, stripOffsets.length, offset)); ifds.add(new TiffIFDEntry(Tiff.Tag.ROWS_PER_STRIP, Tiff.Type.LONG, 1, 1)); offset = this.theChannel.position(); dataBuff.clear(); // stripOffsets and stripCounts are same length by design; can reuse the // ByteBuffer... for (int stripCount : stripCounts) { dataBuff.putInt(stripCount); } dataBuff.flip(); this.theChannel.write(dataBuff); ifds.add( new TiffIFDEntry(Tiff.Tag.STRIP_BYTE_COUNTS, Tiff.Type.LONG, stripCounts.length, offset)); this.appendGeoTiff(ifds, raster); this.writeIFDs(ifds); }