Commit beaa0851 authored by Andrey Filippov's avatar Andrey Filippov

Exported GPS and resolution OK

parent 6894dccd
......@@ -54,13 +54,18 @@ import com.elphel.imagej.ims.Did_ins;
import ij.ImagePlus;
public class ElphelTiffWriter {
public static String TIFF_METADATA_FORMAT = "javax_imageio_tiff_image_1.0";
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_RATIONALS_TAG = "TIFFRationals";
public static String TIFF_RATIONAL_TAG = "TIFFRational";
public static String TIFF_FIELD_VALUE_ATTRIBUTE = "value";
public static String TIFF_METADATA_FORMAT = "javax_imageio_tiff_image_1.0";
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(
......@@ -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();
......@@ -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");
......@@ -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);
......@@ -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
......@@ -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 createResolutionMetadata(double resolutionPixelInMeters) {
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 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");
......@@ -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");
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
return gpsRootNode;
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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment