Index: applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/Tile.java
===================================================================
--- applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/Tile.java	(revision 33208)
+++ applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/Tile.java	(revision 33209)
@@ -4,4 +4,5 @@
 import java.awt.Graphics;
 import java.awt.Graphics2D;
+import java.awt.Point;
 import java.awt.geom.AffineTransform;
 import java.awt.image.BufferedImage;
@@ -40,4 +41,5 @@
     protected int zoom;
     protected BufferedImage image;
+    protected TileAnchor anchor;
     protected String key;
     protected volatile boolean loaded; // field accessed by multiple threads without any monitors, needs to be volatile
@@ -75,5 +77,5 @@
         this.ytile = ytile;
         this.zoom = zoom;
-        this.image = image;
+        this.setImage(image);
         this.key = getTileKey(source, xtile, ytile, zoom);
     }
@@ -239,10 +241,27 @@
     }
 
-    public void setImage(BufferedImage image) {
-        this.image = image;
+    /**
+     * Get the position of the tile inside the image.
+     * @return the position of the tile inside the image
+     * @see #getImage()
+     */
+    public TileAnchor getAnchor() {
+        return anchor;
+    }
+
+    public final synchronized void setImage(BufferedImage image) {
+        if (image == null) {
+            this.image = null;
+            this.anchor = null;
+        } else {
+            this.image = image;
+            this.anchor = new TileAnchor(
+                    new Point.Double(0, 0),
+                    new Point.Double(image.getWidth(), image.getHeight()));
+        }
     }
 
     public void loadImage(InputStream input) throws IOException {
-        image = ImageIO.read(input);
+        setImage(ImageIO.read(input));
     }
 
Index: applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/TileAnchor.java
===================================================================
--- applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/TileAnchor.java	(revision 33209)
+++ applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/TileAnchor.java	(revision 33209)
@@ -0,0 +1,78 @@
+// License: GPL. For details, see Readme.txt file.
+package org.openstreetmap.gui.jmapviewer;
+
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
+import org.openstreetmap.gui.jmapviewer.interfaces.IProjected;
+
+/**
+ * Class that fixes the position of a tile in a given coordinate space.
+ *
+ * This is done by storing the coordinates of the tile origin and the opposite
+ * tile corner.
+ * <p>
+ * It may represent a reprojected tile, i.e. the tile is rotated / deformed in an
+ * arbitrary way. In general, the tile origin cannot be expected to be the
+ * upper left corner of the rectangle that is spanned by the 2 points.
+ * <p>
+ * The coordinate space may be
+ * <ul>
+ *   <li>pixel coordinates of the image file</li>
+ *   <li>projected coordinates (east / north)</li>
+ *   <li>screen pixel coordinates</li>
+ * </ul>
+ */
+public class TileAnchor {
+
+    protected final Point2D tileOrigin, nextTileOrigin;
+
+    /**
+     * Create a new tile anchor.
+     * @param tileOrigin position of the tile origin
+     * @param nextTileOrigin position of the opposite tile corner, i.e. the
+     * origin of the tile with index (x+1,y+1), when current tile has index (x,y)
+     */
+    public TileAnchor(Point2D tileOrigin, Point2D nextTileOrigin) {
+        this.tileOrigin = tileOrigin;
+        this.nextTileOrigin = nextTileOrigin;
+    }
+
+    public TileAnchor(IProjected tileOrigin, IProjected nextTileOrigin) {
+        this.tileOrigin = new Point2D.Double(tileOrigin.getEast(), tileOrigin.getNorth());
+        this.nextTileOrigin = new Point2D.Double(nextTileOrigin.getEast(), nextTileOrigin.getNorth());
+    }
+
+    public Point2D getTileOrigin() {
+        return tileOrigin;
+    }
+
+    public Point2D getNextTileOrigin() {
+        return nextTileOrigin;
+    }
+
+    @Override
+    public String toString() {
+        return "TileAnchor{" + tileOrigin.toString() + "; " + nextTileOrigin.toString() + "}";
+    }
+
+    /**
+     * Create a transformation that converts points from this coordinate space
+     * to another coordinate space.
+     * @param other tile anchor of the tile in the target coordinate space
+     * @return affine transformation from this coordinate space to the target
+     * coordinate space
+     */
+    public AffineTransform convert(TileAnchor other) {
+        Point2D src1 = this.getTileOrigin();
+        Point2D src2 = this.getNextTileOrigin();
+        Point2D dest1 = other.getTileOrigin();
+        Point2D dest2 = other.getNextTileOrigin();
+
+        double scaleX = (dest2.getX() - dest1.getX()) / (src2.getX() - src1.getX());
+        double scaleY = (dest2.getY() - dest1.getY()) / (src2.getY() - src1.getY());
+        double offsetX0 = dest1.getX() - scaleX * src1.getX();
+        double offsetY0 = dest1.getY() - scaleY * src1.getY();
+        return new AffineTransform(scaleX, 0, 0, scaleY, offsetX0, offsetY0);
+    }
+}
+
Index: applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/interfaces/TileSource.java
===================================================================
--- applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/interfaces/TileSource.java	(revision 33208)
+++ applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/interfaces/TileSource.java	(revision 33209)
@@ -98,19 +98,22 @@
 
     /**
+     * Transforms longitude and latitude to pixel space (as if all tiles at specified zoom level where joined).
      * @param lon longitude
      * @param lat latitude
      * @param zoom zoom level
-     * @return transforms longitude and latitude to pixel space (as if all tiles at specified zoom level where joined)
+     * @return the pixel coordinates
      */
     Point latLonToXY(double lat, double lon, int zoom);
 
     /**
+     * Transforms longitude and latitude to pixel space (as if all tiles at specified zoom level where joined).
      * @param point point
      * @param zoom zoom level
-     * @return transforms longitude and latitude to pixel space (as if all tiles at specified zoom level where joined)
+     * @return the pixel coordinates
      */
     Point latLonToXY(ICoordinate point, int zoom);
 
     /**
+     * Transforms a point in pixel space to longitude/latitude (WGS84).
      * @param point point
      * @param zoom zoom level
@@ -120,5 +123,5 @@
 
     /**
-     *
+     * Transforms a point in pixel space to longitude/latitude (WGS84).
      * @param x X coordinate
      * @param y Y coordinate
@@ -129,4 +132,5 @@
 
     /**
+     * Transforms longitude and latitude to tile indices.
      * @param lon longitude
      * @param lat latitude
@@ -137,5 +141,5 @@
 
     /**
-     *
+     * Transforms longitude and latitude to tile indices.
      * @param point point
      * @param zoom zoom level
@@ -145,5 +149,6 @@
 
     /**
-     * @param xy X/Y coordinates
+     * Transforms tile indices to longitude and latitude.
+     * @param xy X/Y tile indices
      * @param zoom zoom level
      * @return WGS84 coordinates of given tile
@@ -152,5 +157,6 @@
 
     /**
-     *
+     * Determines to longitude and latitude of a tile.
+     * (Refers to the tile origin - upper left tile corner)
      * @param tile Tile
      * @return WGS84 coordinates of given tile
@@ -159,7 +165,7 @@
 
     /**
-     *
-     * @param x X coordinate
-     * @param y Y coordinate
+     * Transforms tile indices to longitude and latitude.
+     * @param x x tile index
+     * @param y y tile index
      * @param zoom zoom level
      * @return WGS84 coordinates of given tile
@@ -168,26 +174,28 @@
 
     /**
-     * @param zoom zoom level
-     * @return maximum X index of tile for specified zoom level
+     * Get maximum x index of tile for specified zoom level.
+     * @param zoom zoom level
+     * @return maximum x index of tile for specified zoom level
      */
     int getTileXMax(int zoom);
 
     /**
-     *
-     * @param zoom zoom level
-     * @return minimum X index of tile for specified zoom level
+     * Get minimum x index of tile for specified zoom level.
+     * @param zoom zoom level
+     * @return minimum x index of tile for specified zoom level
      */
     int getTileXMin(int zoom);
 
     /**
-     *
-     * @param zoom zoom level
-     * @return maximum Y index of tile for specified zoom level
+     * Get maximum y index of tile for specified zoom level.
+     * @param zoom zoom level
+     * @return maximum y index of tile for specified zoom level
      */
     int getTileYMax(int zoom);
 
     /**
-     * @param zoom zoom level
-     * @return minimum Y index of tile for specified zoom level
+     * Get minimum y index of tile for specified zoom level
+     * @param zoom zoom level
+     * @return minimum y index of tile for specified zoom level
      */
     int getTileYMin(int zoom);
@@ -213,5 +221,5 @@
 
     /**
-     * Convert tile indeces (x/y/zoom) into projected coordinates of the tile origin.
+     * Convert tile indices (x/y/zoom) into projected coordinates of the tile origin.
      * @param x x tile index
      * @param y z tile index
@@ -255,8 +263,8 @@
 
     /**
-     * Get content reference system for this tile source.
+     * Get coordinate reference system for this tile source.
      *
      * E.g. "EPSG:3857" for Google-Mercator.
-     * @return code for the content reference system in use
+     * @return code for the coordinate reference system in use
      */
     String getServerCRS();
