Index: applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/CacheControl.java
===================================================================
--- applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/CacheControl.java	(revision 17087)
+++ applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/CacheControl.java	(revision 17089)
@@ -16,4 +16,5 @@
 import java.util.concurrent.locks.ReentrantLock;
 
+import javax.swing.JDialog;
 import javax.swing.JOptionPane;
 import org.openstreetmap.josm.Main;
@@ -78,12 +79,18 @@
     public boolean loadCacheIfExist() {
         try {
-            File file = new File(CadastrePlugin.cacheDir + wmsLayer.name + "." + String.valueOf(wmsLayer.lambertZone+1));
+            File file = new File(CadastrePlugin.cacheDir + wmsLayer.getName() + "." + String.valueOf(wmsLayer.lambertZone+1));
             if (file.exists()) {
-                int reply = JOptionPane.showConfirmDialog(null,
-                        "Location \""+wmsLayer.name+"\" found in cache.\n"+
+                JOptionPane pane = new JOptionPane(
+                        tr("Location \"{0}\" found in cache.\n"+
                         "Load cache first ?\n"+
-                        "(No = new cache)",
-                        "Location in cache",
-                        JOptionPane.YES_NO_OPTION);
+                        "(No = new cache)", wmsLayer.getName()),
+                        JOptionPane.QUESTION_MESSAGE, JOptionPane.YES_NO_OPTION, null);
+                // this below is a temporary workaround to fix the "always on top" issue
+                JDialog dialog = pane.createDialog(Main.parent, tr("Select Feuille"));
+                CadastrePlugin.prepareDialog(dialog);
+                dialog.setVisible(true);
+                int reply = (Integer)pane.getValue();
+                // till here
+
                 if (reply == JOptionPane.OK_OPTION) {
                     return loadCache(file, wmsLayer.lambertZone);
@@ -99,5 +106,5 @@
     public void deleteCacheFile() {
         try {
-            File file = new File(CadastrePlugin.cacheDir + wmsLayer.name + "." + String.valueOf(wmsLayer.lambertZone+1));
+            File file = new File(CadastrePlugin.cacheDir + wmsLayer.getName() + "." + String.valueOf(wmsLayer.lambertZone+1));
             if (file.exists())
                 file.delete();
@@ -142,5 +149,5 @@
             imagesLock.unlock();
             if (images != null && !images.isEmpty()) {
-                File file = new File(CadastrePlugin.cacheDir + wmsLayer.name + "." + String.valueOf((wmsLayer.lambertZone + 1)));
+                File file = new File(CadastrePlugin.cacheDir + wmsLayer.getName() + "." + String.valueOf((wmsLayer.lambertZone + 1)));
                 try {
                     if (file.exists()) {
Index: applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/CadastreGrabber.java
===================================================================
--- applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/CadastreGrabber.java	(revision 17087)
+++ applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/CadastreGrabber.java	(revision 17089)
@@ -19,12 +19,7 @@
 public class CadastreGrabber {
 
-    public static final double epsilon = 1e-11;
+    public final static double epsilon = 1e-11;
 
-    private CadastreInterface wmsInterface = new CadastreInterface(this);
-    private String lastWMSLayerName = null;
-
-    CadastreGrabber() {
-        getWmsInterface().downloadCancelled = false;
-    }
+    private CadastreInterface wmsInterface = new CadastreInterface();
 
     public GeorefImage grab(WMSLayer wmsLayer, EastNorth lambertMin, EastNorth lambertMax) throws IOException, OsmTransferException {
@@ -36,7 +31,10 @@
             else
                 url = getURLVector(lambertMin, lambertMax);
-            System.out.println("grab:"+url);
             BufferedImage img = grab(url);
-            ImageModifier imageModified = new ImageModifier(img);
+            ImageModifier imageModified;
+            if (wmsLayer.isRaster())
+                imageModified = new RasterImageModifier(img);
+            else
+                imageModified = new VectorImageModifier(img);
             return new GeorefImage(imageModified.bufferedImage, lambertMin, lambertMax);
         } catch (MalformedURLException e) {
@@ -46,4 +44,6 @@
 
     private URL getURLRaster(WMSLayer wmsLayer, EastNorth lambertMin, EastNorth lambertMax) throws MalformedURLException {
+        // GET /scpc/wms?version=1.1&request=GetMap&layers=CDIF:PMC@QH4480001701&format=image/png&bbox=-1186,0,13555,8830&width=576&height=345&exception=application/vnd.ogc.se_inimage&styles= HTTP/1.1
+        final int cRasterX = 1000; // keep width constant and adjust width to original image proportions
         String str = new String(wmsInterface.baseURL+"/scpc/wms?version=1.1&request=GetMap");
         str += "&layers=CDIF:PMC@";
@@ -52,5 +52,7 @@
         str += "&bbox=";
         str += wmsLayer.eastNorth2raster(lambertMin, lambertMax);
-        str += "&width=600&height=600"; // maximum allowed by wms server
+        //str += "&width=800&height=800"; // maximum allowed by wms server
+        str += "&width="+cRasterX+"&height="; // maximum allowed by wms server (576/345, 800/378, 1000/634)
+        str += (int)(cRasterX*(wmsLayer.communeBBox.max.getY() - wmsLayer.communeBBox.min.getY())/(wmsLayer.communeBBox.max.getX() - wmsLayer.communeBBox.min.getX()));
         str += "&exception=application/vnd.ogc.se_inimage&styles=";
         return new URL(str.replace(" ", "%20"));
@@ -94,11 +96,3 @@
     }
 
-    public String getLastWMSLayerName() {
-        return lastWMSLayerName;
-    }
-
-    public void setLastWMSLayerName(String lastWMSLayerName) {
-        this.lastWMSLayerName = lastWMSLayerName;
-    }
-
 }
Index: applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/CadastreInterface.java
===================================================================
--- applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/CadastreInterface.java	(revision 17087)
+++ applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/CadastreInterface.java	(revision 17089)
@@ -14,4 +14,5 @@
 
 import javax.swing.JComboBox;
+import javax.swing.JDialog;
 import javax.swing.JOptionPane;
 import javax.swing.JPanel;
@@ -26,10 +27,19 @@
     public HttpURLConnection urlConn = null;
 
-    private CadastreGrabber cadastreGrabber;
     private String cookie;
     private String interfaceRef = null;
+    private String lastWMSLayerName = null;
     private URL searchFormURL;
     private Vector<String> listOfCommunes = new Vector<String>();
     private Vector<String> listOfTA = new Vector<String>();
+    class PlanImage {
+        String name;
+        String ref;
+        PlanImage(String name, String ref) {
+            this.name = name;
+            this.ref = ref;
+        }
+    }
+    private Vector<PlanImage> listOfFeuilles = new Vector<PlanImage>();
 
     final String baseURL = "http://www.cadastre.gouv.fr";
@@ -43,9 +53,8 @@
 
     final String cInterfaceVector = "afficherCarteCommune.do";
-    final String cInterfaceRaster = "afficherCarteTa.do";
-
-    CadastreInterface(CadastreGrabber cadastreGrabber) {
-        this.cadastreGrabber = cadastreGrabber;
-    }
+    final String cInterfaceRasterTA = "afficherCarteTa.do";
+    final String cInterfaceRasterFeuille = "afficherCarteFeuille.do";
+    final String cImageLinkStart = "title=\"image\"><a href=\"#\" onClick=\"popup('afficherCarteFeuille.do?f=";
+    final String cImageNameStart = ">Feuille ";
 
     public boolean retrieveInterface(WMSLayer wmsLayer) throws DuplicateLayerException {
@@ -55,14 +64,23 @@
         downloadCancelled = false;
         try {
-            if (cookie == null || !wmsLayer.getName().equals(cadastreGrabber.getLastWMSLayerName())) {
+            if (cookie == null || !wmsLayer.getName().equals(lastWMSLayerName)) {
                 getCookie();
                 getInterface(wmsLayer);
-                cadastreGrabber.setLastWMSLayerName(wmsLayer.getName());
+                this.lastWMSLayerName = wmsLayer.getName();
             }
             openInterface();
         } catch (IOException e) {
-            JOptionPane.showMessageDialog(Main.parent,
+            /*JOptionPane.showMessageDialog(Main.parent,
                     tr("Town/city {0} not found or not available in WMS.\n" +
-                            "Please check its availibility on www.cadastre.gouv.fr", wmsLayer.getLocation()));
+                            "Please check its availibility on www.cadastre.gouv.fr", wmsLayer.getLocation()));*/
+            JOptionPane pane = new JOptionPane(
+                    tr("Town/city {0} not found or not available in WMS.\n" +
+                            "Please check its availibility on www.cadastre.gouv.fr", wmsLayer.getLocation()),
+                            JOptionPane.INFORMATION_MESSAGE);
+            // this below is a temporary workaround to fix the "always on top" issue
+            JDialog dialog = pane.createDialog(Main.parent, tr("Select commune"));
+            CadastrePlugin.prepareDialog(dialog);
+            dialog.setVisible(true);
+            // till here
             return false;
         }
@@ -80,4 +98,5 @@
                 throw new IOException("Cannot get Cadastre cookie.");
             }
+            System.out.println("GET "+searchFormURL);
             BufferedReader in = new BufferedReader(new InputStreamReader(urlConn.getInputStream()));
             while(in.readLine() != null) {}  // read the buffer otherwise we sent POST too early
@@ -97,9 +116,9 @@
 
     public void resetCookie() {
-        cadastreGrabber.setLastWMSLayerName(null);
+        lastWMSLayerName = null;
     }
 
     public void resetCookieIfNewLayer(String newWMSLayerName) {
-        if (!newWMSLayerName.equals(cadastreGrabber.getLastWMSLayerName())) {
+        if (!newWMSLayerName.equals(lastWMSLayerName)) {
             resetCookie();
         }
@@ -107,7 +126,11 @@
 
     public void setCookie() {
-        urlConn.setRequestProperty("Cookie", cookie);
-    }
-
+        this.urlConn.setRequestProperty("Cookie", this.cookie);
+    }
+
+    public void setCookie(HttpURLConnection urlConn) {
+        urlConn.setRequestProperty("Cookie", this.cookie);
+    }
+    
     private void getInterface(WMSLayer wmsLayer) throws IOException, DuplicateLayerException {
         // first attempt : search for given name without codeCommune
@@ -126,9 +149,13 @@
                     interfaceRef = postForm(wmsLayer, wmsLayer.getCodeCommune());
                 }
-                if (wmsLayer.isRaster() && listOfTA.size() > 1) {
-                    // commune known but raster format. Select "tableau d'assemblage" from list.
-                    wmsLayer.setCodeCommune(selectTADialog());
-                    checkLayerDuplicates(wmsLayer);
-                    interfaceRef = buildRasterInterfaceRef(wmsLayer.getCodeCommune());
+                if (listOfCommunes.size() == 1 && wmsLayer.isRaster()) {
+                    // commune known but raster format. Select "Feuille" (non-georeferenced image) from list.
+                    int res = selectFeuilleDialog();
+                    if (res != -1) {
+                        // TODO
+                        wmsLayer.setCodeCommune(listOfFeuilles.elementAt(res).name);
+                        checkLayerDuplicates(wmsLayer);
+                        interfaceRef = buildRasterFeuilleInterfaceRef(wmsLayer.getCodeCommune());
+                    }
                 }
             }
@@ -142,4 +169,6 @@
         try {
             // finally, open the interface on server side giving access to the wms server
+            String lines = null;
+            String ln = null;
             URL interfaceURL = new URL(baseURL + "/scpc/"+interfaceRef);
             urlConn = (HttpURLConnection)interfaceURL.openConnection();
@@ -150,7 +179,10 @@
                 throw new IOException("Cannot open Cadastre interface. GET response:"+urlConn.getResponseCode());
             }
+            System.out.println("GET "+interfaceURL);
             BufferedReader in = new BufferedReader(new InputStreamReader(urlConn.getInputStream()));
-            while(in.readLine() != null) {}  // read the buffer otherwise we sent POST too early
-            System.out.println("GET to open interface sent");
+            //while(in.readLine() != null) {}  // read the buffer otherwise we sent POST too early
+            while ((ln = in.readLine()) != null) {
+                lines += ln;
+            }
         } catch (MalformedURLException e) {
             throw (IOException) new IOException(
@@ -171,8 +203,10 @@
      *   <option value="QK066" >COLMAR - 68000</option>
      *   </select>
+     * The returned string is the interface name used in further requests, e.g. "afficherCarteCommune.do?c=QP224"
+     * where QP224 is the code commune known by the WMS (or "afficherCarteTa.do?c=..." for raster images).
      *
      * @param location
      * @param codeCommune
-     * @return retURL url to available cadastre vectorised master piece; "" if not found
+     * @return retURL url to available code commune in the cadastre; "" if not found
      * @throws IOException
      */
@@ -180,5 +214,5 @@
         try {
             String ln = null;
-            String line = null;
+            String lines = null;
             listOfCommunes.clear();
             listOfTA.clear();
@@ -203,37 +237,46 @@
             OutputStream wr = urlConn.getOutputStream();
             wr.write(content.getBytes());
+            System.out.println("POST "+content);
             wr.flush();
             wr.close();
             BufferedReader rd = new BufferedReader(new InputStreamReader(urlConn.getInputStream()));
             while ((ln = rd.readLine()) != null) {
-                line += ln;
+                lines += ln;
             }
             rd.close();
             urlConn.disconnect();
-            System.out.println("POST="+line);
-            if (line.indexOf(cImageFormat) != -1) {
-                int i = line.indexOf(cImageFormat);
-                int j = line.indexOf(".", i);
-                wmsLayer.setRaster(line.substring(i+cImageFormat.length(), j).equals("image"));
-            }
-            if (!wmsLayer.isRaster() && line.indexOf(cInterfaceVector) != -1) {  // "afficherCarteCommune.do"
+            if (lines.indexOf(cImageFormat) != -1) {
+                int i = lines.indexOf(cImageFormat);
+                int j = lines.indexOf(".", i);
+                wmsLayer.setRaster(lines.substring(i+cImageFormat.length(), j).equals("image"));
+            }
+            if (!wmsLayer.isRaster() && lines.indexOf(cInterfaceVector) != -1) {  // "afficherCarteCommune.do"
                 // shall be something like: interfaceRef = "afficherCarteCommune.do?c=X2269";
-                line = line.substring(line.indexOf(cInterfaceVector),line.length());
-                line = line.substring(0, line.indexOf("'"));
-                System.out.println("interface ref.:"+line);
-                return line;
-            } else if (wmsLayer.isRaster() && line.indexOf(cInterfaceRaster) != -1) { // "afficherCarteTa.do"
-                // list of values parsed in listOfTA (Tableau d'assemblage)
-                parseTAList(line.substring(line.indexOf(cInterfaceRaster)));
-                if (listOfTA.size() == 1) {
-                    wmsLayer.setCodeCommune(listOfTA.firstElement());
-                    return buildRasterInterfaceRef(listOfTA.firstElement());
+                lines = lines.substring(lines.indexOf(cInterfaceVector),lines.length());
+                lines = lines.substring(0, lines.indexOf("'"));
+                System.out.println("interface ref.:"+lines);
+                return lines;
+            } else if (wmsLayer.isRaster() && lines.indexOf(cInterfaceRasterTA) != -1) { // "afficherCarteTa.do"
+                // list of values parsed in listOfFeuilles (list all non-georeferenced images)
+                lines = getFeuillesList();
+                parseFeuillesList(lines);
+                if (listOfFeuilles.size() > 0) {
+                    int res = selectFeuilleDialog();
+                    if (res != -1) {
+                        wmsLayer.setCodeCommune(listOfFeuilles.elementAt(res).name);
+                        checkLayerDuplicates(wmsLayer);
+                        interfaceRef = buildRasterFeuilleInterfaceRef(wmsLayer.getCodeCommune());
+                        wmsLayer.setCodeCommune(listOfFeuilles.elementAt(res).ref);
+                        lines = buildRasterFeuilleInterfaceRef(listOfFeuilles.elementAt(res).ref);
+                        System.out.println("interface ref.:"+lines);
+                        return lines;
+                    }
                 }
                 return null;
-            } else if (line.indexOf(cCommuneListStart) != -1 && line.indexOf(cCommuneListEnd) != -1) {
+            } else if (lines.indexOf(cCommuneListStart) != -1 && lines.indexOf(cCommuneListEnd) != -1) {
                 // list of values parsed in listOfCommunes
-                int i = line.indexOf(cCommuneListStart);
-                int j = line.indexOf(cCommuneListEnd, i);
-                parseCommuneList(line.substring(i, j));
+                int i = lines.indexOf(cCommuneListStart);
+                int j = lines.indexOf(cCommuneListEnd, i);
+                parseCommuneList(lines.substring(i, j));
             }
         } catch (MalformedURLException e) {
@@ -265,17 +308,41 @@
     }
 
-    private void parseTAList(String input) {
-        while (input.indexOf(cInterfaceRaster) != -1) {
-            input = input.substring(input.indexOf(cInterfaceRaster));
-            String codeTA = input.substring(0, input.indexOf("'"));
-            codeTA = codeTA.substring(codeTA.indexOf("=")+1);
-            if (!listOfTA.contains(codeTA)) {
-                System.out.println("parse "+codeTA);
-                listOfTA.add(codeTA);
-            }
-            input = input.substring(cInterfaceRaster.length());
-        }
-    }
-
+    private String getFeuillesList() {
+        // get all images in one html page
+        String ln = null;
+        String lines = null;
+        HttpURLConnection urlConn2 = null;
+        try {
+            URL getAllImagesURL = new URL(baseURL + "/scpc/listerFeuillesParcommune.do?keepVolatileSession=&offset=2000");
+            urlConn2 = (HttpURLConnection)getAllImagesURL.openConnection();
+            setCookie(urlConn2);
+            urlConn2.connect();
+            System.out.println("GET "+getAllImagesURL);
+            BufferedReader rd = new BufferedReader(new InputStreamReader(urlConn2.getInputStream()));
+            while ((ln = rd.readLine()) != null) {
+                lines += ln;
+            }
+            rd.close();
+            urlConn2.disconnect();
+            //System.out.println("GET="+lines);
+        } catch (IOException e) {
+            listOfFeuilles.clear();
+            e.printStackTrace();
+        }
+        return lines;
+    }
+    
+    private void parseFeuillesList(String input) {
+        listOfFeuilles.clear();
+        while (input.indexOf(cImageLinkStart) != -1) {
+            input = input.substring(input.indexOf(cImageLinkStart)+cImageLinkStart.length());
+            String refFeuille = input.substring(0, input.indexOf("'"));
+            String nameFeuille = input.substring(
+                    input.indexOf(cImageNameStart)+cImageNameStart.length(),
+                    input.indexOf(" -"));
+            listOfFeuilles.add(new PlanImage(nameFeuille, refFeuille));
+        }
+    }
+    
     private String selectCommuneDialog() {
         JPanel p = new JPanel(new GridBagLayout());
@@ -290,5 +357,10 @@
             private static final long serialVersionUID = 1L;
         };
-        pane.createDialog(Main.parent, tr("Select commune")).setVisible(true);
+        //pane.createDialog(Main.parent, tr("Select commune")).setVisible(true);
+        // this below is a temporary workaround to fix the "always on top" issue
+        JDialog dialog = pane.createDialog(Main.parent, tr("Select commune"));
+        CadastrePlugin.prepareDialog(dialog);
+        dialog.setVisible(true);
+        // till here
         if (!Integer.valueOf(JOptionPane.OK_OPTION).equals(pane.getValue()))
             return null;
@@ -297,20 +369,27 @@
     }
 
-    private String selectTADialog() {
+    private int selectFeuilleDialog() {
         JPanel p = new JPanel(new GridBagLayout());
-        JComboBox inputTAList = new JComboBox(listOfTA);
-        p.add(inputTAList, GBC.eol().fill(GBC.HORIZONTAL).insets(10, 0, 0, 0));
-        JOptionPane pane = new JOptionPane(p, JOptionPane.INFORMATION_MESSAGE, JOptionPane.OK_CANCEL_OPTION, null) {
-            private static final long serialVersionUID = 1L;
-        };
-        pane.createDialog(Main.parent, tr("Select Tableau d'Assemblage")).setVisible(true);
+        Vector<String> ImageNames = new Vector<String>();
+        for (PlanImage src : listOfFeuilles) {
+            ImageNames.add(src.name);
+        }
+        JComboBox inputFeuilleList = new JComboBox(ImageNames);
+        p.add(inputFeuilleList, GBC.eol().fill(GBC.HORIZONTAL).insets(10, 0, 0, 0));
+        JOptionPane pane = new JOptionPane(p, JOptionPane.INFORMATION_MESSAGE, JOptionPane.OK_CANCEL_OPTION, null);
+        //pane.createDialog(Main.parent, tr("Select Feuille")).setVisible(true);
+        // this below is a temporary workaround to fix the "always on top" issue
+        JDialog dialog = pane.createDialog(Main.parent, tr("Select Feuille"));
+        CadastrePlugin.prepareDialog(dialog);
+        dialog.setVisible(true);
+        // till here
         if (!Integer.valueOf(JOptionPane.OK_OPTION).equals(pane.getValue()))
-            return null;
-        String result = listOfTA.elementAt(inputTAList.getSelectedIndex());
+            return -1;
+        int result = inputFeuilleList.getSelectedIndex();
         return result;
     }
 
-    private String buildRasterInterfaceRef(String codeCommune) {
-        return cInterfaceRaster + "?f=" + codeCommune;
+    private String buildRasterFeuilleInterfaceRef(String codeCommune) {
+        return cInterfaceRasterFeuille + "?f=" + codeCommune;
     }
 
@@ -324,5 +403,4 @@
         content += "&dontSaveLastForward&keepVolatileSession=";
         searchFormURL = new URL(content);
-        System.out.println("HEAD:"+content);
         urlConn = (HttpURLConnection)searchFormURL.openConnection();
         urlConn.setRequestMethod("GET");
@@ -332,4 +410,5 @@
             throw new IOException("Cannot get Cadastre response.");
         }
+        System.out.println("GET "+searchFormURL);
         BufferedReader in = new BufferedReader(new InputStreamReader(urlConn.getInputStream()));
         while ((ln = in.readLine()) != null) {
@@ -377,5 +456,5 @@
         }
         downloadCancelled = true;
-        cadastreGrabber.setLastWMSLayerName(null);
+        lastWMSLayerName = null;
     }
 
Index: applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/CadastrePlugin.java
===================================================================
--- applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/CadastrePlugin.java	(revision 17087)
+++ applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/CadastrePlugin.java	(revision 17089)
@@ -10,4 +10,5 @@
 
 import javax.swing.JCheckBoxMenuItem;
+import javax.swing.JDialog;
 import javax.swing.JMenu;
 import javax.swing.JMenuItem;
@@ -135,4 +136,5 @@
                 menuGrab.setAccelerator(ks);
             }
+            JMenuItem menuActionGrabPlanImage = new JMenuItem(new MenuActionGrabPlanImage());
             JMenuItem menuSettings = new JMenuItem(new MenuActionNewLocation());
             final JCheckBoxMenuItem menuSource = new JCheckBoxMenuItem(tr("Auto sourcing"));
@@ -152,4 +154,5 @@
 
             cadastreJMenu.add(menuGrab);
+            cadastreJMenu.add(menuActionGrabPlanImage);
             cadastreJMenu.add(menuSettings);
             cadastreJMenu.add(menuSource);
@@ -214,5 +217,6 @@
             JMenuItem item = cadastreJMenu.getItem(i);
             if (item != null)
-                if (item.getText().equals(MenuActionGrab.name) /* ||
+                if (item.getText().equals(MenuActionGrab.name) ||
+                    item.getText().equals(MenuActionGrabPlanImage.name) /* ||
                     item.getText().equals(MenuActionBoundaries.name) ||
                     item.getText().equals(MenuActionBuildings.name)*/) {
@@ -229,6 +233,6 @@
             if (oldFrame == null && newFrame != null) {
                 setEnabledAll(true);
-                Main.map.addMapMode(new IconToggleButton
-                        (new WMSAdjustAction(Main.map)));
+                /*Main.map.addMapMode(new IconToggleButton
+                        (new WMSAdjustAction(Main.map)));*/
             } else if (oldFrame != null && newFrame == null) {
                 setEnabledAll(false);
@@ -246,3 +250,23 @@
     }
 
+    public static void safeSleep(long milliseconds) {
+        try {
+            Thread.sleep(milliseconds);
+        } catch (InterruptedException e) {}
+    }
+
+    // See OptionPaneUtil
+    // FIXME: this is a temporary solution. 
+    public static void prepareDialog(JDialog dialog) {
+        if (Main.pref.getBoolean("window-handling.option-pane-always-on-top", true)) {
+            try {
+                dialog.setAlwaysOnTop(true);
+            } catch(SecurityException e) {
+                System.out.println(tr("Warning: failed to put option pane dialog always on top. Exception was: {0}", e.toString()));
+            }
+        }
+        dialog.setModal(true);
+        dialog.toFront();
+        dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
+    }
 }
Index: applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/CadastrePreferenceSetting.java
===================================================================
--- applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/CadastrePreferenceSetting.java	(revision 17087)
+++ applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/CadastrePreferenceSetting.java	(revision 17089)
@@ -50,4 +50,7 @@
     JLabel jLabelCacheSize = new JLabel(tr("Max. cache size (in MB)"));
     private JTextField cacheSize = new JTextField(20);
+    
+    static final String DEFAULT_RASTER_DIVIDER = "5";
+    private JTextField rasterDivider = new JTextField(10);
 
     public void addGui(final PreferenceDialog gui) {
@@ -103,6 +106,6 @@
         cadastrewms.add(drawBoundaries, GBC.eop().insets(0, 0, 0, 5));
 
-        // the downloaded images multiplier
-        JLabel jLabelScale = new JLabel(tr("Image grab multiplier:"));
+        // the vectorized images multiplier
+        JLabel jLabelScale = new JLabel(tr("Vector images grab multiplier:"));
         cadastrewms.add(jLabelScale, GBC.std().insets(0, 5, 10, 0));
         ButtonGroup bg = new ButtonGroup();
@@ -151,4 +154,12 @@
         cadastrewms.add(grabMultiplier4Size, GBC.eol().fill(GBC.HORIZONTAL).insets(5, 5, 0, 5));
 
+        // for raster images (not vectorized), image grab divider (from 1 to 10)
+        String savedRasterDivider = Main.pref.get("cadastrewms.rasterDivider", DEFAULT_RASTER_DIVIDER);
+        JLabel jLabelRasterDivider = new JLabel(tr("Raster images grab multiplier:"));
+        rasterDivider.setText(savedRasterDivider);
+        rasterDivider.setToolTipText("Raster image grab division, from 1 to 10; 10 is very high definition");
+        cadastrewms.add(jLabelRasterDivider, GBC.std().insets(0, 5, 10, 0));
+        cadastrewms.add(rasterDivider, GBC.eol().fill(GBC.HORIZONTAL).insets(5, 5, 200, 5));
+
         // option to enable automatic caching
         enableCache.addActionListener(new ActionListener() {
@@ -167,6 +178,6 @@
         cacheSize.setToolTipText(tr("Oldest files are automatically deleted when this size is exceeded"));
         cadastrewms.add(jLabelCacheSize, GBC.std().insets(20, 0, 0, 0));
-        cadastrewms.add(cacheSize, GBC.eol().fill(GBC.HORIZONTAL).insets(5, 5, 0, 5));
-
+        cadastrewms.add(cacheSize, GBC.eol().fill(GBC.HORIZONTAL).insets(5, 5, 200, 5));
+        
         cadastrewms.add(Box.createVerticalGlue(), GBC.eol().fill(GBC.VERTICAL));
 
@@ -196,4 +207,10 @@
             }
         }
+        try {
+            int i = Integer.parseInt(rasterDivider.getText());
+            if (i > 0 && i < 11)
+                Main.pref.put("cadastrewms.rasterDivider", String.valueOf(i));
+        } catch (NumberFormatException e) { // ignore the last input
+        }
         Main.pref.put("cadastrewms.enableCaching", enableCache.isSelected());
 
Index: applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/DownloadSVGBuilding.java
===================================================================
--- applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/DownloadSVGBuilding.java	(revision 17087)
+++ applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/DownloadSVGBuilding.java	(revision 17089)
@@ -205,5 +205,4 @@
             URL url = null;
             url = getURLsvg(bbox);
-            System.out.println("grab:"+url);
             return grabSVG(url);
         } catch (MalformedURLException e) {
Index: applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/DownloadSVGTask.java
===================================================================
--- applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/DownloadSVGTask.java	(revision 17087)
+++ applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/DownloadSVGTask.java	(revision 17089)
@@ -47,5 +47,5 @@
 
     public DownloadSVGTask(WMSLayer wmsLayer) {
-        super(tr("Downloading {0}", wmsLayer.name));
+        super(tr("Downloading {0}", wmsLayer.getName()));
 
         this.wmsLayer = wmsLayer;
@@ -161,5 +161,4 @@
             URL url = null;
             url = getURLsvg(bbox);
-            System.out.println("grab:"+url);
             return grabSVG(url);
         } catch (MalformedURLException e) {
Index: applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/DownloadWMSPlanImage.java
===================================================================
--- applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/DownloadWMSPlanImage.java	(revision 17089)
+++ applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/DownloadWMSPlanImage.java	(revision 17089)
@@ -0,0 +1,121 @@
+package cadastre_fr;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.concurrent.Future;
+
+import javax.swing.JDialog;
+import javax.swing.JOptionPane;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.gui.MapView;
+import org.openstreetmap.josm.gui.PleaseWaitRunnable;
+
+public class DownloadWMSPlanImage {
+    
+    private Future<Task> task = null;
+    private WMSLayer wmsLayer;
+    private Bounds bounds;
+    private boolean dontGeoreference = false;
+    
+    private class Task extends PleaseWaitRunnable {
+        private CadastreGrabber grabber = CadastrePlugin.cadastreGrabber;
+        public Task(WMSLayer wmsLayer, Bounds bounds) {
+            super(tr("Downloading {0}", wmsLayer.getName()));
+        }
+
+        @Override
+        public void realRun() throws IOException {
+            progressMonitor.indeterminateSubTask(tr("Contacting cadastre WMS ..."));
+            try {
+                if (grabber.getWmsInterface().retrieveInterface(wmsLayer)) {
+                    if (!wmsLayer.images.isEmpty()) {
+                        //JOptionPane.showMessageDialog(Main.parent,tr("Image already loaded"));
+                        JOptionPane pane = new JOptionPane(
+                                tr("Image already loaded")
+                                , JOptionPane.INFORMATION_MESSAGE);
+                        // this below is a temporary workaround to fix the "always on top" issue
+                        JDialog dialog = pane.createDialog(Main.parent, "");
+                        CadastrePlugin.prepareDialog(dialog);
+                        dialog.setVisible(true);
+                        // till here
+                        dontGeoreference = true;
+                    } else if (grabber.getWmsInterface().downloadCancelled){
+                        // do nothing
+                    } else {
+                        // first time we grab an image for this layer
+                        if (CacheControl.cacheEnabled) {
+                            if (wmsLayer.getCacheControl().loadCacheIfExist()) {
+                                dontGeoreference = true;
+                                Main.map.mapView.repaint();
+                                return;
+                            }
+                        }
+                        if (wmsLayer.isRaster()) {
+                            // set raster image commune bounding box based on current view (before adjustment)
+                            wmsLayer.setCommuneBBox( grabber.getWmsInterface().retrieveCommuneBBox());
+                            wmsLayer.setRasterBounds(bounds);
+                            // grab new images from wms server into active layer
+                            wmsLayer.grab(grabber, bounds);
+                            if (grabber.getWmsInterface().downloadCancelled) {
+                                wmsLayer.images.clear();
+                                Main.map.mapView.repaint();
+                            } else {
+                                // next steps follow in method finish() when download is terminated
+                                wmsLayer.joinRasterImages();
+                            }
+                        } else {
+                            /*JOptionPane.showMessageDialog(Main.parent,tr("Municipality vectorized !\n"+
+                                    "Use the normal Cadastre Grab menu."));*/
+                            JOptionPane pane = new JOptionPane(
+                                    tr("Municipality vectorized !\nUse the normal Cadastre Grab menu.")
+                                    , JOptionPane.INFORMATION_MESSAGE);
+                            // this below is a temporary workaround to fix the "always on top" issue
+                            JDialog dialog = pane.createDialog(Main.parent, "");
+                            CadastrePlugin.prepareDialog(dialog);
+                            dialog.setVisible(true);
+                            // till here
+                        }
+                    }
+                }
+            } catch (DuplicateLayerException e) {
+                // we tried to grab onto a duplicated layer (removed)
+                System.err.println("removed a duplicated layer");
+            }
+        }
+        
+        @Override
+        protected void cancel() {
+            grabber.getWmsInterface().cancel();
+        }
+
+        @Override
+        protected void finish() {
+        }
+    }
+    
+    public void download(WMSLayer wmsLayer) {
+        MapView mv = Main.map.mapView;
+        Bounds bounds = new Bounds(mv.getLatLon(0, mv.getHeight()), mv.getLatLon(mv.getWidth(), 0));
+
+        //Main.worker.execute(new DownloadWMSPlanImage(wmsLayer, bounds));
+        Task t = new Task(wmsLayer, bounds);
+        this.wmsLayer = wmsLayer;
+        this.bounds = bounds;
+        task = Main.worker.submit(t, t);
+    }
+
+    public boolean waitFinished() {
+        if (task != null) {
+            try {
+                task.get();
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+        return dontGeoreference;
+    }
+}
Index: applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/DownloadWMSVectorImage.java
===================================================================
--- applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/DownloadWMSVectorImage.java	(revision 17087)
+++ applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/DownloadWMSVectorImage.java	(revision 17089)
@@ -10,5 +10,5 @@
 import org.openstreetmap.josm.gui.PleaseWaitRunnable;
 
-public class DownloadWMSTask extends PleaseWaitRunnable {
+public class DownloadWMSVectorImage extends PleaseWaitRunnable {
 
     private WMSLayer wmsLayer;
@@ -18,6 +18,6 @@
     private CadastreGrabber grabber = CadastrePlugin.cadastreGrabber;
 
-    public DownloadWMSTask(WMSLayer wmsLayer, Bounds bounds) {
-        super(tr("Downloading {0}", wmsLayer.name));
+    public DownloadWMSVectorImage(WMSLayer wmsLayer, Bounds bounds) {
+        super(tr("Downloading {0}", wmsLayer.getName()));
 
         this.wmsLayer = wmsLayer;
@@ -67,5 +67,5 @@
         Bounds bounds = new Bounds(mv.getLatLon(0, mv.getHeight()), mv.getLatLon(mv.getWidth(), 0));
 
-        Main.worker.execute(new DownloadWMSTask(wmsLayer, bounds));
+        Main.worker.execute(new DownloadWMSVectorImage(wmsLayer, bounds));
 
     }
Index: applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/GeorefImage.java
===================================================================
--- applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/GeorefImage.java	(revision 17087)
+++ applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/GeorefImage.java	(revision 17089)
@@ -15,4 +15,5 @@
 import java.io.ObjectOutputStream;
 import java.io.Serializable;
+
 import javax.imageio.ImageIO;
 
@@ -23,16 +24,10 @@
     private static final long serialVersionUID = 1L;
 
-    public EastNorth min, max;
-
-    public EastNorth org_min, org_max;
-
+    public EastNorth min;
+    public EastNorth max;
     public BufferedImage image;
 
-    private double angle = 0; // in radian
-
-    private BufferedImage rotated_image; // only if angle <> 0
-
-    double pixelPerEast;
-    double pixelPerNorth;
+    private double pixelPerEast;
+    private double pixelPerNorth;
 
     public GeorefImage(BufferedImage img, EastNorth min, EastNorth max) {
@@ -43,52 +38,4 @@
     }
 
-    public void displace(double dx, double dy) {
-        min = new EastNorth(min.east() + dx, min.north() + dy);
-        max = new EastNorth(max.east() + dx, max.north() + dy);
-    }
-
-    public void resize(EastNorth rasterCenter, double proportion) {
-        min = min.interpolate(rasterCenter, proportion);
-        max = max.interpolate(rasterCenter, proportion);
-        updatePixelPer();
-    }
-
-    public void rotate(EastNorth pivot, double delta) {
-        if (angle == 0) {
-            org_min = min;
-            org_max = max;
-        }
-        this.angle += delta;
-
-        EastNorth imageCenter = org_min.interpolate(org_max, 0.5);
-        EastNorth newimageCenter = imageCenter.rotate(pivot, angle);
-        min.setLocation(org_min.east() + newimageCenter.east()-imageCenter.east(),
-                org_min.north() + newimageCenter.north()-imageCenter.north());
-        max.setLocation(org_max.east() + newimageCenter.east()-imageCenter.east(),
-                org_max.north() + newimageCenter.north()-imageCenter.north());
-        EastNorth min2 = new EastNorth(min.east(), max.north());
-        EastNorth max2 = new EastNorth(max.east(), min.north());
-        min = org_min.rotate(newimageCenter, angle);
-        max = org_max.rotate(newimageCenter, angle);
-        min2 = min2.rotate(newimageCenter, angle);
-        max2 = max2.rotate(newimageCenter, angle);
-        getNewBounding(min, max, min2, max2);
-
-        rotated_image = tilt(image, angle);
-    }
-
-    public static BufferedImage tilt(BufferedImage image, double angle) {
-        double sin = Math.abs(Math.sin(angle)), cos = Math.abs(Math.cos(angle));
-        int w = image.getWidth(), h = image.getHeight();
-        int neww = (int)Math.floor(w*cos+h*sin), newh = (int)Math.floor(h*cos+w*sin);
-        GraphicsConfiguration gc = getDefaultConfiguration();
-        BufferedImage result = gc.createCompatibleImage(neww, newh, Transparency.TRANSLUCENT);
-        Graphics2D g = result.createGraphics();
-        g.translate((neww-w)/2, (newh-h)/2);
-        g.rotate(angle, w/2, h/2);
-        g.drawRenderedImage(image, null);
-        g.dispose();
-        return result;
-    }
     public static GraphicsConfiguration getDefaultConfiguration() {
         GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
@@ -127,10 +74,4 @@
             return;
 
-        BufferedImage toDisplay;
-        if (angle != 0)
-            toDisplay = rotated_image;
-        else
-            toDisplay = image;
-
         Point minPt = nc.getPoint(min), maxPt = nc.getPoint(max);
 
@@ -144,6 +85,6 @@
             g.drawRect(minPt.x, maxPt.y, maxPt.x - minPt.x, minPt.y - maxPt.y);
         }
-        g.drawImage(toDisplay, minPt.x, maxPt.y, maxPt.x, minPt.y, // dest
-                0, 0, toDisplay.getWidth(), toDisplay.getHeight(), // src
+        g.drawImage(image, minPt.x, maxPt.y, maxPt.x, minPt.y, // dest
+                0, 0, image.getWidth(), image.getHeight(), // src
                 null);
         if (backgroundTransparent && transparency < 1.0f)
@@ -183,9 +124,12 @@
             for (int x = minXMaskPixel; x < minXMaskPixel + widthXMaskPixel; x++)
                 for (int y = minYMaskPixel; y < minYMaskPixel + heightYMaskPixel; y++)
-                    image.setRGB(x, y, ImageModifier.cadastreBackgroundTransp);
+                    image.setRGB(x, y, VectorImageModifier.cadastreBackgroundTransp);
             g.dispose();
         }
     }
 
+    /*
+     * Method required by BufferedImage serialization
+     */
     private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
         max = (EastNorth) in.readObject();
@@ -195,10 +139,7 @@
     }
 
-
-    private void updatePixelPer() {
-        pixelPerEast = image.getWidth()/(max.east()-min.east());
-        pixelPerNorth = image.getHeight()/(max.north()-min.north());
-    }
-
+    /*
+     * Method required by BufferedImage serialization
+     */
     private void writeObject(ObjectOutputStream out) throws IOException {
         out.writeObject(max);
@@ -207,4 +148,17 @@
     }
 
+    private void updatePixelPer() {
+        pixelPerEast = image.getWidth()/(max.east()-min.east());
+        pixelPerNorth = image.getHeight()/(max.north()-min.north());
+    }
+
+    public double getPixelPerEast() {
+        return pixelPerEast;
+    }
+
+    public double getPixelPerNorth() {
+        return pixelPerNorth;
+    }
+
     @Override
     public String toString() {
@@ -212,3 +166,63 @@
     }
 
+    /*
+     * Following methods are used for affine transformation of two points p1 and p2
+     */
+    /**
+     * Add a translation (dx, dy) to this image min,max coordinates
+     * @param dx delta added to X image coordinate
+     * @param dy delta added to Y image coordinate
+     */
+    public void shear(double dx, double dy) {
+        min = new EastNorth(min.east() + dx, min.north() + dy);
+        max = new EastNorth(max.east() + dx, max.north() + dy);
+    }
+    
+    /**
+     * Change this image scale by moving the min,max coordinates around an anchor
+     * @param anchor 
+     * @param proportion
+     */
+    public void scale(EastNorth anchor, double proportion) {
+        min = anchor.interpolate(min, proportion);
+        max = anchor.interpolate(max, proportion);
+        updatePixelPer();
+    }
+
+    /**
+     * Rotate this image and its min/max coordinates around anchor point
+     * @param anchor anchor of rotation
+     * @param angle angle of rotation (in radians)
+     */
+    public void rotate(EastNorth anchor, double angle) {
+        EastNorth min2 = new EastNorth(min.east(), max.north());
+        EastNorth max2 = new EastNorth(max.east(), min.north());
+        min = min.rotate(anchor, angle);
+        max = max.rotate(anchor, angle);
+        min2 = min2.rotate(anchor, angle);
+        max2 = max2.rotate(anchor, angle);
+        getNewBounding(min, max, min2, max2);
+        image = tilt(image, angle);
+    }
+
+    /**
+     * Rotate by copying original buffered image into a new one with new dimensions 
+     * @param image
+     * @param angle
+     * @return
+     */
+    public static BufferedImage tilt(BufferedImage image, double angle) {
+        double sin = Math.abs(Math.sin(angle)), cos = Math.abs(Math.cos(angle));
+        int w = image.getWidth(), h = image.getHeight();
+        int neww = (int)Math.floor(w*cos+h*sin), newh = (int)Math.floor(h*cos+w*sin);
+        GraphicsConfiguration gc = getDefaultConfiguration();
+        BufferedImage result = gc.createCompatibleImage(neww, newh, Transparency.TRANSLUCENT);
+        Graphics2D g = result.createGraphics();
+        g.translate((neww-w)/2, (newh-h)/2);
+        g.rotate(angle, w/2, h/2);
+        g.drawRenderedImage(image, null);
+        g.dispose();
+        return result;
+    }
+
 }
Index: applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/GeorefImageRaster.java
===================================================================
--- applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/GeorefImageRaster.java	(revision 17087)
+++ 	(revision )
@@ -1,15 +1,0 @@
-package cadastre_fr;
-
-import java.awt.image.BufferedImage;
-
-import org.openstreetmap.josm.data.coor.EastNorth;
-
-public class GeorefImageRaster extends GeorefImage {
-
-    private static final long serialVersionUID = 1L;
-
-    public GeorefImageRaster(BufferedImage img, EastNorth min, EastNorth max) {
-        super(img, min, max);
-    }
-
-}
Index: applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/ImageModifier.java
===================================================================
--- applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/ImageModifier.java	(revision 17087)
+++ applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/ImageModifier.java	(revision 17089)
@@ -1,139 +1,15 @@
 package cadastre_fr;
 
-import java.awt.Color;
 import java.awt.image.BufferedImage;
-import java.awt.image.ColorModel;
-import java.awt.image.IndexColorModel;
-import java.awt.image.WritableRaster;
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.tools.ColorHelper;
 
-public class ImageModifier {
-
+public abstract class ImageModifier {
     /**
      * Current background color used by cadastre.gouv.fr
      */
+    //public static int cadastreBackgroundTransp = 1; // original white but transparent
+
     private static final long serialVersionUID = 1L;
-
-    public static final int cadastreBackground = -1; // white
-
-    public static final int cadastreBackgroundTransp = 1; // original white but transparent
 
     public BufferedImage bufferedImage;
 
-    private boolean withBackground = false;
-
-    private int backgroundPixel = 0;
-
-    private int backgroundSampleX, backgroundSampleY;
-
-    public ImageModifier(BufferedImage bi) {
-        bufferedImage = bi;
-        if (Main.pref.getBoolean("cadastrewms.backgroundTransparent"))
-            makeTransparent();
-        else if (Main.pref.getBoolean("cadastrewms.alterColors"))
-            replaceBackground();
-
-        if (Main.pref.getBoolean("cadastrewms.invertGrey"))
-            invertGrey();
-    }
-
-    /**
-     * Replace the background color by the josm color.background color.
-     */
-    private void replaceBackground() {
-        int w = bufferedImage.getWidth();
-        int h = bufferedImage.getHeight();
-        int josmBackgroundColor = ColorHelper.html2color(Main.pref.get("color.background", "#000000")).getRGB();
-        for (int x = 0; x < w; x++) {
-            for (int y = 0; y < h; y++) {
-                int pixel = bufferedImage.getRGB(x, y);
-                if (pixel == cadastreBackground) {
-                    bufferedImage.setRGB(x, y, josmBackgroundColor);
-                    if (!withBackground)
-                        withBackground = true;
-                    backgroundSampleX = x;
-                    backgroundSampleY = y;
-                }
-            }
-        }
-    }
-
-    /**
-     * Invert black/white/grey pixels (to change original black characters to white).
-     */
-    private void invertGrey() {
-        int w = bufferedImage.getWidth();
-        int h = bufferedImage.getHeight();
-        for (int x = 0; x < w; x++) {
-            for (int y = 0; y < h; y++) {
-                int pixel = bufferedImage.getRGB(x, y);
-                if (pixel != cadastreBackground) {
-                    bufferedImage.setRGB(x, y, reverseIfGrey(pixel));
-                }
-            }
-        }
-    }
-
-    /**
-     * Reverse the grey value if the pixel is grey (light grey becomes dark grey)
-     * Used for texts.
-     * @param pixel
-     * @return
-     */
-    private int reverseIfGrey(int pixel) {
-        Color col = new Color(pixel);
-        int r = col.getRed();
-        int g = col.getGreen();
-        int b = col.getBlue();
-        if ((b == r) && (b == g)) {
-            pixel = (0x00 << 32) + ((byte) (255 - r) << 16) + ((byte) (255 - r) << 8) + ((byte) (255 - r));
-        }
-        return pixel;
-    }
-
-    private void makeTransparent() {
-        ColorModel colorModel = bufferedImage.getColorModel();
-        if (bufferedImage.getColorModel() instanceof IndexColorModel) {
-            // vector image (IndexColorModel)
-            IndexColorModel icm = (IndexColorModel) colorModel;
-            WritableRaster raster = bufferedImage.getRaster();
-            // pixel is offset in ICM's palette
-            if (withBackground)
-                backgroundPixel = raster.getSample(backgroundSampleX, backgroundSampleY, 0);
-            else
-                backgroundPixel = 1; // default Cadastre background sample
-            int size = icm.getMapSize();
-            byte[] reds = new byte[size];
-            byte[] greens = new byte[size];
-            byte[] blues = new byte[size];
-            icm.getReds(reds);
-            icm.getGreens(greens);
-            icm.getBlues(blues);
-            IndexColorModel icm2 = new IndexColorModel(colorModel.getPixelSize(), size, reds, greens, blues,
-                    backgroundPixel);
-            bufferedImage = new BufferedImage(icm2, raster, bufferedImage.isAlphaPremultiplied(), null);
-        } else {
-            int width = bufferedImage.getWidth();
-            int height = bufferedImage.getHeight();
-            BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
-            for (int y = 0; y < height; y++) {
-                for (int x = 0; x < width; x++) {
-                    Color c = new Color(bufferedImage.getRGB(x, y));
-                    int r = c.getRed();
-                    int g = c.getGreen();
-                    int b = c.getBlue();
-                    Color maskedColor;
-                    if (r==0 && g==0 && b==0) {
-                        maskedColor = new Color(r, g, b, 0x00);
-                    } else {
-                        maskedColor = new Color(r, g, b, 0xFF);
-                    }
-                    bi.setRGB(x, y, maskedColor.getRGB());
-                }
-            }
-            bufferedImage = bi;
-        }
-        return;
-    }
 }
Index: applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/MenuActionGrab.java
===================================================================
--- applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/MenuActionGrab.java	(revision 17087)
+++ applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/MenuActionGrab.java	(revision 17089)
@@ -32,5 +32,5 @@
                 WMSLayer wmsLayer = WMSDownloadAction.getLayer();
                 if (wmsLayer != null)
-                    DownloadWMSTask.download(wmsLayer);
+                    DownloadWMSVectorImage.download(wmsLayer);
             } else {
                 JOptionPane.showMessageDialog(Main.parent,
Index: applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/MenuActionGrabPlanImage.java
===================================================================
--- applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/MenuActionGrabPlanImage.java	(revision 17089)
+++ applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/MenuActionGrabPlanImage.java	(revision 17089)
@@ -0,0 +1,212 @@
+package cadastre_fr;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.GridBagLayout;
+import java.awt.Point;
+import java.awt.event.ActionEvent;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.util.ArrayList;
+
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.JosmAction;
+import org.openstreetmap.josm.data.coor.EastNorth;
+import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.tools.GBC;
+
+public class MenuActionGrabPlanImage extends JosmAction implements Runnable, MouseListener {
+
+    /**
+     * Action calling the wms grabber for non georeferenced images called "plan image"
+     */
+    private static final long serialVersionUID = 1L;
+
+    public static String name = "Georeference an image";
+    
+    private DownloadWMSPlanImage downloadWMSPlanImage;
+    private WMSLayer wmsLayer;
+    private int countMouseClicked = 0;
+    private int mode = 0;
+    private int cGetCorners = 1;
+    private int cGetLambertCrosspieces = 2;
+    private EastNorth ea1;
+    private Point mousePrevious = new Point();
+    private EastNorth georefpoint1;
+    private EastNorth georefpoint2;
+
+    public MenuActionGrabPlanImage() {
+        super(tr(name), "cadastre_small", tr("Grab non-georeferenced image"), null, false);
+    }
+
+    public void actionCompleted() {
+        countMouseClicked = 0;
+        mode = 0;
+        mousePrevious.setLocation(0, 0);
+    }
+    
+    public void actionInterrupted() {
+        actionCompleted();
+        wmsLayer = null;
+    }
+    
+    @Override
+    protected void updateEnabledState() {
+        if (wmsLayer == null || Main.map == null || Main.map.mapView == null) return;
+        if (countMouseClicked == 0 && mode == 0) return;
+        for (Layer l : Main.map.mapView.getAllLayersAsList())
+            if (l == wmsLayer)
+                return;
+        JOptionPane.showMessageDialog(Main.parent, tr("Georeferencing interrupted"));
+        actionInterrupted();
+    }
+    
+    public void actionPerformed(ActionEvent ae) {
+        if (Main.map != null) {
+            if (CadastrePlugin.isCadastreProjection()) {
+                //wmsLayer = WMSDownloadAction.getLayer();
+                wmsLayer = new MenuActionNewLocation().addNewLayer(new ArrayList<WMSLayer>());
+                if (wmsLayer == null) return;
+                downloadWMSPlanImage = new DownloadWMSPlanImage();
+                downloadWMSPlanImage.download(wmsLayer);
+                // download sub-images of the cadastre scan and join them into one single
+                Main.worker.execute(this);
+            } else {
+                JOptionPane.showMessageDialog(Main.parent,
+                        tr("To enable the cadastre WMS plugin, change\n"
+                         + "the current projection to one of the cadastre\n"
+                         + "projection and retry"));
+            }
+        }
+    }
+
+    public void run() {
+        // wait until plan image is fully loaded and joined into one single image
+        boolean loadedFromCache = downloadWMSPlanImage.waitFinished();
+        if (wmsLayer.images.size() == 1 && !loadedFromCache) {
+            Main.map.mapView.addMouseListener(this);
+            mousePrevious.setLocation(0, 0);
+            mode = cGetCorners;
+            JOptionPane.showMessageDialog(Main.parent,tr("Click first corner for image cropping\n"+
+                    "(two points required)"));
+        } else // action cancelled or image loaded from cache (and already georeferenced)
+            Main.map.repaint();
+    }
+
+    public void mouseClicked(MouseEvent e) {
+        if (e.getX() == mousePrevious.getX() && e.getY() == mousePrevious.getY())
+            return; // double click filtered
+        else
+            mousePrevious.setLocation(e.getX(), e.getY());
+        countMouseClicked++;
+        EastNorth ea = Main.proj.latlon2eastNorth(Main.map.mapView.getLatLon(e.getX(), e.getY()));
+        System.out.println("clic:"+countMouseClicked+" ,"+ea);
+        // ignore clicks outside the image
+        if (ea.east() < wmsLayer.images.get(0).min.east() || ea.east() > wmsLayer.images.get(0).max.east()
+                || ea.north() < wmsLayer.images.get(0).min.north() || ea.north() > wmsLayer.images.get(0).max.north())
+            return;
+        if (mode == cGetCorners) {
+            if (countMouseClicked == 1) {
+                ea1 = ea;
+                JOptionPane.showMessageDialog(Main.parent,tr("Click second corner for image cropping"));
+            }
+            if (countMouseClicked == 2) {
+                wmsLayer.cropImage(ea1, ea);
+                Main.map.mapView.repaint();
+                countMouseClicked = 0;
+                mode = cGetLambertCrosspieces;
+                JOptionPane.showMessageDialog(Main.parent,tr("Click first Lambert crosspiece for georeferencing\n"+
+                    "(two points required)"));
+            }
+        } else if (mode == cGetLambertCrosspieces) {
+            if (countMouseClicked == 1) {
+                ea1 = ea; 
+                georefpoint1 = inputLambertPosition();
+                if (georefpoint1 == null)
+                    return;
+                JOptionPane.showMessageDialog(Main.parent,tr("Click second Lambert crosspiece for georeferencing\n"));
+            }
+            if (countMouseClicked == 2) {
+                Main.map.mapView.removeMouseListener(this);
+                georefpoint2 = inputLambertPosition();
+                if (georefpoint2 == null)
+                    return;
+                affineTransform(ea1, ea, georefpoint1, georefpoint2);
+                wmsLayer.saveNewCache();
+                Main.map.mapView.repaint();
+                actionCompleted();
+            }
+        }
+    }
+    
+    private EastNorth inputLambertPosition() {
+        JLabel labelEnterPosition = new JLabel(tr("Enter cadastre east,north position"));
+        JLabel labelWarning = new JLabel(tr("(Warning: verify north with arrow !!)"));
+        JPanel p = new JPanel(new GridBagLayout());
+        JLabel labelEast = new JLabel(tr("East"));
+        JLabel labelNorth = new JLabel(tr("North"));
+        final JTextField inputEast = new JTextField();
+        final JTextField inputNorth = new JTextField();
+        p.add(labelEnterPosition, GBC.eol());
+        p.add(labelWarning, GBC.eol());
+        p.add(labelEast, GBC.std().insets(0, 0, 10, 0));
+        p.add(inputEast, GBC.eol().fill(GBC.HORIZONTAL).insets(10, 5, 0, 5));
+        p.add(labelNorth, GBC.std().insets(0, 0, 10, 0));
+        p.add(inputNorth, GBC.eol().fill(GBC.HORIZONTAL).insets(10, 5, 0, 5));
+        JOptionPane pane = new JOptionPane(p, JOptionPane.INFORMATION_MESSAGE, JOptionPane.OK_CANCEL_OPTION, null);
+        pane.createDialog(Main.parent, tr("Set Lambert coordinate")).setVisible(true);
+        if (!Integer.valueOf(JOptionPane.OK_OPTION).equals(pane.getValue()))
+            return null;
+        if (inputEast.getText().length() == 0 || inputNorth.getText().length() == 0)
+            return null;
+        try {
+            double e = Double.parseDouble(inputEast.getText());
+            double n = Double.parseDouble(inputNorth.getText());
+            return new EastNorth(e, n);
+        } catch (NumberFormatException e) {
+            return null;
+        }        
+    }
+    
+    /**
+     * Use point org1 as anchor for scale, then move org1 to dst1, then rotate org2 on dst2 
+     * around org1/dst1 anchor 
+     * @param org1 first point at original coordinate system (the grabbed image)
+     * @param org2 second point "
+     * @param dst1 first point at final destination coordinate system (the real east/north coordinate system) 
+     * @param dst2 second point "
+     */
+    private void affineTransform(EastNorth org1, EastNorth org2, EastNorth dst1, EastNorth dst2) {
+        double angle = dst1.heading(dst2) - org1.heading(org2);
+        double proportion = dst1.distance(dst2)/org1.distance(org2);
+        // move
+        double dx = dst1.getX() - org1.getX();
+        double dy = dst1.getY() - org1.getY();
+        wmsLayer.images.get(0).shear(dx, dy);
+        org1 = org1.add(dx, dy); // org1=dst1 now
+        org2 = org2.add(dx, dy);
+        // rotate : org1(=dst1 now) is anchor for rotation and scale
+        wmsLayer.images.get(0).rotate(dst1, angle);
+        org2 = org2.rotate(dst1, angle);
+        // scale image from anchor org1(=dst1 now)
+        wmsLayer.images.get(0).scale(dst1, proportion);
+    }
+    
+    public void mouseEntered(MouseEvent arg0) {
+    }
+
+    public void mouseExited(MouseEvent arg0) {
+    }
+
+    public void mousePressed(MouseEvent arg0) {
+    }
+
+    public void mouseReleased(MouseEvent arg0) {
+    }
+        
+}
Index: applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/MenuActionLoadFromCache.java
===================================================================
--- applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/MenuActionLoadFromCache.java	(revision 17087)
+++ applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/MenuActionLoadFromCache.java	(revision 17089)
@@ -52,5 +52,5 @@
             if (Main.map != null) {
                 for (Layer l : Main.map.mapView.getAllLayers()) {
-                    if (l instanceof WMSLayer && l.name.equals(location)) {
+                    if (l instanceof WMSLayer && l.getName().equals(location)) {
                         System.out.println("The location " + filename + " is already on screen. Cache not loaded.");
                         continue nextFile;
Index: applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/MenuActionNewLocation.java
===================================================================
--- applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/MenuActionNewLocation.java	(revision 17087)
+++ applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/MenuActionNewLocation.java	(revision 17089)
@@ -30,5 +30,5 @@
         WMSLayer wmsLayer = addNewLayer(new ArrayList<WMSLayer>());
         if (wmsLayer != null)
-            DownloadWMSTask.download(wmsLayer);
+            DownloadWMSVectorImage.download(wmsLayer);
     }
 
@@ -79,5 +79,5 @@
                 Main.pref.put("cadastrewms.codeCommune", codeCommune);
                 for (Layer l : Main.map.mapView.getAllLayers()) {
-                    if (l instanceof WMSLayer && l.name.equalsIgnoreCase(location + codeDepartement)) {
+                    if (l instanceof WMSLayer && l.getName().equalsIgnoreCase(location + codeDepartement)) {
                         return null;
                     }
@@ -93,5 +93,5 @@
 
             if (resetCookie)
-                CadastrePlugin.cadastreGrabber.getWmsInterface().resetCookieIfNewLayer(wmsLayer.name);
+                CadastrePlugin.cadastreGrabber.getWmsInterface().resetCookieIfNewLayer(wmsLayer.getName());
             return wmsLayer;
         }
Index: applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/MenuActionSaveRasterAs.java
===================================================================
--- applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/MenuActionSaveRasterAs.java	(revision 17089)
+++ applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/MenuActionSaveRasterAs.java	(revision 17089)
@@ -0,0 +1,44 @@
+package cadastre_fr;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.event.ActionEvent;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+
+import javax.imageio.ImageIO;
+import javax.swing.JFileChooser;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.JosmAction;
+
+public class MenuActionSaveRasterAs extends JosmAction {
+
+    public static String name = "Save image as PNG";
+    
+    private static final long serialVersionUID = 1L;
+    
+    private WMSLayer wmsLayer;
+
+    public MenuActionSaveRasterAs(WMSLayer wmsLayer) {
+        super(tr(name), "save", tr("Export as PNG format (only raster images)"), null, false);
+        this.wmsLayer = wmsLayer;
+    }
+
+    public void actionPerformed(ActionEvent arg0) {
+        File file;
+        JFileChooser fc = new JFileChooser();
+        int returnVal = fc.showSaveDialog(Main.parent);
+        if (returnVal == JFileChooser.APPROVE_OPTION) {
+            file = fc.getSelectedFile();
+            BufferedImage bi = wmsLayer.images.get(0).image; 
+            try {
+                ImageIO.write(bi, "png", file);
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+}
Index: applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/RasterImageModifier.java
===================================================================
--- applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/RasterImageModifier.java	(revision 17089)
+++ applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/RasterImageModifier.java	(revision 17089)
@@ -0,0 +1,88 @@
+package cadastre_fr;
+
+import java.awt.Color;
+import java.awt.image.BufferedImage;
+import java.awt.image.ComponentColorModel;
+
+import org.openstreetmap.josm.Main;
+
+public class RasterImageModifier extends ImageModifier {
+
+    private int cadastreBackground = -1; // white
+    
+    public static int cadastreBackgroundTransp = 16777215; // original white but transparent
+    
+    private boolean transparencyEnabled = false;
+
+    public RasterImageModifier(BufferedImage bi) {
+        bufferedImage = bi;
+        transparencyEnabled = Main.pref.getBoolean("cadastrewms.backgroundTransparent"); 
+        if (transparencyEnabled)
+            makeTransparent();
+        if (Main.pref.getBoolean("cadastrewms.invertGrey"))
+            invertGrey();
+    }
+
+    /**
+     * Invert black/white/grey pixels (to change original black characters to white).
+     */
+    private void invertGrey() {
+        int w = bufferedImage.getWidth();
+        int h = bufferedImage.getHeight();
+        for (int x = 0; x < w; x++) {
+            for (int y = 0; y < h; y++) {
+                int pixel = bufferedImage.getRGB(x, y);
+                if ((!transparencyEnabled && pixel != cadastreBackground) 
+                        || (transparencyEnabled && pixel != cadastreBackgroundTransp)) {
+                    bufferedImage.setRGB(x, y, reverseIfGrey(pixel));
+                }
+            }
+        }
+    }
+
+    /**
+     * Reverse the grey value if the pixel is grey (light grey becomes dark grey)
+     * Used for texts.
+     * @param pixel
+     * @return
+     */
+    private int reverseIfGrey(int pixel) {
+        Color col = new Color(pixel);
+        int r = col.getRed();
+        int g = col.getGreen();
+        int b = col.getBlue();
+        if ((b == r) && (b == g)) {
+            pixel = (0x00 << 32) + ((byte) (255 - r) << 16) + ((byte) (255 - r) << 8) + ((byte) (255 - r));
+        }
+        return pixel;
+    }
+
+    private void makeTransparent() {
+        if (bufferedImage.getColorModel() instanceof ComponentColorModel) {
+            // raster image (ComponentColorModel)
+            int width = bufferedImage.getWidth();
+            int height = bufferedImage.getHeight();
+            BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
+            for (int y = 0; y < height; y++) {
+                for (int x = 0; x < width; x++) {
+                    int rgb = bufferedImage.getRGB(x, y);
+                    Color c = new Color(rgb);
+                    int r = c.getRed();
+                    int g = c.getGreen();
+                    int b = c.getBlue();
+                    Color maskedColor;
+                    if (rgb == cadastreBackground) {
+                        maskedColor = new Color(r, g, b, 0x00); // transparent
+                    } else {
+                        maskedColor = new Color(r, g, b, 0xFF); // opaque
+                    }
+                    //maskedColor = new Color(r, g, b, alpha);
+                    bi.setRGB(x, y, maskedColor.getRGB());
+                }
+            }
+            bufferedImage = bi;
+        }
+        return;
+    }
+
+}
Index: applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/VectorImageModifier.java
===================================================================
--- applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/VectorImageModifier.java	(revision 17089)
+++ applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/VectorImageModifier.java	(revision 17089)
@@ -0,0 +1,111 @@
+package cadastre_fr;
+
+import java.awt.Color;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.IndexColorModel;
+import java.awt.image.WritableRaster;
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.tools.ColorHelper;
+
+public class VectorImageModifier extends ImageModifier {
+
+    private int cadastreBackground = -1; // white
+    
+    public static int cadastreBackgroundTransp = 1; // original white but transparent
+
+    private boolean withBackground = false;
+
+    private int backgroundPixel = 0;
+
+    private int backgroundSampleX, backgroundSampleY;
+
+    public VectorImageModifier(BufferedImage bi) {
+        bufferedImage = bi;
+        if (Main.pref.getBoolean("cadastrewms.backgroundTransparent"))
+            makeTransparent();
+        else if (Main.pref.getBoolean("cadastrewms.alterColors"))
+            replaceBackground();
+        if (Main.pref.getBoolean("cadastrewms.invertGrey"))
+            invertGrey();
+    }
+
+    /**
+     * Replace the background color by the josm color.background color.
+     */
+    private void replaceBackground() {
+        int w = bufferedImage.getWidth();
+        int h = bufferedImage.getHeight();
+        int josmBackgroundColor = ColorHelper.html2color(Main.pref.get("color.background", "#000000")).getRGB();
+        for (int x = 0; x < w; x++) {
+            for (int y = 0; y < h; y++) {
+                int pixel = bufferedImage.getRGB(x, y);
+                if (pixel == cadastreBackground) {
+                    bufferedImage.setRGB(x, y, josmBackgroundColor);
+                    if (!withBackground)
+                        withBackground = true;
+                    backgroundSampleX = x;
+                    backgroundSampleY = y;
+                }
+            }
+        }
+    }
+
+    /**
+     * Invert black/white/grey pixels (to change original black characters to white).
+     */
+    private void invertGrey() {
+        int w = bufferedImage.getWidth();
+        int h = bufferedImage.getHeight();
+        for (int x = 0; x < w; x++) {
+            for (int y = 0; y < h; y++) {
+                int pixel = bufferedImage.getRGB(x, y);
+                if (pixel != cadastreBackground) {
+                    bufferedImage.setRGB(x, y, reverseIfGrey(pixel));
+                }
+            }
+        }
+    }
+
+    /**
+     * Reverse the grey value if the pixel is grey (light grey becomes dark grey)
+     * Used for texts.
+     * @param pixel
+     * @return
+     */
+    private int reverseIfGrey(int pixel) {
+        Color col = new Color(pixel);
+        int r = col.getRed();
+        int g = col.getGreen();
+        int b = col.getBlue();
+        if ((b == r) && (b == g)) {
+            pixel = (0x00 << 32) + ((byte) (255 - r) << 16) + ((byte) (255 - r) << 8) + ((byte) (255 - r));
+        }
+        return pixel;
+    }
+
+    private void makeTransparent() {
+        ColorModel colorModel = bufferedImage.getColorModel();
+        if (bufferedImage.getColorModel() instanceof IndexColorModel) {
+            // vector image (IndexColorModel)
+            IndexColorModel icm = (IndexColorModel) colorModel;
+            WritableRaster raster = bufferedImage.getRaster();
+            // pixel is offset in ICM's palette
+            if (withBackground)
+                backgroundPixel = raster.getSample(backgroundSampleX, backgroundSampleY, 0);
+            else
+                backgroundPixel = 1; // default Cadastre background sample
+            int size = icm.getMapSize();
+            byte[] reds = new byte[size];
+            byte[] greens = new byte[size];
+            byte[] blues = new byte[size];
+            icm.getReds(reds);
+            icm.getGreens(greens);
+            icm.getBlues(blues);
+            IndexColorModel icm2 = new IndexColorModel(colorModel.getPixelSize(), size, reds, greens, blues,
+                    backgroundPixel);
+            bufferedImage = new BufferedImage(icm2, raster, bufferedImage.isAlphaPremultiplied(), null);
+        }
+        return;
+    }
+}
Index: applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/WMSDownloadAction.java
===================================================================
--- applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/WMSDownloadAction.java	(revision 17087)
+++ applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/WMSDownloadAction.java	(revision 17089)
@@ -21,5 +21,5 @@
 
     public void actionPerformed(ActionEvent e) {
-        DownloadWMSTask.download(getLayer());
+        DownloadWMSVectorImage.download(getLayer());
     }
 
Index: applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/WMSLayer.java
===================================================================
--- applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/WMSLayer.java	(revision 17087)
+++ applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/WMSLayer.java	(revision 17089)
@@ -6,6 +6,8 @@
 import java.awt.Graphics;
 import java.awt.Graphics2D;
+import java.awt.Image;
 import java.awt.Toolkit;
 import java.awt.image.BufferedImage;
+import java.awt.image.ImageObserver;
 import java.io.EOFException;
 import java.io.IOException;
@@ -13,4 +15,5 @@
 import java.io.ObjectOutputStream;
 import java.util.ArrayList;
+import java.util.Vector;
 
 import javax.swing.Icon;
@@ -35,5 +38,5 @@
  * server load.
  */
-public class WMSLayer extends Layer {
+public class WMSLayer extends Layer implements ImageObserver {
 
     Component[] component = null;
@@ -44,5 +47,5 @@
             CadastrePlugin.class.getResource("/images/cadastre_small.png")));
 
-    protected ArrayList<GeorefImage> images = new ArrayList<GeorefImage>();
+    protected Vector<GeorefImage> images = new Vector<GeorefImage>();
 
     protected final int serializeFormatVersion = 2;
@@ -56,16 +59,13 @@
     private String codeCommune = "";
 
-    private EastNorthBound communeBBox = new EastNorthBound(new EastNorth(0,0), new EastNorth(0,0));
+    public EastNorthBound communeBBox = new EastNorthBound(new EastNorth(0,0), new EastNorth(0,0));
 
     private boolean isRaster = false;
 
     private EastNorth rasterMin;
-
-    private EastNorth rasterCenter;
-
+    private EastNorth rasterMax;
     private double rasterRatio;
-
-    double cRasterMaxSizeX = 12286;
-    double cRasterMaxSizeY = 8730;
+    
+    private JMenuItem saveAsPng;
 
     public WMSLayer() {
@@ -94,5 +94,10 @@
 
     public void grab(CadastreGrabber grabber, Bounds b) throws IOException {
-        divideBbox(b, Integer.parseInt(Main.pref.get("cadastrewms.scale", Scale.X1.toString())));
+        if (isRaster) {
+            b = new Bounds(Main.proj.eastNorth2latlon(rasterMin), Main.proj.eastNorth2latlon(rasterMax));
+            divideBbox(b, Integer.parseInt(Main.pref.get("cadastrewms.rasterDivider", 
+                    CadastrePreferenceSetting.DEFAULT_RASTER_DIVIDER)));
+        } else
+            divideBbox(b, Integer.parseInt(Main.pref.get("cadastrewms.scale", Scale.X1.toString())));
 
         for (EastNorthBound n : dividedBbox) {
@@ -148,5 +153,5 @@
         double dNorth = (lambertMax.north() - minNorth) / factor;
         dividedBbox.clear();
-        if (factor < 4) {
+        if (factor < 4 || isRaster) {
             for (int xEast = 0; xEast < factor; xEast++)
                 for (int xNorth = 0; xNorth < factor; xNorth++) {
@@ -177,5 +182,5 @@
         if (isRaster) {
             str += "\n"+tr("Is not vectorized.");
-            str += "\n"+tr("Raster center: {0}", rasterCenter);
+            str += "\n"+tr("Raster size: {0}", communeBBox);
         } else
             str += "\n"+tr("Is vectorized.");
@@ -195,7 +200,9 @@
     @Override
     public void paint(Graphics g, final MapView mv) {
-        for (GeorefImage img : images)
-            img.paint((Graphics2D) g, mv, CadastrePlugin.backgroundTransparent,
-                    CadastrePlugin.transparency, CadastrePlugin.drawBoundaries);
+        synchronized(this){
+            for (GeorefImage img : images)
+                img.paint((Graphics2D) g, mv, CadastrePlugin.backgroundTransparent,
+                        CadastrePlugin.transparency, CadastrePlugin.drawBoundaries);
+        }
     }
 
@@ -215,7 +222,13 @@
     @Override
     public Component[] getMenuEntries() {
+        saveAsPng = new JMenuItem(new MenuActionSaveRasterAs(this));
+        saveAsPng.setEnabled(isRaster);
         component = new Component[] { new JMenuItem(LayerListDialog.getInstance().createShowHideLayerAction(this)),
-                new JMenuItem(LayerListDialog.getInstance().createDeleteLayerAction(this)), new JMenuItem(new MenuActionLoadFromCache()),
-                new JMenuItem(new LayerListPopup.InfoAction(this)) };
+                new JMenuItem(LayerListDialog.getInstance().createDeleteLayerAction(this)),
+                new JMenuItem(new MenuActionLoadFromCache()),
+                saveAsPng,
+                new JMenuItem(new LayerListPopup.InfoAction(this)),
+                
+        };
         return component;
     }
@@ -245,5 +258,5 @@
 
     public void saveToCache(GeorefImage image) {
-        if (CacheControl.cacheEnabled) {
+        if (CacheControl.cacheEnabled && !isRaster()) {
             getCacheControl().saveCache(image);
         }
@@ -303,49 +316,27 @@
     public void setRaster(boolean isRaster) {
         this.isRaster = isRaster;
-    }
-
-    /**
-     * Set the eastNorth position in rasterMin which is the 0,0 coordinate (bottom left corner).
-     * The bounds width is the raster width and height is calculate on a fixed image ratio.
-     * @param bounds
+        if (saveAsPng != null)
+            saveAsPng.setEnabled(isRaster);
+    }
+
+    /**
+     * Set raster positions used for grabbing and georeferencing. 
+     * rasterMin is the Eaast North of bottom left corner raster image on the screen when image is grabbed.
+     * The bounds width and height are the raster width and height. The image width matches the current view
+     * and the image height is adapted.
+     * Required: the communeBBox must be set (normally it is catched by CadastreInterface and saved by DownloadWMSPlanImage)   
+     * @param bounds the current main map view boundaries
      */
     public void setRasterBounds(Bounds bounds) {
-        rasterMin = new EastNorth(Main.proj.latlon2eastNorth(bounds.min).east(), Main.proj.latlon2eastNorth(bounds.min).north());
-        EastNorth rasterMax = new EastNorth(Main.proj.latlon2eastNorth(bounds.max).east(), Main.proj.latlon2eastNorth(bounds.max).north());
-        // now, resize on same proportion as wms server raster images (bounds center)
-        double rasterHalfHeight = (rasterMax.east() - rasterMin.east())/cRasterMaxSizeX*cRasterMaxSizeY/2;
-        double rasterMid = rasterMin.north() + (rasterMax.north()-rasterMin.north())/2;
-        rasterMin.setLocation(rasterMin.east(), rasterMid - rasterHalfHeight);
-        rasterMax.setLocation(rasterMax.east(), rasterMid + rasterHalfHeight);
-        rasterCenter = new EastNorth(rasterMin.east()+(rasterMax.east()-rasterMin.east())/2,
-                rasterMin.north()+(rasterMax.north()-rasterMin.north())/2);
-        rasterRatio = (rasterMax.east() - rasterMin.east()) / cRasterMaxSizeX;
-    }
-
-    public EastNorth getRasterMin() {
-        return rasterMin;
-    }
-
-    public void setRasterMin(EastNorth rasterMin) {
-        this.rasterMin = rasterMin;
-    }
-
-    public void displace(double dx, double dy) {
-        this.rasterMin = new EastNorth(rasterMin.east() + dx, rasterMin.north() + dy);
-        this.rasterCenter = new EastNorth(rasterCenter.east() + dx, rasterCenter.north() + dy);
-        for (GeorefImage img : images)
-            img.displace(dx, dy);
-    }
-
-    public void resize(double proportion) {
-        this.rasterMin = rasterMin.interpolate(rasterCenter, proportion);
-        for (GeorefImage img : images)
-            img.resize(rasterCenter, proportion);
-    }
-
-    public void rotate(double angle) {
-        this.rasterMin = rasterMin.rotate(rasterCenter, angle);
-        for (GeorefImage img : images)
-            img.rotate(rasterCenter, angle);
+        EastNorth rasterCenter = Main.proj.latlon2eastNorth(bounds.getCenter());
+        EastNorth eaMin = Main.proj.latlon2eastNorth(bounds.min);
+        EastNorth eaMax = Main.proj.latlon2eastNorth(bounds.max);
+        double rasterSizeX = communeBBox.max.getX() - communeBBox.min.getX(); 
+        double rasterSizeY = communeBBox.max.getY() - communeBBox.min.getY();
+        double ratio = rasterSizeY/rasterSizeX;
+        // keep same ratio on screen as WMS bbox (stored in communeBBox)
+        rasterMin = new EastNorth(eaMin.getX(), rasterCenter.getY()-(eaMax.getX()-eaMin.getX())*ratio/2);
+        rasterMax = new EastNorth(eaMax.getX(), rasterCenter.getY()+(eaMax.getX()-eaMin.getX())*ratio/2);
+        rasterRatio = (rasterMax.getX()-rasterMin.getX())/rasterSizeX;
     }
 
@@ -363,11 +354,12 @@
         if (this.isRaster) {
             oos.writeObject(this.rasterMin);
-            oos.writeObject(this.rasterCenter);
+            oos.writeObject(this.rasterMax);
             oos.writeDouble(this.rasterRatio);
-        } else {
-            oos.writeObject(this.communeBBox);
-        }
-        for (GeorefImage img : imgs) {
-            oos.writeObject(img);
+        }
+        oos.writeObject(this.communeBBox);
+        synchronized(this){
+            for (GeorefImage img : imgs) {
+                oos.writeObject(img);
+            }
         }
     }
@@ -389,12 +381,11 @@
         this.setCodeCommune((String) ois.readObject());
         this.lambertZone = ois.readInt();
-        this.isRaster = ois.readBoolean();
+        this.setRaster(ois.readBoolean());
         if (this.isRaster) {
             this.rasterMin = (EastNorth) ois.readObject();
-            this.rasterCenter = (EastNorth) ois.readObject();
+            this.rasterMax = (EastNorth) ois.readObject();
             this.rasterRatio = ois.readDouble();
-        } else {
-            this.communeBBox = (EastNorthBound) ois.readObject();
-        }
+        }
+        this.communeBBox = (EastNorthBound) ois.readObject();
         if (this.lambertZone != currentLambertZone) {
             JOptionPane.showMessageDialog(Main.parent, tr("Lambert zone {0} in cache "+
@@ -403,41 +394,94 @@
             return false;
         }
-        boolean EOF = false;
-        try {
-            while (!EOF) {
-                GeorefImage newImage = (GeorefImage) ois.readObject();
-                for (GeorefImage img : this.images) {
-                    if (CadastrePlugin.backgroundTransparent) {
-                        if (img.overlap(newImage))
-                            // mask overlapping zone in already grabbed image
-                            img.withdraw(newImage);
-                        else
-                            // mask overlapping zone in new image only when
-                            // new image covers completely the existing image
-                            newImage.withdraw(img);
+        synchronized(this){
+            boolean EOF = false;
+            try {
+                while (!EOF) {
+                    GeorefImage newImage = (GeorefImage) ois.readObject();
+                    for (GeorefImage img : this.images) {
+                        if (CadastrePlugin.backgroundTransparent) {
+                            if (img.overlap(newImage))
+                                // mask overlapping zone in already grabbed image
+                                img.withdraw(newImage);
+                            else
+                                // mask overlapping zone in new image only when
+                                // new image covers completely the existing image
+                                newImage.withdraw(img);
+                        }
                     }
+                    this.images.add(newImage);
                 }
-                this.images.add(newImage);
-            }
-        } catch (EOFException ex) {
-            // expected exception when all images are read
+            } catch (EOFException ex) {
+                // expected exception when all images are read
+            }
         }
         return true;
     }
-
-    public double getRasterRatio() {
-        return rasterRatio;
-    }
-
-    public void setRasterRatio(double rasterRatio) {
-        this.rasterRatio = rasterRatio;
-    }
-
-    public EastNorth getRasterCenter() {
-        return rasterCenter;
-    }
-
-    public void setRasterCenter(EastNorth rasterCenter) {
-        this.rasterCenter = rasterCenter;
+    
+    /**
+     * Join the grabbed images into one single.
+     * Works only for images grabbed from non-georeferenced images (Feuilles cadastrales)(same amount of
+     * images in x and y)
+     */
+    public void joinRasterImages() {
+        if (images.size() > 1) {
+            EastNorth min = images.get(0).min;
+            EastNorth max = images.get(images.size()-1).max;
+            int oldImgWidth = images.get(0).image.getWidth();
+            int oldImgHeight = images.get(0).image.getHeight(); 
+            int newWidth = oldImgWidth*(int)Math.sqrt(images.size());
+            int newHeight = oldImgHeight*(int)Math.sqrt(images.size());
+            BufferedImage new_img = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_ARGB);
+            Graphics g = new_img.getGraphics();
+            // Coordinate (0,0) is on top,left corner where images are grabbed from bottom left
+            int rasterDivider = (int)Math.sqrt(images.size());
+            for (int h = 0; h < rasterDivider; h++) {
+                for (int v = 0; v < rasterDivider; v++) {
+                    int newx = h*oldImgWidth;
+                    int newy = newHeight - oldImgHeight - (v*oldImgHeight);
+                    int j = h*rasterDivider + v;
+                    g.drawImage(images.get(j).image, newx, newy, this);
+                }
+            }
+            synchronized(this) {
+                images.clear();
+                images.add(new GeorefImage(new_img, min, max));
+            }
+        }
+    }
+    
+    /**
+     * Image cropping based on two EN coordinates pointing to two corners in diagonal
+     * Because it's coming from user mouse clics, we have to sort de positions first.
+     * Works only for raster image layer (only one image in collection).
+     * Updates layer georeferences. 
+     * @param en1
+     * @param en2
+     */
+    public void cropImage(EastNorth en1, EastNorth en2){
+        // adj1 is corner bottom, left 
+        EastNorth adj1 = new EastNorth(en1.east() <= en2.east() ? en1.east() : en2.east(),
+                en1.north() <= en2.north() ? en1.north() : en2.north());
+        // adj2 is corner top, right
+        EastNorth adj2 = new EastNorth(en1.east() > en2.east() ? en1.east() : en2.east(),
+                en1.north() > en2.north() ? en1.north() : en2.north());
+        // s1 and s2 have 0,0 at top, left where all EastNorth coord. have 0,0 at bottom, left
+        int sx1 = (int)((adj1.getX() - images.get(0).min.getX())*images.get(0).getPixelPerEast());
+        int sy1 = (int)((images.get(0).max.getY() - adj2.getY())*images.get(0).getPixelPerNorth());
+        int sx2 = (int)((adj2.getX() - images.get(0).min.getX())*images.get(0).getPixelPerEast());
+        int sy2 = (int)((images.get(0).max.getY() - adj1.getY())*images.get(0).getPixelPerNorth());
+        int newWidth = Math.abs(sx2 - sx1);
+        int newHeight = Math.abs(sy2 - sy1);
+        BufferedImage new_img = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_ARGB);
+        Graphics g = new_img.getGraphics();
+        g.drawImage(images.get(0).image, 0, 0, newWidth-1, newHeight-1,
+                (int)sx1, (int)sy1, (int)sx2, (int)sy2,
+                this);
+        images.set(0, new GeorefImage(new_img, adj1, adj2));
+        // important: update the layer georefs !
+        rasterMin = adj1;
+        rasterMax = adj2;
+        rasterRatio = (rasterMax.getX()-rasterMin.getX())/(communeBBox.max.getX() - communeBBox.min.getX());
+        setCommuneBBox(new EastNorthBound(new EastNorth(0,0), new EastNorth(newWidth-1,newHeight-1)));
     }
 
@@ -450,3 +494,10 @@
     }
 
+    /**
+     * Method required by ImageObserver when drawing an image 
+     */
+    public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height) {
+        return false;
+    }
+
 }
