Features

Download

Online

Gallery

Blog

  Index  | Recent Threads  | List Attachments  | Help  | Search
 Welcome Guest  |  Register  |  Login
Login Name  Password
 

Sweet Home 3D Forum



No member browsing this thread
Thread Status: Active
Total posts in this thread: 4
[ Jump to Last Post ]
Post new Thread
Author
Previous Thread This topic has been viewed 3841 times and has 3 replies Next Thread
digitaltrails
Member



New Zealand
Joined: Dec 28, 2014
Post Count: 45
Status: Offline
Reply to this Post  Reply with Quote 
Photo Date-Time Metadata and Annotations

I originally emailed info@eteks, but having got no response, I thought this forum might be the more correct place for development suggestions.

I've been experimenting with sun angles at different times of the year.  I found it useful to write the as-at date-time into the PNG to keep track of which date-times each images illustrates. For example:

% exiftool -a ~/3D/test2.png
ExifTool Version Number : 9.34
File Name : test2.png
Directory : /home/michael/3D
File Size : 30 kB
File Modification Date/Time : 2015:02:13 22:51:30+13:00
...
Create Date Time : 2015.02.13 22:51:16+13:00
Date Time Original : 2015.02.13 12:00:00+13:00
Image Size : 400x223


As well as this I added code to optionally annotate the actual PNG graphic - note the Add Date check-box and displayed dates in the following image:



Patch is as follows (only tested with English):
diff -r -u ../SweetHome3D-4.6-src-original/src/com/eteks/sweethome3d/swing/package.properties src/com/eteks/sweethome3d/swing/package.properties
--- ../SweetHome3D-4.6-src-original/src/com/eteks/sweethome3d/swing/package.properties 2015-02-02 21:39:30.000000000 +1300
+++ src/com/eteks/sweethome3d/swing/package.properties 2015-02-13 21:44:57.009095228 +1300
@@ -1539,6 +1539,8 @@
PhotoSizeAndQualityPanel.heightLabel.mnemonic=H
PhotoSizeAndQualityPanel.applyProportionsCheckBox.text=Apply proportions:
PhotoSizeAndQualityPanel.applyProportionsCheckBox.mnemonic=A
+PhotoSizeAndQualityPanel.addDateCheckBox.text=Add Date
+PhotoSizeAndQualityPanel.addDateCheckBox.mnemonic=D
PhotoSizeAndQualityPanel.aspectRatioComboBox.view3DRatio.text=3D view
PhotoSizeAndQualityPanel.aspectRatioComboBox.squareRatio.text=Square
PhotoSizeAndQualityPanel.qualityLabel.text=Quality:
diff -r -u ../SweetHome3D-4.6-src-original/src/com/eteks/sweethome3d/swing/PhotoPanel.java src/com/eteks/sweethome3d/swing/PhotoPanel.java
--- ../SweetHome3D-4.6-src-original/src/com/eteks/sweethome3d/swing/PhotoPanel.java 2015-02-02 21:39:30.000000000 +1300
+++ src/com/eteks/sweethome3d/swing/PhotoPanel.java 2015-02-13 22:50:38.674348690 +1300
@@ -20,10 +20,12 @@
package com.eteks.sweethome3d.swing;

import java.awt.CardLayout;
+import java.awt.Color;
import java.awt.Component;
import java.awt.ComponentOrientation;
import java.awt.Dimension;
import java.awt.EventQueue;
+import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
@@ -62,7 +64,13 @@
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

+import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
+import javax.imageio.ImageTypeSpecifier;
+import javax.imageio.ImageWriteParam;
+import javax.imageio.ImageWriter;
+import javax.imageio.metadata.IIOMetadata;
+import javax.imageio.metadata.IIOMetadataNode;
import javax.swing.ActionMap;
import javax.swing.DefaultListCellRenderer;
import javax.swing.Icon;
@@ -139,6 +147,7 @@
private JButton createButton;
private JButton saveButton;
private JButton closeButton;
+ private long photoDateTimeOriginal;

private static PhotoPanel currentPhotoPanel; // Support only one photo panel opened at a time

@@ -761,6 +770,8 @@
int bestImageHeight;
// Check correct ratio if lens is fisheye or spherical
Camera camera = home.getCamera();
+ // Seem to be in local time - adjust back to UTC
+ photoDateTimeOriginal = camera.getTime() - TimeZone.getDefault().getOffset(camera.getTime());
if (camera.getLens() == Camera.Lens.FISHEYE) {
bestImageHeight = imageWidth;
} else if (camera.getLens() == Camera.Lens.SPHERICAL) {
@@ -781,6 +792,7 @@
}
} else {
// Compute 3D view offscreen image
+ photoDateTimeOriginal = System.currentTimeMillis();
HomeComponent3D homeComponent3D = new HomeComponent3D(
home, this.preferences, this.object3dFactory, quality == 1, null);
image = homeComponent3D.getOffScreenImage(imageWidth, imageHeight);
@@ -802,6 +814,9 @@
getActionMap().get(ActionType.SAVE_PHOTO).setEnabled(photoImage != null);
if (photoImage != null) {
getRootPane().setDefaultButton(saveButton);
+ if (controller.isDateShown()) {
+ annotatePhoto(photoImage, photoCreationStartTime, photoDateTimeOriginal);
+ }
}
createButton.setAction(getActionMap().get(ActionType.START_PHOTO_CREATION));
photoComponent.setImage(photoImage);
@@ -854,14 +869,16 @@

/**
* Saves the created image.
+ * @param showDate
*/
private void savePhoto() {
String pngFile = this.controller.getContentManager().showSaveDialog(this,
this.preferences.getLocalizedString(PhotoPanel.class, "savePhotoDialog.title"),
ContentManager.ContentType.PNG, this.home.getName());
try {
- if (pngFile != null) {
- ImageIO.write(this.photoComponent.getImage(), "PNG", new File(pngFile));
+ if (pngFile != null) {
+ writePhoto(this.photoComponent.getImage(), "PNG", new File(pngFile), this.photoCreationStartTime, this.photoDateTimeOriginal);
+ //ImageIO.write(this.photoComponent.getImage(), "PNG", new File(pngFile));
}
} catch (IOException ex) {
String messageFormat = this.preferences.getLocalizedString(PhotoPanel.class, "savePhotoError.message");
@@ -870,6 +887,51 @@
}
}

+ private void writePhoto(BufferedImage image, String string, File file, long createDateTime, long dateTimeOriginal) throws IOException {
+ SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy.MM.dd HH:mm:ssXXX");
+
+ String createTime = dateFormatter.format(createDateTime);
+ IIOMetadataNode textEntry1 = new IIOMetadataNode("tEXtEntry");
+ textEntry1.setAttribute("keyword", "CreateDateTime");
+ textEntry1.setAttribute("value", createTime);
+ IIOMetadataNode textNode1 = new IIOMetadataNode("tEXt");
+ textNode1.appendChild(textEntry1);
+
+ String photoTime = dateFormatter.format(dateTimeOriginal);
+ IIOMetadataNode textEntry2 = new IIOMetadataNode("tEXtEntry");
+ textEntry2.setAttribute("keyword", "DateTimeOriginal");
+ textEntry2.setAttribute("value", photoTime);
+ IIOMetadataNode textNode2 = new IIOMetadataNode("tEXt");
+ textNode2.appendChild(textEntry2);
+
+ IIOMetadataNode root = new IIOMetadataNode("javax_imageio_png_1.0");
+ root.appendChild(textNode1);
+ root.appendChild(textNode2);
+
+ ImageWriter writer = ImageIO.getImageWritersByFormatName("png").next();
+ ImageWriteParam writeParam = writer.getDefaultWriteParam();
+ ImageTypeSpecifier imageTypeSpecifier = ImageTypeSpecifier.createFromBufferedImageType(image.getType());
+ IIOMetadata imageMetadata = writer.getDefaultImageMetadata(imageTypeSpecifier, writeParam);
+ imageMetadata.mergeTree("javax_imageio_png_1.0", root);
+
+ IIOImage imageWithMetadata = new IIOImage(image, null, imageMetadata);
+ Object stream = ImageIO.createImageOutputStream(file);
+ writer.setOutput(stream);
+
+ writer.write(imageMetadata, imageWithMetadata, writeParam);
+ }
+
+ private void annotatePhoto(BufferedImage image, long createDateTime, long dateTimeOriginal) {
+ SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy.MM.dd HH:mm:ssXXX");
+ String photoTime = dateFormatter.format(dateTimeOriginal);
+ String createTime = dateFormatter.format(createDateTime);
+ Graphics graphics = image.getGraphics();
+ graphics.setFont(graphics.getFont().deriveFont(10f));
+ graphics.setColor(Color.RED);
+ graphics.drawString(photoTime + " (" + createTime + ")", 20, 20);
+ graphics.dispose();
+ }
+
/**
* Manages closing of this pane.
*/
Only in src/com/eteks/sweethome3d/swing: PhotoPanel.java.dateTimeOriginal
Only in src/com/eteks/sweethome3d/swing: PhotoPanel.java.keep
diff -r -u ../SweetHome3D-4.6-src-original/src/com/eteks/sweethome3d/swing/PhotoSizeAndQualityPanel.java src/com/eteks/sweethome3d/swing/PhotoSizeAndQualityPanel.java
--- ../SweetHome3D-4.6-src-original/src/com/eteks/sweethome3d/swing/PhotoSizeAndQualityPanel.java 2015-02-02 21:39:30.000000000 +1300
+++ src/com/eteks/sweethome3d/swing/PhotoSizeAndQualityPanel.java 2015-02-13 21:52:42.458590124 +1300
@@ -72,6 +72,7 @@
private JLabel heightLabel;
private JSpinner heightSpinner;
private JCheckBox applyProportionsCheckBox;
+ private JCheckBox addDateCheckBox;
private JComboBox aspectRatioComboBox;
private JLabel qualityLabel;
private JSlider qualitySlider;
@@ -141,6 +142,14 @@
: AspectRatio.FREE_RATIO);
}
});
+
+ this.addDateCheckBox = new JCheckBox();
+ this.addDateCheckBox.setSelected(controller.isDateShown());
+ this.addDateCheckBox.addItemListener(new ItemListener() {
+ public void itemStateChanged(ItemEvent ev) {
+ controller.setDateShown(addDateCheckBox.isSelected());
+ }
+ });
this.aspectRatioComboBox = new JComboBox(new Object [] {
AspectRatio.VIEW_3D_RATIO,
AspectRatio.SQUARE_RATIO,
@@ -196,6 +205,7 @@
applyProportionsCheckBox.setSelected(notFreeAspectRatio);
aspectRatioComboBox.setEnabled(notFreeAspectRatio);
aspectRatioComboBox.setSelectedItem(controller.getAspectRatio());
+ addDateCheckBox.setSelected(controller.isDateShown());
}
});

@@ -309,6 +319,8 @@
PhotoSizeAndQualityPanel.class, "heightLabel.text"));
this.applyProportionsCheckBox.setText(SwingTools.getLocalizedLabelText(preferences,
PhotoSizeAndQualityPanel.class, "applyProportionsCheckBox.text"));
+ this.addDateCheckBox.setText(SwingTools.getLocalizedLabelText(preferences,
+ PhotoSizeAndQualityPanel.class, "addDateCheckBox.text"));
this.qualityLabel.setText(SwingTools.getLocalizedLabelText(preferences,
PhotoSizeAndQualityPanel.class, "qualityLabel.text"));
this.fastQualityLabel.setText(SwingTools.getLocalizedLabelText(preferences,
@@ -333,6 +345,8 @@
this.heightLabel.setLabelFor(this.heightSpinner);
this.applyProportionsCheckBox.setMnemonic(KeyStroke.getKeyStroke(preferences.getLocalizedString(
PhotoSizeAndQualityPanel.class, "applyProportionsCheckBox.mnemonic")).getKeyCode());
+ this.addDateCheckBox.setMnemonic(KeyStroke.getKeyStroke(preferences.getLocalizedString(
+ PhotoSizeAndQualityPanel.class, "addDateCheckBox.mnemonic")).getKeyCode());
this.qualityLabel.setDisplayedMnemonic(KeyStroke.getKeyStroke(preferences.getLocalizedString(
PhotoSizeAndQualityPanel.class, "qualityLabel.mnemonic")).getKeyCode());
this.qualityLabel.setLabelFor(this.qualitySlider);
@@ -394,6 +408,7 @@
JPanel proportionsPanel = new JPanel();
proportionsPanel.add(this.applyProportionsCheckBox);
proportionsPanel.add(this.aspectRatioComboBox);
+ proportionsPanel.add(this.addDateCheckBox);
add(proportionsPanel, new GridBagConstraints(
0, 1, 4, 1, 0, 0, GridBagConstraints.CENTER,
GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
@@ -423,6 +438,7 @@
this.widthSpinner.setEnabled(enabled);
this.heightSpinner.setEnabled(enabled);
this.applyProportionsCheckBox.setEnabled(enabled);
+ this.addDateCheckBox.setEnabled(enabled);
this.aspectRatioComboBox.setEnabled(enabled);
this.qualitySlider.setEnabled(enabled);
}
diff -r -u ../SweetHome3D-4.6-src-original/src/com/eteks/sweethome3d/viewcontroller/AbstractPhotoController.java src/com/eteks/sweethome3d/viewcontroller/AbstractPhotoController.java
--- ../SweetHome3D-4.6-src-original/src/com/eteks/sweethome3d/viewcontroller/AbstractPhotoController.java 2015-02-02 21:39:30.000000000 +1300
+++ src/com/eteks/sweethome3d/viewcontroller/AbstractPhotoController.java 2015-02-13 21:52:42.439590123 +1300
@@ -51,6 +51,7 @@
private int quality;
private float view3DAspectRatio;
private int ceilingLightColor;
+ private boolean dateShown;

public AbstractPhotoController(Home home,
UserPreferences preferences,
@@ -309,4 +310,14 @@
Object propertyValue) {
this.home.setVisualProperty(propertyName, propertyValue);
}
+
+ public boolean isDateShown() {
+ return this.dateShown;
+ }
+
+ public void setDateShown(boolean dateShown) {
+ this.dateShown = dateShown;
+ }
+
+
}

[Feb 18, 2015 6:45:11 AM] Show Printable Version of Post    View Member Profile    Send Private Message    https://www.flickr.com/photos/digitaltrails/ [Link] Report threatening or abusive post: please login first  Go to top 
okh
Advanced Member




Joined: May 12, 2013
Post Count: 1287
Status: Offline
Reply to this Post  Reply with Quote 
Re: Photo Date-Time Metadata and Annotations

Nice idea! How about the geo fields (LAT/LON) which also have a great impact on how the sun renders... ?
[Feb 19, 2015 8:02:30 AM] Show Printable Version of Post    View Member Profile    Send Private Message    Hidden to Guest [Link] Report threatening or abusive post: please login first  Go to top 
digitaltrails
Member



New Zealand
Joined: Dec 28, 2014
Post Count: 45
Status: Offline
Reply to this Post  Reply with Quote 
Re: Photo Date-Time Metadata and Annotations

Nice idea! How about the geo fields (LAT/LON) which also have a great impact on how the sun renders... ?

That would be possible.

Extra info such as the render camera settings would definitely be useful.

I did consider embedding the geo data, but I wasn't sure I wanted GPS coordinates to my house buried inside the images, especially if it was a overhead plan view (I'm sure you're all nice people, but...). If this were to be done, I think it would have to be controlled by a setting that would default to off.

If the eTeks decide to fold this code in, I don't mind putting it some effort to include a few more attributes.

Initially I wasn't sure whether displaying text on the image was totally necessary. But metadata embedded in PNG's is only supported by a few imaging tools. It turns out there is no well established metadata standard for PNG's (that came as a bit of a shock). That pushed me to experimenting with an option for annotating the actual image.
[Feb 19, 2015 9:04:57 AM] Show Printable Version of Post    View Member Profile    Send Private Message    https://www.flickr.com/photos/digitaltrails/ [Link] Report threatening or abusive post: please login first  Go to top 
okh
Advanced Member




Joined: May 12, 2013
Post Count: 1287
Status: Offline
Reply to this Post  Reply with Quote 
Re: Photo Date-Time Metadata and Annotations

It turns out there is no well established metadata standard for PNG's...
Yes, isn't that strange? Has puzzled me too (even if ExifTool, I think, has set some sort of standard?). But then, (standardised) meta-data in general, is not very often a priority. About the GEO data, I certainly see the pricacy issues (could be a good idea to remove compass data when posting .sh3d files). ok
[Feb 20, 2015 8:18:35 AM] Show Printable Version of Post    View Member Profile    Send Private Message    Hidden to Guest [Link] Report threatening or abusive post: please login first  Go to top 
[ Jump to Last Post ]
Show Printable Version of Thread  Post new Thread

    Get Sweet Home 3D at SourceForge.net. Fast, secure and Free Open Source software downloads
   
© Copyright 2006-2017 eTeks - All rights reserved