// License: GPL. For details, see LICENSE file. package org.insignificant.josm.plugins.imagewaypoint; import static org.openstreetmap.josm.tools.I18n.tr; import java.awt.Image; import java.awt.Point; import java.awt.Rectangle; import java.awt.Toolkit; import java.awt.image.ImageObserver; import java.awt.image.MemoryImageSource; import java.awt.image.PixelGrabber; import java.io.File; import javax.swing.Icon; import org.openstreetmap.josm.data.gpx.WayPoint; import org.openstreetmap.josm.gui.MapView; import org.openstreetmap.josm.tools.ImageProvider; public final class ImageEntry implements Comparable<ImageEntry> { public interface IImageReadyListener { void onImageReady(ImageEntry imageEntry, Image image); } private static final class Observer implements ImageObserver { private final ImageEntry imageEntry; Observer(final ImageEntry imageEntry) { this.imageEntry = imageEntry; } /** * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, * int, int, int, int) * @return true if this ImageObserver still wants to be updates about * image loading progress */ @Override public boolean imageUpdate(final Image image, final int infoflags, final int x, final int y, final int width, final int height) { final boolean complete = ImageObserver.ALLBITS == (infoflags | ImageObserver.ALLBITS); if (complete) { this.imageEntry.imageLoaded(image); } return !complete; } } public static final class Orientation { private static final Orientation[] orientations = new Orientation[4]; public static final Orientation NORMAL = new Orientation(tr("Normal"), 0); public static final Orientation ROTATE_90 = new Orientation(tr("Rotate 90"), 1); public static final Orientation ROTATE_180 = new Orientation(tr("Rotate 180"), 2); public static final Orientation ROTATE_270 = new Orientation(tr("Rotate 270"), 3); private final String name; private final int index; private Orientation(final String name, final int index) { this.name = name; this.index = index; Orientation.orientations[index] = this; } public Orientation rotateRight() { if (this.index < Orientation.orientations.length - 1) { return Orientation.orientations[this.index + 1]; } else { return Orientation.orientations[0]; } } public Orientation rotateLeft() { if (this.index == 0) { return Orientation.orientations[Orientation.orientations.length - 1]; } else { return Orientation.orientations[this.index - 1]; } } @Override public String toString() { return "[" + this.name + "]"; } } public static final Icon ICON = ImageProvider.get("dialogs/imagewaypoint-marker"); public static final Icon SELECTED_ICON = ImageProvider.get("dialogs/imagewaypoint-marker-selected"); private static final int ICON_WIDTH = ImageEntry.ICON.getIconWidth(); private static final int ICON_HEIGHT = ImageEntry.ICON.getIconHeight(); private final String filePath; private final String fileName; private final ImageObserver observer; private WayPoint wayPoint; private Orientation orientation; private IImageReadyListener listener; private Image normalImage; private Image rotatedImage; public ImageEntry(final File file) { this.filePath = file.getAbsolutePath(); this.fileName = file.getName(); this.observer = new Observer(this); this.wayPoint = null; this.orientation = Orientation.NORMAL; this.listener = null; this.normalImage = null; this.rotatedImage = null; } @Override public int compareTo(final ImageEntry image) { return this.fileName.compareTo(image.fileName); } public String getFileName() { return fileName; } public WayPoint getWayPoint() { return wayPoint; } public void setWayPoint(final WayPoint wayPoint) { this.wayPoint = wayPoint; } public Orientation getOrientation() { return orientation; } public void setOrientation(final Orientation orientation) { this.orientation = orientation; this.normalImage = null; this.rotatedImage = null; } public Rectangle getBounds(final MapView mapView) { final Rectangle bounds; if (null == this.wayPoint) { bounds = null; } else { final Point point = mapView.getPoint(this.getWayPoint().getCoor()); bounds = new Rectangle(point.x - ImageEntry.ICON_WIDTH, point.y - ImageEntry.ICON_HEIGHT, ImageEntry.ICON_WIDTH, ImageEntry.ICON_WIDTH); } return bounds; } public void requestImage(final IImageReadyListener imageReadyListener) { this.listener = imageReadyListener; if (null == this.rotatedImage) { final Image image = Toolkit.getDefaultToolkit() .getImage(this.filePath); if (Toolkit.getDefaultToolkit().prepareImage(image, -1, -1, this.observer)) { this.imageLoaded(image); } } else if (null != this.listener) { this.listener.onImageReady(this, this.rotatedImage); } } public void flush() { if (null != this.normalImage) { this.normalImage.flush(); this.normalImage = null; } if (null != this.rotatedImage) { this.rotatedImage.flush(); this.rotatedImage = null; } } private void imageLoaded(final Image image) { if (Orientation.NORMAL == this.getOrientation()) { this.rotatedImage = image; } else { final int[] buffer = new int[image.getWidth(null) * image.getHeight(null)]; PixelGrabber grabber = new PixelGrabber(image, 0, 0, image.getWidth(null), image.getHeight(null), buffer, 0, image.getWidth(null)); try { grabber.grabPixels(); final int newHeight; final int newWidth; if (Orientation.ROTATE_180 == this.getOrientation()) { newHeight = image.getHeight(null); newWidth = image.getWidth(null); } else { newHeight = image.getWidth(null); newWidth = image.getHeight(null); } final int[] destination = new int[image.getWidth(null) * image.getHeight(null)]; for (int x = 0; x < image.getWidth(null); x++) { for (int y = 0; y < image.getHeight(null); y++) { final int pix = buffer[x + (y * image.getWidth(null))]; final int newX; final int newY; if (Orientation.ROTATE_90 == this.getOrientation()) { newX = newWidth - y; newY = x; } else if (Orientation.ROTATE_180 == this.getOrientation()) { newX = newWidth - x; newY = newHeight - y; } else { // Orientation.ROTATE_270 == // this.getOrientation() newX = y; newY = newHeight - x; } final int newIndex = newX + (newY * newWidth); if (newIndex < destination.length) { destination[newIndex] = pix; } } } this.rotatedImage = Toolkit.getDefaultToolkit() .createImage(new MemoryImageSource(newWidth, newHeight, destination, 0, newWidth)); } catch (final InterruptedException e) { this.rotatedImage = null; } } if (null != this.listener) { this.listener.onImageReady(this, this.rotatedImage); } } }