Changeset 19845 in osm for applications/editors/josm
- Timestamp:
- 2010-02-03T11:10:46+01:00 (15 years ago)
- Location:
- applications/editors/josm/plugins/photo_geotagging
- Files:
-
- 2 added
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
applications/editors/josm/plugins/photo_geotagging/build.xml
r19672 r19845 25 25 26 26 <!-- enter the SVN commit message --> 27 <property name="commit.message" value="josm plugin photo_geotagging: update" />27 <property name="commit.message" value="josm plugin photo_geotagging: added mtime handling and GPSTimeStamp writing" /> 28 28 <!-- enter the *lowest* JOSM version this plugin is currently compatible with --> 29 <property name="plugin.main.version" value="29 04" />29 <property name="plugin.main.version" value="2931" /> 30 30 31 31 -
applications/editors/josm/plugins/photo_geotagging/src/org/openstreetmap/josm/plugins/photo_geotagging/ExifGPSTagger.java
r19671 r19845 1 // This is from a file of the sanselan project that is supposed to show, how the library can be used: 2 // https://svn.apache.org/repos/asf/commons/proper/sanselan/trunk/src/test/java/org/apache/sanselan/sampleUsage/WriteExifMetadataExample.java 1 // Wrapper class for sanselan library 3 2 package org.openstreetmap.josm.plugins.photo_geotagging; 4 3 … … 6 5 7 6 import java.io.BufferedOutputStream; 8 import java.io.IOException;9 7 import java.io.File; 10 8 import java.io.FileOutputStream; 9 import java.io.IOException; 11 10 import java.io.OutputStream; 11 import java.util.Calendar; 12 import java.util.GregorianCalendar; 13 import java.util.TimeZone; 14 import java.text.DecimalFormat; 12 15 13 16 import org.apache.sanselan.ImageReadException; … … 18 21 import org.apache.sanselan.formats.jpeg.exifRewrite.ExifRewriter; 19 22 import org.apache.sanselan.formats.tiff.TiffImageMetadata; 23 import org.apache.sanselan.formats.tiff.constants.TagInfo; 24 import org.apache.sanselan.formats.tiff.constants.TiffConstants; 25 import org.apache.sanselan.formats.tiff.fieldtypes.FieldType; 26 import org.apache.sanselan.formats.tiff.write.TiffOutputDirectory; 27 import org.apache.sanselan.formats.tiff.write.TiffOutputField; 20 28 import org.apache.sanselan.formats.tiff.write.TiffOutputSet; 21 29 … … 24 32 * Set the GPS values in JPEG EXIF metadata. 25 33 * This is taken from one of the examples of the sanselan project. 26 * 27 * @param jpegImageFile 28 * A source image file. 29 * @param dst 30 * The output file. 31 * @throws IOException 32 * @throws ImageReadException 33 * @throws ImageWriteException 34 * 35 * @param jpegImageFile A source image file. 36 * @param dst The output file. 37 * @param lat latitude 38 * @param lon longitude 39 * @param gpsTime time in milliseconds 34 40 */ 35 public static void setExifGPSTag(File jpegImageFile, File dst, double lat, double lon) throws IOException { 41 public static void setExifGPSTag(File jpegImageFile, File dst, double lat, double lon, long gpsTime) throws IOException { 36 42 try { 37 setExifGPSTagWorker(jpegImageFile, dst, lat, lon); 43 setExifGPSTagWorker(jpegImageFile, dst, lat, lon, gpsTime); 38 44 } catch (ImageReadException ire) { 39 45 throw new IOException(tr("Read error!")); … … 41 47 throw new IOException(tr("Write error!")); 42 48 } 43 } 44 45 public static void setExifGPSTagWorker(File jpegImageFile, File dst, double lat, double lon) throws IOException, 49 } 50 51 public static void setExifGPSTagWorker(File jpegImageFile, File dst, double lat, double lon, long gpsTime) throws IOException, 46 52 ImageReadException, ImageWriteException 47 53 { 48 54 OutputStream os = null; 49 try 50 { 55 try { 51 56 TiffOutputSet outputSet = null; 52 57 53 // note that metadata might be null if no metadata is found.54 58 IImageMetadata metadata = Sanselan.getMetadata(jpegImageFile); 55 59 JpegImageMetadata jpegMetadata = (JpegImageMetadata) metadata; 56 if (null != jpegMetadata) 57 { 58 // note that exif might be null if no Exif metadata is found. 60 if (null != jpegMetadata) { 59 61 TiffImageMetadata exif = jpegMetadata.getExif(); 60 62 61 if (null != exif) 62 { 63 // TiffImageMetadata class is immutable (read-only). 64 // TiffOutputSet class represents the Exif data to write. 65 // 66 // Usually, we want to update existing Exif metadata by 67 // changing 68 // the values of a few fields, or adding a field. 69 // In these cases, it is easiest to use getOutputSet() to 70 // start with a "copy" of the fields read from the image. 63 if (null != exif) { 71 64 outputSet = exif.getOutputSet(); 72 65 } 73 66 } 74 67 75 // if file does not contain any exif metadata, we create an empty 76 // set of exif metadata. Otherwise, we keep all of the other 77 // existing tags. 78 if (null == outputSet) 68 if (null == outputSet) { 79 69 outputSet = new TiffOutputSet(); 70 } 80 71 81 { 82 outputSet.setGPSInDegrees(lon, lat); 83 } 72 Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone("UTC")); 73 74 calendar.setTimeInMillis(gpsTime); 75 76 final int year = calendar.get(Calendar.YEAR); 77 final int month = calendar.get(Calendar.MONTH); 78 final int day = calendar.get(Calendar.DAY_OF_MONTH); 79 final int hour = calendar.get(Calendar.HOUR_OF_DAY); 80 final int minute = calendar.get(Calendar.MINUTE); 81 final int second = calendar.get(Calendar.SECOND); 82 83 DecimalFormat yearFormatter = new DecimalFormat("0000"); 84 DecimalFormat monthFormatter = new DecimalFormat("00"); 85 DecimalFormat dayFormatter = new DecimalFormat("00"); 86 87 final String yearStr = yearFormatter.format(year); 88 final String monthStr = monthFormatter.format(month); 89 final String dayStr = dayFormatter.format(day); 90 final String dateStamp = yearStr+":"+monthStr+":"+dayStr; 91 //System.err.println("date: "+dateStamp+" h/m/s: "+hour+"/"+minute+"/"+second); 92 93 Double[] timeStamp = {new Double(hour), new Double(minute), new Double(second)}; 94 TiffOutputField gpsTimeStamp = TiffOutputField.create( 95 TiffConstants.GPS_TAG_GPS_TIME_STAMP, 96 outputSet.byteOrder, timeStamp); 97 TiffOutputDirectory exifDirectory = outputSet.getOrCreateGPSDirectory(); 98 // make sure to remove old value if present (this method will 99 // not fail if the tag does not exist). 100 exifDirectory.removeField(TiffConstants.GPS_TAG_GPS_TIME_STAMP); 101 exifDirectory.add(gpsTimeStamp); 102 103 TiffOutputField gpsDateStamp = SanselanFixes.create( 104 TiffConstants.GPS_TAG_GPS_DATE_STAMP, 105 outputSet.byteOrder, dateStamp); 106 // make sure to remove old value if present (this method will 107 // not fail if the tag does not exist). 108 exifDirectory.removeField(TiffConstants.GPS_TAG_GPS_DATE_STAMP); 109 exifDirectory.add(gpsDateStamp); 110 111 SanselanFixes.setGPSInDegrees(outputSet, lon, lat); 84 112 85 113 os = new FileOutputStream(dst); … … 91 119 os.close(); 92 120 os = null; 93 } finally 94 { 95 if (os != null) 96 try 97 { 121 } finally { 122 if (os != null) { 123 try { 98 124 os.close(); 99 } catch (IOException e) 100 { 101 102 } 125 } catch (IOException e) {} 126 } 103 127 } 104 128 } -
applications/editors/josm/plugins/photo_geotagging/src/org/openstreetmap/josm/plugins/photo_geotagging/GeotaggingPlugin.java
r19671 r19845 5 5 6 6 import java.awt.Component; 7 import java.awt.Dimension;8 import java.awt.GridBagLayout;9 import java.awt.Rectangle;10 import java.awt.event.ActionEvent;11 import java.awt.event.ActionListener;12 7 13 import java.io.IOException; 14 import java.io.File; 8 import javax.swing.JMenuItem; 15 9 16 import java.util.ArrayList;17 import java.util.List;18 19 import javax.swing.AbstractListModel;20 import javax.swing.JCheckBox;21 import javax.swing.JLabel;22 import javax.swing.JList;23 import javax.swing.JMenuItem;24 import javax.swing.JOptionPane;25 import javax.swing.JPanel;26 import javax.swing.JScrollPane;27 import javax.swing.UIManager;28 29 import java.text.DecimalFormat;30 31 import org.openstreetmap.josm.Main;32 import org.openstreetmap.josm.gui.ExtendedDialog;33 import org.openstreetmap.josm.gui.PleaseWaitRunnable;34 10 import org.openstreetmap.josm.gui.layer.Layer; 35 11 import org.openstreetmap.josm.gui.layer.geoimage.GeoImageLayer; 36 12 import org.openstreetmap.josm.gui.layer.geoimage.ImageEntry; 37 import org.openstreetmap.josm.gui.progress.ProgressMonitor;38 13 import org.openstreetmap.josm.plugins.Plugin; 39 14 import org.openstreetmap.josm.plugins.PluginInformation; 40 import org.openstreetmap.josm.tools.GBC;41 15 import org.openstreetmap.josm.tools.ImageProvider; 42 16 … … 46 20 * It extends the core geoimage feature of JOSM by adding a new entry 47 21 * to the right click menu of any image layer. 48 * 22 * 49 23 * The real work (writing lat/lon values to file) is done by the pure Java 50 24 * sanselan library. 51 25 */ 52 26 public class GeotaggingPlugin extends Plugin { 53 final static boolean debug = false;54 final static String KEEP_BACKUP = "plugins.photo_geotagging.keep_backup";55 56 27 public GeotaggingPlugin(PluginInformation info) { 57 28 super(info); 58 29 GeoImageLayer.registerMenuAddition(new GeotaggingMenuAddition()); 59 30 } 60 31 32 /** 33 * Adds a menu entry to the right click menu of each geoimage layer. 34 */ 61 35 class GeotaggingMenuAddition implements GeoImageLayer.LayerMenuAddition { 62 36 public Component getComponent(Layer layer) { 63 37 JMenuItem geotaggingItem = new JMenuItem(tr("Write coordinates to image header"), ImageProvider.get("geotagging"));; 64 geotaggingItem.addActionListener(new GeotagImages((GeoImageLayer) layer)); 38 geotaggingItem.addActionListener(new GeotaggingAction((GeoImageLayer) layer)); 39 geotaggingItem.setEnabled(enabled((GeoImageLayer) layer)); 65 40 return geotaggingItem; 66 41 } 67 } 68 69 class GeotagImages implements ActionListener { 70 final private GeoImageLayer layer; 71 public GeotagImages(GeoImageLayer layer) { 72 this.layer = layer; 73 } 74 75 public void actionPerformed(ActionEvent arg0) { 76 final List<ImageEntry> images = new ArrayList<ImageEntry>(); 42 43 /** 44 * Check if there is any suitable image. 45 */ 46 private boolean enabled(GeoImageLayer layer) { 77 47 for (ImageEntry e : layer.getImages()) { 78 if (e.getPos() != null) { 79 images.add(e); 80 } 48 if (e.getPos() != null && e.getGpsTime() != null) 49 return true; 81 50 } 82 83 final JPanel cont = new JPanel(new GridBagLayout()); 84 cont.add(new JLabel(tr("Write position information into the exif header of the following files:")), GBC.eol()); 85 86 FileList files = new FileList(); 87 files.setVisibleRowCount(Math.min(files.getModel().getSize(), 10)); 88 final List<String> strs = new ArrayList<String>(); 89 DecimalFormat cDdFormatter = new DecimalFormat("###0.000000"); 90 91 for (ImageEntry e : images) { 92 strs.add(e.getFile().getAbsolutePath()+" ("+cDdFormatter.format(e.getPos().lat())+","+cDdFormatter.format(e.getPos().lon())+")"); 93 } 94 files.getFileListModel().setFiles(strs); 95 JScrollPane scroll = new JScrollPane(files); 96 scroll.setPreferredSize(new Dimension(300, 250)); 97 cont.add(scroll, GBC.eol().fill(GBC.BOTH)); 98 99 final JCheckBox backups = new JCheckBox(tr("keep backup files"), Main.pref.getBoolean(KEEP_BACKUP, true)); 100 cont.add(backups, GBC.eol()); 101 102 int result = new ExtendedDialog( 103 Main.parent, 104 tr("Photo Geotagging Plugin"), 105 new String[] {tr("OK"), tr("Cancel")}) 106 .setButtonIcons(new String[] {"ok.png", "cancel.png"}) 107 .setContent(cont) 108 .setCancelButton(2) 109 .setDefaultButton(1) 110 .showDialog() 111 .getValue(); 112 113 if (result != 1) 114 return; 115 116 final boolean keep_backup = backups.isSelected(); 117 Main.pref.put(KEEP_BACKUP, keep_backup); 118 119 Main.worker.execute(new GeoTaggingRunnable(images, keep_backup)); 51 return false; 120 52 } 121 53 } 122 123 class GeoTaggingRunnable extends PleaseWaitRunnable {124 private boolean cancelled = false;125 final private boolean keep_backup;126 final List<ImageEntry> images;127 private Boolean override_backup = null;128 129 private File fileFrom;130 private File fileTo;131 private File fileDelete;132 133 public GeoTaggingRunnable(List<ImageEntry> images, boolean keep_backup) {134 super(tr("Photo Geotagging Plugin"));135 this.images = images;136 this.keep_backup = keep_backup;137 }138 @Override139 protected void realRun() {140 progressMonitor.subTask(tr("Writing position information to image files..."));141 progressMonitor.setTicksCount(images.size());142 143 144 for (int i=0; i<images.size(); ++i) {145 if (cancelled) return;146 147 ImageEntry e = images.get(i);148 if (debug) {149 System.err.print("i:"+i+" "+e.getFile().getName()+" ");150 }151 152 fileFrom = null;153 fileTo = null;154 fileDelete = null;155 156 try {157 chooseFiles(e.getFile());158 if (cancelled) return;159 ExifGPSTagger.setExifGPSTag(fileFrom, fileTo, e.getPos().lat(), e.getPos().lon());160 cleanupFiles();161 } catch (IOException ioe) {162 ioe.printStackTrace();163 JOptionPane.showMessageDialog(Main.parent, tr("Error: ")+ioe.getMessage(), tr("Error"), JOptionPane.ERROR_MESSAGE);164 return;165 }166 progressMonitor.worked(1);167 if (debug) {168 System.err.println("");169 }170 }171 }172 173 private void chooseFiles(File file) throws IOException {174 if (debug) {175 System.err.println("f: "+file.getAbsolutePath());176 }177 178 if (!keep_backup) {179 chooseFilesNoBackup(file);180 return;181 }182 183 File fileBackup = new File(file.getParentFile(),file.getName()+"_");184 if (fileBackup.exists()) {185 if (debug) {186 System.err.println("FILE EXISTS");187 }188 189 confirm_override();190 if (cancelled)191 return;192 193 if (override_backup) {194 if (!fileBackup.delete())195 throw new IOException(tr("File could not be deleted!"));196 } else {197 chooseFilesNoBackup(file);198 return;199 }200 }201 if (!file.renameTo(fileBackup))202 throw new IOException(tr("Could not rename file!"));203 204 fileFrom = fileBackup;205 fileTo = file;206 fileDelete = null;207 }208 209 private void chooseFilesNoBackup(File file) throws IOException {210 File fileTmp;211 fileTmp = File.createTempFile("img", ".jpg", file.getParentFile());212 if (debug) {213 System.err.println("TMP: "+fileTmp.getAbsolutePath());214 }215 if (! file.renameTo(fileTmp))216 throw new IOException(tr("Could not rename file!"));217 218 fileFrom = fileTmp;219 fileTo = file;220 fileDelete = fileTmp;221 }222 223 private void confirm_override() {224 if (override_backup == null) {225 JLabel l = new JLabel(tr("<html><h3>There are old backup files in the image directory!</h3>"));226 l.setIcon(UIManager.getIcon("OptionPane.warningIcon"));227 int override = new ExtendedDialog(228 Main.parent,229 tr("Override old backup files?"),230 new String[] {tr("Cancel"), tr("Keep old backups and continue"), tr("Override")})231 .setButtonIcons(new String[] {"cancel.png", "ok.png", "dialogs/delete.png"})232 .setContent(l)233 .setCancelButton(1)234 .setDefaultButton(2)235 .showDialog()236 .getValue();237 if (override == 2) {238 override_backup = false;239 } else if (override == 3) {240 override_backup = true;241 } else {242 cancelled = true;243 return;244 }245 }246 }247 248 private void cleanupFiles() throws IOException {249 if (fileDelete != null) {250 if (!fileDelete.delete())251 throw new IOException(tr("Could not delete temporary file!"));252 }253 }254 255 @Override256 protected void finish() {257 }258 259 @Override260 protected void cancel() {261 cancelled = true;262 }263 }264 265 static class FileList extends JList {266 public FileList() {267 super(new FileListModel());268 }269 270 public FileListModel getFileListModel() {271 return (FileListModel)getModel();272 }273 }274 275 static class FileListModel extends AbstractListModel{276 private List<String> files;277 278 public FileListModel() {279 files = new ArrayList<String>();280 }281 282 public FileListModel(List<String> files) {283 setFiles(files);284 }285 286 public void setFiles(List<String> files) {287 if (files == null) {288 this.files = new ArrayList<String>();289 } else {290 this.files = files;291 }292 fireContentsChanged(this,0,getSize());293 }294 295 public Object getElementAt(int index) {296 if (files == null) return null;297 return files.get(index);298 }299 300 public int getSize() {301 if (files == null) return 0;302 return files.size();303 }304 }305 54 }
Note:
See TracChangeset
for help on using the changeset viewer.