Loading src/main/java/com/elphel/imagej/readers/ElphelTiffWriter.java +266 −26 Original line number Diff line number Diff line Loading @@ -58,9 +58,14 @@ public class ElphelTiffWriter { public static String TIFF_FIELD_TAG = "TIFFField"; public static String TIFF_ASCIIS_TAG = "TIFFAsciis"; public static String TIFF_ASCII_TAG = "TIFFAscii"; public static String TIFF_BYTES_TAG = "TIFFBytes"; public static String TIFF_BYTE_TAG = "TIFFByte"; public static String TIFF_SHORTS_TAG = "TIFFShorts"; public static String TIFF_SHORT_TAG = "TIFFShort"; public static String TIFF_RATIONALS_TAG = "TIFFRationals"; public static String TIFF_RATIONAL_TAG = "TIFFRational"; public static String TIFF_FIELD_VALUE_ATTRIBUTE = "value"; public static String TIFF_FIELD_DESCRIPTION_ATTRIBUTE = "description"; public static void saveTiffARGB32( Loading Loading @@ -146,7 +151,7 @@ Sets an array of integer pixels in the default RGB color model (TYPE_INT_ARGB) a double [] lla = { 49.9476514222895,28.5547846609957,323.750316821841}; LocalDateTime dt = Did_ins.getLocalDateTime(2286, 491072.634526699); double pix_in_meters = 0.01; int cm_dig_after = 9; /* ExifGPSTagSet exif_tag_set = ExifGPSTagSet.getInstance(); Loading Loading @@ -181,18 +186,27 @@ Sets an array of integer pixels in the default RGB color model (TYPE_INT_ARGB) a } TIFFTagSet tag_set = ExifGPSTagSet.getInstance(); TIFFTagSet eptts = ExifParentTIFFTagSet.getInstance(); // Try changing node attributes w/o need for directory directory.addTagSet(tag_set); // ExifGPSTagSet.getInstance()); directory.addTagSet(eptts); // ExifParentTIFFTagSet.getInstance()); //ExifGPSTagSet imageMetadata = directory.getAsMetadata(); /* */ Node root_gps = imageMetadata.getAsTree(TIFF_METADATA_FORMAT);//? IIOMetadataNode root_new = (IIOMetadataNode) imageMetadata.getAsTree(TIFF_METADATA_FORMAT);//? System.out.println("\n=== root_new ===:"); DumpImageMetadata.displayMetadataNode(root_new, 1); // createGpsMetadata(double [] lla, LocalDateTime dt) System.out.println("\n=== root_gps ===:"); DumpImageMetadata.displayMetadataNode(root_gps, 1); Node ifd = root_gps.getFirstChild(); IIOMetadataNode ifd = (IIOMetadataNode) root_new.getFirstChild(); String ifd_attr = ifd.getAttribute("tagSets"); // set it to ifd_attr "javax.imageio.plugins.tiff.BaselineTIFFTagSet,javax.imageio.plugins.tiff.ExifGPSTagSet,javax.imageio.plugins.tiff.ExifParentTIFFTagSet" (id=187) // remove directory above and addTagSet IIOMetadataNode gpsRootNode = createGpsMetadata(lla, dt); /* IIOMetadataNode gpsRootNode = new IIOMetadataNode("TIFFIFD"); gpsRootNode.setAttribute("parentTagNumber", "34853"); gpsRootNode.setAttribute("parentTagName", "GPSInfoIFDPointer"); Loading @@ -207,7 +221,14 @@ Sets an array of integer pixels in the default RGB color model (TYPE_INT_ARGB) a asciiNode.appendChild(childAsciiNode); childNode.appendChild(asciiNode); gpsRootNode.appendChild(childNode); */ System.out.println("\n=== gpsRootNode ===:"); DumpImageMetadata.displayMetadataNode(gpsRootNode, 1); addResolutionMetadata(ifd,pix_in_meters,cm_dig_after); ifd.appendChild(gpsRootNode); System.out.println("\n=== ifd ===:"); DumpImageMetadata.displayMetadataNode(ifd, 1); Loading Loading @@ -238,33 +259,29 @@ outstr.close(); public static String TIFF_RATIONALS_TAG = "TIFFRationals"; public static String TIFF_RATIONAL_TAG = "TIFFRational"; public static String TIFF_FIELD_VALUE_ATTRIBUTE = "value"; */ IIOMetadataNode dimension = createResolutionMetadata(pix_in_meters); // imageMetadata.appendChild(dimension); //// IIOMetadataNode root_dimension = new IIOMetadataNode(TIFF_METADATA_FORMAT); // IIOMetadataFormatImpl.standardMetadataFormatName); // root_dimension.appendChild(dimension); //// root_dimension.appendChild(root_gps); System.out.println("\n=== root_gps ===:"); // should have 2 tagSets, but has only baseline //// root_dimension.appendChild(root_new); //// System.out.println("\n=== root_new ===:"); // should have 2 tagSets, but has only baseline /* <javax_imageio_tiff_image_1.0> <TIFFIFD tagSets='javax.imageio.plugins.tiff.BaselineTIFFTagSet,javax.imageio.plugins.tiff.GeoTIFFTagSet'> */ DumpImageMetadata.displayMetadataNode(root_gps, 1); System.out.println("\n=== root_new ===:"); DumpImageMetadata.displayMetadataNode(root_new, 1); System.out.println("\n=== imageMetadata - before merge ===:"); DumpImageMetadata.displayMetadataNode(imageMetadata.getAsTree(TIFF_METADATA_FORMAT), 1); // lost GPS data after merge try { imageMetadata.mergeTree(TIFF_METADATA_FORMAT, root_gps); // dimension); // Root must have "TIFFIFD" child imageMetadata.mergeTree(TIFF_METADATA_FORMAT, root_new); // dimension); // Root must have "TIFFIFD" child // imageMetadata.setFromTree(TIFF_METADATA_FORMAT, root_dimension); // dimension); } catch (IIOInvalidTreeException e1) { // TODO Auto-generated catch block Loading Loading @@ -304,8 +321,162 @@ outstr.close(); System.out.println(); } private static IIOMetadataNode createRationalDegrees(double d, int digits_after) { // 8 int denom = 1; for (int i = 0; i < digits_after; i++) denom *= 10; int degs = (int) Math.floor(d); d = 60* (d - degs); int mins = (int) Math.floor(d); d = 60* (d - mins); int fsec = (int) Math.round(d*denom); IIOMetadataNode node_rationals = new IIOMetadataNode(TIFF_RATIONALS_TAG); IIOMetadataNode node_degs = new IIOMetadataNode(TIFF_RATIONAL_TAG); node_degs.setAttribute(TIFF_FIELD_VALUE_ATTRIBUTE, degs+"/1"); IIOMetadataNode node_mins = new IIOMetadataNode(TIFF_RATIONAL_TAG); node_mins.setAttribute(TIFF_FIELD_VALUE_ATTRIBUTE, mins+"/1"); IIOMetadataNode node_secs = new IIOMetadataNode(TIFF_RATIONAL_TAG); node_secs.setAttribute(TIFF_FIELD_VALUE_ATTRIBUTE, fsec+"/"+denom); node_rationals.appendChild(node_degs); node_rationals.appendChild(node_mins); node_rationals.appendChild(node_secs); return node_rationals; } private static IIOMetadataNode createRationalMeters(double d, int digits_after) { // 3 int denom = 1; for (int i = 0; i < digits_after; i++) denom *= 10; int fmeters = (int) Math.round(d*denom); IIOMetadataNode node_rationals = new IIOMetadataNode(TIFF_RATIONALS_TAG); IIOMetadataNode node_meters = new IIOMetadataNode(TIFF_RATIONAL_TAG); node_meters.setAttribute(TIFF_FIELD_VALUE_ATTRIBUTE, fmeters+"/"+denom); node_rationals.appendChild(node_meters); return node_rationals; } private static IIOMetadataNode createTimeStamp(LocalDateTime dt, int digits_after) { // 3 int denom = 1; for (int i = 0; i < digits_after; i++) denom *= 10; int fsec = dt.getSecond()*denom+((int) Math.round(denom * dt.getNano()*1E-9)); IIOMetadataNode node_rationals = new IIOMetadataNode(TIFF_RATIONALS_TAG); IIOMetadataNode node_hrs = new IIOMetadataNode(TIFF_RATIONAL_TAG); node_hrs.setAttribute(TIFF_FIELD_VALUE_ATTRIBUTE, dt.getHour()+"/1"); IIOMetadataNode node_mins = new IIOMetadataNode(TIFF_RATIONAL_TAG); node_mins.setAttribute(TIFF_FIELD_VALUE_ATTRIBUTE, dt.getMinute()+"/1"); IIOMetadataNode node_secs = new IIOMetadataNode(TIFF_RATIONAL_TAG); node_secs.setAttribute(TIFF_FIELD_VALUE_ATTRIBUTE, fsec+"/"+denom); node_rationals.appendChild(node_hrs); node_rationals.appendChild(node_mins); node_rationals.appendChild(node_secs); return node_rationals; } private static IIOMetadataNode createDateStamp(LocalDateTime dt) { IIOMetadataNode node_date = new IIOMetadataNode(TIFF_ASCIIS_TAG); IIOMetadataNode node_date_ascii = new IIOMetadataNode(TIFF_ASCII_TAG); node_date_ascii.setAttribute(TIFF_FIELD_VALUE_ATTRIBUTE, String.format("%04d:%02d:%02d", dt.getYear(), dt.getMonthValue(), dt.getDayOfMonth())); node_date.appendChild(node_date_ascii); return node_date; } private static IIOMetadataNode createResolutionMetadata(double resolutionPixelInMeters) { private static IIOMetadataNode createGpsMetadata(double [] lla, LocalDateTime dt) { int ang_sec_after = 5; int meters_after = 3; int seconds_after = 3; // WGS84 latitude, longitude, height above ellipsoid (degrees,degrees,meters) IIOMetadataNode gpsRootNode = new IIOMetadataNode("TIFFIFD"); gpsRootNode.setAttribute("parentTagNumber", "34853"); gpsRootNode.setAttribute("parentTagName", "GPSInfoIFDPointer"); gpsRootNode.setAttribute("tagSets", "javax.imageio.plugins.tiff.ExifGPSTagSet"); boolean lat_south = lla[0] < 0; double lat_abs = Math.abs(lla[0]); boolean long_west = lla[1] < 0; double long_abs = Math.abs(lla[1]); boolean alt_down = lla[2] < 0; double alt_abs = Math.abs(lla[2]); // Latitude IIOMetadataNode node_lat_ref = new IIOMetadataNode(TIFF_FIELD_TAG); node_lat_ref.setAttribute("number", "1"); node_lat_ref.setAttribute("name", "GPSLatitudeRef"); IIOMetadataNode node_lat_ref_asciis = new IIOMetadataNode(TIFF_ASCIIS_TAG); IIOMetadataNode node_lat_ref_ascii = new IIOMetadataNode(TIFF_ASCII_TAG); node_lat_ref_ascii.setAttribute(TIFF_FIELD_VALUE_ATTRIBUTE, lat_south?"S":"N"); node_lat_ref_asciis.appendChild(node_lat_ref_ascii); node_lat_ref.appendChild(node_lat_ref_asciis); gpsRootNode.appendChild(node_lat_ref); IIOMetadataNode node_lat = new IIOMetadataNode(TIFF_FIELD_TAG); node_lat.setAttribute("number", "2"); node_lat.setAttribute("name", "GPSLatitude"); node_lat.appendChild(createRationalDegrees(lat_abs, ang_sec_after)); gpsRootNode.appendChild(node_lat); System.out.println("\n=== gpsRootNode after latitude ===:"); DumpImageMetadata.displayMetadataNode(gpsRootNode, 1); // Longitude IIOMetadataNode node_long_ref = new IIOMetadataNode(TIFF_FIELD_TAG); node_long_ref.setAttribute("number", "3"); node_long_ref.setAttribute("name", "GPSLongitudeRef"); IIOMetadataNode node_long_ref_asciis = new IIOMetadataNode(TIFF_ASCIIS_TAG); IIOMetadataNode node_long_ref_ascii = new IIOMetadataNode(TIFF_ASCII_TAG); node_long_ref_ascii.setAttribute(TIFF_FIELD_VALUE_ATTRIBUTE, long_west?"W":"E"); node_long_ref_asciis.appendChild(node_long_ref_ascii); node_long_ref.appendChild(node_long_ref_asciis); gpsRootNode.appendChild(node_long_ref); IIOMetadataNode node_long = new IIOMetadataNode(TIFF_FIELD_TAG); node_long.setAttribute("number", "4"); node_long.setAttribute("name", "GPSLongitude"); node_long.appendChild(createRationalDegrees(long_abs, ang_sec_after)); gpsRootNode.appendChild(node_long); System.out.println("\n=== gpsRootNode after longitude ===:"); DumpImageMetadata.displayMetadataNode(gpsRootNode, 1); // Altitude IIOMetadataNode node_alt_ref = new IIOMetadataNode(TIFF_FIELD_TAG); node_alt_ref.setAttribute("number", "5"); node_alt_ref.setAttribute("name", "GPSAltitudeRef"); IIOMetadataNode node_alt_ref_asciis = new IIOMetadataNode(TIFF_BYTES_TAG); IIOMetadataNode node_alt_ref_ascii = new IIOMetadataNode(TIFF_BYTE_TAG); node_alt_ref_ascii.setAttribute(TIFF_FIELD_VALUE_ATTRIBUTE, alt_down?"1":"0"); node_alt_ref_ascii.setAttribute(TIFF_FIELD_DESCRIPTION_ATTRIBUTE, "Sea level"); node_alt_ref_asciis.appendChild(node_alt_ref_ascii); node_alt_ref.appendChild(node_alt_ref_asciis); gpsRootNode.appendChild(node_alt_ref); IIOMetadataNode node_alt = new IIOMetadataNode(TIFF_FIELD_TAG); node_alt.setAttribute("number", "6"); node_alt.setAttribute("name", "GPSAltitude"); node_alt.appendChild(createRationalMeters(alt_abs, meters_after)); gpsRootNode.appendChild(node_alt); System.out.println("\n=== gpsRootNode after altitude ===:"); DumpImageMetadata.displayMetadataNode(gpsRootNode, 1); if (dt != null) { // Time IIOMetadataNode node_time = new IIOMetadataNode(TIFF_FIELD_TAG); node_time.setAttribute("number", "7"); node_time.setAttribute("name", "GPSTimeStamp"); node_time.appendChild(createTimeStamp(dt,seconds_after)); gpsRootNode.appendChild(node_time); System.out.println("\n=== gpsRootNode after time ===:"); DumpImageMetadata.displayMetadataNode(gpsRootNode, 1); // Date IIOMetadataNode node_date = new IIOMetadataNode(TIFF_FIELD_TAG); node_date.setAttribute("number", "29"); node_date.setAttribute("name", "GPSDateStamp"); node_date.appendChild(createDateStamp(dt)); gpsRootNode.appendChild(node_date); } System.out.println("\n=== gpsRootNode after date ===:"); DumpImageMetadata.displayMetadataNode(gpsRootNode, 1); return gpsRootNode; } private static IIOMetadataNode createResolutionMetadataStd(double resolutionPixelInMeters) { // String pixelSize = Double.toString(25.4 / resolutionDPI); String pixelSize = Double.toString(1000*resolutionPixelInMeters); // millimeters IIOMetadataNode horizontal = new IIOMetadataNode("HorizontalPixelSize"); Loading @@ -320,13 +491,82 @@ outstr.close(); // root.appendChild(dimension); // return root; } private static IIOMetadataNode createGpsMetadata(double [] lla, LocalDateTime dt) { IIOMetadataNode gpsRootNode = new IIOMetadataNode("TIFFIFD"); // gpsRootNode.setAttribute(FileConstants.TIFF_FIELD_NUMBER_ATTRIBUTE, "34853"); return gpsRootNode; private static void addResolutionMetadata( IIOMetadataNode ifd, double resolutionPixelInMeters, int digits_after) { int denom = 1; for (int i = 0; i < digits_after; i++) denom *= 10; int fppcm = (int) Math.round(denom * 0.01/resolutionPixelInMeters); // pixels per cm IIOMetadataNode node_resolution_unit = new IIOMetadataNode(TIFF_FIELD_TAG); node_resolution_unit.setAttribute("number", "296"); node_resolution_unit.setAttribute("name", "ResolutionUnit"); IIOMetadataNode node_ru_shorts = new IIOMetadataNode(TIFF_SHORTS_TAG); IIOMetadataNode node_ru_short = new IIOMetadataNode(TIFF_SHORT_TAG); node_ru_short.setAttribute(TIFF_FIELD_VALUE_ATTRIBUTE, "3"); // cm node_ru_short.setAttribute(TIFF_FIELD_DESCRIPTION_ATTRIBUTE, "Centimeter"); // cm node_ru_shorts.appendChild(node_ru_short); node_resolution_unit.appendChild(node_ru_shorts); ifd.appendChild(node_resolution_unit); IIOMetadataNode node_x_resolution = new IIOMetadataNode(TIFF_FIELD_TAG); node_x_resolution.setAttribute("number", "282"); node_x_resolution.setAttribute("name", "XResolution"); IIOMetadataNode node_x_rationals = new IIOMetadataNode(TIFF_RATIONALS_TAG); IIOMetadataNode node_x_rational = new IIOMetadataNode(TIFF_RATIONAL_TAG); node_x_rational.setAttribute(TIFF_FIELD_VALUE_ATTRIBUTE, fppcm+"/"+denom); node_x_rationals.appendChild(node_x_rational); node_x_resolution.appendChild(node_x_rationals); ifd.appendChild(node_x_resolution); IIOMetadataNode node_y_resolution = new IIOMetadataNode(TIFF_FIELD_TAG); node_y_resolution.setAttribute("number", "283"); node_y_resolution.setAttribute("name", "YResolution"); IIOMetadataNode node_y_rationals = new IIOMetadataNode(TIFF_RATIONALS_TAG); IIOMetadataNode node_y_rational = new IIOMetadataNode(TIFF_RATIONAL_TAG); node_y_rational.setAttribute(TIFF_FIELD_VALUE_ATTRIBUTE, fppcm+"/"+denom); node_y_rationals.appendChild(node_y_rational); node_y_resolution.appendChild(node_y_rationals); ifd.appendChild(node_y_resolution); } /* * IIOMetadataNode node_rationals = new IIOMetadataNode(TIFF_RATIONALS_TAG); IIOMetadataNode node_hrs = new IIOMetadataNode(TIFF_RATIONAL_TAG); node_hrs.setAttribute(TIFF_FIELD_VALUE_ATTRIBUTE, dt.getHour()+"/1"); IIOMetadataNode node_mins = new IIOMetadataNode(TIFF_RATIONAL_TAG); node_mins.setAttribute(TIFF_FIELD_VALUE_ATTRIBUTE, dt.getMinute()+"/1"); IIOMetadataNode node_secs = new IIOMetadataNode(TIFF_RATIONAL_TAG); node_secs.setAttribute(TIFF_FIELD_VALUE_ATTRIBUTE, fsec+"/"+denom); node_rationals.appendChild(node_hrs); node_rationals.appendChild(node_mins); node_rationals.appendChild(node_secs); * * The number of pixels per ResolutionUnit in the ImageWidth direction. <TIFFField number='282' name='XResolution'> <TIFFRationals> <TIFFRational value='1/1'/> </TIFFRationals> </TIFFField> <TIFFField number='283' name='YResolution'> <TIFFRationals> <TIFFRational value='1/1'/> </TIFFRationals> </TIFFField> <TIFFField number='296' name='ResolutionUnit'> <TIFFShorts> <TIFFShort value='1' description='None'/> </TIFFShorts> </TIFFField> public static String TIFF_SHORTS_TAG = "TIFFShorts"; public static String TIFF_SHORT_TAG = "TIFFShort"; */ /* * FileImageOutputStream outputStream = new FileImageOutputStream(outputFile); Loading Loading
src/main/java/com/elphel/imagej/readers/ElphelTiffWriter.java +266 −26 Original line number Diff line number Diff line Loading @@ -58,9 +58,14 @@ public class ElphelTiffWriter { public static String TIFF_FIELD_TAG = "TIFFField"; public static String TIFF_ASCIIS_TAG = "TIFFAsciis"; public static String TIFF_ASCII_TAG = "TIFFAscii"; public static String TIFF_BYTES_TAG = "TIFFBytes"; public static String TIFF_BYTE_TAG = "TIFFByte"; public static String TIFF_SHORTS_TAG = "TIFFShorts"; public static String TIFF_SHORT_TAG = "TIFFShort"; public static String TIFF_RATIONALS_TAG = "TIFFRationals"; public static String TIFF_RATIONAL_TAG = "TIFFRational"; public static String TIFF_FIELD_VALUE_ATTRIBUTE = "value"; public static String TIFF_FIELD_DESCRIPTION_ATTRIBUTE = "description"; public static void saveTiffARGB32( Loading Loading @@ -146,7 +151,7 @@ Sets an array of integer pixels in the default RGB color model (TYPE_INT_ARGB) a double [] lla = { 49.9476514222895,28.5547846609957,323.750316821841}; LocalDateTime dt = Did_ins.getLocalDateTime(2286, 491072.634526699); double pix_in_meters = 0.01; int cm_dig_after = 9; /* ExifGPSTagSet exif_tag_set = ExifGPSTagSet.getInstance(); Loading Loading @@ -181,18 +186,27 @@ Sets an array of integer pixels in the default RGB color model (TYPE_INT_ARGB) a } TIFFTagSet tag_set = ExifGPSTagSet.getInstance(); TIFFTagSet eptts = ExifParentTIFFTagSet.getInstance(); // Try changing node attributes w/o need for directory directory.addTagSet(tag_set); // ExifGPSTagSet.getInstance()); directory.addTagSet(eptts); // ExifParentTIFFTagSet.getInstance()); //ExifGPSTagSet imageMetadata = directory.getAsMetadata(); /* */ Node root_gps = imageMetadata.getAsTree(TIFF_METADATA_FORMAT);//? IIOMetadataNode root_new = (IIOMetadataNode) imageMetadata.getAsTree(TIFF_METADATA_FORMAT);//? System.out.println("\n=== root_new ===:"); DumpImageMetadata.displayMetadataNode(root_new, 1); // createGpsMetadata(double [] lla, LocalDateTime dt) System.out.println("\n=== root_gps ===:"); DumpImageMetadata.displayMetadataNode(root_gps, 1); Node ifd = root_gps.getFirstChild(); IIOMetadataNode ifd = (IIOMetadataNode) root_new.getFirstChild(); String ifd_attr = ifd.getAttribute("tagSets"); // set it to ifd_attr "javax.imageio.plugins.tiff.BaselineTIFFTagSet,javax.imageio.plugins.tiff.ExifGPSTagSet,javax.imageio.plugins.tiff.ExifParentTIFFTagSet" (id=187) // remove directory above and addTagSet IIOMetadataNode gpsRootNode = createGpsMetadata(lla, dt); /* IIOMetadataNode gpsRootNode = new IIOMetadataNode("TIFFIFD"); gpsRootNode.setAttribute("parentTagNumber", "34853"); gpsRootNode.setAttribute("parentTagName", "GPSInfoIFDPointer"); Loading @@ -207,7 +221,14 @@ Sets an array of integer pixels in the default RGB color model (TYPE_INT_ARGB) a asciiNode.appendChild(childAsciiNode); childNode.appendChild(asciiNode); gpsRootNode.appendChild(childNode); */ System.out.println("\n=== gpsRootNode ===:"); DumpImageMetadata.displayMetadataNode(gpsRootNode, 1); addResolutionMetadata(ifd,pix_in_meters,cm_dig_after); ifd.appendChild(gpsRootNode); System.out.println("\n=== ifd ===:"); DumpImageMetadata.displayMetadataNode(ifd, 1); Loading Loading @@ -238,33 +259,29 @@ outstr.close(); public static String TIFF_RATIONALS_TAG = "TIFFRationals"; public static String TIFF_RATIONAL_TAG = "TIFFRational"; public static String TIFF_FIELD_VALUE_ATTRIBUTE = "value"; */ IIOMetadataNode dimension = createResolutionMetadata(pix_in_meters); // imageMetadata.appendChild(dimension); //// IIOMetadataNode root_dimension = new IIOMetadataNode(TIFF_METADATA_FORMAT); // IIOMetadataFormatImpl.standardMetadataFormatName); // root_dimension.appendChild(dimension); //// root_dimension.appendChild(root_gps); System.out.println("\n=== root_gps ===:"); // should have 2 tagSets, but has only baseline //// root_dimension.appendChild(root_new); //// System.out.println("\n=== root_new ===:"); // should have 2 tagSets, but has only baseline /* <javax_imageio_tiff_image_1.0> <TIFFIFD tagSets='javax.imageio.plugins.tiff.BaselineTIFFTagSet,javax.imageio.plugins.tiff.GeoTIFFTagSet'> */ DumpImageMetadata.displayMetadataNode(root_gps, 1); System.out.println("\n=== root_new ===:"); DumpImageMetadata.displayMetadataNode(root_new, 1); System.out.println("\n=== imageMetadata - before merge ===:"); DumpImageMetadata.displayMetadataNode(imageMetadata.getAsTree(TIFF_METADATA_FORMAT), 1); // lost GPS data after merge try { imageMetadata.mergeTree(TIFF_METADATA_FORMAT, root_gps); // dimension); // Root must have "TIFFIFD" child imageMetadata.mergeTree(TIFF_METADATA_FORMAT, root_new); // dimension); // Root must have "TIFFIFD" child // imageMetadata.setFromTree(TIFF_METADATA_FORMAT, root_dimension); // dimension); } catch (IIOInvalidTreeException e1) { // TODO Auto-generated catch block Loading Loading @@ -304,8 +321,162 @@ outstr.close(); System.out.println(); } private static IIOMetadataNode createRationalDegrees(double d, int digits_after) { // 8 int denom = 1; for (int i = 0; i < digits_after; i++) denom *= 10; int degs = (int) Math.floor(d); d = 60* (d - degs); int mins = (int) Math.floor(d); d = 60* (d - mins); int fsec = (int) Math.round(d*denom); IIOMetadataNode node_rationals = new IIOMetadataNode(TIFF_RATIONALS_TAG); IIOMetadataNode node_degs = new IIOMetadataNode(TIFF_RATIONAL_TAG); node_degs.setAttribute(TIFF_FIELD_VALUE_ATTRIBUTE, degs+"/1"); IIOMetadataNode node_mins = new IIOMetadataNode(TIFF_RATIONAL_TAG); node_mins.setAttribute(TIFF_FIELD_VALUE_ATTRIBUTE, mins+"/1"); IIOMetadataNode node_secs = new IIOMetadataNode(TIFF_RATIONAL_TAG); node_secs.setAttribute(TIFF_FIELD_VALUE_ATTRIBUTE, fsec+"/"+denom); node_rationals.appendChild(node_degs); node_rationals.appendChild(node_mins); node_rationals.appendChild(node_secs); return node_rationals; } private static IIOMetadataNode createRationalMeters(double d, int digits_after) { // 3 int denom = 1; for (int i = 0; i < digits_after; i++) denom *= 10; int fmeters = (int) Math.round(d*denom); IIOMetadataNode node_rationals = new IIOMetadataNode(TIFF_RATIONALS_TAG); IIOMetadataNode node_meters = new IIOMetadataNode(TIFF_RATIONAL_TAG); node_meters.setAttribute(TIFF_FIELD_VALUE_ATTRIBUTE, fmeters+"/"+denom); node_rationals.appendChild(node_meters); return node_rationals; } private static IIOMetadataNode createTimeStamp(LocalDateTime dt, int digits_after) { // 3 int denom = 1; for (int i = 0; i < digits_after; i++) denom *= 10; int fsec = dt.getSecond()*denom+((int) Math.round(denom * dt.getNano()*1E-9)); IIOMetadataNode node_rationals = new IIOMetadataNode(TIFF_RATIONALS_TAG); IIOMetadataNode node_hrs = new IIOMetadataNode(TIFF_RATIONAL_TAG); node_hrs.setAttribute(TIFF_FIELD_VALUE_ATTRIBUTE, dt.getHour()+"/1"); IIOMetadataNode node_mins = new IIOMetadataNode(TIFF_RATIONAL_TAG); node_mins.setAttribute(TIFF_FIELD_VALUE_ATTRIBUTE, dt.getMinute()+"/1"); IIOMetadataNode node_secs = new IIOMetadataNode(TIFF_RATIONAL_TAG); node_secs.setAttribute(TIFF_FIELD_VALUE_ATTRIBUTE, fsec+"/"+denom); node_rationals.appendChild(node_hrs); node_rationals.appendChild(node_mins); node_rationals.appendChild(node_secs); return node_rationals; } private static IIOMetadataNode createDateStamp(LocalDateTime dt) { IIOMetadataNode node_date = new IIOMetadataNode(TIFF_ASCIIS_TAG); IIOMetadataNode node_date_ascii = new IIOMetadataNode(TIFF_ASCII_TAG); node_date_ascii.setAttribute(TIFF_FIELD_VALUE_ATTRIBUTE, String.format("%04d:%02d:%02d", dt.getYear(), dt.getMonthValue(), dt.getDayOfMonth())); node_date.appendChild(node_date_ascii); return node_date; } private static IIOMetadataNode createResolutionMetadata(double resolutionPixelInMeters) { private static IIOMetadataNode createGpsMetadata(double [] lla, LocalDateTime dt) { int ang_sec_after = 5; int meters_after = 3; int seconds_after = 3; // WGS84 latitude, longitude, height above ellipsoid (degrees,degrees,meters) IIOMetadataNode gpsRootNode = new IIOMetadataNode("TIFFIFD"); gpsRootNode.setAttribute("parentTagNumber", "34853"); gpsRootNode.setAttribute("parentTagName", "GPSInfoIFDPointer"); gpsRootNode.setAttribute("tagSets", "javax.imageio.plugins.tiff.ExifGPSTagSet"); boolean lat_south = lla[0] < 0; double lat_abs = Math.abs(lla[0]); boolean long_west = lla[1] < 0; double long_abs = Math.abs(lla[1]); boolean alt_down = lla[2] < 0; double alt_abs = Math.abs(lla[2]); // Latitude IIOMetadataNode node_lat_ref = new IIOMetadataNode(TIFF_FIELD_TAG); node_lat_ref.setAttribute("number", "1"); node_lat_ref.setAttribute("name", "GPSLatitudeRef"); IIOMetadataNode node_lat_ref_asciis = new IIOMetadataNode(TIFF_ASCIIS_TAG); IIOMetadataNode node_lat_ref_ascii = new IIOMetadataNode(TIFF_ASCII_TAG); node_lat_ref_ascii.setAttribute(TIFF_FIELD_VALUE_ATTRIBUTE, lat_south?"S":"N"); node_lat_ref_asciis.appendChild(node_lat_ref_ascii); node_lat_ref.appendChild(node_lat_ref_asciis); gpsRootNode.appendChild(node_lat_ref); IIOMetadataNode node_lat = new IIOMetadataNode(TIFF_FIELD_TAG); node_lat.setAttribute("number", "2"); node_lat.setAttribute("name", "GPSLatitude"); node_lat.appendChild(createRationalDegrees(lat_abs, ang_sec_after)); gpsRootNode.appendChild(node_lat); System.out.println("\n=== gpsRootNode after latitude ===:"); DumpImageMetadata.displayMetadataNode(gpsRootNode, 1); // Longitude IIOMetadataNode node_long_ref = new IIOMetadataNode(TIFF_FIELD_TAG); node_long_ref.setAttribute("number", "3"); node_long_ref.setAttribute("name", "GPSLongitudeRef"); IIOMetadataNode node_long_ref_asciis = new IIOMetadataNode(TIFF_ASCIIS_TAG); IIOMetadataNode node_long_ref_ascii = new IIOMetadataNode(TIFF_ASCII_TAG); node_long_ref_ascii.setAttribute(TIFF_FIELD_VALUE_ATTRIBUTE, long_west?"W":"E"); node_long_ref_asciis.appendChild(node_long_ref_ascii); node_long_ref.appendChild(node_long_ref_asciis); gpsRootNode.appendChild(node_long_ref); IIOMetadataNode node_long = new IIOMetadataNode(TIFF_FIELD_TAG); node_long.setAttribute("number", "4"); node_long.setAttribute("name", "GPSLongitude"); node_long.appendChild(createRationalDegrees(long_abs, ang_sec_after)); gpsRootNode.appendChild(node_long); System.out.println("\n=== gpsRootNode after longitude ===:"); DumpImageMetadata.displayMetadataNode(gpsRootNode, 1); // Altitude IIOMetadataNode node_alt_ref = new IIOMetadataNode(TIFF_FIELD_TAG); node_alt_ref.setAttribute("number", "5"); node_alt_ref.setAttribute("name", "GPSAltitudeRef"); IIOMetadataNode node_alt_ref_asciis = new IIOMetadataNode(TIFF_BYTES_TAG); IIOMetadataNode node_alt_ref_ascii = new IIOMetadataNode(TIFF_BYTE_TAG); node_alt_ref_ascii.setAttribute(TIFF_FIELD_VALUE_ATTRIBUTE, alt_down?"1":"0"); node_alt_ref_ascii.setAttribute(TIFF_FIELD_DESCRIPTION_ATTRIBUTE, "Sea level"); node_alt_ref_asciis.appendChild(node_alt_ref_ascii); node_alt_ref.appendChild(node_alt_ref_asciis); gpsRootNode.appendChild(node_alt_ref); IIOMetadataNode node_alt = new IIOMetadataNode(TIFF_FIELD_TAG); node_alt.setAttribute("number", "6"); node_alt.setAttribute("name", "GPSAltitude"); node_alt.appendChild(createRationalMeters(alt_abs, meters_after)); gpsRootNode.appendChild(node_alt); System.out.println("\n=== gpsRootNode after altitude ===:"); DumpImageMetadata.displayMetadataNode(gpsRootNode, 1); if (dt != null) { // Time IIOMetadataNode node_time = new IIOMetadataNode(TIFF_FIELD_TAG); node_time.setAttribute("number", "7"); node_time.setAttribute("name", "GPSTimeStamp"); node_time.appendChild(createTimeStamp(dt,seconds_after)); gpsRootNode.appendChild(node_time); System.out.println("\n=== gpsRootNode after time ===:"); DumpImageMetadata.displayMetadataNode(gpsRootNode, 1); // Date IIOMetadataNode node_date = new IIOMetadataNode(TIFF_FIELD_TAG); node_date.setAttribute("number", "29"); node_date.setAttribute("name", "GPSDateStamp"); node_date.appendChild(createDateStamp(dt)); gpsRootNode.appendChild(node_date); } System.out.println("\n=== gpsRootNode after date ===:"); DumpImageMetadata.displayMetadataNode(gpsRootNode, 1); return gpsRootNode; } private static IIOMetadataNode createResolutionMetadataStd(double resolutionPixelInMeters) { // String pixelSize = Double.toString(25.4 / resolutionDPI); String pixelSize = Double.toString(1000*resolutionPixelInMeters); // millimeters IIOMetadataNode horizontal = new IIOMetadataNode("HorizontalPixelSize"); Loading @@ -320,13 +491,82 @@ outstr.close(); // root.appendChild(dimension); // return root; } private static IIOMetadataNode createGpsMetadata(double [] lla, LocalDateTime dt) { IIOMetadataNode gpsRootNode = new IIOMetadataNode("TIFFIFD"); // gpsRootNode.setAttribute(FileConstants.TIFF_FIELD_NUMBER_ATTRIBUTE, "34853"); return gpsRootNode; private static void addResolutionMetadata( IIOMetadataNode ifd, double resolutionPixelInMeters, int digits_after) { int denom = 1; for (int i = 0; i < digits_after; i++) denom *= 10; int fppcm = (int) Math.round(denom * 0.01/resolutionPixelInMeters); // pixels per cm IIOMetadataNode node_resolution_unit = new IIOMetadataNode(TIFF_FIELD_TAG); node_resolution_unit.setAttribute("number", "296"); node_resolution_unit.setAttribute("name", "ResolutionUnit"); IIOMetadataNode node_ru_shorts = new IIOMetadataNode(TIFF_SHORTS_TAG); IIOMetadataNode node_ru_short = new IIOMetadataNode(TIFF_SHORT_TAG); node_ru_short.setAttribute(TIFF_FIELD_VALUE_ATTRIBUTE, "3"); // cm node_ru_short.setAttribute(TIFF_FIELD_DESCRIPTION_ATTRIBUTE, "Centimeter"); // cm node_ru_shorts.appendChild(node_ru_short); node_resolution_unit.appendChild(node_ru_shorts); ifd.appendChild(node_resolution_unit); IIOMetadataNode node_x_resolution = new IIOMetadataNode(TIFF_FIELD_TAG); node_x_resolution.setAttribute("number", "282"); node_x_resolution.setAttribute("name", "XResolution"); IIOMetadataNode node_x_rationals = new IIOMetadataNode(TIFF_RATIONALS_TAG); IIOMetadataNode node_x_rational = new IIOMetadataNode(TIFF_RATIONAL_TAG); node_x_rational.setAttribute(TIFF_FIELD_VALUE_ATTRIBUTE, fppcm+"/"+denom); node_x_rationals.appendChild(node_x_rational); node_x_resolution.appendChild(node_x_rationals); ifd.appendChild(node_x_resolution); IIOMetadataNode node_y_resolution = new IIOMetadataNode(TIFF_FIELD_TAG); node_y_resolution.setAttribute("number", "283"); node_y_resolution.setAttribute("name", "YResolution"); IIOMetadataNode node_y_rationals = new IIOMetadataNode(TIFF_RATIONALS_TAG); IIOMetadataNode node_y_rational = new IIOMetadataNode(TIFF_RATIONAL_TAG); node_y_rational.setAttribute(TIFF_FIELD_VALUE_ATTRIBUTE, fppcm+"/"+denom); node_y_rationals.appendChild(node_y_rational); node_y_resolution.appendChild(node_y_rationals); ifd.appendChild(node_y_resolution); } /* * IIOMetadataNode node_rationals = new IIOMetadataNode(TIFF_RATIONALS_TAG); IIOMetadataNode node_hrs = new IIOMetadataNode(TIFF_RATIONAL_TAG); node_hrs.setAttribute(TIFF_FIELD_VALUE_ATTRIBUTE, dt.getHour()+"/1"); IIOMetadataNode node_mins = new IIOMetadataNode(TIFF_RATIONAL_TAG); node_mins.setAttribute(TIFF_FIELD_VALUE_ATTRIBUTE, dt.getMinute()+"/1"); IIOMetadataNode node_secs = new IIOMetadataNode(TIFF_RATIONAL_TAG); node_secs.setAttribute(TIFF_FIELD_VALUE_ATTRIBUTE, fsec+"/"+denom); node_rationals.appendChild(node_hrs); node_rationals.appendChild(node_mins); node_rationals.appendChild(node_secs); * * The number of pixels per ResolutionUnit in the ImageWidth direction. <TIFFField number='282' name='XResolution'> <TIFFRationals> <TIFFRational value='1/1'/> </TIFFRationals> </TIFFField> <TIFFField number='283' name='YResolution'> <TIFFRationals> <TIFFRational value='1/1'/> </TIFFRationals> </TIFFField> <TIFFField number='296' name='ResolutionUnit'> <TIFFShorts> <TIFFShort value='1' description='None'/> </TIFFShorts> </TIFFField> public static String TIFF_SHORTS_TAG = "TIFFShorts"; public static String TIFF_SHORT_TAG = "TIFFShort"; */ /* * FileImageOutputStream outputStream = new FileImageOutputStream(outputFile); Loading