001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.plugins.streetside.io.export; 003 004import java.awt.image.BufferedImage; 005import java.io.BufferedOutputStream; 006import java.io.ByteArrayOutputStream; 007import java.io.FileOutputStream; 008import java.io.IOException; 009import java.io.OutputStream; 010import java.util.concurrent.ArrayBlockingQueue; 011 012import javax.imageio.ImageIO; 013 014import org.apache.commons.imaging.ImageReadException; 015import org.apache.commons.imaging.ImageWriteException; 016import org.apache.commons.imaging.common.RationalNumber; 017import org.apache.commons.imaging.formats.jpeg.exif.ExifRewriter; 018import org.apache.commons.imaging.formats.tiff.constants.ExifTagConstants; 019import org.apache.commons.imaging.formats.tiff.constants.GpsTagConstants; 020import org.apache.commons.imaging.formats.tiff.write.TiffOutputDirectory; 021import org.apache.commons.imaging.formats.tiff.write.TiffOutputSet; 022import org.apache.log4j.Logger; 023import org.openstreetmap.josm.gui.progress.ProgressMonitor; 024import org.openstreetmap.josm.gui.progress.swing.PleaseWaitProgressMonitor; 025import org.openstreetmap.josm.plugins.streetside.StreetsideAbstractImage; 026 027/** 028 * Writes the images from the queue in the file system. 029 * 030 * @author nokutu 031 * @see StreetsideExportManager 032 */ 033public class StreetsideExportWriterThread extends Thread { 034 035 final static Logger logger = Logger.getLogger(StreetsideExportWriterThread.class); 036 037 private final String path; 038 private final ArrayBlockingQueue<BufferedImage> queue; 039 private final ArrayBlockingQueue<StreetsideAbstractImage> queueImages; 040 private final int amount; 041 private final ProgressMonitor monitor; 042 043 /** 044 * Main constructor. 045 * 046 * @param path 047 * Path to write the pictures. 048 * @param queue 049 * Queue of {@link StreetsideAbstractImage} objects. 050 * @param queueImages 051 * Queue of {@link BufferedImage} objects. 052 * @param amount 053 * Amount of images that are going to be exported. 054 * @param monitor 055 * Progress monitor. 056 */ 057 public StreetsideExportWriterThread(String path, 058 ArrayBlockingQueue<BufferedImage> queue, 059 ArrayBlockingQueue<StreetsideAbstractImage> queueImages, int amount, 060 ProgressMonitor monitor) { 061 this.path = path; 062 this.queue = queue; 063 this.queueImages = queueImages; 064 this.amount = amount; 065 this.monitor = monitor; 066 } 067 068 @Override 069 public void run() { 070 monitor.setCustomText("Downloaded 0/" + amount); 071 BufferedImage img; 072 StreetsideAbstractImage mimg; 073 String finalPath = ""; 074 for (int i = 0; i < amount; i++) { 075 try { 076 img = queue.take(); 077 mimg = queueImages.take(); 078 079 080 // Transforms the image into a byte array. 081 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 082 ImageIO.write(img, "jpg", outputStream); 083 byte[] imageBytes = outputStream.toByteArray(); 084 085 // Write EXIF tags 086 TiffOutputSet outputSet = null; 087 TiffOutputDirectory exifDirectory; 088 TiffOutputDirectory gpsDirectory; 089 // If the image is imported, loads the rest of the EXIF data. 090 091 if (null == outputSet) { 092 outputSet = new TiffOutputSet(); 093 } 094 exifDirectory = outputSet.getOrCreateExifDirectory(); 095 gpsDirectory = outputSet.getOrCreateGPSDirectory(); 096 097 gpsDirectory.removeField(GpsTagConstants.GPS_TAG_GPS_IMG_DIRECTION_REF); 098 gpsDirectory.add(GpsTagConstants.GPS_TAG_GPS_IMG_DIRECTION_REF, 099 GpsTagConstants.GPS_TAG_GPS_IMG_DIRECTION_REF_VALUE_TRUE_NORTH); 100 101 gpsDirectory.removeField(GpsTagConstants.GPS_TAG_GPS_IMG_DIRECTION); 102 gpsDirectory.add(GpsTagConstants.GPS_TAG_GPS_IMG_DIRECTION, 103 RationalNumber.valueOf(mimg.getMovingHe())); 104 105 exifDirectory.removeField(ExifTagConstants.EXIF_TAG_DATE_TIME_ORIGINAL); 106 107 outputSet.setGPSInDegrees(mimg.getMovingLatLon().lon(), mimg.getMovingLatLon().lat()); 108 OutputStream os = new BufferedOutputStream(new FileOutputStream(finalPath + ".jpg")); 109 new ExifRewriter().updateExifMetadataLossless(imageBytes, os, outputSet); 110 111 os.close(); 112 } catch (InterruptedException e) { 113 logger.info("Streetside export cancelled"); 114 return; 115 } catch (IOException | ImageReadException | ImageWriteException e) { 116 logger.error(e); 117 } 118 119 // Increases the progress bar. 120 monitor.worked(PleaseWaitProgressMonitor.PROGRESS_BAR_MAX / amount); 121 monitor.setCustomText("Downloaded " + (i + 1) + "/" + amount); 122 } 123 } 124}