示例#1
0
  // Returns the task if we started the task or the task is already started.
  private Future<?> startTaskIfNeeded(int index, int which) {
    if (index < mActiveStart || index >= mActiveEnd) return null;

    ImageEntry entry = mImageCache.get(getVersion(index));
    if (entry == null) return null;

    if (which == BIT_SCREEN_NAIL && entry.screenNailTask != null) {
      return entry.screenNailTask;
    } else if (which == BIT_FULL_IMAGE && entry.fullImageTask != null) {
      return entry.fullImageTask;
    }

    MediaItem item = mData[index % DATA_CACHE_SIZE];
    Utils.assertTrue(item != null);

    if (which == BIT_SCREEN_NAIL && (entry.requestedBits & BIT_SCREEN_NAIL) == 0) {
      entry.requestedBits |= BIT_SCREEN_NAIL;
      entry.screenNailTask =
          mThreadPool.submit(
              new ScreenNailJob(item), new ScreenNailListener(item.getDataVersion()));
      // request screen nail
      return entry.screenNailTask;
    }
    if (which == BIT_FULL_IMAGE
        && (entry.requestedBits & BIT_FULL_IMAGE) == 0
        && (item.getSupportedOperations() & MediaItem.SUPPORT_FULL_IMAGE) != 0) {
      entry.requestedBits |= BIT_FULL_IMAGE;
      entry.fullImageTask =
          mThreadPool.submit(
              item.requestLargeImage(), new FullImageListener(item.getDataVersion()));
      // request full image
      return entry.fullImageTask;
    }
    return null;
  }
示例#2
0
  private void updateImageCache() {
    HashSet<Long> toBeRemoved = new HashSet<Long>(mImageCache.keySet());
    for (int i = mActiveStart; i < mActiveEnd; ++i) {
      MediaItem item = mData[i % DATA_CACHE_SIZE];
      long version = item == null ? MediaObject.INVALID_DATA_VERSION : item.getDataVersion();
      if (version == MediaObject.INVALID_DATA_VERSION) continue;
      ImageEntry entry = mImageCache.get(version);
      toBeRemoved.remove(version);
      if (entry != null) {
        if (Math.abs(i - mCurrentIndex) > 1) {
          if (entry.fullImageTask != null) {
            entry.fullImageTask.cancel();
            entry.fullImageTask = null;
          }
          entry.fullImage = null;
          entry.requestedBits &= ~BIT_FULL_IMAGE;
        }
      } else {
        entry = new ImageEntry();
        entry.rotation = item.getFullImageRotation();
        mImageCache.put(version, entry);
      }
    }

    // Clear the data and requests for ImageEntries outside the new window.
    for (Long version : toBeRemoved) {
      ImageEntry entry = mImageCache.remove(version);
      if (entry.fullImageTask != null) entry.fullImageTask.cancel();
      if (entry.screenNailTask != null) entry.screenNailTask.cancel();
    }
  }
示例#3
0
  private void updateImageRequests() {
    if (!mIsActive) return;

    int currentIndex = mCurrentIndex;
    MediaItem item = mData[currentIndex % DATA_CACHE_SIZE];
    if (item == null || item.getPath() != mItemPath) {
      // current item mismatch - don't request image
      return;
    }

    // 1. Find the most wanted request and start it (if not already started).
    Future<?> task = null;
    for (int i = 0; i < sImageFetchSeq.length; i++) {
      int offset = sImageFetchSeq[i].indexOffset;
      int bit = sImageFetchSeq[i].imageBit;
      task = startTaskIfNeeded(currentIndex + offset, bit);
      if (task != null) break;
    }

    // 2. Cancel everything else.
    for (ImageEntry entry : mImageCache.values()) {
      if (entry.screenNailTask != null && entry.screenNailTask != task) {
        entry.screenNailTask.cancel();
        entry.screenNailTask = null;
        entry.requestedBits &= ~BIT_SCREEN_NAIL;
      }
      if (entry.fullImageTask != null && entry.fullImageTask != task) {
        entry.fullImageTask.cancel();
        entry.fullImageTask = null;
        entry.requestedBits &= ~BIT_FULL_IMAGE;
      }
    }
  }
示例#4
0
  /**
   * Returns a list of images that fulfill the given criteria. Default setting is to return untagged
   * images, but may be overwritten.
   *
   * @param exif also returns images with exif-gps info
   * @param tagged also returns tagged images
   * @return matching images
   */
  private List<ImageEntry> getSortedImgList(boolean exif, boolean tagged) {
    if (yLayer.data == null) {
      return Collections.emptyList();
    }
    List<ImageEntry> dateImgLst = new ArrayList<>(yLayer.data.size());
    for (ImageEntry e : yLayer.data) {
      if (!e.hasExifTime()) {
        continue;
      }

      if (e.getExifCoor() != null && !exif) {
        continue;
      }

      if (e.isTagged() && e.getExifCoor() == null && !tagged) {
        continue;
      }

      dateImgLst.add(e);
    }

    Collections.sort(
        dateImgLst,
        new Comparator<ImageEntry>() {
          @Override
          public int compare(ImageEntry arg0, ImageEntry arg1) {
            return arg0.getExifTime().compareTo(arg1.getExifTime());
          }
        });

    return dateImgLst;
  }
示例#5
0
 public List<ImageEntry> getImages() {
   List<ImageEntry> copy = new ArrayList<ImageEntry>();
   for (ImageEntry ie : data) {
     copy.add(ie.clone());
   }
   return copy;
 }
示例#6
0
 /**
  * Returns the image that matches the position of the mouse event.
  *
  * @param evt Mouse event
  * @return Image at mouse position, or {@code null} if there is no image at the mouse position
  * @since 6392
  */
 public ImageEntry getPhotoUnderMouse(MouseEvent evt) {
   if (data != null) {
     for (int idx = data.size() - 1; idx >= 0; --idx) {
       ImageEntry img = data.get(idx);
       if (img.getPos() == null) {
         continue;
       }
       Point p = Main.map.mapView.getPoint(img.getPos());
       Rectangle r;
       if (useThumbs && img.hasThumbnail()) {
         Dimension d = scaledDimension(img.getThumbnail());
         r = new Rectangle(p.x - d.width / 2, p.y - d.height / 2, d.width, d.height);
       } else {
         r =
             new Rectangle(
                 p.x - icon.getIconWidth() / 2,
                 p.y - icon.getIconHeight() / 2,
                 icon.getIconWidth(),
                 icon.getIconHeight());
       }
       if (r.contains(evt.getPoint())) {
         return img;
       }
     }
   }
   return null;
 }
示例#7
0
    @Override
    protected void finish() {
      if (!errorMessages.isEmpty()) {
        JOptionPane.showMessageDialog(
            Main.parent, formatErrorMessages(), tr("Error"), JOptionPane.ERROR_MESSAGE);
      }
      if (layer != null) {
        Main.main.addLayer(layer);
        layer.hook_up_mouse_events(); // Main.map.mapView should exist
        // now. Can add mouse listener
        Main.map.mapView.addPropertyChangeListener(layer);
        if (Main.map.getToggleDialog(ImageViewerDialog.class) == null) {
          ImageViewerDialog.newInstance();
          Main.map.addToggleDialog(ImageViewerDialog.getInstance());
        }

        if (!cancelled && layer.data.size() > 0) {
          boolean noGeotagFound = true;
          for (ImageEntry e : layer.data) {
            if (e.getPos() != null) {
              noGeotagFound = false;
            }
          }
          if (noGeotagFound) {
            new CorrelateGpxWithImages(layer).actionPerformed(null);
          }
        }
      }
    }
示例#8
0
  private void updateScreenNail(long version, Future<Bitmap> future) {
    ImageEntry entry = mImageCache.get(version);
    if (entry == null || entry.screenNailTask != future) {
      Bitmap screenNail = future.get();
      if (screenNail != null) screenNail.recycle();
      return;
    }

    entry.screenNailTask = null;
    entry.screenNail = future.get();

    if (entry.screenNail == null) {
      entry.failToLoad = true;
      /*a@nufront start*/
      for (int i = -1; i <= 1; ++i) {
        if (version == getVersion(mCurrentIndex + i)) {
          if (0 == i) updateTileProvider(entry);
          mPhotoView.notifyImageInvalidated(i);
        }
      }
      /*a@nufront end*/
    } else {
      if (mDataListener != null) {
        mDataListener.onPhotoAvailable(version, false);
      }
      for (int i = -1; i <= 1; ++i) {
        if (version == getVersion(mCurrentIndex + i)) {
          if (i == 0) updateTileProvider(entry);
          mPhotoView.notifyImageInvalidated(i);
        }
      }
    }
    updateImageRequests();
  }
示例#9
0
 private FetchEntry getFetchEntry(String urlString, URL url) {
   ImageEntry imageEntry = new ImageEntry(urlString);
   String hash =
       toHexString(shaHash.get().digest(urlString.getBytes(ClientConfiguration.UTF8_CHARSET)));
   String cacheFileName = getCacheFileName(hash, urlString);
   imageEntry.cacheFile = Paths.get(cacheFileName);
   // from url
   FetchEntry fetchEntry = new FetchEntry(imageEntry);
   fetchEntry.url = url;
   // from cache
   Path cachePath = Paths.get(cacheFileName);
   if (Files.exists(cachePath)) {
     FetchEntry cacheFetchEntry = new FetchEntry(imageEntry);
     try {
       cacheFetchEntry.url = cachePath.toUri().toURL();
     } catch (MalformedURLException e) {
       throw new AssertionError(e);
     }
     cacheFetchEntry.setAlternateEntry(fetchEntry);
     fetchEntry = cacheFetchEntry;
   } else {
     logger.debug("Cache miss: {}", urlString);
   }
   return fetchEntry;
 }
示例#10
0
 /**
  * Prepare the string that is displayed if layer information is requested.
  *
  * @return String with layer information
  */
 private String infoText() {
   int tagged = 0;
   int newdata = 0;
   int n = 0;
   if (data != null) {
     n = data.size();
     for (ImageEntry e : data) {
       if (e.getPos() != null) {
         tagged++;
       }
       if (e.hasNewGpsData()) {
         newdata++;
       }
     }
   }
   return "<html>"
       + trn("{0} image loaded.", "{0} images loaded.", n, n)
       + ' '
       + trn("{0} was found to be GPS tagged.", "{0} were found to be GPS tagged.", tagged, tagged)
       + (newdata > 0
           ? "<br>"
               + trn("{0} has updated GPS data.", "{0} have updated GPS data.", newdata, newdata)
           : "")
       + "</html>";
 }
示例#11
0
    @Override
    public void windowDeactivated(WindowEvent e) {
      int result = checkAndSave();
      switch (result) {
        case NOTHING:
          break;
        case CANCEL:
          if (yLayer != null) {
            if (yLayer.data != null) {
              for (ImageEntry ie : yLayer.data) {
                ie.discardTmp();
              }
            }
            yLayer.updateBufferAndRepaint();
          }
          break;
        case AGAIN:
          actionPerformed(null);
          break;
        case DONE:
          Main.pref.put("geoimage.timezone", formatTimezone(timezone));
          Main.pref.put("geoimage.delta", Long.toString(delta * 1000));
          Main.pref.put("geoimage.showThumbs", yLayer.useThumbs);

          yLayer.useThumbs = cbShowThumbs.isSelected();
          yLayer.startLoadThumbs();

          // Search whether an other layer has yet defined some bounding box.
          // If none, we'll zoom to the bounding box of the layer with the photos.
          boolean boundingBoxedLayerFound = false;
          for (Layer l : Main.map.mapView.getAllLayers()) {
            if (l != yLayer) {
              BoundingXYVisitor bbox = new BoundingXYVisitor();
              l.visitBoundingBox(bbox);
              if (bbox.getBounds() != null) {
                boundingBoxedLayerFound = true;
                break;
              }
            }
          }
          if (!boundingBoxedLayerFound) {
            BoundingXYVisitor bbox = new BoundingXYVisitor();
            yLayer.visitBoundingBox(bbox);
            Main.map.mapView.zoomTo(bbox);
          }

          if (yLayer.data != null) {
            for (ImageEntry ie : yLayer.data) {
              ie.applyTmp();
            }
          }

          yLayer.updateBufferAndRepaint();

          break;
        default:
          throw new IllegalStateException();
      }
    }
示例#12
0
 private String infoText() {
   int i = 0;
   for (ImageEntry e : data)
     if (e.getPos() != null) {
       i++;
     }
   return trn("{0} image loaded.", "{0} images loaded.", data.size(), data.size())
       + " "
       + trn("{0} was found to be GPS tagged.", "{0} were found to be GPS tagged.", i, i);
 }
示例#13
0
  public void removeCurrentPhotoFromDisk() {
    ImageEntry toDelete;
    if (data != null && !data.isEmpty() && currentPhoto >= 0 && currentPhoto < data.size()) {
      toDelete = data.get(currentPhoto);

      int result =
          new ExtendedDialog(
                  Main.parent,
                  tr("Delete image file from disk"),
                  new String[] {tr("Cancel"), tr("Delete")})
              .setButtonIcons(new String[] {"cancel", "dialogs/delete"})
              .setContent(
                  new JLabel(
                      tr(
                          "<html><h3>Delete the file {0} from disk?<p>The image file will be permanently lost!</h3></html>",
                          toDelete.getFile().getName()),
                      ImageProvider.get("dialogs/geoimage/deletefromdisk"),
                      SwingConstants.LEFT))
              .toggleEnable("geoimage.deleteimagefromdisk")
              .setCancelButton(1)
              .setDefaultButton(2)
              .showDialog()
              .getValue();

      if (result == 2) {
        data.remove(currentPhoto);
        if (currentPhoto >= data.size()) {
          currentPhoto = data.size() - 1;
        }
        if (currentPhoto >= 0) {
          ImageViewerDialog.showImage(this, data.get(currentPhoto));
        } else {
          ImageViewerDialog.showImage(this, null);
        }

        if (Utils.deleteFile(toDelete.getFile())) {
          Main.info("File " + toDelete.getFile() + " deleted. ");
        } else {
          JOptionPane.showMessageDialog(
              Main.parent,
              tr("Image file could not be deleted."),
              tr("Error"),
              JOptionPane.ERROR_MESSAGE);
        }

        updateOffscreenBuffer = true;
        Main.map.repaint();
      }
    }
  }
示例#14
0
  /**
   * 画像を取得する。
   *
   * @param entry イメージエントリ
   * @throws java.lang.InterruptedException interrupted
   */
  protected void fetchImage(FetchEntry entry) throws InterruptedException {
    synchronized (entry) {
      if (entry.isFinished()) {
        return;
      }

      byte[] imageData = NetworkSupport.fetchContents(entry.connectionInfo);
      ImageEntry imageEntry = entry.imageEntry;
      imageEntry.rawData = imageData;
      imageEntry.image = Toolkit.getDefaultToolkit().createImage(imageData);
      cachedImages.put(entry.getImageUrl(), entry.imageEntry);
      configuration.addJob(JobQueue.PRIORITY_IDLE, new ImageFlusher(imageEntry));
    }
  }
示例#15
0
  @Override
  public void mergeFrom(Layer from) {
    GeoImageLayer l = (GeoImageLayer) from;

    // Stop to load thumbnails on both layers.  Thumbnail loading will continue the next time
    // the layer is painted.
    stopLoadThumbs();
    l.stopLoadThumbs();

    final ImageEntry selected =
        l.data != null && l.currentPhoto >= 0 ? l.data.get(l.currentPhoto) : null;

    if (l.data != null) {
      data.addAll(l.data);
    }
    Collections.sort(data);

    // Supress the double photos.
    if (data.size() > 1) {
      ImageEntry cur;
      ImageEntry prev = data.get(data.size() - 1);
      for (int i = data.size() - 2; i >= 0; i--) {
        cur = data.get(i);
        if (cur.getFile().equals(prev.getFile())) {
          data.remove(i);
        } else {
          prev = cur;
        }
      }
    }

    if (selected != null && !data.isEmpty()) {
      GuiHelper.runInEDTAndWait(
          new Runnable() {
            @Override
            public void run() {
              for (int i = 0; i < data.size(); i++) {
                if (selected.equals(data.get(i))) {
                  currentPhoto = i;
                  ImageViewerDialog.showImage(GeoImageLayer.this, data.get(i));
                  break;
                }
              }
            }
          });
    }

    setName(l.getName());
    thumbsLoaded &= l.thumbsLoaded;
  }
示例#16
0
  /** set the value for the specified cell */
  public void setValueAt(final Object value, final int row, final int column) {
    final List<ImageEntry> entries = _imageEntries;

    if (row >= entries.size()) return;

    final ImageEntry entry = entries.get(row);

    switch (column) {
      case TITLE_COLUMN:
        entry.setTitle(value.toString());
        break;
      default:
        break;
    }
  }
示例#17
0
  /** get the value for the specified cell */
  public Object getValueAt(final int row, final int column) {
    final List<ImageEntry> entries = _imageEntries;

    if (row >= entries.size()) return null;

    final ImageEntry entry = entries.get(row);

    switch (column) {
      case FILE_NAME_COLUMN:
        return entry.getImageFile().getName();
      case TITLE_COLUMN:
        return entry.getTitle();
      default:
        return null;
    }
  }
示例#18
0
    @Override
    protected void realRun() throws IOException {

      progressMonitor.subTask(tr("Starting directory scan"));
      Collection<File> files = new ArrayList<File>();
      try {
        addRecursiveFiles(files, selection);
      } catch (NullPointerException npe) {
        rememberError(tr("One of the selected files was null"));
      }

      if (cancelled) return;
      progressMonitor.subTask(tr("Read photos..."));
      progressMonitor.setTicksCount(files.size());

      progressMonitor.subTask(tr("Read photos..."));
      progressMonitor.setTicksCount(files.size());

      // read the image files
      List<ImageEntry> data = new ArrayList<ImageEntry>(files.size());

      for (File f : files) {

        if (cancelled) {
          break;
        }

        progressMonitor.subTask(tr("Reading {0}...", f.getName()));
        progressMonitor.worked(1);

        ImageEntry e = new ImageEntry();

        // Changed to silently cope with no time info in exif. One case
        // of person having time that couldn't be parsed, but valid GPS info

        try {
          e.setExifTime(ExifReader.readTime(f));
        } catch (ParseException e1) {
          e.setExifTime(null);
        }
        e.setFile(f);
        extractExif(e);
        data.add(e);
      }
      layer = new GeoImageLayer(data, gpxLayer);
      files.clear();
    }
 private void refreshPage() {
   this.errorMessage.setText("");
   this.txtName.setText("");
   this.txtURL.setText("");
   int fila = 1;
   for (ImageEntry image : model.getImageEntries()) {
     this.imageTable.setText(fila, 0, image.getName());
     final int row = fila;
     final Image newImage = new Image(image.getURL());
     newImage.addClickHandler(
         new ClickHandler() {
           @Override
           public void onClick(ClickEvent event) {
             selectImageEntry(imageTable.getText(row, 0));
           }
         });
     this.imageTable.setWidget(fila, 1, newImage);
     fila += 1;
   }
 }
示例#20
0
  private void updateFullImage(long version, Future<BitmapRegionDecoder> future) {
    ImageEntry entry = mImageCache.get(version);
    if (entry == null || entry.fullImageTask != future) {
      BitmapRegionDecoder fullImage = future.get();
      if (fullImage != null) fullImage.recycle();
      return;
    }

    entry.fullImageTask = null;
    entry.fullImage = future.get();
    if (entry.fullImage != null) {
      if (mDataListener != null) {
        mDataListener.onPhotoAvailable(version, true);
      }
      if (version == getVersion(mCurrentIndex)) {
        updateTileProvider(entry);
        mPhotoView.notifyImageInvalidated(0);
      }
    }
    updateImageRequests();
  }
示例#21
0
    @Override
    protected void finish() {
      if (!errorMessages.isEmpty()) {
        JOptionPane.showMessageDialog(
            Main.parent, formatErrorMessages(), tr("Error"), JOptionPane.ERROR_MESSAGE);
      }
      if (layer != null) {
        Main.main.addLayer(layer);

        if (!canceled && layer.data != null && !layer.data.isEmpty()) {
          boolean noGeotagFound = true;
          for (ImageEntry e : layer.data) {
            if (e.getPos() != null) {
              noGeotagFound = false;
            }
          }
          if (noGeotagFound) {
            new CorrelateGpxWithImages(layer).actionPerformed(null);
          }
        }
      }
    }
示例#22
0
  @Override
  public void mergeFrom(Layer from) {
    GeoImageLayer l = (GeoImageLayer) from;

    ImageEntry selected = null;
    if (l.currentPhoto >= 0) {
      selected = l.data.get(l.currentPhoto);
    }

    data.addAll(l.data);
    Collections.sort(data);

    // Supress the double photos.
    if (data.size() > 1) {
      ImageEntry cur;
      ImageEntry prev = data.get(data.size() - 1);
      for (int i = data.size() - 2; i >= 0; i--) {
        cur = data.get(i);
        if (cur.getFile().equals(prev.getFile())) {
          data.remove(i);
        } else {
          prev = cur;
        }
      }
    }

    if (selected != null) {
      for (int i = 0; i < data.size(); i++) {
        if (data.get(i) == selected) {
          currentPhoto = i;
          ImageViewerDialog.showImage(GeoImageLayer.this, data.get(i));
          break;
        }
      }
    }

    setName(l.getName());
  }
示例#23
0
    @Override
    protected void realRun() throws IOException {

      progressMonitor.subTask(tr("Starting directory scan"));
      Collection<File> files = new ArrayList<>();
      try {
        addRecursiveFiles(files, selection);
      } catch (IllegalStateException e) {
        rememberError(e.getMessage());
      }

      if (canceled) return;
      progressMonitor.subTask(tr("Read photos..."));
      progressMonitor.setTicksCount(files.size());

      progressMonitor.subTask(tr("Read photos..."));
      progressMonitor.setTicksCount(files.size());

      // read the image files
      List<ImageEntry> entries = new ArrayList<>(files.size());

      for (File f : files) {

        if (canceled) {
          break;
        }

        progressMonitor.subTask(tr("Reading {0}...", f.getName()));
        progressMonitor.worked(1);

        ImageEntry e = new ImageEntry(f);
        e.extractExif();
        entries.add(e);
      }
      layer = new GeoImageLayer(entries, gpxLayer);
      files.clear();
    }
示例#24
0
    private String statusText() {
      try {
        timezone = parseTimezone(tfTimezone.getText().trim());
        delta = parseOffset(tfOffset.getText().trim());
      } catch (ParseException e) {
        return e.getMessage();
      }

      // The selection of images we are about to correlate may have changed.
      // So reset all images.
      if (yLayer.data != null) {
        for (ImageEntry ie : yLayer.data) {
          ie.discardTmp();
        }
      }

      // Construct a list of images that have a date, and sort them on the date.
      List<ImageEntry> dateImgLst = getSortedImgList();
      // Create a temporary copy for each image
      for (ImageEntry ie : dateImgLst) {
        ie.createTmp();
        ie.tmp.setPos(null);
      }

      GpxDataWrapper selGpx = selectedGPX(false);
      if (selGpx == null) return tr("No gpx selected");

      final long offset_ms = ((long) (timezone * 3600) + delta) * 1000; // in milliseconds
      lastNumMatched = matchGpxTrack(dateImgLst, selGpx.data, offset_ms);

      return trn(
          "<html>Matched <b>{0}</b> of <b>{1}</b> photo to GPX track.</html>",
          "<html>Matched <b>{0}</b> of <b>{1}</b> photos to GPX track.</html>",
          dateImgLst.size(),
          lastNumMatched,
          dateImgLst.size());
    }
 private void selectImageEntry(String imageName) {
   ImageEntry entry = model.getImageByName(imageName);
   txtName.setText(entry.getName());
   txtURL.setText(entry.getURL());
 }
示例#26
0
  @Override
  public void paint(Graphics2D g, MapView mv, Bounds bounds) {
    int width = Main.map.mapView.getWidth();
    int height = Main.map.mapView.getHeight();
    Rectangle clip = g.getClipBounds();
    if (useThumbs) {
      if (null == offscreenBuffer
          || offscreenBuffer.getWidth() != width // reuse the old buffer if possible
          || offscreenBuffer.getHeight() != height) {
        offscreenBuffer = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        updateOffscreenBuffer = true;
      }

      if (updateOffscreenBuffer) {
        Graphics2D tempG = offscreenBuffer.createGraphics();
        tempG.setColor(new Color(0, 0, 0, 0));
        Composite saveComp = tempG.getComposite();
        tempG.setComposite(AlphaComposite.Clear); // remove the old images
        tempG.fillRect(0, 0, width, height);
        tempG.setComposite(saveComp);

        for (ImageEntry e : data) {
          if (e.getPos() == null) {
            continue;
          }
          Point p = mv.getPoint(e.getPos());
          if (e.thumbnail != null) {
            Dimension d = scaledDimension(e.thumbnail);
            Rectangle target =
                new Rectangle(p.x - d.width / 2, p.y - d.height / 2, d.width, d.height);
            if (clip.intersects(target)) {
              tempG.drawImage(e.thumbnail, target.x, target.y, target.width, target.height, null);
            }
          } else { // thumbnail not loaded yet
            icon.paintIcon(
                mv, tempG, p.x - icon.getIconWidth() / 2, p.y - icon.getIconHeight() / 2);
          }
        }
        updateOffscreenBuffer = false;
      }
      g.drawImage(offscreenBuffer, 0, 0, null);
    } else {
      for (ImageEntry e : data) {
        if (e.getPos() == null) {
          continue;
        }
        Point p = mv.getPoint(e.getPos());
        icon.paintIcon(mv, g, p.x - icon.getIconWidth() / 2, p.y - icon.getIconHeight() / 2);
      }
    }

    if (currentPhoto >= 0 && currentPhoto < data.size()) {
      ImageEntry e = data.get(currentPhoto);

      if (e.getPos() != null) {
        Point p = mv.getPoint(e.getPos());

        if (e.thumbnail != null) {
          Dimension d = scaledDimension(e.thumbnail);
          g.setColor(new Color(128, 0, 0, 122));
          g.fillRect(p.x - d.width / 2, p.y - d.height / 2, d.width, d.height);
        } else {
          if (e.getExifImgDir() != null) {
            double arrowlength = 25;
            double arrowwidth = 18;

            double dir = e.getExifImgDir();
            // Rotate 90 degrees CCW
            double headdir = (dir < 90) ? dir + 270 : dir - 90;
            double leftdir = (headdir < 90) ? headdir + 270 : headdir - 90;
            double rightdir = (headdir > 270) ? headdir - 270 : headdir + 90;

            double ptx = p.x + Math.cos(Math.toRadians(headdir)) * arrowlength;
            double pty = p.y + Math.sin(Math.toRadians(headdir)) * arrowlength;

            double ltx = p.x + Math.cos(Math.toRadians(leftdir)) * arrowwidth / 2;
            double lty = p.y + Math.sin(Math.toRadians(leftdir)) * arrowwidth / 2;

            double rtx = p.x + Math.cos(Math.toRadians(rightdir)) * arrowwidth / 2;
            double rty = p.y + Math.sin(Math.toRadians(rightdir)) * arrowwidth / 2;

            g.setColor(Color.white);
            int[] xar = {(int) ltx, (int) ptx, (int) rtx, (int) ltx};
            int[] yar = {(int) lty, (int) pty, (int) rty, (int) lty};
            g.fillPolygon(xar, yar, 4);
          }

          selectedIcon.paintIcon(
              mv, g, p.x - selectedIcon.getIconWidth() / 2, p.y - selectedIcon.getIconHeight() / 2);
        }
      }
    }
  }
示例#27
0
  static int matchPoints(
      List<ImageEntry> images,
      WayPoint prevWp,
      long prevWpTime,
      WayPoint curWp,
      long curWpTime,
      long offset) {
    // Time between the track point and the previous one, 5 sec if first point, i.e. photos take
    // 5 sec before the first track point can be assumed to be take at the starting position
    long interval = prevWpTime > 0 ? Math.abs(curWpTime - prevWpTime) : 5 * 1000;
    int ret = 0;

    // i is the index of the timewise last photo that has the same or earlier EXIF time
    int i = getLastIndexOfListBefore(images, curWpTime);

    // no photos match
    if (i < 0) return 0;

    Double speed = null;
    Double prevElevation = null;

    if (prevWp != null) {
      double distance = prevWp.getCoor().greatCircleDistance(curWp.getCoor());
      // This is in km/h, 3.6 * m/s
      if (curWpTime > prevWpTime) {
        speed = 3600 * distance / (curWpTime - prevWpTime);
      }
      prevElevation = getElevation(prevWp);
    }

    Double curElevation = getElevation(curWp);

    // First trackpoint, then interval is set to five seconds, i.e. photos up to five seconds
    // before the first point will be geotagged with the starting point
    if (prevWpTime == 0 || curWpTime <= prevWpTime) {
      while (i >= 0) {
        final ImageEntry curImg = images.get(i);
        long time = curImg.getExifTime().getTime();
        if (time > curWpTime || time < curWpTime - interval) {
          break;
        }
        if (curImg.tmp.getPos() == null) {
          curImg.tmp.setPos(curWp.getCoor());
          curImg.tmp.setSpeed(speed);
          curImg.tmp.setElevation(curElevation);
          curImg.tmp.setGpsTime(new Date(curImg.getExifTime().getTime() - offset));
          curImg.flagNewGpsData();
          ret++;
        }
        i--;
      }
      return ret;
    }

    // This code gives a simple linear interpolation of the coordinates between current and
    // previous track point assuming a constant speed in between
    while (i >= 0) {
      ImageEntry curImg = images.get(i);
      long imgTime = curImg.getExifTime().getTime();
      if (imgTime < prevWpTime) {
        break;
      }

      if (curImg.tmp.getPos() == null && prevWp != null) {
        // The values of timeDiff are between 0 and 1, it is not seconds but a dimensionless
        // variable
        double timeDiff = (double) (imgTime - prevWpTime) / interval;
        curImg.tmp.setPos(prevWp.getCoor().interpolate(curWp.getCoor(), timeDiff));
        curImg.tmp.setSpeed(speed);
        if (curElevation != null && prevElevation != null) {
          curImg.tmp.setElevation(prevElevation + (curElevation - prevElevation) * timeDiff);
        }
        curImg.tmp.setGpsTime(new Date(curImg.getExifTime().getTime() - offset));
        curImg.flagNewGpsData();

        ret++;
      }
      i--;
    }
    return ret;
  }
示例#28
0
  private static void extractExif(ImageEntry e) {

    double deg;
    double min, sec;
    double lon, lat;
    Metadata metadata = null;
    Directory dir = null;

    try {
      metadata = JpegMetadataReader.readMetadata(e.getFile());
      dir = metadata.getDirectory(GpsDirectory.class);
    } catch (CompoundException p) {
      e.setExifCoor(null);
      e.setPos(null);
      return;
    }

    try {
      // longitude

      Rational[] components = dir.getRationalArray(GpsDirectory.TAG_GPS_LONGITUDE);

      deg = components[0].doubleValue();
      min = components[1].doubleValue();
      sec = components[2].doubleValue();

      if (Double.isNaN(deg) && Double.isNaN(min) && Double.isNaN(sec))
        throw new IllegalArgumentException();

      lon =
          (Double.isNaN(deg)
              ? 0
              : deg
                  + (Double.isNaN(min) ? 0 : (min / 60))
                  + (Double.isNaN(sec) ? 0 : (sec / 3600)));

      if (dir.getString(GpsDirectory.TAG_GPS_LONGITUDE_REF).charAt(0) == 'W') {
        lon = -lon;
      }

      // latitude

      components = dir.getRationalArray(GpsDirectory.TAG_GPS_LATITUDE);

      deg = components[0].doubleValue();
      min = components[1].doubleValue();
      sec = components[2].doubleValue();

      if (Double.isNaN(deg) && Double.isNaN(min) && Double.isNaN(sec))
        throw new IllegalArgumentException();

      lat =
          (Double.isNaN(deg)
              ? 0
              : deg
                  + (Double.isNaN(min) ? 0 : (min / 60))
                  + (Double.isNaN(sec) ? 0 : (sec / 3600)));

      if (Double.isNaN(lat)) throw new IllegalArgumentException();

      if (dir.getString(GpsDirectory.TAG_GPS_LATITUDE_REF).charAt(0) == 'S') {
        lat = -lat;
      }

      // Store values

      e.setExifCoor(new LatLon(lat, lon));
      e.setPos(e.getExifCoor());

    } catch (CompoundException p) {
      // Try to read lon/lat as double value (Nonstandard, created by some cameras -> #5220)
      try {
        Double longitude = dir.getDouble(GpsDirectory.TAG_GPS_LONGITUDE);
        Double latitude = dir.getDouble(GpsDirectory.TAG_GPS_LATITUDE);
        if (longitude == null || latitude == null) throw new CompoundException("");

        // Store values

        e.setExifCoor(new LatLon(latitude, longitude));
        e.setPos(e.getExifCoor());
      } catch (CompoundException ex) {
        e.setExifCoor(null);
        e.setPos(null);
      }
    } catch (Exception ex) { // (other exceptions, e.g. #5271)
      System.err.println("Error when reading EXIF from file: " + ex);
      e.setExifCoor(null);
      e.setPos(null);
    }

    // compass direction value

    Rational direction = null;

    try {
      direction = dir.getRational(GpsDirectory.TAG_GPS_IMG_DIRECTION);
      if (direction != null) {
        e.setExifImgDir(direction.doubleValue());
      }
    } catch (Exception ex) { // (CompoundException and other exceptions, e.g. #5271)
      // Do nothing
    }
  }
示例#29
0
  @Override
  public void paint(Graphics2D g, MapView mv, Bounds bounds) {
    int width = mv.getWidth();
    int height = mv.getHeight();
    Rectangle clip = g.getClipBounds();
    if (useThumbs) {
      if (!thumbsLoaded) {
        startLoadThumbs();
      }

      if (null == offscreenBuffer
          || offscreenBuffer.getWidth() != width // reuse the old buffer if possible
          || offscreenBuffer.getHeight() != height) {
        offscreenBuffer = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        updateOffscreenBuffer = true;
      }

      if (updateOffscreenBuffer) {
        Graphics2D tempG = offscreenBuffer.createGraphics();
        tempG.setColor(new Color(0, 0, 0, 0));
        Composite saveComp = tempG.getComposite();
        tempG.setComposite(AlphaComposite.Clear); // remove the old images
        tempG.fillRect(0, 0, width, height);
        tempG.setComposite(saveComp);

        if (data != null) {
          for (ImageEntry e : data) {
            if (e.getPos() == null) {
              continue;
            }
            Point p = mv.getPoint(e.getPos());
            if (e.hasThumbnail()) {
              Dimension d = scaledDimension(e.getThumbnail());
              Rectangle target =
                  new Rectangle(p.x - d.width / 2, p.y - d.height / 2, d.width, d.height);
              if (clip.intersects(target)) {
                tempG.drawImage(
                    e.getThumbnail(), target.x, target.y, target.width, target.height, null);
              }
            } else { // thumbnail not loaded yet
              icon.paintIcon(
                  mv, tempG, p.x - icon.getIconWidth() / 2, p.y - icon.getIconHeight() / 2);
            }
          }
        }
        updateOffscreenBuffer = false;
      }
      g.drawImage(offscreenBuffer, 0, 0, null);
    } else if (data != null) {
      for (ImageEntry e : data) {
        if (e.getPos() == null) {
          continue;
        }
        Point p = mv.getPoint(e.getPos());
        icon.paintIcon(mv, g, p.x - icon.getIconWidth() / 2, p.y - icon.getIconHeight() / 2);
      }
    }

    if (currentPhoto >= 0 && currentPhoto < data.size()) {
      ImageEntry e = data.get(currentPhoto);

      if (e.getPos() != null) {
        Point p = mv.getPoint(e.getPos());

        int imgWidth;
        int imgHeight;
        if (useThumbs && e.hasThumbnail()) {
          Dimension d = scaledDimension(e.getThumbnail());
          imgWidth = d.width;
          imgHeight = d.height;
        } else {
          imgWidth = selectedIcon.getIconWidth();
          imgHeight = selectedIcon.getIconHeight();
        }

        if (e.getExifImgDir() != null) {
          // Multiplier must be larger than sqrt(2)/2=0.71.
          double arrowlength = Math.max(25, Math.max(imgWidth, imgHeight) * 0.85);
          double arrowwidth = arrowlength / 1.4;

          double dir = e.getExifImgDir();
          // Rotate 90 degrees CCW
          double headdir = (dir < 90) ? dir + 270 : dir - 90;
          double leftdir = (headdir < 90) ? headdir + 270 : headdir - 90;
          double rightdir = (headdir > 270) ? headdir - 270 : headdir + 90;

          double ptx = p.x + Math.cos(Math.toRadians(headdir)) * arrowlength;
          double pty = p.y + Math.sin(Math.toRadians(headdir)) * arrowlength;

          double ltx = p.x + Math.cos(Math.toRadians(leftdir)) * arrowwidth / 2;
          double lty = p.y + Math.sin(Math.toRadians(leftdir)) * arrowwidth / 2;

          double rtx = p.x + Math.cos(Math.toRadians(rightdir)) * arrowwidth / 2;
          double rty = p.y + Math.sin(Math.toRadians(rightdir)) * arrowwidth / 2;

          g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
          g.setColor(new Color(255, 255, 255, 192));
          int[] xar = {(int) ltx, (int) ptx, (int) rtx, (int) ltx};
          int[] yar = {(int) lty, (int) pty, (int) rty, (int) lty};
          g.fillPolygon(xar, yar, 4);
          g.setColor(Color.black);
          g.setStroke(new BasicStroke(1.2f));
          g.drawPolyline(xar, yar, 3);
        }

        if (useThumbs && e.hasThumbnail()) {
          g.setColor(new Color(128, 0, 0, 122));
          g.fillRect(p.x - imgWidth / 2, p.y - imgHeight / 2, imgWidth, imgHeight);
        } else {
          selectedIcon.paintIcon(mv, g, p.x - imgWidth / 2, p.y - imgHeight / 2);
        }
      }
    }
  }
示例#30
0
 @Override
 public void visitBoundingBox(BoundingXYVisitor v) {
   for (ImageEntry e : data) {
     v.visit(e.getPos());
   }
 }