private void writeGeographicImageGeoKeys(ArrayList<TiffIFDEntry> ifds, AVList params) throws IOException { long offset = this.theChannel.position(); if (isImage(params) && isGeographic(params)) { int epsg = GeoTiff.GCS.WGS_84; if (params.hasKey(AVKey.PROJECTION_EPSG_CODE)) epsg = (Integer) params.getValue(AVKey.PROJECTION_EPSG_CODE); short[] values = new short[] { // GeoKeyDirectory header GeoTiff.GeoKeyHeader.KeyDirectoryVersion, GeoTiff.GeoKeyHeader.KeyRevision, GeoTiff.GeoKeyHeader.MinorRevision, 0, // IMPORTANT!! we will update count below, after the array initialization // end of header - // geo keys array /* key 1 */ GeoTiff.GeoKey.ModelType, 0, 1, GeoTiff.ModelType.Geographic, /* key 2 */ GeoTiff.GeoKey.RasterType, 0, 1, (short) (0xFFFF & GeoTiff.RasterType.RasterPixelIsArea), /* key 3 */ GeoTiff.GeoKey.GeographicType, 0, 1, (short) (0xFFFF & epsg), /* key 4 */ GeoTiff.GeoKey.GeogAngularUnits, 0, 1, GeoTiff.Unit.Angular.Angular_Degree }; // IMPORTANT!! update count - number of geokeys values[3] = (short) (values.length / 4); byte[] bytes = this.getBytes(values); this.theChannel.write(ByteBuffer.wrap(bytes)); ifds.add( new TiffIFDEntry(GeoTiff.Tag.GEO_KEY_DIRECTORY, Tiff.Type.SHORT, values.length, offset)); } }
private void writeGeographicElevationGeoKeys(ArrayList<TiffIFDEntry> ifds, AVList params) throws IOException { long offset = this.theChannel.position(); if (isElevation(params) && isGeographic(params)) { int epsg = GeoTiff.GCS.WGS_84; if (params.hasKey(AVKey.PROJECTION_EPSG_CODE)) epsg = (Integer) params.getValue(AVKey.PROJECTION_EPSG_CODE); int elevUnits = GeoTiff.Unit.Linear.Meter; if (params.hasKey(AVKey.ELEVATION_UNIT)) { if (AVKey.UNIT_FOOT.equals(params.getValue(AVKey.ELEVATION_UNIT))) elevUnits = GeoTiff.Unit.Linear.Foot; } int rasterType = GeoTiff.RasterType.RasterPixelIsArea; if (params.hasKey(AVKey.RASTER_PIXEL) && AVKey.RASTER_PIXEL_IS_POINT.equals(params.getValue(AVKey.RASTER_PIXEL))) rasterType = GeoTiff.RasterType.RasterPixelIsPoint; short[] values = new short[] { // GeoKeyDirectory header GeoTiff.GeoKeyHeader.KeyDirectoryVersion, GeoTiff.GeoKeyHeader.KeyRevision, GeoTiff.GeoKeyHeader.MinorRevision, 0, // IMPORTANT!! we will update count below, after the array initialization // end of header - // geo keys array /* key 1 */ GeoTiff.GeoKey.ModelType, 0, 1, GeoTiff.ModelType.Geographic, /* key 2 */ // TODO: Replace GeoTiff.RasterType.RasterPixelIsPoint GeoTiff.GeoKey.RasterType, 0, 1, (short) (0xFFFF & rasterType), /* key 3 */ GeoTiff.GeoKey.GeographicType, 0, 1, (short) (0xFFFF & epsg), /* key 4 */ GeoTiff.GeoKey.GeogAngularUnits, 0, 1, GeoTiff.Unit.Angular.Angular_Degree, /* key 5 */ GeoTiff.GeoKey.VerticalCSType, 0, 1, GeoTiff.VCS.WGS_84_ellipsoid, /* key 6 */ GeoTiff.GeoKey.VerticalUnits, 0, 1, (short) (0xFFFF & elevUnits), }; // IMPORTANT!! update count - number of geokeys values[3] = (short) (values.length / 4); byte[] bytes = this.getBytes(values); this.theChannel.write(ByteBuffer.wrap(bytes)); ifds.add( new TiffIFDEntry(GeoTiff.Tag.GEO_KEY_DIRECTORY, Tiff.Type.SHORT, values.length, offset)); } }
private static boolean isGeographic(AVList params) { return (null != params && params.hasKey(AVKey.COORDINATE_SYSTEM) && AVKey.COORDINATE_SYSTEM_GEOGRAPHIC.equals(params.getValue(AVKey.COORDINATE_SYSTEM))); }
private static boolean isProjected(AVList params) { return (null != params && params.hasKey(AVKey.COORDINATE_SYSTEM) && AVKey.COORDINATE_SYSTEM_PROJECTED.equals(params.getValue(AVKey.COORDINATE_SYSTEM))); }
private static boolean isImage(AVList params) { return (null != params && params.hasKey(AVKey.PIXEL_FORMAT) && AVKey.IMAGE.equals(params.getValue(AVKey.PIXEL_FORMAT))); }
private static boolean isElevation(AVList params) { return (null != params && params.hasKey(AVKey.PIXEL_FORMAT) && AVKey.ELEVATION.equals(params.getValue(AVKey.PIXEL_FORMAT))); }
protected void validateParameters(AVList list, int srcWidth, int srcHeight) throws IllegalArgumentException { if (null == list || 0 == list.getValues().size()) { String reason = Logging.getMessage("nullValue.AVListIsNull"); String msg = Logging.getMessage("GeotiffWriter.GeoKeysMissing", reason); Logging.logger().finest(msg); throw new IllegalArgumentException(msg); } if (!(srcWidth > 0 && srcHeight > 0)) { String msg = Logging.getMessage("generic.InvalidImageSize", srcWidth, srcHeight); Logging.logger().finest(msg); throw new IllegalArgumentException(msg); } if (list.hasKey(AVKey.WIDTH)) { int width = (Integer) list.getValue(AVKey.WIDTH); if (width != srcWidth) { String msg = Logging.getMessage("GeotiffWriter.ImageWidthMismatch", width, srcWidth); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } } else list.setValue(AVKey.WIDTH, srcWidth); if (list.hasKey(AVKey.HEIGHT)) { int height = (Integer) list.getValue(AVKey.HEIGHT); if (height != srcHeight) { String msg = Logging.getMessage("GeotiffWriter.ImageHeightMismatch", height, srcHeight); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } } else list.setValue(AVKey.HEIGHT, srcHeight); Sector sector = null; if (list.hasKey(AVKey.SECTOR)) sector = (Sector) list.getValue(AVKey.SECTOR); if (null == sector) { String msg = Logging.getMessage("GeotiffWriter.NoSectorSpecified"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } if (!list.hasKey(AVKey.COORDINATE_SYSTEM)) { String msg = Logging.getMessage("GeotiffWriter.GeoKeysMissing", AVKey.COORDINATE_SYSTEM); Logging.logger().finest(msg); // throw new IllegalArgumentException(msg); // assume Geodetic Coordinate System list.setValue(AVKey.COORDINATE_SYSTEM, AVKey.COORDINATE_SYSTEM_GEOGRAPHIC); } if (!list.hasKey(AVKey.PROJECTION_EPSG_CODE)) { if (isGeographic(list)) { // assume WGS84 list.setValue(AVKey.PROJECTION_EPSG_CODE, GeoTiff.GCS.WGS_84); } else { String msg = Logging.getMessage("GeotiffWriter.GeoKeysMissing", AVKey.PROJECTION_EPSG_CODE); Logging.logger().finest(msg); throw new IllegalArgumentException(msg); } } // if PIXEL_WIDTH is specified, we are not overriding it because UTM images // will have different pixel size if (!list.hasKey(AVKey.PIXEL_WIDTH)) { if (isGeographic(list)) { double pixelWidth = sector.getDeltaLonDegrees() / (double) srcWidth; list.setValue(AVKey.PIXEL_WIDTH, pixelWidth); } else { String msg = Logging.getMessage("GeotiffWriter.GeoKeysMissing", AVKey.PIXEL_WIDTH); Logging.logger().finest(msg); throw new IllegalArgumentException(msg); } } // if PIXEL_HEIGHT is specified, we are not overriding it // because UTM images will have different pixel size if (!list.hasKey(AVKey.PIXEL_HEIGHT)) { if (isGeographic(list)) { double pixelHeight = sector.getDeltaLatDegrees() / (double) srcHeight; list.setValue(AVKey.PIXEL_HEIGHT, pixelHeight); } else { String msg = Logging.getMessage("GeotiffWriter.GeoKeysMissing", AVKey.PIXEL_HEIGHT); Logging.logger().finest(msg); throw new IllegalArgumentException(msg); } } if (!list.hasKey(AVKey.PIXEL_FORMAT)) { String msg = Logging.getMessage("GeotiffWriter.GeoKeysMissing", AVKey.PIXEL_FORMAT); Logging.logger().finest(msg); throw new IllegalArgumentException(msg); } else { String pixelFormat = list.getStringValue(AVKey.PIXEL_FORMAT); if (!AVKey.ELEVATION.equals(pixelFormat) && !AVKey.IMAGE.equals(pixelFormat)) { String msg = Logging.getMessage("Geotiff.UnknownGeoKeyValue", pixelFormat, AVKey.PIXEL_FORMAT); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } } // validate elevation parameters if (AVKey.ELEVATION.equals(list.getValue(AVKey.PIXEL_FORMAT))) { if (!list.hasKey(AVKey.DATA_TYPE)) { String msg = Logging.getMessage("GeotiffWriter.GeoKeysMissing", AVKey.DATA_TYPE); Logging.logger().finest(msg); throw new IllegalArgumentException(msg); } String type = list.getStringValue(AVKey.DATA_TYPE); if (!AVKey.FLOAT32.equals(type) && !AVKey.INT16.equals(type)) { String msg = Logging.getMessage("Geotiff.UnknownGeoKeyValue", type, AVKey.DATA_TYPE); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } } if (!list.hasKey(AVKey.ORIGIN)) { // set UpperLeft corner as the origin, if not specified LatLon origin = new LatLon(sector.getMaxLatitude(), sector.getMinLongitude()); list.setValue(AVKey.ORIGIN, origin); } if (list.hasKey(AVKey.BYTE_ORDER) && !AVKey.BIG_ENDIAN.equals(list.getStringValue(AVKey.BYTE_ORDER))) { String msg = Logging.getMessage( "generic.UnrecognizedByteOrder", list.getStringValue(AVKey.BYTE_ORDER)); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } if (!list.hasKey(AVKey.DATE_TIME)) { // add NUL (\0) termination as required by TIFF v6 spec (20 bytes length) String timestamp = String.format("%1$tY:%1$tm:%1$td %tT\0", Calendar.getInstance()); list.setValue(AVKey.DATE_TIME, timestamp); } if (!list.hasKey(AVKey.VERSION)) { list.setValue(AVKey.VERSION, Version.getVersion()); } }
private void appendGeoTiff(ArrayList<TiffIFDEntry> ifds, AVList params) throws IOException, IllegalArgumentException { if (null == params || 0 == params.getEntries().size()) { String reason = Logging.getMessage("nullValue.AVListIsNull"); Logging.logger().finest(Logging.getMessage("GeotiffWriter.GeoKeysMissing", reason)); return; } long offset = this.theChannel.position(); if (params.hasKey(AVKey.DISPLAY_NAME)) { String value = params.getStringValue(AVKey.DISPLAY_NAME); if (null != value && 0 < value.trim().length()) { offset = this.theChannel.position(); byte[] bytes = value.trim().getBytes(); this.theChannel.write(ByteBuffer.wrap(bytes)); ifds.add(new TiffIFDEntry(Tiff.Tag.DOCUMENT_NAME, Tiff.Type.ASCII, bytes.length, offset)); } } if (params.hasKey(AVKey.DESCRIPTION)) { String value = params.getStringValue(AVKey.DESCRIPTION); if (null != value && 0 < value.trim().length()) { offset = this.theChannel.position(); byte[] bytes = value.trim().getBytes(); this.theChannel.write(ByteBuffer.wrap(bytes)); ifds.add( new TiffIFDEntry(Tiff.Tag.IMAGE_DESCRIPTION, Tiff.Type.ASCII, bytes.length, offset)); } } if (params.hasKey(AVKey.VERSION)) { String value = params.getStringValue(AVKey.VERSION); if (null != value && 0 < value.trim().length()) { offset = this.theChannel.position(); byte[] bytes = value.trim().getBytes(); this.theChannel.write(ByteBuffer.wrap(bytes)); ifds.add( new TiffIFDEntry(Tiff.Tag.SOFTWARE_VERSION, Tiff.Type.ASCII, bytes.length, offset)); } } if (params.hasKey(AVKey.DATE_TIME)) { String value = params.getStringValue(AVKey.DATE_TIME); if (null != value && 0 < value.trim().length()) { offset = this.theChannel.position(); byte[] bytes = value.getBytes(); this.theChannel.write(ByteBuffer.wrap(bytes)); ifds.add(new TiffIFDEntry(Tiff.Tag.DATE_TIME, Tiff.Type.ASCII, bytes.length, offset)); } } if (params.hasKey(AVKey.SECTOR)) { if (params.hasKey(AVKey.PIXEL_WIDTH) && params.hasKey(AVKey.PIXEL_HEIGHT)) { offset = this.theChannel.position(); double[] values = new double[] { (Double) params.getValue(AVKey.PIXEL_WIDTH), (Double) params.getValue(AVKey.PIXEL_HEIGHT), isElevation(params) ? 1d : 0d }; byte[] bytes = this.getBytes(values); this.theChannel.write(ByteBuffer.wrap(bytes)); ifds.add( new TiffIFDEntry( GeoTiff.Tag.MODEL_PIXELSCALE, Tiff.Type.DOUBLE, values.length, offset)); } if (params.hasKey(AVKey.WIDTH) && params.hasKey(AVKey.HEIGHT)) { offset = this.theChannel.position(); double w = (Integer) params.getValue(AVKey.WIDTH); double h = (Integer) params.getValue(AVKey.HEIGHT); Sector sec = (Sector) params.getValue(AVKey.SECTOR); double[] values = new double[] { // i , j, k=0, x, y, z=0 0d, 0d, 0d, sec.getMinLongitude().degrees, sec.getMaxLatitude().degrees, 0d, w - 1, 0d, 0d, sec.getMaxLongitude().degrees, sec.getMaxLatitude().degrees, 0d, w - 1, h - 1, 0d, sec.getMaxLongitude().degrees, sec.getMinLatitude().degrees, 0d, 0d, h - 1, 0d, sec.getMinLongitude().degrees, sec.getMinLatitude().degrees, 0d, }; byte[] bytes = this.getBytes(values); this.theChannel.write(ByteBuffer.wrap(bytes)); ifds.add( new TiffIFDEntry(GeoTiff.Tag.MODEL_TIEPOINT, Tiff.Type.DOUBLE, values.length, offset)); } // Tiff.Tag.MODEL_TRANSFORMATION excludes Tiff.Tag.MODEL_TIEPOINT & Tiff.Tag.MODEL_PIXELSCALE if (params.hasKey(AVKey.MISSING_DATA_SIGNAL) || params.hasKey(AVKey.MISSING_DATA_REPLACEMENT)) { offset = this.theChannel.position(); Object nodata = params.hasKey(AVKey.MISSING_DATA_SIGNAL) ? params.getValue(AVKey.MISSING_DATA_SIGNAL) : params.getValue(AVKey.MISSING_DATA_REPLACEMENT); String value = "" + nodata + "\0"; byte[] bytes = value.getBytes(); this.theChannel.write(ByteBuffer.wrap(bytes)); ifds.add(new TiffIFDEntry(GeoTiff.Tag.GDAL_NODATA, Tiff.Type.ASCII, bytes.length, offset)); } if (params.hasKey(AVKey.COORDINATE_SYSTEM)) { String cs = params.getStringValue(AVKey.COORDINATE_SYSTEM); if (AVKey.COORDINATE_SYSTEM_GEOGRAPHIC.equals(cs)) { if (isElevation(params)) this.writeGeographicElevationGeoKeys(ifds, params); else this.writeGeographicImageGeoKeys(ifds, params); } else if (AVKey.COORDINATE_SYSTEM_PROJECTED.equals(cs)) { String msg = Logging.getMessage("GeotiffWriter.FeatureNotImplementedd", cs); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); // TODO extract PCS (Projection Coordinate System) } else { String msg = Logging.getMessage("GeotiffWriter.UnknownCoordinateSystem", cs); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } } } }
public void write(BufferedImage image, AVList params) throws IOException { if (image == null) { String msg = Logging.getMessage("nullValue.ImageSource"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } if (0 == image.getWidth() || 0 == image.getHeight()) { String msg = Logging.getMessage("generic.InvalidImageSize", image.getWidth(), image.getHeight()); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } if (null == params || 0 == params.getValues().size()) { String reason = Logging.getMessage("nullValue.AVListIsNull"); Logging.logger().finest(Logging.getMessage("GeotiffWriter.GeoKeysMissing", reason)); params = new AVListImpl(); } else { this.validateParameters(params, image.getWidth(), image.getHeight()); } // how we proceed in part depends upon the image type... int type = image.getType(); // handle CUSTOM type which comes from our GeoTiffreader (for now) if (BufferedImage.TYPE_CUSTOM == type) { int numColorComponents = 0, numComponents = 0, pixelSize = 0, dataType = 0, csType = 0; boolean hasAlpha = false; if (null != image.getColorModel()) { ColorModel cm = image.getColorModel(); numColorComponents = cm.getNumColorComponents(); numComponents = cm.getNumComponents(); pixelSize = cm.getPixelSize(); hasAlpha = cm.hasAlpha(); ColorSpace cs = cm.getColorSpace(); if (null != cs) csType = cs.getType(); } if (null != image.getSampleModel()) { SampleModel sm = image.getSampleModel(); dataType = sm.getDataType(); } if (dataType == DataBuffer.TYPE_FLOAT && pixelSize == Float.SIZE && numComponents == 1) { type = BufferedImage_TYPE_ELEVATION_FLOAT32; } else if (dataType == DataBuffer.TYPE_SHORT && pixelSize == Short.SIZE && numComponents == 1) { type = BufferedImage_TYPE_ELEVATION_SHORT16; } else if (ColorSpace.CS_GRAY == csType && pixelSize == Byte.SIZE) { type = BufferedImage.TYPE_BYTE_GRAY; } else if (dataType == DataBuffer.TYPE_USHORT && ColorSpace.CS_GRAY == csType && pixelSize == Short.SIZE) { type = BufferedImage.TYPE_USHORT_GRAY; } else if (ColorSpace.TYPE_RGB == csType && pixelSize == 3 * Byte.SIZE && numColorComponents == 3) { type = BufferedImage.TYPE_3BYTE_BGR; } else if (ColorSpace.TYPE_RGB == csType && hasAlpha && pixelSize == 4 * Byte.SIZE && numComponents == 4) { type = BufferedImage.TYPE_4BYTE_ABGR; } } switch (type) { case BufferedImage.TYPE_3BYTE_BGR: case BufferedImage.TYPE_4BYTE_ABGR: case BufferedImage.TYPE_4BYTE_ABGR_PRE: case BufferedImage.TYPE_INT_RGB: case BufferedImage.TYPE_INT_BGR: case BufferedImage.TYPE_INT_ARGB: case BufferedImage.TYPE_INT_ARGB_PRE: { this.writeColorImage(image, params); } break; case BufferedImage.TYPE_USHORT_GRAY: case BufferedImage.TYPE_BYTE_GRAY: { this.writeGrayscaleImage(image, params); } break; case BufferedImage_TYPE_ELEVATION_SHORT16: case BufferedImage_TYPE_ELEVATION_FLOAT32: { String msg = Logging.getMessage("GeotiffWriter.FeatureNotImplementedd", type); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } // break; case BufferedImage.TYPE_CUSTOM: default: { ColorModel cm = image.getColorModel(); SampleModel sm = image.getSampleModel(); StringBuffer sb = new StringBuffer(Logging.getMessage("GeotiffWriter.UnsupportedType", type)); sb.append("\n"); sb.append("NumBands=").append(sm.getNumBands()).append("\n"); sb.append("NumDataElements=").append(sm.getNumDataElements()).append("\n"); sb.append("NumColorComponents=").append(cm.getNumColorComponents()).append("\n"); sb.append("NumComponents=").append(cm.getNumComponents()).append("\n"); sb.append("PixelSize=").append(cm.getPixelSize()).append("\n"); sb.append("hasAlpha=").append(cm.hasAlpha()); String msg = sb.toString(); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } } }