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}