Index: /applications/editors/josm/plugins/pdfimport/.checkstyle
===================================================================
--- /applications/editors/josm/plugins/pdfimport/.checkstyle	(revision 34608)
+++ /applications/editors/josm/plugins/pdfimport/.checkstyle	(revision 34609)
@@ -10,5 +10,5 @@
   <filter name="DerivedFiles" enabled="true"/>
   <filter name="FilesFromPackage" enabled="true">
-    <filter-data value="src/pdfimport/pdfbox/operators"/>
+    <filter-data value="src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators"/>
     <filter-data value="data"/>
     <filter-data value="images"/>
Index: /applications/editors/josm/plugins/pdfimport/.classpath
===================================================================
--- /applications/editors/josm/plugins/pdfimport/.classpath	(revision 34608)
+++ /applications/editors/josm/plugins/pdfimport/.classpath	(revision 34609)
@@ -12,5 +12,5 @@
 	<classpathentry kind="lib" path="lib/fontbox-1.8.12.jar"/>
 	<classpathentry kind="lib" path="lib/jempbox-1.8.12.jar"/>
-	<classpathentry kind="lib" path="lib/pdfbox-1.8.12.jar"/>
+	<classpathentry kind="lib" path="lib/pdfbox-1.8.12.jar" sourcepath="C:/Users/vippy/.m2/repository/org/apache/pdfbox/pdfbox/1.8.12/pdfbox-1.8.12-sources.jar"/>
 	<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
 	<classpathentry kind="output" path="bin"/>
Index: /applications/editors/josm/plugins/pdfimport/README
===================================================================
--- /applications/editors/josm/plugins/pdfimport/README	(revision 34608)
+++ /applications/editors/josm/plugins/pdfimport/README	(revision 34609)
@@ -70,5 +70,4 @@
 =================
 . Building:
-  . add pdfimport/src to your buildpath
   . add to buildpath|libraries: josm-custom.jar, fontbox-...jar, jempbox...jar, pdfbox...jar
   . build with ant, if any resources have changed (at least after svn update); eclipse cant handle build of resources, etc
Index: /applications/editors/josm/plugins/pdfimport/build.xml
===================================================================
--- /applications/editors/josm/plugins/pdfimport/build.xml	(revision 34608)
+++ /applications/editors/josm/plugins/pdfimport/build.xml	(revision 34609)
@@ -10,5 +10,5 @@
     -->
     <property name="plugin.author" value="extropy"/>
-    <property name="plugin.class" value="pdfimport.PdfImportPlugin"/>
+    <property name="plugin.class" value="org.openstreetmap.josm.plugins.pdfimport.PdfImportPlugin"/>
     <property name="plugin.description" value="Import PDF file into a layer and convert pdf lines to ways."/>
     <property name="plugin.icon" value="images/pdf_import.png"/>
Index: /applications/editors/josm/plugins/pdfimport/resources/org/openstreetmap/josm/plugins/pdfimport/pdfbox/PageDrawer.properties
===================================================================
--- /applications/editors/josm/plugins/pdfimport/resources/org/openstreetmap/josm/plugins/pdfimport/pdfbox/PageDrawer.properties	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/resources/org/openstreetmap/josm/plugins/pdfimport/pdfbox/PageDrawer.properties	(revision 34609)
@@ -0,0 +1,92 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# this Table is a correspondance Map of the PDF stream operators with concretes class of the
+# OperatorProcessor abstract class for the stategy pattern used in the 
+# org.apache.pdfbox.util.PDFStreamEngine class.
+# To change the behaviour of the system, remplace the class name by a new class name.
+b=org.openstreetmap.josm.plugins.pdfimport.pdfbox.operators.CloseFillNonZeroAndStrokePath
+B=org.openstreetmap.josm.plugins.pdfimport.pdfbox.operators.FillNonZeroAndStrokePath
+b*=org.openstreetmap.josm.plugins.pdfimport.pdfbox.operators.CloseFillEvenOddAndStrokePath
+B*=org.openstreetmap.josm.plugins.pdfimport.pdfbox.operators.FillEvenOddAndStrokePath
+#BDC org.apache.pdfbox.util.operator.NotImplemented ##Begin Marked Content -- section 10.5
+BI=org.openstreetmap.josm.plugins.pdfimport.pdfbox.operators.BeginInlineImage
+#BMC org.apache.pdfbox.util.operator.NotImplemented ##Begin Marked Content -- section 10.5
+BT=org.apache.pdfbox.util.operator.BeginText
+#BX org.apache.pdfbox.util.operator.NotImplemented
+c=org.openstreetmap.josm.plugins.pdfimport.pdfbox.operators.CurveTo
+cm=org.apache.pdfbox.util.operator.Concatenate
+CS=org.apache.pdfbox.util.operator.SetStrokingColorSpace
+cs=org.apache.pdfbox.util.operator.SetNonStrokingColorSpace
+d=org.openstreetmap.josm.plugins.pdfimport.pdfbox.operators.SetLineDashPattern
+#d0 org.apache.pdfbox.util.operator.NotImplemented
+#d1 org.apache.pdfbox.util.operator.NotImplemented
+Do=org.openstreetmap.josm.plugins.pdfimport.pdfbox.operators.Invoke
+#DP org.apache.pdfbox.util.operator.NotImplemented ##Marked Content Point-- section 10.5
+#El org.apache.pdfbox.util.operator.NotImplemented
+#EMC org.apache.pdfbox.util.operator.NotImplemented ##End Marked Content -- section 10.5
+ET=org.apache.pdfbox.util.operator.EndText
+#EX org.apache.pdfbox.util.operator.NotImplemented
+f=org.openstreetmap.josm.plugins.pdfimport.pdfbox.operators.FillNonZeroRule
+F=org.openstreetmap.josm.plugins.pdfimport.pdfbox.operators.FillNonZeroRule
+f*=org.openstreetmap.josm.plugins.pdfimport.pdfbox.operators.FillEvenOddRule
+G=org.apache.pdfbox.util.operator.SetStrokingGrayColor
+g=org.apache.pdfbox.util.operator.SetNonStrokingGrayColor
+gs=org.apache.pdfbox.util.operator.SetGraphicsStateParameters
+h=org.openstreetmap.josm.plugins.pdfimport.pdfbox.operators.ClosePath
+#i org.apache.pdfbox.util.operator.NotImplemented
+#ID org.apache.pdfbox.util.operator.NotImplemented
+j=org.openstreetmap.josm.plugins.pdfimport.pdfbox.operators.SetLineJoinStyle
+J=org.openstreetmap.josm.plugins.pdfimport.pdfbox.operators.SetLineCapStyle
+K=org.apache.pdfbox.util.operator.SetStrokingCMYKColor
+k=org.apache.pdfbox.util.operator.SetNonStrokingCMYKColor
+l=org.openstreetmap.josm.plugins.pdfimport.pdfbox.operators.LineTo
+m=org.openstreetmap.josm.plugins.pdfimport.pdfbox.operators.MoveTo
+M=org.openstreetmap.josm.plugins.pdfimport.pdfbox.operators.SetLineMiterLimit
+#MP org.apache.pdfbox.util.operator.NotImplemented ##Marked Content Point-- section 10.5
+n=org.openstreetmap.josm.plugins.pdfimport.pdfbox.operators.EndPath
+q=org.apache.pdfbox.util.operator.GSave
+Q=org.apache.pdfbox.util.operator.GRestore
+re=org.openstreetmap.josm.plugins.pdfimport.pdfbox.operators.AppendRectangleToPath
+RG=org.apache.pdfbox.util.operator.SetStrokingRGBColor
+rg=org.apache.pdfbox.util.operator.SetNonStrokingRGBColor
+#ri org.apache.pdfbox.util.operator.NotImplemented
+s=org.apache.pdfbox.util.operator.CloseAndStrokePath
+S=org.openstreetmap.josm.plugins.pdfimport.pdfbox.operators.StrokePath
+SC=org.apache.pdfbox.util.operator.SetStrokingColor
+sc=org.apache.pdfbox.util.operator.SetNonStrokingColor
+SCN=org.apache.pdfbox.util.operator.SetStrokingColor
+scn=org.apache.pdfbox.util.operator.SetNonStrokingColor
+sh=org.openstreetmap.josm.plugins.pdfimport.pdfbox.operators.SHFill
+T*=org.apache.pdfbox.util.operator.NextLine
+Tc=org.apache.pdfbox.util.operator.SetCharSpacing
+Td=org.apache.pdfbox.util.operator.MoveText
+TD=org.apache.pdfbox.util.operator.MoveTextSetLeading
+Tf=org.apache.pdfbox.util.operator.SetTextFont
+Tj=org.apache.pdfbox.util.operator.ShowText
+TJ=org.apache.pdfbox.util.operator.ShowTextGlyph
+TL=org.apache.pdfbox.util.operator.SetTextLeading
+Tm=org.apache.pdfbox.util.operator.SetMatrix
+Tr=org.apache.pdfbox.util.operator.SetTextRenderingMode
+Ts=org.apache.pdfbox.util.operator.SetTextRise
+Tw=org.apache.pdfbox.util.operator.SetWordSpacing
+Tz=org.apache.pdfbox.util.operator.SetHorizontalTextScaling
+v=org.openstreetmap.josm.plugins.pdfimport.pdfbox.operators.CurveToReplicateInitialPoint
+w=org.openstreetmap.josm.plugins.pdfimport.pdfbox.operators.SetLineWidth
+W org.openstreetmap.josm.plugins.pdfimport.pdfbox.operators.ClipNonZeroRule
+W* org.openstreetmap.josm.plugins.pdfimport.pdfbox.operators.ClipEvenOddRule
+y=org.openstreetmap.josm.plugins.pdfimport.pdfbox.operators.CurveToReplicateFinalPoint
+\'=org.apache.pdfbox.util.operator.MoveAndShow
+\"=org.apache.pdfbox.util.operator.SetMoveAndShow
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/DuplicateNodesFinder.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/DuplicateNodesFinder.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/DuplicateNodesFinder.java	(revision 34609)
@@ -0,0 +1,86 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.pdfimport;
+
+import java.awt.geom.Point2D;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+public final class DuplicateNodesFinder {
+
+    private DuplicateNodesFinder() {
+        // Hide default constructor for utilities classes
+    }
+
+    /***
+     * This method finds very close nodes and constructs a mapping from node to suggested representative node.
+     * Works by performing a sweep and noting down similar nodes.
+     * @param nodes the nodes to process
+     * @return map from nodes that need replacement to a representative node.
+     */
+    public static Map<Point2D, Point2D> findDuplicateNodes(Collection<Point2D> nodes, final double tolerance) {
+        List<Point2D> points = new ArrayList<>(nodes);
+        Collections.sort(points, new Comparator<Point2D>() {
+            @Override
+            public int compare(Point2D o1, Point2D o2) {
+                double diff = o1.getY() - o2.getY();
+                return diff > 0 ? 1 : (diff < 0 ? -1 : 0);
+            }
+        });
+
+        Map<Point2D, Point2D> result = new HashMap<>();
+        TreeMap<Point2D, Point2D> sweepLine = new TreeMap<>(new Comparator<Point2D>() {
+            @Override
+            public int compare(Point2D o1, Point2D o2) {
+                double diff = o1.getX() - o2.getX();
+
+                if (Math.abs(diff) <= tolerance) {
+                    return 0;
+                }
+
+                return diff > 0 ? 1 : (diff < 0 ? -1 : 0);
+            }
+        });
+
+        //sweep from top to bottom.
+        double prevY = Double.NEGATIVE_INFINITY;
+
+        for (Point2D point: points) {
+            boolean mappedToOtherPoint = false;
+
+            if (point.getY() - prevY > tolerance) {
+                sweepLine.clear();
+                //big offset, clear old points
+            } else {
+                //small offset, test against existing points (there may be more than one)
+
+                while (!mappedToOtherPoint && sweepLine.containsKey(point)) {
+                    //a close point found
+                    Point2D closePoint = sweepLine.get(point);
+                    double dy = point.getY() - closePoint.getY();
+                    if (dy <= tolerance) {
+                        //mark them as close
+                        result.put(point, closePoint);
+                        mappedToOtherPoint = true;
+                    } else {
+                        sweepLine.remove(point);
+
+                    }
+                }
+            }
+
+            if (!mappedToOtherPoint) {
+                sweepLine.put(point, point);
+            }
+
+            prevY = point.getY();
+        }
+
+        return result;
+    }
+}
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/FilePlacement.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/FilePlacement.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/FilePlacement.java	(revision 34609)
@@ -0,0 +1,213 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.pdfimport;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
+import java.util.Properties;
+
+import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.data.coor.EastNorth;
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.projection.Projection;
+
+public class FilePlacement {
+    /*
+     * provide data and services to place a PDF-File to world coordinates
+     * enhanced by FilePlacement18 but kept for compatibilty to existing code
+     */
+    protected Projection projection = null;
+    protected double minX = 0;
+    protected double maxX = 1;
+    protected double minY = 0;
+    protected double maxY = 1;
+
+    protected double minEast = 0;
+    protected double maxEast = 10000;
+    protected double minNorth = 0;
+    protected double maxNorth = 10000;
+
+    private AffineTransform transform;
+
+    public void setPdfBounds(double minX, double minY, double maxX, double maxY) {
+        this.minX = minX;
+        this.minY = minY;
+        this.maxX = maxX;
+        this.maxY = maxY;
+    }
+
+    public void setEastNorthBounds(double minEast, double minNorth, double maxEast, double maxNorth) {
+        this.minEast = minEast;
+        this.maxEast = maxEast;
+        this.minNorth = minNorth;
+        this.maxNorth = maxNorth;
+    }
+
+    protected Properties toProperties() {
+        Properties p = new Properties();
+        if (projection != null) {
+            p.setProperty("Projection", projection.toCode());
+        }
+
+        p.setProperty("minX", Double.toString(minX));
+        p.setProperty("maxX", Double.toString(maxX));
+        p.setProperty("minY", Double.toString(minY));
+        p.setProperty("maxY", Double.toString(maxY));
+        p.setProperty("minEast", Double.toString(minEast));
+        p.setProperty("maxEast", Double.toString(maxEast));
+        p.setProperty("minNorth", Double.toString(minNorth));
+        p.setProperty("maxNorth", Double.toString(maxNorth));
+
+        return p;
+    }
+
+    protected void fromProperties(Properties p) {
+        String projectionCode = p.getProperty("Projection", null);
+        if (projectionCode != null) {
+            projection = ProjectionInfo.getProjectionByCode(projectionCode); // TODO: Handle non-core Projections
+        } else {
+            projection = null;
+        }
+
+        minX = parseProperty(p, "minX", minX);
+        maxX = parseProperty(p, "maxX", maxX);
+        minY = parseProperty(p, "minY", minY);
+        maxY = parseProperty(p, "maxY", maxY);
+
+        minEast = parseProperty(p, "minEast", minEast);
+        maxEast = parseProperty(p, "maxEast", maxEast);
+        minNorth = parseProperty(p, "minNorth", minNorth);
+        maxNorth = parseProperty(p, "maxNorth", maxNorth);
+    }
+
+    protected double parseProperty(Properties p, String name, double defaultValue) {
+        if (!p.containsKey(name)) {
+            return defaultValue;
+        }
+
+        String value = p.getProperty(name);
+
+        try {
+            return Double.parseDouble(value);
+        } catch (Exception e) {
+            return defaultValue;
+        }
+    }
+
+    protected String prepareTransform() {
+        if (this.minX > this.maxX) {
+            return tr("Transform error: Min X must be smaller than max");
+        }
+
+        if (this.minY > this.maxY) {
+            return tr("Transform error: Min Y must be smaller than max");
+        }
+
+        if (Math.abs(this.minY - this.maxY) < 1 &&
+                Math.abs(this.minX - this.maxX) < 1) {
+            return tr("Transform error: Points too close");
+        } else if (Math.abs(this.minX - this.maxX) < 1) {
+            //x axis equal, assume same scale in both dimensions
+            if (this.minEast == this.maxEast) {
+                //no rotation
+                this.maxX = this.minX + this.maxY - this.minY;
+                this.maxEast = this.minEast + this.maxNorth - this.minNorth;
+            } else if (this.minNorth == this.maxNorth) {
+                //needs rotated 90 degrees clockwise, or counter
+                this.maxX = this.minX + this.maxY - this.minY;
+                this.maxNorth = this.minNorth - (this.maxEast - this.minEast);
+            } else {
+                return tr("Transform error: Unsupported variant.");
+            }
+        } else if (Math.abs(this.minY - this.maxY) < 1) {
+            //Y axis equal, assume same scale in both dimensions
+            if (this.minNorth == this.maxNorth) {
+                //no rotation
+                this.maxY = this.minY + this.maxX - this.minX;
+                this.maxNorth = this.minNorth + this.maxEast - this.minEast;
+            } else if (this.minEast == this.maxEast) {
+                //needs rotated 90 degrees clockwise, or counter
+                this.maxY = this.minY + this.maxX - this.minX;
+                this.maxEast = this.minEast - (this.maxNorth - this.minNorth);
+            } else {
+                return tr("Transform error: Unsupported variant.");
+            }
+        }
+
+        if (this.minEast < this.maxEast && this.minNorth < this.maxNorth) {
+            //no rotation
+            this.transform = new AffineTransform();
+            this.transform.translate(this.minEast, this.minNorth);
+            this.transform.scale(
+                    (this.maxEast - this.minEast) / (this.maxX - this.minX),
+                    (this.maxNorth - this.minNorth) / (this.maxY - this.minY));
+            this.transform.translate(-this.minX, -this.minY);
+        } else if (this.minEast > this.maxEast && this.minNorth < this.maxNorth) {
+            //need to rotate 90 degrees counterclockwise
+            this.transform = new AffineTransform();
+            //transform to 0..1, 0..1 range
+            this.transform.preConcatenate(AffineTransform.getTranslateInstance(-this.minX, -this.minY));
+            this.transform.preConcatenate(AffineTransform.getScaleInstance(1/(this.maxX - this.minX), 1/(this.maxY - this.minY)));
+
+            //rotate -90 degs around min
+            this.transform.preConcatenate(AffineTransform.getQuadrantRotateInstance(1, 0, 0));
+
+            //transform back to target range
+            this.transform.preConcatenate(AffineTransform.getScaleInstance(
+                    (this.minEast - this.maxEast),
+                    (this.maxNorth - this.minNorth)));
+            this.transform.preConcatenate(AffineTransform.getTranslateInstance(this.minEast, this.minNorth));
+        } else if (this.minEast < this.maxEast && this.minNorth > this.maxNorth) {
+            //need to rotate 90 degrees clockwise
+            this.transform = new AffineTransform();
+            //transform to 0..1, 0..1 range
+            this.transform.preConcatenate(AffineTransform.getTranslateInstance(-this.minX, -this.minY));
+            this.transform.preConcatenate(AffineTransform.getScaleInstance(1/(this.maxX - this.minX), 1/(this.maxY - this.minY)));
+
+            //rotate 90 degs around min
+            this.transform.preConcatenate(AffineTransform.getQuadrantRotateInstance(-1, 0, 0));
+
+            //transform back to target range
+            this.transform.preConcatenate(AffineTransform.getScaleInstance(
+                    (this.maxEast - this.minEast),
+                    (this.minNorth - this.maxNorth)));
+            this.transform.preConcatenate(AffineTransform.getTranslateInstance(this.minEast, this.minNorth));
+        } else {
+            return tr("Transform error: Unsupported orientation");
+        }
+
+        return null;
+
+    }
+
+    EastNorth en = new EastNorth(0, 0);
+    Point2D src = new Point2D.Double();
+
+    protected Bounds getWorldBounds(PathOptimizer data) {
+        LatLon min = this.tranformCoords(new Point2D.Double(data.bounds.getMinX(), data.bounds.getMinY()));
+        LatLon max = this.tranformCoords(new Point2D.Double(data.bounds.getMaxX(), data.bounds.getMaxY()));
+        return new Bounds(min, max);
+    }
+
+    protected LatLon tranformCoords(Point2D pt) {
+
+        if (this.projection == null) {
+            return new LatLon(pt.getY() / 1000, pt.getX() / 1000);
+        } else {
+            Point2D dest = new Point2D.Double();
+            this.transform.transform(pt, dest);
+            en = new EastNorth(dest.getX(), dest.getY());
+            return this.projection.eastNorth2latlon(en);
+        }
+    }
+
+    protected EastNorth reverseTransform(LatLon coor) {
+        if (this.projection == null) {
+            return new EastNorth(coor.lon() * 1000, coor.lat() * 1000);
+        } else {
+            return null;
+        }
+    }
+
+}
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/FilePlacement18.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/FilePlacement18.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/FilePlacement18.java	(revision 34609)
@@ -0,0 +1,425 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.pdfimport;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.Color;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Properties;
+
+import javax.swing.BorderFactory;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.SwingConstants;
+
+import org.openstreetmap.josm.data.coor.EastNorth;
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.projection.Projection;
+import org.openstreetmap.josm.gui.MainApplication;
+
+public class FilePlacement18 extends FilePlacement {
+    /*
+     * Handle plasement of a pdf File
+     * provide transformation, load & save, GUI-componennt
+     * superseeds (legacy) class FilePlacement
+     */
+
+    public class PlacementPanel {
+        private class CoorFields {
+            /*
+             * Coordinte Fields
+             * keep Fields representing a Coordinate together
+             * functionality: allow entering coordinate in the first field and transfer Y-Part to the second field
+             * TODO: encapsulate to Componente
+             */
+            private GuiFieldDouble x;
+            private GuiFieldDouble y;
+
+            private void checkCoords(GuiFieldDouble x, GuiFieldDouble y) {
+                int splitpos = 0;
+                String val2 = x.getText().trim();
+                if ((splitpos = val2.indexOf(';')) >= 0) {
+                    // Split a coordinate into its parts for ease of data entry
+                    y.setText(val2.substring(splitpos + 1).trim());
+                    x.setText(val2.substring(0, splitpos).trim());
+                }
+                y.checker.check(y);
+                x.checker.check(x);
+            }
+
+            @SuppressWarnings("unused")
+            private CoorFields() {
+            }
+
+            CoorFields(GuiFieldDouble x, GuiFieldDouble y) {
+                this.x = x;
+                this.y = y;
+                x.addFocusListener(new FocusListener() {
+                    @Override
+                    public void focusLost(FocusEvent e) {
+                        checkCoords(x, y);
+                    }
+
+                    @Override
+                    public void focusGained(FocusEvent e) {
+                    }
+                });
+            }
+            public void SetCoor(EastNorth en) {
+                x.requestFocusInWindow();        // make shure focus-lost events will be triggered later
+                x.setValue(en.getX());
+                y.requestFocusInWindow();
+                y.setValue(en.getY());
+            }
+            public EastNorth getCorr() {
+                return new EastNorth(x.getValue(),y.getValue());
+            }
+        }
+
+        private GuiFieldDouble minXField;
+        private GuiFieldDouble minYField;
+        private GuiFieldDouble minEastField;
+        private GuiFieldDouble minNorthField;
+        private JButton getMinButton;
+        private JButton getMaxButton;
+        private GuiFieldDouble maxNorthField;
+        private GuiFieldDouble maxEastField;
+        private GuiFieldDouble maxYField;
+        private GuiFieldDouble maxXField;
+        private GuiPanel panel;
+        private JLabel hintField;
+        private CoorFields pdfMin;
+        private CoorFields pdfMax;
+        private CoorFields worldMin;
+        private CoorFields worldMax;
+        private GuiProjections projectionChooser;
+        private FilePlacement18 fc = null;        // reference to enclosing FilePlacement
+        private JComponent dependsOnValid = null;
+
+        public PlacementPanel(FilePlacement18 parrent) {
+            if (parrent==null) throw new IllegalArgumentException();
+            fc=parrent;
+        }
+
+        private PlacementPanel () {
+
+        }
+
+        private class Monitor implements FocusListener {
+
+            private PlacementPanel target=null;
+
+            public Monitor(PlacementPanel home) {
+                target=home;
+            }
+
+            @Override
+            public void focusGained(FocusEvent e) {
+            }
+
+            @Override
+            public void focusLost(FocusEvent e) {
+                try {
+                    target.Verify();
+                } catch (Exception ee) {
+                }
+            }
+        }
+
+        void load() {
+            /*
+             * load GUI from setting
+             */
+            try {
+                minXField.setValue(fc.minX);
+                maxXField.setValue(fc.maxX);
+                minYField.setValue(fc.minY);
+                maxYField.setValue(fc.maxY);
+                minEastField.setValue(fc.minEast);
+                maxEastField.setValue(fc.maxEast);
+                minNorthField.setValue(fc.minNorth);
+                maxNorthField.setValue(fc.maxNorth);
+                projectionChooser.setProjection(fc.projection);
+            } finally {
+                Verify();
+            }
+        }
+
+        void build() {
+/*
+ * Construct Objects
+ *
+ */
+            Monitor monitor = new Monitor(this);
+            projectionChooser = new GuiProjections();
+
+            pdfMin = new CoorFields(minXField = new GuiFieldDouble(0), minYField = new GuiFieldDouble(0));
+            minXField.setToolTipText(tr("X-value of bottom left reference point"));
+            minXField.addFocusListener(monitor);
+            minYField.setToolTipText(tr("Y-value of bottom left reference point"));
+            minYField.addFocusListener(monitor);
+
+//
+            worldMin = new CoorFields(minEastField = new GuiFieldDouble(0), minNorthField = new GuiFieldDouble(0));
+            minEastField.setToolTipText(tr("East-value of bottom left reference point"));
+            minEastField.addFocusListener(monitor);
+            minNorthField.setToolTipText(tr("North-value of bottom left reference point"));
+            minNorthField.addFocusListener(monitor);
+//
+            getMinButton = new JButton(tr("Get from Preview"));
+            getMinButton.setToolTipText(tr("Select a single node from preview"));
+            getMinButton.addActionListener(new ActionListener() {
+                @Override
+                public void actionPerformed(ActionEvent e) {
+                    setFromCoor(pdfMin);
+                }
+            });
+//
+            pdfMax = new CoorFields(maxXField = new GuiFieldDouble(1000), maxYField = new GuiFieldDouble(1000));
+            maxXField.setToolTipText(tr("X-value of top right reference point"));
+            maxXField.addFocusListener(monitor);
+            maxYField.setToolTipText(tr("Y-value of top right  reference point"));
+            maxYField.addFocusListener(monitor);
+//
+            worldMax = new CoorFields(maxEastField = new GuiFieldDouble(1),    maxNorthField = new GuiFieldDouble(1));
+            maxEastField.setToolTipText(tr("East-value of top right reference point"));
+            maxEastField.addFocusListener(monitor);
+            maxNorthField.setToolTipText(tr("North-value of top right reference point"));
+            maxNorthField.addFocusListener(monitor);
+//
+            getMaxButton = new JButton(tr("Get from Preview"));
+            getMaxButton.setToolTipText(tr("Select a single node from preview"));
+            getMaxButton.addActionListener(new ActionListener() {
+                @Override
+                public void actionPerformed(ActionEvent e) {
+                    setFromCoor(pdfMax);
+                }
+            });
+
+//
+            hintField = new JLabel(tr("Check Placement"),SwingConstants.CENTER);
+            hintField.setForeground(Color.RED);
+//
+            panel = new GuiPanel(new GridBagLayout());
+            panel.setBorder(BorderFactory.createTitledBorder(tr("Bind to coordinates")));
+
+            GridBagConstraints cBasic = new GridBagConstraints(GridBagConstraints.RELATIVE, GridBagConstraints.RELATIVE,
+                    1, 1, 0.0, 0.0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START,
+                    new Insets(1, 0, 0, 4), 0, 0);
+            cBasic.gridx = GridBagConstraints.RELATIVE;
+            cBasic.gridy = GridBagConstraints.RELATIVE;
+            cBasic.insets = new Insets(1, 0, 0, 4);
+            cBasic.anchor = GridBagConstraints.LINE_START;
+            cBasic.fill = GridBagConstraints.HORIZONTAL;
+            cBasic.gridheight = 1;
+            cBasic.gridwidth = 1;
+            cBasic.ipadx = 0;
+            cBasic.ipady = 0;
+            cBasic.weightx = 0.0;
+            cBasic.weighty = 0.0;
+            GridBagConstraints cCornerHeading = (GridBagConstraints) cBasic.clone();
+            cCornerHeading.gridwidth = GridBagConstraints.REMAINDER;
+            cCornerHeading.gridx = 0;
+            cCornerHeading.insets = new Insets(3, 0, 0, 0);
+
+            GridBagConstraints cLine = (GridBagConstraints) cBasic.clone();
+
+            GridBagConstraints cGetButton = (GridBagConstraints) cBasic.clone();
+            cGetButton.gridx = 1;
+            cGetButton.gridwidth = GridBagConstraints.REMAINDER;
+            cGetButton.fill = GridBagConstraints.NONE;
+
+            GridBagConstraints c = new GridBagConstraints();
+            /*
+             * Projection
+             */
+            panel.add(projectionChooser.getPanel(), cCornerHeading);
+            /*
+             * Max Corner
+             */
+            panel.add(new JLabel(tr("Top right (max) corner:"),SwingConstants.CENTER), cCornerHeading);
+            c = (GridBagConstraints) cLine.clone();
+            c.weightx = 0.0; panel.add(new JLabel(tr("X:"),SwingConstants.RIGHT),c);
+            c.weightx = 1.0; panel.add(maxXField, c);
+            c.weightx = 0.0; panel.add(new JLabel(tr("East:"),SwingConstants.RIGHT),c);
+            c.weightx = 1.0; panel.add(maxEastField, c);
+
+            c.gridy = 4;
+            c.weightx = 0.0; panel.add(new JLabel(tr("Y:"),SwingConstants.RIGHT),c);
+            c.weightx = 1.0; panel.add(maxYField, c);
+            c.weightx = 0.0; panel.add(new JLabel(tr("North:"),SwingConstants.RIGHT),c);
+            c.weightx = 1.0; panel.add(maxNorthField, c);
+            panel.add(getMaxButton, cGetButton);
+            /*
+             * Min Corner
+             */
+            panel.add(new JLabel(tr("Bottom left (min) corner:"),SwingConstants.CENTER), cCornerHeading);
+            c = (GridBagConstraints) cLine.clone();
+            c.weightx = 0.0; panel.add(new JLabel(tr("X:"),SwingConstants.RIGHT),c);
+            c.weightx = 1.0; panel.add(minXField, c);
+            c.weightx = 0.0; panel.add(new JLabel(tr("East:"),SwingConstants.RIGHT),c);
+            c.weightx = 1.0; panel.add(minEastField, c);
+
+            c.gridy = 8;
+            c.weightx = 0.0; panel.add(new JLabel(tr("Y:"),SwingConstants.RIGHT),c);
+            c.weightx = 1.0; panel.add(minYField, c);
+            c.weightx = 0.0; panel.add(new JLabel(tr("North:"),SwingConstants.RIGHT),c);
+            c.weightx = 1.0; panel.add(minNorthField, c);
+
+            panel.add(getMinButton, cGetButton);
+            /*
+             * Hints
+             */
+            c.gridx = 0;c.gridy = 11;c.gridwidth = GridBagConstraints.REMAINDER; c.fill = GridBagConstraints.HORIZONTAL;
+            panel.add(hintField, cGetButton);
+        }
+
+        private EastNorth getSelectedCoor() {
+            /*
+             * Assumtions:
+             *    selection is from preview,
+             *    preview has been create without any projection / transformation
+             *    TODO: enshure this
+             */
+            hintField.setText("");
+            Collection<OsmPrimitive> selected = MainApplication.getLayerManager().getEditDataSet().getSelected();
+
+            if (selected.size() != 1 || !(selected.iterator().next() instanceof Node)) {
+                hintField.setText(tr("Please select exactly one node."));
+                return null;
+            }
+
+            LatLon ll = ((Node) selected.iterator().next()).getCoor();
+//            FilePlacement pl = new FilePlacement();
+//            return pl.reverseTransform(ll);
+            return new EastNorth(ll.lon() * 1000, ll.lat() * 1000);
+        }
+
+        private void Verify() {
+            hintField.setText("");
+            String Hint = "";
+            fc.valid = false;
+            FilePlacement placement = fc;
+            try {
+                placement.projection = projectionChooser.getProjection();
+                try {
+                    placement.setPdfBounds(minXField.getValue(), minYField.getValue(), maxXField.getValue(),
+                            maxYField.getValue());
+                    placement.setEastNorthBounds(minEastField.getValue(), minNorthField.getValue(),
+                            maxEastField.getValue(), maxNorthField.getValue());
+                } catch (Exception e) {
+                    Hint=(tr("Check numbers"));
+                    return;
+                }
+                String transformError = placement.prepareTransform();
+                if (transformError != null) {
+                    Hint=(transformError);
+                    return;
+                }
+                fc.valid = true;
+            } finally {
+                hintField.setText(Hint);
+                if (dependsOnValid!=null) dependsOnValid.setEnabled(fc.valid && panel.isEnabled());
+            }
+
+            return;
+        }
+
+        public void setDependsOnValid(JComponent c) {
+            dependsOnValid=c;
+        }
+
+        void setFromCoor(CoorFields f) {
+            EastNorth en = getSelectedCoor();
+
+            if (en != null) {
+                f.SetCoor(en);
+            }
+
+        }
+
+    }
+
+    private PlacementPanel panel=null;
+    private boolean valid=false;    // the data is consistent and the object ready to use for transformation
+
+    public boolean isValid() {
+        /*
+         * TODO: compupte it now
+         */
+        return valid;
+    }
+    public void setDependsOnValid(JComponent c) {
+        panel.setDependsOnValid(c);
+    }
+
+    public JPanel getGui() {
+        if (panel==null) panel = new PlacementPanel(this);
+        if (panel.panel==null) panel.build();
+        return panel.panel;
+    }
+
+    public FilePlacement18 () {
+        panel = new PlacementPanel(this);
+    }
+
+    public void load(File baseFile) throws IOException {
+        File file = new File(baseFile + ".placement");
+        Properties p = new Properties();
+        try (FileInputStream s = new FileInputStream(file)){
+            p.load(s);
+            s.close();
+        };
+        fromProperties(p);
+    }
+
+    public void verify() {
+        panel.Verify();
+    }
+
+    public void save(File baseFile) throws IOException {
+        File file = new File(baseFile + ".placement");
+        FileOutputStream s = new FileOutputStream(file);
+        Properties p = toProperties();
+        p.store(s, "PDF file placement on OSM");
+        s.close();
+    }
+
+    private Projection getProjection(Properties p, String name) {
+        String projectionCode = p.getProperty("Projection", null);
+        if (projectionCode != null) {
+            return ProjectionInfo.getProjectionByCode(p.getProperty("Projection", null));
+        }
+        return null;
+    }
+
+    private double getDouble(Properties p, String name, double defaultValue) {
+        try {
+            return Double.parseDouble(p.getProperty(name));
+        } catch (Exception e) {
+            return defaultValue;
+        }
+    }
+
+    @Override
+    protected void fromProperties(Properties p) {
+        super.fromProperties(p);
+        panel.load();
+    }
+
+}
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/GuiFieldBool.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/GuiFieldBool.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/GuiFieldBool.java	(revision 34609)
@@ -0,0 +1,86 @@
+// License: GPL. For details, see LICENSE file.
+
+package org.openstreetmap.josm.plugins.pdfimport;
+
+import javax.swing.Action;
+import javax.swing.Icon;
+import javax.swing.JCheckBox;
+import javax.swing.JComponent;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+public class GuiFieldBool extends JCheckBox {
+    /*
+     * TODO: evolve to a component with integrated display of dependend components
+     */
+    private JComponent companion =null;
+    private boolean value = false;
+
+    public JComponent getCompanion() {
+        return companion;
+    }
+
+    public void setCompanion(JComponent c) {
+        companion = c;
+        if (companion != null) companion.setEnabled(isSelected());
+    }
+
+    public boolean getValue() {
+        return super.isSelected();
+    }
+
+    public void setValue(boolean value) {
+        this.value = value;
+        super.setSelected(value);
+    }
+
+    public GuiFieldBool() {
+        super();
+        addChangeListener(new Monitor());
+    }
+
+    public GuiFieldBool(Action a) {
+        super(a);
+        addChangeListener(new Monitor());
+    }
+
+    public GuiFieldBool(Icon icon, boolean selected) {
+        super(icon, selected);
+        addChangeListener(new Monitor());
+    }
+
+    public GuiFieldBool(Icon icon) {
+        super(icon);
+        addChangeListener(new Monitor());
+    }
+
+    public GuiFieldBool(String text, boolean selected) {
+        super(text, selected);
+        addChangeListener(new Monitor());
+    }
+
+    public GuiFieldBool(String text, Icon icon, boolean selected) {
+        super(text, icon, selected);
+        addChangeListener(new Monitor());
+    }
+
+    public GuiFieldBool(String text, Icon icon) {
+        super(text, icon);
+        addChangeListener(new Monitor());
+    }
+
+    public GuiFieldBool(String text) {
+        super(text);
+        addChangeListener(new Monitor());
+    }
+
+    private class Monitor implements ChangeListener {
+
+        @Override
+        public void stateChanged(ChangeEvent e) {
+            GuiFieldBool o = (GuiFieldBool) e.getSource();
+            value = o.isSelected();
+            if (o.companion != null) o.companion.setEnabled(value);
+        }
+    }
+}
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/GuiFieldDouble.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/GuiFieldDouble.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/GuiFieldDouble.java	(revision 34609)
@@ -0,0 +1,67 @@
+// License: GPL. For details, see LICENSE file.
+
+package org.openstreetmap.josm.plugins.pdfimport;
+
+import java.awt.Color;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+
+import javax.swing.BorderFactory;
+
+public class GuiFieldDouble extends GuiFieldString {
+
+    private double value;
+    public CheckDouble checker;
+
+    public GuiFieldDouble() {
+        super();
+        addFocusListener(checker = new CheckDouble());
+        setValue(0.0);
+    }
+
+    @SuppressWarnings("unused")
+    private GuiFieldDouble(String text) {
+        super(text);
+        addFocusListener(checker = new CheckDouble());
+    }
+
+    public GuiFieldDouble(double v) {
+        super();
+        addFocusListener(checker = new CheckDouble());
+        setValue(v);
+    }
+
+    public void setValue(double v) {
+        super.setText(Double.toString(v));
+        this.checker.check(this);
+    }
+
+    public double getValue() throws NumberFormatException {
+        if (!dataValid) throw new NumberFormatException();
+        return value;
+    }
+
+    public class CheckDouble implements FocusListener {
+
+        @Override
+        public void focusGained(FocusEvent e) {
+        }
+
+        @Override
+        public void focusLost(FocusEvent event) {
+            check((GuiFieldDouble) event.getSource());
+        }
+
+        public void check(GuiFieldDouble field) {
+            try {
+                value = Double.parseDouble(field.getText());
+                dataValid =true;
+                field.setBorder(defaultBorder);
+            } catch (NumberFormatException e) {
+                field.setBorder(BorderFactory.createLineBorder(Color.red));
+                value = Double.NaN;
+                dataValid = false;
+            }
+        }
+    }
+}
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/GuiFieldHex.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/GuiFieldHex.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/GuiFieldHex.java	(revision 34609)
@@ -0,0 +1,79 @@
+/**
+ * License: GPL. For details, see LICENSE file.
+ */
+package org.openstreetmap.josm.plugins.pdfimport;
+
+import java.awt.Color;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+
+import javax.swing.BorderFactory;
+
+/**
+ * @author Nzara
+ *
+ */
+public class GuiFieldHex extends GuiFieldString {
+
+    private int value;
+    public CheckHex checker;
+
+    public GuiFieldHex() {
+        super();
+        addFocusListener(checker = new CheckHex());
+        setValue(0);
+    }
+
+    @SuppressWarnings("unused")
+    public GuiFieldHex(String text) {
+        super(text);
+        addFocusListener(checker = new CheckHex());
+    }
+
+    public GuiFieldHex(int v) {
+        super();
+        addFocusListener(checker = new CheckHex());
+        setValue(v);
+    }
+
+    public void setValue(int v) {
+        super.setText("#" + Integer.toHexString(v));
+        value=v;
+        this.checker.check(this);
+    }
+
+    public int getValue() throws NumberFormatException {
+        if (!dataValid) throw new NumberFormatException();
+        return value;
+    }
+
+    @Override
+    public void setEnabled(boolean enabled) {
+        super.setEnabled(enabled);
+        this.checker.check(this);
+    }
+
+    public class CheckHex implements FocusListener {
+
+        @Override
+        public void focusGained(FocusEvent e) {
+        }
+
+        @Override
+        public void focusLost(FocusEvent event) {
+            check((GuiFieldHex) event.getSource());
+        }
+
+        public void check(GuiFieldHex field) {
+            try {
+                value = Integer.decode(field.getText());
+//                value = Integer.parseUnsignedInt(field.getText().replace("#", ""), 16);
+                dataValid = true;
+                field.setBorder(defaultBorder);
+            } catch (NumberFormatException e) {
+                field.setBorder(BorderFactory.createLineBorder(Color.red));
+                dataValid = false;
+            }
+        }
+    }
+}
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/GuiFieldInteger.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/GuiFieldInteger.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/GuiFieldInteger.java	(revision 34609)
@@ -0,0 +1,68 @@
+// License: GPL. For details, see LICENSE file.
+
+package org.openstreetmap.josm.plugins.pdfimport;
+
+import java.awt.Color;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+
+import javax.swing.BorderFactory;
+
+
+public class GuiFieldInteger extends GuiFieldString {
+
+    private int value;
+    public CheckInteger checker;
+
+    public GuiFieldInteger() {
+        super();
+        addFocusListener(checker = new CheckInteger());
+        setValue(0);
+    }
+
+    @SuppressWarnings("unused")
+    private GuiFieldInteger(String text) {
+        super(text);
+        addFocusListener(checker = new CheckInteger());
+    }
+
+    public GuiFieldInteger(int v) {
+        super();
+        addFocusListener(checker = new CheckInteger());
+        setValue(v);
+    }
+
+    public void setValue(int v) {
+        super.setText(Integer.toString(v));
+        value=v;
+        this.checker.check(this);
+    }
+
+    public int getValue() throws NumberFormatException {
+        if (!dataValid) throw new NumberFormatException();
+        return value;
+    }
+
+    public class CheckInteger implements FocusListener {
+
+        @Override
+        public void focusGained(FocusEvent e) {
+        }
+
+        @Override
+        public void focusLost(FocusEvent event) {
+            check((GuiFieldInteger) event.getSource());
+        }
+
+        public void check(GuiFieldInteger field) {
+            try {
+                value = Integer.valueOf(field.getText());
+                dataValid = true;
+                field.setBorder(defaultBorder);
+            } catch (NumberFormatException e) {
+                field.setBorder(BorderFactory.createLineBorder(Color.red));
+                dataValid = false;
+            }
+        }
+    }
+}
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/GuiFieldLong.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/GuiFieldLong.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/GuiFieldLong.java	(revision 34609)
@@ -0,0 +1,68 @@
+// License: GPL. For details, see LICENSE file.
+
+package org.openstreetmap.josm.plugins.pdfimport;
+
+import java.awt.Color;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+
+import javax.swing.BorderFactory;
+
+
+public class GuiFieldLong extends GuiFieldString {
+
+    private long value;
+    public CheckLong checker;
+
+    public GuiFieldLong() {
+        super();
+        addFocusListener(checker = new CheckLong());
+        setValue(0);
+    }
+
+    @SuppressWarnings("unused")
+    private GuiFieldLong(String text) {
+        super(text);
+        addFocusListener(checker = new CheckLong());
+    }
+
+    public GuiFieldLong(long v) {
+        super();
+        addFocusListener(checker = new CheckLong());
+        setValue(v);
+    }
+
+    public void setValue(long v) {
+        super.setText(Long.toString(v));
+        value=v;
+        this.checker.check(this);
+    }
+
+    public long getValue() throws NumberFormatException {
+        if (!dataValid) throw new NumberFormatException();
+        return value;
+    }
+
+    public class CheckLong implements FocusListener {
+
+        @Override
+        public void focusGained(FocusEvent e) {
+        }
+
+        @Override
+        public void focusLost(FocusEvent event) {
+            check((GuiFieldLong) event.getSource());
+        }
+
+        public void check(GuiFieldLong field) {
+            try {
+                value = Long.valueOf(field.getText());
+                dataValid = true;
+                field.setBorder(defaultBorder);
+            } catch (NumberFormatException e) {
+                field.setBorder(BorderFactory.createLineBorder(Color.red));
+                dataValid = false;
+            }
+        }
+    }
+}
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/GuiFieldString.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/GuiFieldString.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/GuiFieldString.java	(revision 34609)
@@ -0,0 +1,32 @@
+// License: GPL. For details, see LICENSE file.
+
+package org.openstreetmap.josm.plugins.pdfimport;
+
+import javax.swing.JTextField;
+import javax.swing.border.Border;
+
+public class GuiFieldString extends JTextField {
+    /*
+     * TODO: integrate presentation of dataValid;
+     */
+
+    protected Border defaultBorder;
+    protected boolean dataValid;
+
+    public GuiFieldString() {
+        super();
+        defaultBorder = getBorder();
+    }
+
+    public GuiFieldString(String text) {
+        super(text);
+        defaultBorder = getBorder();
+    }
+
+    public boolean isDataValid() {
+        return dataValid;
+    }
+
+}
+
+
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/GuiPanel.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/GuiPanel.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/GuiPanel.java	(revision 34609)
@@ -0,0 +1,27 @@
+// License: GPL. For details, see LICENSE file.
+
+package org.openstreetmap.josm.plugins.pdfimport;
+
+import java.awt.Component;
+import java.awt.LayoutManager;
+
+import javax.swing.JPanel;
+
+public class GuiPanel extends JPanel{
+
+    public GuiPanel() {
+        super();
+    }
+
+    public GuiPanel(LayoutManager layout) {
+        super(layout);
+    }
+
+    @Override
+    public void setEnabled(boolean enabled) {
+        for (Component c : this.getComponents()) {
+            c.setEnabled(enabled);
+        }
+        super.setEnabled(enabled);
+    }
+}
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/GuiProjections.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/GuiProjections.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/GuiProjections.java	(revision 34609)
@@ -0,0 +1,276 @@
+// License: GPL. For details, see LICENSE file.
+
+package org.openstreetmap.josm.plugins.pdfimport;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.SwingConstants;
+
+import org.openstreetmap.josm.data.ProjectionBounds;
+import org.openstreetmap.josm.data.projection.Projection;
+import org.openstreetmap.josm.data.projection.ProjectionRegistry;
+import org.openstreetmap.josm.gui.preferences.projection.CodeProjectionChoice;
+import org.openstreetmap.josm.gui.preferences.projection.CustomProjectionChoice;
+import org.openstreetmap.josm.gui.preferences.projection.ProjectionChoice;
+import org.openstreetmap.josm.gui.preferences.projection.ProjectionPreference;
+import org.openstreetmap.josm.gui.preferences.projection.SingleProjectionChoice;
+import org.openstreetmap.josm.spi.preferences.Config;
+import org.openstreetmap.josm.tools.Logging;
+
+public class GuiProjections {
+    /*
+     * provide a component let the user select a projection
+     * TODO: allow preferences for sub-projections like UTM, Gauss-Krüger, etc.
+     * TODO: allow selection of projection by code (EPSG)
+     * TODO: allow selection of custom projection
+     */
+    private GuiPanel panel = null;
+    private Chooser chooser = null;
+    private JLabel pCode = null;
+    private JLabel pName = null;
+    private JLabel pInfo = null;
+    private Projection projection = null;
+
+    private class Chooser extends JComboBox<ProjectionChoice> {
+        /*
+         * Component to choose a Projection
+         */
+        public Chooser() {
+            setEditable(false);
+            setToolTipText(tr("Projection of the PDF-Document"));
+             Monitor monitor = new Monitor();
+             for (ProjectionChoice p : ProjectionPreference.getProjectionChoices()) {
+                 if ((p instanceof CodeProjectionChoice)) continue;    // can not handle this projection for now
+                 if ((p instanceof CustomProjectionChoice)) continue;    // can not handle this projection for now
+                 addItem(p);
+            }
+            addActionListener(monitor);
+            setProjection (ProjectionRegistry.getProjection());
+        }
+
+        public void setProjection (Projection p) {
+            /*
+             * set current Projection to @p
+             * update internal variables
+             */
+            if (p==null) return;    // better keep the old one
+            projection = p;
+            pName.setText(p.toString());
+            pCode.setText(p.toCode());
+            pInfo.setText(userHints(p));
+            /*
+             * find projectionChoice that matches current code
+             */
+            final String projectionCode = p.toCode();
+            for (ProjectionChoice projectionChoice : ProjectionPreference.getProjectionChoices()) {
+                for (String code : projectionChoice.allCodes()) {
+                    if (code.equals(projectionCode)) {
+                        setSelectedItem(projectionChoice);
+                        return;    // stop searching
+                    }
+                }
+            }
+            /*
+             * Not found ==> search in combobox
+             */
+            final String localId = "PdfImport:" + projectionCode;
+            for (int i=getItemCount()-1; i>=0; i--) {
+                ProjectionChoice projectionChoice = getItemAt(i);
+                if (!(projectionChoice instanceof SingleProjectionChoice)) continue;
+                if (localId.equals(projectionChoice.getId())) {
+                    setSelectedItem(projectionChoice);
+                    return;    // stop searching
+                }
+            }
+            /*
+             * Still not found ==> add it now
+             */
+            Logging.debug("New projection encountered");
+            ProjectionChoice px = new SingleProjectionChoice(p.toString(), localId, projectionCode) ;
+            addItem(px);
+            setSelectedItem(px);
+        }
+
+        private class Monitor implements ActionListener {
+            /*
+             * (non-Javadoc)
+             * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
+             *
+             * monitor user selection and set internal var accordingly
+             */
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                try {
+                ProjectionChoice pc = (ProjectionChoice)((Chooser) e.getSource()).getSelectedItem();
+                setProjection(pc.getProjection());
+                } catch (Exception X) {
+                }
+            }
+        }
+    }
+
+    public GuiProjections(){
+        build();
+    }
+
+    public static String getDefault() {
+        /*
+         * provide default projection
+         */
+        return Config.getPref().get("projection.default");
+    }
+
+    public JPanel getPanel() {
+        return panel;
+    }
+
+    public Projection getProjection() {
+        return projection;
+    }
+
+    public void setProjection(Projection p) {
+        chooser.setProjection(p);
+    }
+
+    private String userHints(Projection p) {
+        /*
+         * Provide some hints about projection @p
+         */
+        String s="";
+        ProjectionBounds bd;
+        try {
+            bd=p.getWorldBoundsBoxEastNorth();
+            s += String.format("(%3$.0f %4$.0f) : (%5$.0f %6$.0f)", bd.getCenter().east(),bd.getCenter().north(), bd.getMin().east(),bd.getMin().north(),bd.getMax().east(),bd.getMax().north());
+        } catch (Exception e) {
+            e.toString();
+            // Leave it, if we cant get it
+        }
+        return s;
+    }
+
+    private void build() {
+//        JButton specBtn = new JButton(tr("Specifiy"));
+        pCode = new JLabel("code",SwingConstants.RIGHT);
+        pName = new JLabel("Name",SwingConstants.RIGHT);
+        pInfo = new JLabel("Info",SwingConstants.RIGHT);
+        chooser = new Chooser();
+
+        GridBagConstraints c = new GridBagConstraints();
+        c.fill = GridBagConstraints.NONE;
+        c.insets = new Insets(1, 1, 1, 4);
+        c.anchor = GridBagConstraints.LINE_END;
+
+        panel = new GuiPanel(new GridBagLayout());
+        panel.add(new JLabel(tr("Projection:"),SwingConstants.RIGHT),c);
+        panel.add(pCode,c);
+        c.weightx = 1.0; c.gridx = 2; panel.add(chooser,c);
+        c.weightx = 0.0; c.gridy = 1; c.gridx = 0; c.gridwidth = 3; c.anchor = GridBagConstraints.LINE_END;
+        panel.add(pInfo,c);
+    }
+}
+
+//class ProjectionSubPrefsDialog extends JDialog {
+///*
+// * note currently non-functional ==> not used
+// */
+//private final ProjectionChoice projPref;
+//private OKAction actOK;
+//private CancelAction actCancel;
+//private JPanel projPrefPanel;
+//
+//ProjectionSubPrefsDialog(Component parent, ProjectionChoice pr) {
+//    super(JOptionPane.getFrameForComponent(parent), ModalityType.DOCUMENT_MODAL);
+//
+//    projPref = pr;
+//
+//    setTitle(tr("Projection Preferences"));
+//    setDefaultCloseOperation(DISPOSE_ON_CLOSE);
+//
+//    build();
+//}
+//
+//protected void makeButtonRespondToEnter(SideButton btn) {
+//    btn.setFocusable(true);
+//    btn.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "enter");
+//    btn.getActionMap().put("enter", btn.getAction());
+//}
+//
+//protected JPanel buildInputForm() {
+//    return projPref.getPreferencePanel(null);
+//}
+//
+//protected JPanel buildButtonRow() {
+//    JPanel pnl = new JPanel(new FlowLayout());
+//
+//    actOK = new OKAction();
+//    actCancel = new CancelAction();
+//
+//    SideButton btn;
+//    pnl.add(btn = new SideButton(actOK));
+//    // makeButtonRespondToEnter(btn);
+//    // pnl.add(btn = new SideButton(actCancel));
+//    // makeButtonRespondToEnter(btn);
+//    return pnl;
+//}
+//
+//protected void build() {
+//    projPrefPanel = buildInputForm();
+//    getContentPane().setLayout(new BorderLayout());
+//    getContentPane().add(projPrefPanel, BorderLayout.CENTER);
+//    getContentPane().add(buildButtonRow(), BorderLayout.SOUTH);
+//    pack();
+//
+//    // make dialog respond to ESCAPE
+//    getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
+//            .put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "escape");
+//    getRootPane().getActionMap().put("escape", actCancel);
+//}
+//
+//class OKAction extends AbstractAction {
+//    OKAction() {
+//        putValue(NAME, tr("OK"));
+//        putValue(SHORT_DESCRIPTION, tr("Close the dialog and apply projection preferences"));
+//        putValue(SMALL_ICON, ImageProvider.get("ok"));
+//    }
+//
+//    @Override
+//    public void actionPerformed(ActionEvent e) {
+//        projPref.setPreferences(projPref.getPreferences(projPrefPanel));
+//        setVisible(false);
+//    }
+//}
+//
+//class CancelAction extends AbstractAction {
+//    CancelAction() {
+//        putValue(NAME, tr("Cancel"));
+//        putValue(SHORT_DESCRIPTION, tr("Close the dialog, discard projection preference changes"));
+//        putValue(SMALL_ICON, ImageProvider.get("cancel"));
+//    }
+//
+//    @Override
+//    public void actionPerformed(ActionEvent e) {
+//        setVisible(false);
+//    }
+//}
+//
+//@Override
+//public void setVisible(boolean visible) {
+//    if (visible) {
+//        new WindowGeometry(getClass().getName() + ".geometry",
+//                WindowGeometry.centerOnScreen(new Dimension(400, 300))).applySafe(this);
+//    } else if (isShowing()) { // Avoid IllegalComponentStateException like in #8775
+//        new WindowGeometry(this).remember(getClass().getName() + ".geometry");
+//    }
+//    super.setVisible(visible);
+//}
+//}
+
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/LayerContents.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/LayerContents.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/LayerContents.java	(revision 34609)
@@ -0,0 +1,14 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.pdfimport;
+
+import java.awt.geom.Point2D;
+import java.util.ArrayList;
+import java.util.List;
+
+public class LayerContents {
+
+    List<Point2D> points = new ArrayList<>();
+    List<PdfPath> paths = new ArrayList<>();
+    List<PdfMultiPath> multiPaths = new ArrayList<>();
+    LayerInfo info;
+}
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/LayerInfo.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/LayerInfo.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/LayerInfo.java	(revision 34609)
@@ -0,0 +1,60 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.pdfimport;
+
+import java.awt.Color;
+
+public class LayerInfo {
+    public Color fill;
+    public Color stroke;
+    public int dash;
+    public double width;
+    public int divider;
+    public boolean isGroup;
+
+    public int nr;
+
+    @Override
+    public int hashCode() {
+        int code = Double.toString(width).hashCode() ^ this.divider ^ this.dash;
+
+        if (this.fill != null) {
+            code ^= this.fill.hashCode();
+        }
+
+        if (this.stroke != null) {
+            code ^= this.stroke.hashCode();
+        }
+
+        return code;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        LayerInfo l = (LayerInfo) o;
+        boolean eq = this.width == l.width &&
+        this.divider == l.divider &&
+        this.dash == l.dash;
+
+
+        if (this.fill != null) {
+            eq &= this.fill.equals(l.fill);
+        }
+
+        if (this.stroke != null) {
+            eq &= this.stroke.equals(l.stroke);
+        }
+
+        return eq;
+    }
+
+    public LayerInfo copy() {
+        LayerInfo result = new LayerInfo();
+        result.fill = this.fill;
+        result.stroke = this.stroke;
+        result.dash = this.dash;
+        result.width = this.width;
+        result.divider = this.divider;
+        return result;
+    }
+
+}
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/LoadPdfDialog.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/LoadPdfDialog.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/LoadPdfDialog.java	(revision 34609)
@@ -0,0 +1,754 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.pdfimport;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Cursor;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+import javax.swing.BorderFactory;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JFileChooser;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JProgressBar;
+import javax.swing.JTextField;
+import javax.swing.SwingConstants;
+import javax.swing.SwingUtilities;
+import javax.swing.filechooser.FileFilter;
+
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.UploadPolicy;
+import org.openstreetmap.josm.gui.MainApplication;
+import org.openstreetmap.josm.gui.io.importexport.OsmExporter;
+import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
+import org.openstreetmap.josm.gui.progress.ProgressRenderer;
+import org.openstreetmap.josm.gui.progress.swing.SwingRenderingProgressMonitor;
+import org.openstreetmap.josm.plugins.pdfimport.pdfbox.PdfBoxParser;
+import org.openstreetmap.josm.tools.Logging;
+
+public class LoadPdfDialog extends JFrame {
+
+    public static class MainButtons {
+        public JButton okButton;
+        public JButton cancelButton;
+        public JButton showButton;
+        public JButton saveButton;
+        public JPanel panel;
+
+        public MainButtons() {
+        }
+
+        void build(LoadPdfDialog loadPdfDialog) {
+            /*
+             * build the dialog Window from components
+             */
+            okButton = new JButton(tr("Import"));
+            okButton.addActionListener(new ActionListener() {
+                @Override
+                public void actionPerformed(ActionEvent e) {
+                    loadPdfDialog.importAction();
+                }
+            });
+            saveButton = new JButton(tr("Save"));
+            saveButton.addActionListener(new ActionListener() {
+                @Override
+                public void actionPerformed(ActionEvent e) {
+                    loadPdfDialog.saveAction();
+                }
+            });
+
+            showButton = new JButton(tr("Show target"));
+            showButton.addActionListener(new ActionListener() {
+                @Override
+                public void actionPerformed(ActionEvent e) {
+                    loadPdfDialog.showAction();
+                }
+            });
+
+            cancelButton = new JButton(tr("Cancel"));
+            cancelButton.addActionListener(new ActionListener() {
+                @Override
+                public void actionPerformed(ActionEvent e) {
+                    loadPdfDialog.cancelAction();
+                }
+            });
+
+            panel = new JPanel(new FlowLayout());
+            panel.add(cancelButton);
+            panel.add(showButton);
+            panel.add(okButton);
+            panel.add(saveButton);
+            showButton.setVisible(Preferences.isLegacyActions());
+            saveButton.setVisible(Preferences.isLegacyActions());
+        }
+    }
+
+
+    private static class Config {
+        /*
+         * encapsulate options for Path optimizer
+         * provide GUI
+         */
+        public GuiFieldBool debugModeCheck;
+        public GuiFieldBool mergeCloseNodesCheck;
+        public GuiFieldDouble mergeCloseNodesTolerance;
+        public GuiFieldBool removeSmallObjectsCheck;
+        public GuiFieldDouble removeSmallObjectsSize;
+        public JTextField colorFilterColor;
+        public GuiFieldBool colorFilterCheck;
+        public GuiFieldBool removeParallelSegmentsCheck;
+        public GuiFieldDouble removeParallelSegmentsTolerance;
+        public GuiFieldBool removeLargeObjectsCheck;
+        public GuiFieldDouble removeLargeObjectsSize;
+        public GuiFieldBool limitPathCountCheck;
+        public GuiFieldInteger limitPathCount;
+        public GuiFieldBool splitOnColorChangeCheck;
+        public GuiFieldBool splitOnShapeClosedCheck;
+        public GuiFieldBool splitOnSingleSegmentCheck;
+        public GuiFieldBool splitOnOrthogonalCheck;
+        private JPanel panel;
+
+        public Config() {
+            build();
+        }
+
+        public JComponent getComponent() {
+            return panel;
+        }
+
+        private void build() {
+
+
+            debugModeCheck = new GuiFieldBool(tr("Debug info"), Preferences.isDebugTags());
+
+            mergeCloseNodesTolerance = new GuiFieldDouble(Preferences.getMergeNodesValue());
+            mergeCloseNodesCheck = new GuiFieldBool(tr("Merge close nodes"), Preferences.isMergeNodes());
+            mergeCloseNodesCheck.setCompanion(mergeCloseNodesTolerance);
+
+            removeSmallObjectsSize = new GuiFieldDouble(Preferences.getRemoveSmallValue());
+            removeSmallObjectsCheck = new GuiFieldBool(tr("Remove objects smaller than"),Preferences.isRemoveSmall());
+            removeSmallObjectsCheck.setCompanion(removeSmallObjectsSize);
+
+            removeLargeObjectsSize = new GuiFieldDouble((Preferences.getRemoveLargeValue()));
+            removeLargeObjectsCheck = new GuiFieldBool(tr("Remove objects larger than"),Preferences.isRemoveLarge());
+            removeLargeObjectsCheck.setCompanion(removeLargeObjectsSize);
+
+            colorFilterColor = new GuiFieldHex(Preferences.getLimitColorValue());
+            colorFilterCheck = new GuiFieldBool(tr("Only this color"), Preferences.isLimitColor());
+            colorFilterCheck.setCompanion(colorFilterColor);
+
+            removeParallelSegmentsTolerance = new GuiFieldDouble((Preferences.getRemoveParallelValue()));
+            removeParallelSegmentsCheck = new GuiFieldBool(tr("Remove parallel lines"),Preferences.isRemoveParallel());
+            removeParallelSegmentsCheck.setCompanion(removeParallelSegmentsTolerance);
+
+            limitPathCount = new GuiFieldInteger((Preferences.getLimitPathValue()));
+            limitPathCountCheck = new GuiFieldBool(tr("Take only first X paths"),Preferences.isLimitPath());
+            limitPathCountCheck.setCompanion(limitPathCount);
+
+            splitOnColorChangeCheck = new GuiFieldBool(tr("Color/width change"),Preferences.isLayerAttribChange());
+            splitOnShapeClosedCheck = new GuiFieldBool(tr("Shape closed"), Preferences.isLayerClosed());
+
+            splitOnSingleSegmentCheck = new GuiFieldBool(tr("Single segments", Preferences.isLayerSegment()));
+            splitOnOrthogonalCheck = new GuiFieldBool(tr("Orthogonal shapes", Preferences.isLayerOrtho()));
+
+            panel = new JPanel(new GridBagLayout());
+            panel.setBorder(BorderFactory.createTitledBorder(tr("Import settings")));
+
+            GridBagConstraints cBasic = new GridBagConstraints();
+            cBasic.gridx = GridBagConstraints.RELATIVE;
+            cBasic.gridy = GridBagConstraints.RELATIVE;
+            cBasic.insets = new Insets(0, 0, 0, 4);
+            cBasic.anchor = GridBagConstraints.LINE_START;
+            cBasic.fill = GridBagConstraints.HORIZONTAL;
+            cBasic.gridheight = 1;
+            cBasic.gridwidth = 1;
+            cBasic.ipadx = 0;
+            cBasic.ipady = 0;
+            cBasic.weightx = 0.0;
+            cBasic.weighty = 0.0;
+
+            GridBagConstraints cLeft = (GridBagConstraints) cBasic.clone();
+            cLeft.gridx = 0;
+
+            GridBagConstraints cMiddle = (GridBagConstraints) cBasic.clone();
+            cMiddle.gridx = 1;
+            cMiddle.anchor = GridBagConstraints.LINE_END;
+
+            GridBagConstraints cRight = (GridBagConstraints) cBasic.clone();
+            cRight.gridx = 2;
+
+            panel.add(mergeCloseNodesCheck, cLeft);
+            panel.add(new JLabel(tr("Tolerance:"),SwingConstants.RIGHT), cMiddle);
+            panel.add(mergeCloseNodesTolerance, cRight);
+
+            panel.add(removeSmallObjectsCheck, cLeft);
+            panel.add(new JLabel(tr("Tolerance:"),SwingConstants.RIGHT), cMiddle);
+            panel.add(removeSmallObjectsSize, cRight);
+
+            panel.add(removeLargeObjectsCheck, cLeft);
+            panel.add(new JLabel(tr("Tolerance:"),SwingConstants.RIGHT), cMiddle);
+            panel.add(removeLargeObjectsSize, cRight);
+
+            panel.add(removeParallelSegmentsCheck, cLeft);
+            panel.add(new JLabel(tr("Max distance:"),SwingConstants.RIGHT), cMiddle);
+            panel.add(removeParallelSegmentsTolerance, cRight);
+
+            panel.add(limitPathCountCheck, cLeft);
+            panel.add(limitPathCount, cRight);
+
+            panel.add(colorFilterCheck, cLeft);
+            panel.add(colorFilterColor, cRight);
+
+            panel.add(debugModeCheck, cLeft);
+
+            cLeft.gridy = 8; panel.add(new JLabel(tr("Introduce separate layers for:")), cLeft);
+            cMiddle.gridy = 8; panel.add(splitOnShapeClosedCheck, cMiddle);
+            cRight.gridy = 8; panel.add(splitOnSingleSegmentCheck, cRight);
+            cMiddle.gridy = 9; panel.add(splitOnColorChangeCheck, cMiddle);
+            cRight.gridy = 9;panel.add(splitOnOrthogonalCheck, cRight);
+        }
+    }
+
+    static class LoadProgressRenderer implements ProgressRenderer {
+        private final JProgressBar pBar;
+        private String title = "";
+
+        LoadProgressRenderer(JProgressBar pb) {
+            this.pBar = pb;
+            this.pBar.setMinimum(0);
+            this.pBar.setValue(0);
+            this.pBar.setMaximum(1);
+            this.pBar.setString("");
+            this.pBar.setStringPainted(true);
+
+        }
+
+        @Override
+        public void setCustomText(String message) {
+            this.pBar.setString(this.title + message);
+        }
+
+        @Override
+        public void setIndeterminate(boolean indeterminate) {
+            this.pBar.setIndeterminate(indeterminate);
+        }
+
+        @Override
+        public void setMaximum(int maximum) {
+            this.pBar.setMaximum(maximum);
+        }
+
+        @Override
+        public void setTaskTitle(String taskTitle) {
+            this.title = taskTitle;
+            this.pBar.setString(this.title);
+        }
+
+        @Override
+        public void setValue(int value) {
+            this.pBar.setValue(value);
+        }
+
+        public void finish() {
+            this.pBar.setString(tr("Finished"));
+            this.pBar.setValue(this.pBar.getMaximum());
+        }
+
+    }
+
+    private File pdfFile;
+    private final FilePlacement18 placement = new FilePlacement18();
+
+    private PathOptimizer pdfData;
+//    private OsmDataLayer dataLayer;
+
+    private final JButton loadFileButton = new JButton(tr("Load preview ..."));
+
+    private final JProgressBar loadProgress = new JProgressBar();
+;
+    private OsmDataLayer newLayer;
+
+    private LoadProgressRenderer progressRenderer;
+
+    public LoadPdfDialog() {
+        buildGUI();
+        removeLayer();
+        if (Preferences.getGuiMode() == Preferences.GuiMode.Simple) {
+            loadFileButton.setVisible(false);
+            configPanel.panel.setVisible(false);
+            actionPanel.saveButton.setVisible(false);
+            actionPanel.showButton.setVisible(false);
+            setSize(new Dimension(380, 350));
+            if (!loadAction()) {
+                cancelAction();
+                return;
+            }
+        } else {
+            setSize(new Dimension(450, 600));
+        }
+        setAlwaysOnTop(true);
+        setVisible(true);
+    }
+
+    Component placementPanel = placement.getGui();
+    MainButtons actionPanel = new MainButtons();
+    Config configPanel = new Config();
+
+    private void buildGUI() {
+        /*
+         * build the GUI from Components
+         */
+        GridBagConstraints c = new GridBagConstraints();
+        c.gridheight = 1;
+        c.gridwidth = 1;
+        c.gridx = 0;
+        c.gridy = GridBagConstraints.RELATIVE;
+        c.fill = GridBagConstraints.BOTH;
+        c.insets = new java.awt.Insets(0, 0, 0, 0);
+
+        actionPanel.build(this);
+
+        loadFileButton.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                loadAction();
+            }
+        });
+
+        progressRenderer = new LoadProgressRenderer(loadProgress);
+
+        JPanel panel = new JPanel(new GridBagLayout());
+
+        panel.add(configPanel.getComponent(), c);
+        c.fill = GridBagConstraints.HORIZONTAL;
+        panel.add(loadFileButton, c);
+        c.fill = GridBagConstraints.BOTH;
+        panel.add(placementPanel, c);
+        panel.add(actionPanel.panel, c);
+        c.fill = GridBagConstraints.HORIZONTAL;
+        panel.add(this.loadProgress, c);
+
+        setContentPane(panel);
+        addWindowListener(new WindowAdapter() {
+            @Override
+            public void windowClosing(WindowEvent e) {
+                cancelAction();
+            }
+        });
+        placement.setDependsOnValid(actionPanel.okButton);
+
+        /*
+         * TODO: Make okButton to default Button of Dialog, make cancelButton to react on ESC-Key
+         */
+//        SwingUtilities.getRootPane(panel).setDefaultButton(actionPanel.okButton);
+    }
+
+     private boolean loadAction() {
+         /*
+          * perform load PDF file to preview
+          * TODO: load preview to previous placement, involves reverse transform
+          */
+        final File newFileName = this.chooseFile();
+
+        if (newFileName == null) {
+            return false;
+        }
+        Logging.debug("PdfImport: Load Preview");
+        this.removeLayer();
+
+        this.loadFileButton.setEnabled(false);
+
+        this.runAsBackgroundTask(new Runnable() {
+            @Override
+            public void run() {
+                // async part
+                LoadPdfDialog.this.loadProgress.setVisible(true);
+                SwingRenderingProgressMonitor monitor = new SwingRenderingProgressMonitor(progressRenderer);
+                monitor.beginTask("Loading file", 1000);
+                pdfData = loadPDF(newFileName, monitor.createSubTaskMonitor(500, false));
+                OsmBuilder.Mode mode = LoadPdfDialog.this.configPanel.debugModeCheck.getValue()
+                        ? OsmBuilder.Mode.Debug
+                        : OsmBuilder.Mode.Draft;
+
+                if (pdfData != null) {
+                    LoadPdfDialog.this.newLayer = LoadPdfDialog.this.makeLayer(
+                            tr("PDF preview: ") + newFileName.getName(), new FilePlacement(), mode,
+                            monitor.createSubTaskMonitor(500, false));
+                }
+
+                monitor.finishTask();
+                progressRenderer.finish();
+            }
+        }, new ActionListener() {
+
+            @Override
+            public void actionPerformed(ActionEvent event) {
+                // sync part
+                LoadPdfDialog.this.pdfFile = newFileName;
+                if (pdfData != null) {
+                    Preview.set(newLayer, new FilePlacement());
+                    MainApplication.getMap().mapView.zoomTo(placement.getWorldBounds(pdfData));
+                    try {
+                        LoadPdfDialog.this.placement.load(newFileName);
+                    } catch (IOException e) {
+                        // Saved placement does not exist, corrupt, ... ---> ignore it
+                    } finally {
+                        LoadPdfDialog.this.placement.verify();
+                    }
+                    LoadPdfDialog.this.newLayer = null;
+                    LoadPdfDialog.this.loadFileButton.setEnabled(true);
+                    LoadPdfDialog.this.placementPanel.setEnabled(true);
+                    LoadPdfDialog.this.actionPanel.panel.setEnabled(true);
+                    LoadPdfDialog.this.actionPanel.showButton.setEnabled(true);
+                    LoadPdfDialog.this.actionPanel.saveButton.setEnabled(true);
+                    LoadPdfDialog.this.actionPanel.okButton.setEnabled(true);
+                    LoadPdfDialog.this.loadProgress.setVisible(false);
+                }
+            }
+        });
+        return true;
+    }
+
+    private void importAction() {
+
+        if (!placement.isValid()) return;
+        try {
+            placement.save(pdfFile);
+        } catch (IOException e) {
+            e.toString();
+        }
+        removeLayer();
+
+        runAsBackgroundTask(new Runnable() {
+            @Override
+            public void run() {
+                // async part
+                LoadPdfDialog.this.loadProgress.setVisible(true);
+                SwingRenderingProgressMonitor monitor = new SwingRenderingProgressMonitor(progressRenderer);
+                LoadPdfDialog.this.newLayer = LoadPdfDialog.this.makeLayer(tr("PDF: ") + pdfFile.getName(), placement,
+                        OsmBuilder.Mode.Final, monitor);
+                progressRenderer.finish();
+            }
+        }, new ActionListener() {
+
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                // sync part
+                // rebuild layer with latest projection
+                MainApplication.getLayerManager().addLayer(newLayer);
+                MainApplication.getMap().mapView.zoomTo(placement.getWorldBounds(pdfData));
+                LoadPdfDialog.this.setVisible(false);
+            }
+        });
+    }
+
+    private void saveAction() {
+        /*
+         * perform save preview layer to file
+         * TODO: is this action valueable? Can be easily performed from main menu
+         */
+
+        if (!placement.isValid()) return;
+
+        final java.io.File file = this.chooseSaveFile();
+
+        if (file == null) {
+            return;
+        }
+
+        this.removeLayer();
+
+        this.runAsBackgroundTask(new Runnable() {
+            @Override
+            public void run() {
+                // async part
+                SwingRenderingProgressMonitor monitor = new SwingRenderingProgressMonitor(progressRenderer);
+                LoadPdfDialog.this.saveLayer(file, placement, monitor);
+                progressRenderer.finish();
+            }
+        }, new ActionListener() {
+
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                // sync part
+                LoadPdfDialog.this.setVisible(false);
+            }
+        });
+    }
+
+    private void showAction() {
+        /*
+         * perform show action
+         * TODO: is this action valuable? User can do it easy from OSM Main Menu
+         */
+        if (!placement.isValid()) return;
+
+        // zoom to new location
+        MainApplication.getMap().mapView.zoomTo(placement.getWorldBounds(pdfData));
+        MainApplication.getMap().repaint();
+    }
+
+    private void cancelAction() {
+        /*
+         * perform cancel action
+         */
+        removeLayer();
+        setVisible(false);
+    }
+
+    // Implementation methods
+
+    private static JFileChooser loadChooser = null;
+
+    private java.io.File chooseFile() {
+        // get PDF file to load
+        if (loadChooser == null) {
+            loadChooser = new JFileChooser(Preferences.getLoadDir());
+            loadChooser.setAcceptAllFileFilterUsed(false);
+            loadChooser.setMultiSelectionEnabled(false);
+            loadChooser.setFileFilter(new FileFilter() {
+                @Override
+                public boolean accept(java.io.File pathname) {
+                    return pathname.isDirectory() || pathname.getName().endsWith(".pdf");
+                }
+
+                @Override
+                public String getDescription() {
+                    return tr("PDF files");
+                }
+            });
+        } else {
+            loadChooser.rescanCurrentDirectory();
+        }
+        int result = loadChooser.showDialog(this, tr("Import PDF"));
+        if (result != JFileChooser.APPROVE_OPTION) {
+            return null;
+        } else {
+            Preferences.setLoadDir(loadChooser.getSelectedFile().getParentFile().getAbsolutePath());
+            return loadChooser.getSelectedFile();
+        }
+    }
+
+    private java.io.File chooseSaveFile() {
+        // get file name
+        JFileChooser fc = new JFileChooser();
+        fc.setAcceptAllFileFilterUsed(true);
+        fc.setMultiSelectionEnabled(false);
+        fc.setFileFilter(new FileFilter() {
+            @Override
+            public boolean accept(java.io.File pathname) {
+                return pathname.isDirectory() || pathname.getName().endsWith(".osm");
+            }
+
+            @Override
+            public String getDescription() {
+                return tr("OSM files");
+            }
+        });
+        int result = fc.showOpenDialog(MainApplication.getMainFrame());
+
+        if (result != JFileChooser.APPROVE_OPTION) {
+            return null;
+        } else {
+            return fc.getSelectedFile();
+        }
+    }
+
+    private void runAsBackgroundTask(final Runnable task, final ActionListener after) {
+        /*
+         * run @task in background (asychronosly , run @after when @task has finished
+         */
+        this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
+        Thread t = new Thread(new Runnable() {
+            @Override
+            public void run() {
+                task.run();
+
+                SwingUtilities.invokeLater(new Runnable() {
+                    @Override
+                    public void run() {
+                        setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
+                        after.actionPerformed(null);
+                    }
+                });
+            }
+        });
+        t.start();
+    }
+
+    private PathOptimizer loadPDF(File fileName, ProgressMonitor monitor) {
+        /*
+         * postprocess load PDF-file according to options
+         */
+
+        monitor.beginTask("", 100);
+        monitor.setTicks(0);
+        monitor.setCustomText(tr("Preparing"));
+
+        double nodesTolerance = 0.0;
+        Color color = null;
+        int maxPaths = Integer.MAX_VALUE;
+
+        if (configPanel.mergeCloseNodesCheck.getValue() && configPanel.mergeCloseNodesTolerance.isDataValid()) {
+                nodesTolerance = configPanel.mergeCloseNodesTolerance.getValue();
+        }
+
+        if (configPanel.colorFilterCheck.getValue()) {
+            try {
+                String colString = this.configPanel.colorFilterColor.getText().replace("#", "");
+                color = new Color(Integer.parseInt(colString, 16));
+            } catch (Exception e) {
+                JOptionPane.showMessageDialog(MainApplication.getMainFrame(), tr("Could not parse color"));
+                return null;
+            }
+        }
+
+        if (configPanel.limitPathCountCheck.getValue() && configPanel.limitPathCount.isDataValid()) {
+                maxPaths = configPanel.limitPathCount.getValue();
+        }
+
+        monitor.setTicks(10);
+        monitor.setCustomText(tr("Parsing file"));
+
+        PathOptimizer data = new PathOptimizer(nodesTolerance, color, configPanel.splitOnColorChangeCheck.getValue());
+
+        try {
+            PdfBoxParser parser = new PdfBoxParser(data);
+            parser.parse(fileName, maxPaths, monitor.createSubTaskMonitor(80, false));
+
+        } catch (FileNotFoundException e1) {
+            JOptionPane.showMessageDialog(MainApplication.getMainFrame(), tr("File not found."));
+            return null;
+        } catch (Exception e) {
+            e.printStackTrace();
+            JOptionPane.showMessageDialog(MainApplication.getMainFrame(), tr("Error while parsing: {0}", e.getMessage()));
+            return null;
+        }
+
+        monitor.setTicks(80);
+
+        if (configPanel.removeParallelSegmentsCheck.getValue() && configPanel.removeParallelSegmentsTolerance.isDataValid()) {
+                double tolerance = configPanel.removeParallelSegmentsTolerance.getValue();
+                monitor.setCustomText(tr("Removing parallel segments"));
+        }
+
+        if (nodesTolerance > 0.0) {
+            monitor.setTicks(83);
+            monitor.setCustomText(tr("Joining nodes"));
+            data.mergeNodes();
+        }
+
+        monitor.setTicks(85);
+        monitor.setCustomText(tr("Joining adjacent segments"));
+        data.mergeSegments();
+
+        if (configPanel.removeSmallObjectsCheck.getValue() && configPanel.removeSmallObjectsSize.isDataValid()) {
+                double tolerance = configPanel.removeSmallObjectsSize.getValue();
+                monitor.setTicks(90);
+                monitor.setCustomText(tr("Removing small objects"));
+
+                data.removeSmallObjects(tolerance);
+
+        }
+
+        if (configPanel.removeLargeObjectsCheck.getValue() && configPanel.removeLargeObjectsSize.isDataValid()) {
+                double tolerance = configPanel.removeLargeObjectsSize.getValue();
+                monitor.setTicks(90);
+                monitor.setCustomText(tr("Removing large objects"));
+                data.removeLargeObjects(tolerance);
+        }
+
+        monitor.setTicks(95);
+        monitor.setCustomText(tr("Finalizing layers"));
+        data.splitLayersByPathKind(configPanel.splitOnShapeClosedCheck.getValue(),
+                configPanel.splitOnSingleSegmentCheck.getValue(),
+                configPanel.splitOnOrthogonalCheck.getValue());
+        data.finish();
+
+        monitor.finishTask();
+        return data;
+    }
+
+    private OsmDataLayer makeLayer(String name, FilePlacement placement, OsmBuilder.Mode mode,
+            ProgressMonitor monitor) {
+        /*
+         * create a layer from data
+         */
+        monitor.beginTask(tr("Building JOSM layer"), 100);
+        OsmBuilder builder = new OsmBuilder(placement);
+        DataSet data = builder.build(pdfData.getLayers(), mode, monitor.createSubTaskMonitor(50, false));
+        data.setUploadPolicy(UploadPolicy.BLOCKED);
+        monitor.setTicks(50);
+        monitor.setCustomText(tr("Postprocessing layer"));
+        OsmDataLayer result = new OsmDataLayer(data, name, null);
+        result.setUploadDiscouraged(true);
+        result.setBackgroundLayer(true);
+        result.onPostLoadFromFile();
+
+        monitor.finishTask();
+        return result;
+    }
+
+        private void removeLayer() {
+        /*
+         * remove preview layer
+         */
+//        if (dataLayer != null) {
+//            MainApplication.getLayerManager().removeLayer(dataLayer);
+//            dataLayer.data.clear(); // saves memory
+//            dataLayer = null;
+//        }
+        Preview.clear();
+        // No layer ==> no actions
+        actionPanel.showButton.setEnabled(false);
+        actionPanel.saveButton.setEnabled(false);
+        actionPanel.okButton.setEnabled(false);
+        placementPanel.setEnabled(false);
+
+    }
+
+    private void saveLayer(java.io.File file, FilePlacement placement, ProgressMonitor monitor) {
+        /*
+         * save layer to file
+         * TODO: is this methode valuable? Functionality can easily performed from Main-Menu
+         */
+        monitor.beginTask(tr("Saving to file."), 1000);
+
+        OsmBuilder builder = new OsmBuilder(placement);
+        DataSet data = builder.build(this.pdfData.getLayers(), OsmBuilder.Mode.Final,
+                monitor.createSubTaskMonitor(500, false));
+        OsmDataLayer layer = new OsmDataLayer(data, file.getName(), file);
+
+        monitor.setCustomText(tr(" Writing to file"));
+        monitor.setTicks(500);
+
+        OsmExporter exporter = new OsmExporter();
+
+        try {
+            exporter.exportData(file, layer);
+        } catch (IOException e) {
+            Logging.error(e);
+        }
+
+        monitor.finishTask();
+    }
+
+}
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/OrthogonalShapesFilter.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/OrthogonalShapesFilter.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/OrthogonalShapesFilter.java	(revision 34609)
@@ -0,0 +1,46 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.pdfimport;
+
+import java.awt.geom.Point2D;
+
+public class OrthogonalShapesFilter {
+    private double tolerance;
+
+    public OrthogonalShapesFilter(double toleranceDegrees) {
+        tolerance = Math.toRadians(toleranceDegrees);
+    }
+
+    public boolean isOrthogonal(PdfPath path) {
+
+        if (path.points.size() < 3)
+            return false;
+
+        int targetPos = path.isClosed() ? path.points.size() : path.points.size() - 1;
+
+        for (int pos = 1; pos < targetPos; pos++) {
+            Point2D p1 = path.points.get(pos -1);
+            Point2D p2 = path.points.get(pos);
+            Point2D p3 = pos+1 == path.points.size() ? path.points.get(1) : path.points.get(pos+1);
+
+            double angle1 = Math.atan2(p2.getY() - p1.getY(), p2.getX() - p1.getX());
+            double angle2 = Math.atan2(p3.getY() - p2.getY(), p3.getX() - p2.getX());
+
+            double angleDifference = angle1 - angle2;
+            while (angleDifference < 0) angleDifference += Math.PI;
+
+            //test straight angles
+            boolean hasGoodVariant = false;
+
+            for (int quadrant = 0; quadrant <= 4; quadrant++) {
+                double difference = angleDifference - Math.PI / 2 * quadrant;
+                if (Math.abs(difference) <= tolerance)
+                    hasGoodVariant = true;
+            }
+
+            if (!hasGoodVariant)
+                return false;
+        }
+
+        return true;
+    }
+}
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/OsmBuilder.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/OsmBuilder.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/OsmBuilder.java	(revision 34609)
@@ -0,0 +1,192 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.pdfimport;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.Color;
+import java.awt.geom.Point2D;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.Relation;
+import org.openstreetmap.josm.data.osm.RelationMember;
+import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
+
+public class OsmBuilder {
+
+    enum Mode { Draft, Final, Debug }
+
+    private final FilePlacement placement;
+
+    private String layerName;
+    private String fillName;
+    private String lineName;
+    private Mode mode;
+
+    private ProgressMonitor monitor;
+    private int monitorPos;
+    private int monitorTotal;
+
+    public OsmBuilder(FilePlacement placement) {
+        this.placement = placement;
+    }
+
+    public DataSet build(List<LayerContents> data, Mode mode, ProgressMonitor monitor) {
+
+        this.monitor = monitor;
+        this.monitorPos = 0;
+        this.mode = mode;
+        DataSet result = new DataSet();
+
+        //count total items for progress monitor.
+        this.monitorTotal = 0;
+        for (LayerContents layer: data) {
+            this.monitorTotal += layer.paths.size();
+            for (PdfMultiPath mp: layer.multiPaths) {
+                this.monitorTotal += mp.paths.size();
+            }
+        }
+
+        monitor.beginTask(tr("Building JOSM layer"), this.monitorTotal);
+
+
+        for (LayerContents layer: data) {
+            this.addLayer(result, layer);
+        }
+
+        monitor.finishTask();
+        return result;
+    }
+
+    private void addLayer(DataSet target, LayerContents layer) {
+        Map<Point2D, Node> point2Node = new HashMap<>();
+
+        this.fillName = this.printColor(layer.info.fill);
+        this.lineName = this.printColor(layer.info.stroke);
+        this.layerName = "" + layer.info.nr;
+
+        //insert nodes
+        for (Point2D pt: layer.points) {
+            Node node = new Node();
+            node.setCoor(this.placement.tranformCoords(pt));
+
+            target.addPrimitive(node);
+            point2Node.put(pt, node);
+        }
+
+        //insert ways
+        Map<PdfPath, Way> path2Way = new HashMap<>();
+
+        for (PdfPath path: layer.paths) {
+            Way w = this.insertWay(path, point2Node, -1, false);
+            target.addPrimitive(w);
+            path2Way.put(path, w);
+        }
+
+        int pathId = 0;
+        for (PdfMultiPath mpath: layer.multiPaths) {
+            for (PdfPath path: mpath.paths) {
+                Way w = this.insertWay(path, point2Node, pathId, true);
+                target.addPrimitive(w);
+                path2Way.put(path, w);
+            }
+            pathId++;
+        }
+
+        if (this.mode != Mode.Draft) {
+            //insert relations
+            for (PdfMultiPath mpath: layer.multiPaths) {
+                Relation rel = new Relation();
+
+                Map<String, String> keys = new HashMap<>();
+                keys.put("type", "multipolygon");
+                keys.put("area", "yes");
+                rel.setKeys(keys);
+
+                for (PdfPath path: mpath.paths) {
+                    Way w = path2Way.get(path);
+                    rel.addMember(new RelationMember("", w));
+                }
+
+                target.addPrimitive(rel);
+            }
+        }
+    }
+
+    private Way insertWay(PdfPath path, Map<Point2D, Node> point2Node, int multipathId, boolean multipolygon) {
+
+        if (this.monitorPos % 100 == 0) {
+            monitor.setExtraText(tr(" "+this.monitorPos+"/"+this.monitorTotal));
+            monitor.setTicks(this.monitorPos);
+        }
+        this.monitorPos++;
+
+        List<Node> nodes = new ArrayList<>(path.points.size());
+
+        for (Point2D point: path.points) {
+            Node node = point2Node.get(point);
+            if (node == null) {
+                throw new RuntimeException();
+            }
+
+            nodes.add(node);
+        }
+
+        Map<String, String> keys = new HashMap<>();
+
+        if (this.mode != Mode.Draft) {
+            keys.put("PDF_nr", "" + path.nr);
+            keys.put("PDF_layer", this.layerName);
+
+            if (path.isClosed()) {
+                keys.put("PDF_closed", "yes");
+            }
+
+            if (this.fillName != null) {
+                keys.put("PDF_fillColor", this.fillName);
+            }
+
+            if (this.lineName != null) {
+                keys.put("PDF_lineColor", this.lineName);
+            }
+
+            if (multipathId != -1) {
+                keys.put("PDF_multipath", ""+ multipathId);
+            } else if (path.layer.info.fill != null && !multipolygon) {
+                keys.put("area", "yes");
+            }
+        }
+
+        if (this.mode == Mode.Debug) {
+
+            keys.put("PDF_pathLayer", ""+path.layer.info.nr);
+            keys.put("PDF_lineWidth", ""+path.layer.info.width);
+            keys.put("PDF_lineDash", ""+path.layer.info.dash);
+            keys.put("PDF_layerHash", ""+path.layer.info.hashCode());
+            keys.put("PDF_layerDivider", ""+path.layer.info.divider);
+        }
+
+        Way newWay = new Way();
+        newWay.setNodes(nodes);
+        newWay.setKeys(keys);
+        return newWay;
+    }
+
+    private String printColor(Color col) {
+        if (col == null) {
+            return null;
+        }
+
+        String s = Integer.toHexString(col.getRGB() & 0xffffff);
+        while (s.length() < 6) {
+            s = "0" + s;
+        }
+
+        return "#" + s;
+    }
+}
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/ParallelSegmentsFinder.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/ParallelSegmentsFinder.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/ParallelSegmentsFinder.java	(revision 34609)
@@ -0,0 +1,169 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.pdfimport;
+
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class ParallelSegmentsFinder {
+    public double angle;
+    public double angleSum;
+    public int refCount;
+    public List<PdfPath> paths = new ArrayList<>();
+
+    public void addPath(PdfPath path, double angle2) {
+        angleSum += angle2;
+        paths.add(path);
+        angle = angleSum /paths.size();
+    }
+
+    public List<ParallelSegmentsFinder> splitByDistance(double maxDistance) {
+        //sort perpendicular to angle
+        AffineTransform tr = new AffineTransform();
+        tr.rotate(-angle);
+
+        final Map<PdfPath, Point2D> positions = new HashMap<>();
+        Point2D src = new Point2D.Double();
+
+        for (PdfPath path: paths) {
+            src.setLocation((path.firstPoint().getX() + path.lastPoint().getX()) / 2, (path.firstPoint().getY() + path.lastPoint().getY()) / 2);
+            Point2D dest = new Point2D.Double();
+            Point2D destA = new Point2D.Double();
+            Point2D destB = new Point2D.Double();
+            tr.transform(src, dest);
+            tr.transform(path.firstPoint(), destA);
+            tr.transform(path.lastPoint(), destB);
+            positions.put(path, dest);
+        }
+        //point.y = Perpendicular lines, point.x = parallel lines
+
+        Collections.sort(paths, new Comparator<PdfPath>() {
+            @Override
+            public int compare(PdfPath o1, PdfPath o2) {
+                double y1 = positions.get(o1).getY();
+                double y2 = positions.get(o2).getY();
+                return y1 > y2 ? 1 : y1 < y2 ? -1 : 0;
+            }
+        });
+
+        //process sweep
+        List<ParallelSegmentsFinder> result = new ArrayList<>();
+
+        Map<PdfPath, ParallelSegmentsFinder> sweepLine = new HashMap<>();
+
+        Set<ParallelSegmentsFinder> adjacentClustersSet = new HashSet<>();
+        List<ParallelSegmentsFinder> adjacentClusters = new ArrayList<>();
+        List<PdfPath> pathsToRemove = new ArrayList<>();
+
+        for (PdfPath path: paths) {
+            adjacentClusters.clear();
+            adjacentClustersSet.clear();
+            pathsToRemove.clear();
+
+            for (PdfPath p: sweepLine.keySet()) {
+                Point2D pathPos = positions.get(path);
+                Point2D pPos = positions.get(p);
+
+                if (pathPos.getY() - pPos.getY() > maxDistance) {
+                    //path too far from sweep line
+                    pathsToRemove.add(p);
+                } else {
+
+                    double distance = distanceLineLine(path, p);
+
+                    if (distance <= maxDistance) {
+                        if (adjacentClustersSet.add(sweepLine.get(p))) {
+                            adjacentClusters.add(sweepLine.get(p));
+                        }
+                    }
+                }
+            }
+
+            //remove segments too far apart
+            for (PdfPath p: pathsToRemove) {
+                ParallelSegmentsFinder finder = sweepLine.remove(p);
+                finder.refCount--;
+                if (finder.refCount == 0) {
+                    result.add(finder);
+                }
+            }
+
+            //join together joinable parts
+            if (adjacentClusters.size() > 0) {
+                ParallelSegmentsFinder finder = adjacentClusters.remove(0);
+                finder.paths.add(path);
+                sweepLine.put(path, finder);
+                finder.refCount++;
+
+                for (ParallelSegmentsFinder finder1: adjacentClusters) {
+                    for (PdfPath path1: finder1.paths) {
+                        finder.paths.add(path1);
+                        sweepLine.put(path1, finder);
+                        finder.refCount++;
+                    }
+                }
+            } else {
+                ParallelSegmentsFinder finder = new ParallelSegmentsFinder();
+                finder.addPath(path, angle);
+                sweepLine.put(path, finder);
+                finder.refCount = 1;
+            }
+        }
+
+        //process remaining paths in sweep line
+        for (PdfPath p: sweepLine.keySet()) {
+            ParallelSegmentsFinder finder = sweepLine.get(p);
+            finder.refCount--;
+            if (finder.refCount == 0) {
+                result.add(finder);
+            }
+        }
+
+        return result;
+    }
+
+    private double distanceLineLine(PdfPath p1, PdfPath p2) {
+        return distanceLineLine(p1.firstPoint(), p1.lastPoint(), p2.firstPoint(), p2.lastPoint());
+    }
+
+    private double distanceLineLine(Point2D p1, Point2D p2, Point2D p3, Point2D p4) {
+        double dist1 = closestPointToSegment(p1, p2, p3).distance(p3);
+        double dist2 = closestPointToSegment(p1, p2, p4).distance(p4);
+        double dist3 = closestPointToSegment(p3, p4, p1).distance(p1);
+        double dist4 = closestPointToSegment(p3, p4, p2).distance(p2);
+        return Math.min(Math.min(dist1, dist2), Math.min(dist3, dist4));
+    }
+
+    /**
+     * Calculates closest point to a line segment.
+     * @return segmentP1 if it is the closest point, segmentP2 if it is the closest point,
+     * a new point if closest point is between segmentP1 and segmentP2.
+     */
+    public static Point2D closestPointToSegment(Point2D segmentP1, Point2D segmentP2, Point2D point) {
+
+        double ldx = segmentP2.getX() - segmentP1.getX();
+        double ldy = segmentP2.getY() - segmentP1.getY();
+
+        if (ldx == 0 && ldy == 0) //segment zero length
+            return segmentP1;
+
+        double pdx = point.getX() - segmentP1.getX();
+        double pdy = point.getY() - segmentP1.getY();
+
+        double offset = (pdx * ldx + pdy * ldy) / (ldx * ldx + ldy * ldy);
+
+        if (offset <= 0)
+            return segmentP1;
+        else if (offset >= 1)
+            return segmentP2;
+        else
+            return new Point2D.Double(segmentP1.getX() + ldx * offset, segmentP1.getY() + ldy * offset);
+    }
+}
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/PathOptimizer.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/PathOptimizer.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/PathOptimizer.java	(revision 34609)
@@ -0,0 +1,758 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.pdfimport;
+
+import java.awt.Color;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class PathOptimizer {
+
+    public List<Point2D> uniquePoints;
+    public Map<Point2D, Point2D> uniquePointMap;
+    private final Map<LayerInfo, LayerContents> layerMap;
+    private List<LayerContents> layers;
+    public Rectangle2D bounds;
+    private final double pointsTolerance;
+    private final Color color;
+    boolean splitOnColorChange;
+
+    LayerContents prevLayer = null;
+
+    public PathOptimizer(double _pointsTolerance, Color _color, boolean _splitOnColorChange) {
+        uniquePointMap = new HashMap<>();
+        uniquePoints = new ArrayList<>();
+        layerMap = new HashMap<>();
+        layers = new ArrayList<>();
+        pointsTolerance = _pointsTolerance;
+        color = _color;
+        splitOnColorChange = _splitOnColorChange;
+    }
+
+    public Point2D getUniquePoint(Point2D point) {
+
+        if (uniquePointMap.containsKey(point)) {
+            return uniquePointMap.get(point);
+        } else {
+            uniquePointMap.put(point, point);
+            uniquePoints.add(point);
+            return point;
+        }
+    }
+
+    public void addPath(LayerInfo info, PdfPath path) {
+        if (!isColorOK(info)) {
+            return;
+        }
+
+        LayerContents layer = this.getLayer(info);
+        layer.paths.add(path);
+    }
+
+    public void addMultiPath(LayerInfo info, List<PdfPath> paths) {
+
+        if (!isColorOK(info)) {
+            return;
+        }
+
+        LayerContents layer = this.getLayer(info);
+
+        //optimize the paths
+        Set<Point2D> points = new HashSet<>();
+        for (PdfPath path: paths) {
+            points.addAll(path.points);
+        }
+        LayerContents multipathLayer = new LayerContents();
+        multipathLayer.paths = paths;
+        Map<Point2D, Point2D> pointMap = DuplicateNodesFinder.findDuplicateNodes(points, pointsTolerance);
+        this.fixPoints(multipathLayer, pointMap);
+        this.concatenatePaths(multipathLayer);
+
+        paths = multipathLayer.paths;
+
+        boolean goodMultiPath = true;
+        for (PdfPath path: paths) {
+            goodMultiPath &= path.isClosed();
+        }
+
+        if (goodMultiPath) {
+            PdfMultiPath p = new PdfMultiPath(paths);
+            layer.multiPaths.add(p);
+        } else {
+            layer.paths.addAll(paths);
+        }
+    }
+
+    private boolean isColorOK(LayerInfo info) {
+
+        if (color == null) {
+            return true;
+        }
+
+        int rgb = color.getRGB() & 0xffffff;
+        boolean good = false;
+
+        if (info.fill != null && (info.fill.getRGB() & 0xffffff) == rgb) {
+            good = true;
+        }
+
+        if (info.stroke != null && (info.stroke.getRGB() & 0xffffff) == rgb) {
+            good = true;
+        }
+
+        return good;
+    }
+
+    public void removeParallelLines(double maxDistance) {
+        for (LayerContents layer: this.layers) {
+            this.removeParallelLines(layer, maxDistance);
+        }
+    }
+
+    public void mergeNodes() {
+        Map<Point2D, Point2D> pointMap = DuplicateNodesFinder.findDuplicateNodes(uniquePoints, pointsTolerance);
+
+        for (LayerContents layer: this.layers) {
+            this.fixPoints(layer, pointMap);
+        }
+    }
+
+    public void mergeSegments() {
+        for (LayerContents layer: this.layers) {
+            this.concatenatePaths(layer);
+        }
+    }
+
+    public void removeSmallObjects(double tolerance) {
+        for (LayerContents layer: this.layers) {
+            this.removeSmallObjects(layer, tolerance, Double.POSITIVE_INFINITY);
+        }
+    }
+
+    public void removeLargeObjects(double tolerance) {
+        for (LayerContents layer: this.layers) {
+            this.removeSmallObjects(layer, 0.0, tolerance);
+        }
+    }
+
+    public void splitLayersBySimilarShapes(double tolerance) {
+        List<LayerContents> newLayers = new ArrayList<>();
+        for (LayerContents l: this.layers) {
+            List<LayerContents> splitResult = splitBySimilarGroups(l);
+
+            for (LayerContents ll: splitResult) {
+                newLayers.add(ll);
+            }
+        }
+        this.layers = newLayers;
+    }
+
+    public void splitLayersByPathKind(boolean closed, boolean single, boolean orthogonal) {
+        List<LayerContents> newLayers = new ArrayList<>();
+        for (LayerContents l: this.layers) {
+            List<LayerContents> splitResult = splitBySegmentKind(l, closed, single, orthogonal);
+
+            for (LayerContents ll: splitResult) {
+                newLayers.add(ll);
+            }
+        }
+
+        this.layers = newLayers;
+    }
+
+    public void finish() {
+        int nr = 0;
+        for (LayerContents layer: this.layers) {
+            layer.info.nr = nr;
+            nr++;
+            finalizeLayer(layer);
+        }
+    }
+
+    private LayerContents getLayer(LayerInfo info) {
+
+        LayerContents layer = null;
+
+        if (this.layerMap.containsKey(info)) {
+            layer = this.layerMap.get(info);
+
+            if (layer != this.prevLayer && this.splitOnColorChange) {
+                layer = null;
+            }
+        }
+
+        if (layer == null) {
+            layer = new LayerContents();
+            layer.info = info.copy();
+            layer.info.nr = this.layers.size();
+            this.layerMap.put(layer.info, layer);
+            this.layers.add(layer);
+        }
+
+        this.prevLayer = layer;
+        return layer;
+    }
+
+    private void finalizeLayer(LayerContents layer) {
+        Set<Point2D> points = new HashSet<>();
+        layer.points = new ArrayList<>();
+
+        for (PdfPath pp: layer.paths) {
+            pp.layer = layer;
+
+            for (Point2D point: pp.points) {
+                if (!points.contains(point)) {
+                    layer.points.add(point);
+                    points.add(point);
+                }
+            }
+        }
+
+        for (PdfMultiPath multipath: layer.multiPaths) {
+            multipath.layer = layer;
+            for (PdfPath pp: multipath.paths) {
+                pp.layer = layer;
+
+                for (Point2D point: pp.points) {
+                    if (!points.contains(point)) {
+                        layer.points.add(point);
+                        points.add(point);
+                    }
+                }
+            }
+        }
+    }
+
+    private void fixPoints(LayerContents layer, Map<Point2D, Point2D> pointMap) {
+
+        List<PdfPath> newPaths = new ArrayList<>(layer.paths.size());
+
+        for (PdfPath path: layer.paths) {
+            List<Point2D> points = fixPoints(path.points, pointMap);
+            path.points = points;
+            if (points.size() > 2 || (!path.isClosed() && points.size() > 1)) {
+
+                newPaths.add(path);
+            }
+        }
+
+        layer.paths = newPaths;
+
+        for (PdfMultiPath mp: layer.multiPaths) {
+            for (PdfPath path: mp.paths) {
+                path.points = fixPoints(path.points, pointMap);
+            }
+        }
+    }
+
+    private List<Point2D> fixPoints(List<Point2D> points, Map<Point2D, Point2D> pointMap) {
+
+        List<Point2D> newPoints = new ArrayList<>(points.size());
+        Point2D prevPoint = null;
+
+        for (Point2D p: points) {
+            Point2D pp = p;
+
+            if (pointMap.containsKey(p)) {
+                pp = pointMap.get(p);
+            }
+
+            if (prevPoint != pp) {
+                newPoints.add(pp);
+            }
+
+            prevPoint = pp;
+        }
+
+        return newPoints;
+    }
+
+    private void removeSmallObjects(LayerContents layer, double min, double max) {
+        List<PdfPath> newPaths = new ArrayList<>(layer.paths.size());
+
+        for (PdfPath path: layer.paths) {
+            double size = getShapeSize(path);
+            boolean good = size >= min && size <= max;
+
+            if (good) {
+                newPaths.add(path);
+            }
+        }
+
+        layer.paths = newPaths;
+
+        List<PdfMultiPath> newMPaths = new ArrayList<>(layer.multiPaths.size());
+
+        for (PdfMultiPath mp: layer.multiPaths) {
+            boolean good = true;
+            for (PdfPath path: mp.paths) {
+                double size = getShapeSize(path);
+                good &= size >= min && size <= max;
+            }
+
+            if (good) {
+                newMPaths.add(mp);
+            }
+        }
+
+        layer.multiPaths = newMPaths;
+    }
+
+    private double getShapeSize(PdfPath path) {
+
+        Rectangle2D bounds = new Rectangle2D.Double();
+        bounds.setRect(path.points.get(0).getX(), path.points.get(0).getY(), 0, 0);
+
+        for (Point2D n: path.points) {
+            bounds.add(n);
+        }
+
+        return Math.max(bounds.getWidth(), bounds.getHeight());
+    }
+
+    /***
+     * This method finds parralel lines with similar distance and removes them.
+     */
+    private void removeParallelLines(LayerContents layer, double maxDistance) {
+        double angleTolerance = 1.0 / 180.0 * Math.PI; // 1 degree
+        int minSegments = 10;
+
+        //filter paths by direction
+        List<ParallelSegmentsFinder> angles = new ArrayList<>();
+
+        for (PdfPath path: layer.paths) {
+            if (path.points.size() != 2) {
+                continue;
+            }
+
+            Point2D p1 = path.firstPoint();
+            Point2D p2 = path.lastPoint();
+            double angle = Math.atan2(p2.getX() - p1.getX(), p2.getY() - p1.getY());
+            //normalize between 0 and 180 degrees
+            while (angle < 0) angle += Math.PI;
+            while (angle > Math.PI) angle -= Math.PI;
+            boolean added = false;
+
+            for (ParallelSegmentsFinder pa: angles) {
+                if (Math.abs(pa.angle - angle) < angleTolerance) {
+                    pa.addPath(path, angle);
+                    added = true;
+                    break;
+                }
+            }
+
+            if (!added) {
+                ParallelSegmentsFinder pa = new ParallelSegmentsFinder();
+                pa.addPath(path, angle);
+                angles.add(pa);
+            }
+        }
+
+        Set<PdfPath> pathsToRemove = new HashSet<>();
+
+        //process each direction
+        for (ParallelSegmentsFinder pa: angles) {
+            if (pa.paths.size() < minSegments) {
+                continue;
+            }
+
+            List<ParallelSegmentsFinder> parts = pa.splitByDistance(maxDistance);
+
+            for (ParallelSegmentsFinder part: parts) {
+                if (part.paths.size() >= minSegments) {
+                    pathsToRemove.addAll(part.paths);
+                }
+            }
+        }
+
+        //generate new path list
+        List<PdfPath> result = new ArrayList<>(layer.paths.size() - pathsToRemove.size());
+
+        for (PdfPath path: layer.paths) {
+            if (!pathsToRemove.contains(path)) {
+                result.add(path);
+            }
+        }
+
+        layer.paths = result;
+    }
+
+
+    /**
+     * This method merges together paths with common end nodes.
+     * @param layer the layer to process.
+     */
+    private void concatenatePaths(LayerContents layer) {
+        Map<Point2D, List<PdfPath>> pathEndpoints = new HashMap<>();
+        Set<PdfPath> mergedPaths = new HashSet<>();
+        List<PdfPath> newPaths = new ArrayList<>();
+
+        //fill pathEndpoints map
+        for (PdfPath pp: layer.paths) {
+            if (pp.isClosed()) {
+                newPaths.add(pp);
+                continue;
+            }
+
+            List<PdfPath> paths = pathEndpoints.get(pp.firstPoint());
+            if (paths == null) {
+                paths = new ArrayList<>(2);
+                pathEndpoints.put(pp.firstPoint(), paths);
+            }
+            paths.add(pp);
+
+            paths = pathEndpoints.get(pp.lastPoint());
+            if (paths == null) {
+                paths = new ArrayList<>(2);
+                pathEndpoints.put(pp.lastPoint(), paths);
+            }
+            paths.add(pp);
+        }
+
+        List<PdfPath> pathChain = new ArrayList<>(2);
+        Set<Point2D> pointsInPath = new HashSet<>();
+
+        //join the paths
+        for (PdfPath pp: layer.paths) {
+
+            if (pp.isClosed() || mergedPaths.contains(pp)) {
+                continue;
+            }
+
+            boolean changed = true;
+
+            PdfPath firstPath = pp;
+            PdfPath lastPath = pp;
+            Point2D firstPoint = pp.firstPoint();
+            Point2D lastPoint = pp.lastPoint();
+
+
+            pathChain.clear();
+            pathChain.add(pp);
+            pointsInPath.clear();
+            pointsInPath.add(firstPoint);
+            pointsInPath.add(lastPoint);
+
+            //process last point
+            while (changed && firstPoint != lastPoint) {
+                changed = false;
+
+                List<PdfPath> adjacentPaths = pathEndpoints.get(lastPoint);
+                PdfPath nextPath = findNextPath(adjacentPaths, lastPath);
+
+                if (nextPath != null) {
+                    Point2D nextPoint = nextPath.getOtherEnd(lastPoint);
+
+                    lastPoint = nextPoint;
+                    lastPath = nextPath;
+                    pathChain.add(lastPath);
+
+                    if (!pointsInPath.contains(lastPoint)) {
+                        pointsInPath.add(lastPoint);
+                        changed = true;
+                    } else {
+                        //closed path found
+                        //remove excess segments from start of chain
+                        while (lastPoint != firstPoint) {
+                            PdfPath pathToRemove = pathChain.remove(0);
+                            firstPoint = pathToRemove.getOtherEnd(firstPoint);
+                        }
+
+                        changed = false;
+                    }
+                }
+            }
+
+            //process first point
+            changed = true;
+            while (changed && firstPoint != lastPoint) {
+                changed = false;
+
+                List<PdfPath> adjacentPaths = pathEndpoints.get(firstPoint);
+                PdfPath nextPath = findNextPath(adjacentPaths, firstPath);
+
+                if (nextPath != null) {
+                    Point2D nextPoint = nextPath.getOtherEnd(firstPoint);
+
+                    firstPoint = nextPoint;
+                    firstPath = nextPath;
+                    pathChain.add(0, firstPath);
+
+                    if (!pointsInPath.contains(firstPoint)) {
+                        pointsInPath.add(firstPoint);
+                        changed = true;
+                    } else {
+                        //closed path found
+                        //remove excess segments from end of chain
+                        while (lastPoint != firstPoint) {
+                            PdfPath pathToRemove = pathChain.remove(pathChain.size() - 1);
+                            lastPoint = pathToRemove.getOtherEnd(lastPoint);
+                        }
+
+                        changed = false;
+                    }
+                }
+            }
+
+            //remove from map
+            for (PdfPath path: pathChain) {
+                pathEndpoints.get(path.firstPoint()).remove(path);
+                pathEndpoints.get(path.lastPoint()).remove(path);
+                mergedPaths.add(path);
+            }
+
+            //construct path
+            PdfPath path = pathChain.get(0);
+
+            for (int pos = 1; pos < pathChain.size(); pos++) {
+                path.points = tryMergeNodeLists(path.points, pathChain.get(pos).points);
+
+                if (path.points == null) {
+                    throw new RuntimeException();
+                }
+            }
+
+            newPaths.add(path);
+        }
+
+        layer.paths = newPaths;
+    }
+
+    private PdfPath findNextPath(List<PdfPath> adjacentPaths, PdfPath firstPath) {
+        for (int pos = 0; pos < adjacentPaths.size(); pos++) {
+            PdfPath p = adjacentPaths.get(pos);
+            if (p != firstPath && !isSubpathOf(firstPath, p)) {
+                return p;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Tests if sub is subpath of main.
+     */
+    private boolean isSubpathOf(PdfPath main, PdfPath sub) {
+
+        Set<Point2D> points = new HashSet<>(main.points);
+
+        for (Point2D point: sub.points) {
+            if (!points.contains(point)) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    private List<LayerContents> splitBySegmentKind(LayerContents layer, boolean closed, boolean single, boolean orthogonal) {
+        if (!closed && !single) {
+            return Collections.singletonList(layer);
+        }
+
+        OrthogonalShapesFilter of = new OrthogonalShapesFilter(10);
+
+        List<PdfPath> singleSegmentPaths = new ArrayList<>();
+        List<PdfPath> multiSegmentPaths = new ArrayList<>();
+        List<PdfPath> closedPaths = new ArrayList<>();
+        List<PdfPath> orthogonalPaths = new ArrayList<>();
+        List<PdfPath> orthogonalClosedPaths = new ArrayList<>();
+
+        for (PdfPath path: layer.paths) {
+            boolean pathOrthgonal = orthogonal && of.isOrthogonal(path);
+            boolean pathUnclosed = !path.isClosed() && closed;
+            boolean pathSingleSegment = path.points.size() <= 3 && single;
+
+            if (pathSingleSegment) {
+                singleSegmentPaths.add(path);
+            } else if (pathUnclosed) {
+                if (pathOrthgonal) {
+                    orthogonalPaths.add(path);
+                } else {
+                    multiSegmentPaths.add(path);
+                }
+            } else {
+                if (pathOrthgonal) {
+                    orthogonalClosedPaths.add(path);
+                } else {
+                    closedPaths.add(path);
+                }
+            }
+        }
+
+        List<LayerContents> layers = new ArrayList<>();
+
+        if (multiSegmentPaths.size() > 0) {
+            LayerContents l = new LayerContents();
+            l.paths = multiSegmentPaths;
+            l.info = layer.info.copy();
+
+            layers.add(l);
+        }
+
+        if (singleSegmentPaths.size() > 0) {
+            LayerContents l = new LayerContents();
+            l.paths = singleSegmentPaths;
+            l.info = layer.info.copy();
+            layers.add(l);
+        }
+
+        if (orthogonalPaths.size() > 0) {
+            LayerContents l = new LayerContents();
+            l.paths = orthogonalPaths;
+            l.info = layer.info.copy();
+            layers.add(l);
+        }
+
+        if (orthogonalClosedPaths.size() > 0) {
+            LayerContents l = new LayerContents();
+            l.paths = orthogonalClosedPaths;
+            l.info = layer.info.copy();
+            layers.add(l);
+        }
+
+        if (closedPaths.size() > 0 || layer.multiPaths.size() > 0) {
+            LayerContents l = new LayerContents();
+            l.paths = closedPaths;
+            l.info = layer.info.copy();
+            l.multiPaths = layer.multiPaths;
+            layers.add(l);
+        }
+
+        return layers;
+    }
+
+    private List<LayerContents> splitBySimilarGroups(LayerContents layer) {
+        List<List<PdfPath>> subparts = new ArrayList<>();
+
+        //split into similar parts
+        for (PdfPath path: layer.paths) {
+            List<PdfPath> sublayer = null;
+
+            for (List<PdfPath> ll: subparts) {
+                if (this.pathsSimilar(ll.get(0).points, path.points)) {
+                    sublayer = ll;
+                    break;
+                }
+            }
+
+            if (sublayer == null) {
+                sublayer = new ArrayList<>();
+                subparts.add(sublayer);
+            }
+
+            sublayer.add(path);
+        }
+
+        //get groups
+        int minGroupTreshold = 10;
+
+        List<PdfPath> independantPaths = new ArrayList<>();
+        List<LayerContents> result = new ArrayList<>();
+
+        for (List<PdfPath> list: subparts) {
+            if (list.size() >= minGroupTreshold) {
+                LayerContents l = new LayerContents();
+                l.paths = list;
+                l.info = layer.info.copy();
+                l.info.isGroup = true;
+                l.multiPaths = Collections.emptyList();
+                result.add(l);
+            } else {
+                independantPaths.addAll(list);
+            }
+        }
+
+        if (independantPaths.size() > 0 || layer.multiPaths.size() > 0) {
+            LayerContents l = new LayerContents();
+            l.paths = independantPaths;
+            l.info = layer.info.copy();
+            l.info.isGroup = false;
+            l.multiPaths = layer.multiPaths;
+            result.add(l);
+        }
+
+        return result;
+    }
+
+    private List<Point2D> tryMergeNodeLists(List<Point2D> nodes1, List<Point2D> nodes2) {
+
+        boolean nodes1Closed = (nodes1.get(0) == nodes1.get(nodes1.size() - 1));
+        boolean nodes2Closed = (nodes2.get(0) == nodes2.get(nodes2.size() - 1));
+
+        if (nodes1Closed || nodes2Closed) {
+            return null;
+        }
+
+        if (nodes1.get(nodes1.size() - 1) == nodes2.get(0)) {
+            nodes1.remove(nodes1.size() -1);
+            nodes1.addAll(nodes2);
+            return nodes1;
+        } else if (nodes1.get(nodes1.size() - 1) == nodes2.get(nodes2.size() -1)) {
+            nodes1.remove(nodes1.size() -1);
+            for (int pos = nodes2.size() - 1; pos >= 0; pos--) {
+                nodes1.add(nodes2.get(pos));
+            }
+
+            return nodes1;
+        } else if (nodes1.get(0) == nodes2.get(nodes2.size() - 1)) {
+            nodes1.remove(0);
+            nodes1.addAll(0, nodes2);
+            return nodes1;
+        } else if (nodes1.get(0) == nodes2.get(0)) {
+            nodes1.remove(0);
+            for (int pos = 0; pos < nodes2.size(); pos++) {
+                nodes1.add(0, nodes2.get(pos));
+            }
+
+            return nodes1;
+        } else {
+            return null;
+        }
+    }
+
+    public List<LayerContents> getLayers() {
+        return this.layers;
+    }
+
+    /**
+     * Test if paths are different only by offset.
+     */
+    private boolean pathsSimilar(List<Point2D> path1, List<Point2D> path2) {
+        if (path1.size() != path2.size()) {
+            return false;
+        }
+
+        if (path1.size() < 3) {
+            return false;
+            //cannot judge so small paths
+        }
+
+        Point2D p1 = path1.get(0);
+        Point2D p2 = path2.get(0);
+
+        double offsetX = p1.getX() - p2.getX();
+        double offsetY = p1.getY() - p2.getY();
+        double tolerance = 1e-4;
+
+        for (int pos = 0; pos < path1.size(); pos++) {
+            p1 = path1.get(pos);
+            p2 = path2.get(pos);
+
+            double errorX = p1.getX() - p2.getX() - offsetX;
+            double errorY = p1.getY() - p2.getY() - offsetY;
+
+            if (Math.abs(errorX) + Math.abs(errorY) > tolerance) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+}
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/PdfImportAction.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/PdfImportAction.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/PdfImportAction.java	(revision 34609)
@@ -0,0 +1,41 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.pdfimport;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+
+import org.openstreetmap.josm.actions.JosmAction;
+import org.openstreetmap.josm.tools.Shortcut;
+
+/**
+ * Loads a PDF file into a new layer.
+ *
+ */
+public class PdfImportAction extends JosmAction {
+
+    public PdfImportAction() {
+        super(tr("Import PDF file"), "pdf_import",
+            tr("Import PDF file."),
+            Shortcut.registerShortcut("tools:pdfimport", tr("Tool: {0}", tr("Import PDF file")),
+            KeyEvent.VK_F, Shortcut.ALT_CTRL_SHIFT), true);
+    }
+
+    /**
+     * The action button has been clicked
+     *
+     * @param e
+     *            Action Event
+     */
+    @Override
+    public void actionPerformed(ActionEvent e) {
+
+        //show dialog asking to select coordinate axes and input coordinates and projection.
+        /*
+         * TODO: make dialog reusable
+         */
+        LoadPdfDialog dialog = new LoadPdfDialog();
+        dialog.setTitle(tr("Import PDF"));
+    }
+}
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/PdfImportPlugin.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/PdfImportPlugin.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/PdfImportPlugin.java	(revision 34609)
@@ -0,0 +1,54 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.pdfimport;
+
+import org.openstreetmap.josm.gui.MainApplication;
+import org.openstreetmap.josm.gui.MainMenu;
+import org.openstreetmap.josm.gui.preferences.PreferenceSetting;
+import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane;
+import org.openstreetmap.josm.gui.preferences.SubPreferenceSetting;
+import org.openstreetmap.josm.gui.preferences.TabPreferenceSetting;
+import org.openstreetmap.josm.plugins.Plugin;
+import org.openstreetmap.josm.plugins.PluginInformation;
+
+/**
+ * A plugin to import a PDF file.
+ */
+public class PdfImportPlugin extends Plugin {
+
+    public PdfImportPlugin(PluginInformation info) {
+        super(info);
+        MainMenu.add(MainApplication.getMenu().imagerySubMenu, new PdfImportAction());
+        new Preferences(getPluginInformation().name);
+    }
+
+    public static class pdfimportPrefs implements SubPreferenceSetting {
+        @Override
+        public TabPreferenceSetting getTabPreferenceSetting(PreferenceTabbedPane gui) {
+            return null;
+        }
+
+        @Override
+        public void addGui(PreferenceTabbedPane gui) {
+            return;
+        }
+
+        @Override
+        public boolean ok() {
+            return false;
+        }
+
+        @Override
+        public boolean isExpert() {
+            return false;
+        }
+    }
+
+    @Override
+    public PreferenceSetting getPreferenceSetting() {
+        /*
+         * TODO: implement it
+         */
+        return new pdfimportPrefs();
+        }
+
+}
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/PdfMultiPath.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/PdfMultiPath.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/PdfMultiPath.java	(revision 34609)
@@ -0,0 +1,13 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.pdfimport;
+
+import java.util.List;
+
+public class PdfMultiPath {
+    public List<PdfPath> paths;
+    public LayerContents layer;
+
+    public PdfMultiPath(List<PdfPath> paths2) {
+        paths = paths2;
+    }
+}
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/PdfPath.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/PdfPath.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/PdfPath.java	(revision 34609)
@@ -0,0 +1,52 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.pdfimport;
+
+import java.awt.geom.Point2D;
+import java.util.List;
+
+public class PdfPath {
+    public List<Point2D> points;
+    public double length;
+
+    LayerContents layer;
+    public int nr;
+
+    public PdfPath(List<Point2D> nodes) {
+        points = nodes;
+    }
+
+    public boolean isClosed() {
+        return points.size() > 1 && points.get(0) == points.get(points.size() - 1);
+    }
+
+    public Point2D firstPoint() {
+        return points.get(0);
+    }
+
+    public Point2D lastPoint() {
+        return points.get(points.size() - 1);
+    }
+
+    public void calculateLength() {
+        double len = 0;
+
+        for (int pos = 1; pos < points.size(); pos++) {
+            len += points.get(pos).distance(points.get(pos -1));
+        }
+
+        this.length = len;
+    }
+
+    public Point2D getOtherEnd(Point2D endPoint) {
+        if (this.firstPoint() == endPoint) {
+            return this.lastPoint();
+        }
+
+        if (this.lastPoint() == endPoint) {
+            return this.firstPoint();
+        }
+
+        throw new RuntimeException("Unexpected point");
+
+    }
+}
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/Preferences.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/Preferences.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/Preferences.java	(revision 34609)
@@ -0,0 +1,122 @@
+/**
+ * License: GPL. For details, see LICENSE file.
+ */
+package org.openstreetmap.josm.plugins.pdfimport;
+
+import org.openstreetmap.josm.spi.preferences.Config;
+
+public class Preferences {
+
+    public enum GuiMode {
+        Auto, Expert, Simple
+    };
+
+    public static String getLoadDir() {
+        return     Config.getPref().get(Preferences.prefix + "loadDir");
+    }
+
+    public static void setLoadDir(String loadDir) {
+        Config.getPref().put(Preferences.prefix + "loadDir", loadDir);
+    }
+
+    public static GuiMode getGuiMode() {
+        int GuiCode = Config.getPref().getInt(Preferences.prefix + "guiCode", 0);
+        switch (GuiCode) {
+        case -1:
+        case 1:
+            return GuiMode.Expert;
+        case 2:
+            return GuiMode.Simple;
+        default:
+            if (Config.getPref().getBoolean("expert"))
+                return GuiMode.Expert;
+            else
+                return GuiMode.Simple;
+        }
+    }
+
+    public static boolean isLegacyActions() {
+        return (Config.getPref().getInt(Preferences.prefix + "guiCode", 0) == -1);
+    }
+
+    public static boolean isMergeNodes() {
+        return Config.getPref().getBoolean(Preferences.prefix + "mergeNodes");
+    }
+
+    public static double getMergeNodesValue() {
+        return Config.getPref().getDouble(Preferences.prefix + "mergeNodes.value", 1e-3);
+    }
+
+    public static boolean isRemoveSmall() {
+        return Config.getPref().getBoolean(Preferences.prefix + "removeSmall");
+    }
+
+    public static double getRemoveSmallValue() {
+        return Config.getPref().getDouble(Preferences.prefix + "removeSmall.value", 1);
+    }
+
+    public static boolean isRemoveLarge() {
+        return Config.getPref().getBoolean(Preferences.prefix + "removeLarge");
+    }
+
+    public static double getRemoveLargeValue() {
+        return Config.getPref().getDouble(Preferences.prefix + "removeLarge.value", 10);
+    }
+
+    public static boolean isRemoveParallel() {
+        return Config.getPref().getBoolean(Preferences.prefix + "removeParallel");
+    }
+
+    public static double getRemoveParallelValue() {
+        return Config.getPref().getDouble(Preferences.prefix + "removeParallel.value", 3);
+    }
+
+    public static boolean isLimitPath() {
+        return Config.getPref().getBoolean(Preferences.prefix + "limitPath");
+    }
+
+    public static int getLimitPathValue() {
+        return Config.getPref().getInt(Preferences.prefix + "limitPath.value", Integer.MAX_VALUE);
+    }
+
+    public static boolean isLimitColor() {
+        return Config.getPref().getBoolean(Preferences.prefix + "limitColor");
+    }
+
+    public static String getLimitColorValue() {
+        return Config.getPref().get(Preferences.prefix + "limitColor.value","#000000");
+    }
+
+    public static boolean isDebugTags() {
+        return Config.getPref().getBoolean(Preferences.prefix + "debugTags");
+    }
+
+    public static boolean isLayerClosed() {
+        return Config.getPref().getBoolean(Preferences.prefix + "layerClosed");
+    }
+
+    public static boolean isLayerSegment() {
+        return Config.getPref().getBoolean(Preferences.prefix + "layerSegment");
+    }
+
+    public static boolean isLayerAttribChange() {
+        return Config.getPref().getBoolean(Preferences.prefix + "layerAttribChanges");
+    }
+
+    public static boolean isLayerOrtho() {
+        return Config.getPref().getBoolean(Preferences.prefix + "layerOrtho");
+    }
+
+    protected static int GuiCode;
+
+    private static String prefix;
+
+    private Preferences() {
+        return;
+    }
+
+    public Preferences (String p) {
+        prefix = p + "." ;
+    }
+
+}
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/Preview.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/Preview.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/Preview.java	(revision 34609)
@@ -0,0 +1,41 @@
+/**
+ * License: GPL. For details, see LICENSE file.
+ */
+package org.openstreetmap.josm.plugins.pdfimport;
+
+import org.openstreetmap.josm.gui.MainApplication;
+import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+
+import com.drew.lang.annotations.NotNull;
+
+/**
+ * @author Nzara
+ *
+ */
+public class Preview {
+    public static OsmDataLayer dataLayer;
+    public static FilePlacement placement;
+    
+    public static synchronized void set (@NotNull OsmDataLayer dataLayer, @NotNull FilePlacement placement) {
+        clear();
+        Preview.dataLayer = dataLayer;
+        Preview.placement = placement;
+        MainApplication.getLayerManager().addLayer(dataLayer); 
+
+    }
+    
+    public static void clear() {
+        if (Preview.dataLayer != null) {
+            MainApplication.getLayerManager().removeLayer(Preview.dataLayer);
+            Preview.dataLayer.data.clear(); // saves memory
+        }
+        Preview.dataLayer = null;
+        Preview.placement = null;
+    }
+    
+    public void save() {
+//        TODO: implement
+    }
+
+
+}
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/ProjectionInfo.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/ProjectionInfo.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/ProjectionInfo.java	(revision 34609)
@@ -0,0 +1,47 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.pdfimport;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.openstreetmap.josm.data.projection.Projection;
+import org.openstreetmap.josm.gui.preferences.projection.ProjectionChoice;
+import org.openstreetmap.josm.gui.preferences.projection.ProjectionPreference;
+import org.openstreetmap.josm.gui.preferences.projection.SingleProjectionChoice;
+
+public final class ProjectionInfo {
+    private static Map<String, ProjectionChoice> allCodesPC = new HashMap<>();
+    private static Map<String, Projection> allCodes = new HashMap<>();
+
+    static {
+        for (ProjectionChoice pc : ProjectionPreference.getProjectionChoices()) {
+            for (String code : pc.allCodes()) {
+                allCodesPC.put(code, pc);
+            }
+        }
+    }
+
+    private ProjectionInfo() {
+        // Hide default constructor for utilities classes
+    }
+
+    public static Projection getProjectionByCode(String code) {
+        try {
+            ProjectionChoice pc = new SingleProjectionChoice(code.toString(), code.toString(), code);
+            Projection p = pc.getProjection();
+            return p;
+        } catch (Exception e) {
+            throw new IllegalArgumentException();
+        }
+
+//        Projection p = allCodes.get(code);
+//        if (p != null) return p;
+//        ProjectionChoice pc = allCodesPC.get(code);
+//        if (pc == null) return null;
+//        Collection<String> pref = pc.getPreferencesFromCode(code);
+//        pc.setPreferences(pref);
+//        p = pc.getProjection();
+//        allCodes.put(code, p);
+//        return p;
+    }
+}
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/GraphicsProcessor.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/GraphicsProcessor.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/GraphicsProcessor.java	(revision 34609)
@@ -0,0 +1,215 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.pdfimport.pdfbox;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Shape;
+import java.awt.Stroke;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.PathIterator;
+import java.awt.geom.Point2D;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
+import org.openstreetmap.josm.plugins.pdfimport.LayerInfo;
+import org.openstreetmap.josm.plugins.pdfimport.PathOptimizer;
+import org.openstreetmap.josm.plugins.pdfimport.PdfPath;
+
+public class GraphicsProcessor {
+
+    public PathOptimizer target;
+    private Shape clipShape;
+    private List<PdfPath> clipPath;
+    private final LayerInfo info = new LayerInfo();
+    int pathNo = 0;
+    private boolean complexClipShape;
+    private boolean clipAreaDrawn;
+
+    private final AffineTransform transform;
+    private final ProgressMonitor monitor;
+    private final int maxPaths;
+
+    public GraphicsProcessor(PathOptimizer target, int rotation, int maxPaths, ProgressMonitor monitor) {
+        this.maxPaths = maxPaths;
+        this.target = target;
+        this.transform = new AffineTransform();
+        this.transform.rotate(-Math.toRadians(rotation));
+        this.info.stroke = Color.BLACK;
+        this.info.fill = Color.BLACK;
+        this.monitor = monitor;
+    }
+
+    private void addPath(Shape s, boolean closed) {
+        pathNo++;
+
+        if (pathNo % 100 == 0) {
+            this.monitor.setCustomText(tr(" {0} objects so far", pathNo));
+        }
+
+        if (pathNo >= maxPaths) {
+            return;
+        }
+
+        List<PdfPath> paths = this.parsePath(s, closed);
+
+        for (PdfPath p: paths) {
+            p.nr = pathNo;
+        }
+
+
+        if (paths.size() > 1) {
+            this.target.addMultiPath(this.info, paths);
+            this.parsePath(s, closed);
+        } else if (paths.size() == 1) {
+            this.target.addPath(this.info, paths.get(0));
+        }
+    }
+
+    private List<PdfPath> parsePath(Shape s, boolean closed) {
+        List<PdfPath> result = new ArrayList<>(2);
+        List<Point2D> points = new ArrayList<>(2);
+
+        PathIterator iter = s.getPathIterator(null);
+        double[] coords = new double[6];
+
+        while (!iter.isDone()) {
+            int type = iter.currentSegment(coords);
+
+            if (type == PathIterator.SEG_CLOSE) {
+                //close polygon
+                this.addPoint(points, points.get(0));
+                if (points.size() > 1) {
+                    result.add(new PdfPath(points));
+                }
+                points = new ArrayList<>(2);
+            } else if (type == PathIterator.SEG_CUBICTO) {
+                //cubic curve
+                this.addPoint(points, this.parsePoint(coords, 4));
+            } else if (type == PathIterator.SEG_LINETO) {
+                this.addPoint(points, this.parsePoint(coords, 0));
+            } else if (type == PathIterator.SEG_MOVETO) {
+                //new path
+                if (points.size() > 1) {
+                    result.add(new PdfPath(points));
+                }
+                points = new ArrayList<>(2);
+                this.addPoint(points, this.parsePoint(coords, 0));
+            } else if (type == PathIterator.SEG_QUADTO) {
+                //quadratic curve
+                this.addPoint(points, this.parsePoint(coords, 2));
+            } else if (type == PathIterator.WIND_EVEN_ODD) {
+                //fill even odd
+            } else if (type == PathIterator.WIND_NON_ZERO) {
+                //fill all
+            }
+
+            iter.next();
+        }
+
+        if (points.size() > 1) {
+            if (closed) {
+                this.addPoint(points, points.get(0));
+            }
+
+            result.add(new PdfPath(points));
+        }
+
+        return result;
+    }
+
+    private void addPoint(List<Point2D> points, Point2D point) {
+        if (points.size() > 0) {
+            Point2D prevPoint = points.get(points.size() - 1);
+
+            if (prevPoint.getX() == point.getX() && prevPoint.getY() == point.getY()) {
+                return;
+            }
+        }
+
+        points.add(point);
+    }
+
+    private Point2D parsePoint(double[] buffer, int offset) {
+        //invert Y.
+        Point2D point = new Point2D.Double(buffer[offset], buffer[offset + 1]);
+        Point2D dest = new Point2D.Double();
+        this.transform.transform(point, dest);
+        return this.target.getUniquePoint(dest);
+    }
+
+    public void drawPath(Shape path, Color stroke, Color fill,
+            int windingRule) {
+
+        if (complexClipShape) {
+            if (!this.clipAreaDrawn) {
+                this.info.stroke = null;
+                this.info.fill = Color.CYAN;
+                this.addPath(this.clipShape, true);
+                this.clipAreaDrawn = true;
+            }
+        }
+
+        if (!complexClipShape || fill != null) {
+            this.info.stroke = stroke;
+            this.info.fill = fill;
+            this.addPath(path, fill != null);
+        }
+    }
+
+    public void drawImage() {
+
+        if (!this.clipAreaDrawn) {
+            this.info.stroke = null;
+            this.info.fill = Color.CYAN;
+            this.addPath(this.clipShape, true);
+            this.clipAreaDrawn = true;
+        }
+    }
+
+    public void setClip(Shape clip) {
+        if (this.shapesEqual(this.clipShape, clip))
+            return;
+
+        this.clipPath = this.parsePath(clip, true);
+
+        boolean complexClipPath = false;
+
+        if (clipPath.size() > 1) {
+            complexClipPath = true;
+        } else if (clipPath.size() == 1 && clipPath.get(0).points.size() > 5) {
+            //more than 4 points.
+            complexClipPath = true;
+        }
+
+        this.complexClipShape = complexClipPath;
+        this.clipAreaDrawn = false;
+        this.clipShape = clip;
+    }
+
+    private boolean shapesEqual(Shape shape1, Shape shape2) {
+
+        if (shape1 == null || shape2 == null) {
+            return false;
+        }
+
+        return shape1.getBounds2D().equals(shape2.getBounds2D());
+    }
+
+    public void setStroke(Stroke s) {
+        BasicStroke stroke = (BasicStroke) s;
+        this.info.width = stroke.getLineWidth();
+        this.info.dash = 0;
+
+        if (stroke.getDashArray() != null) {
+            this.info.dash = Arrays.hashCode(stroke.getDashArray());
+        }
+    }
+
+    public void drawString(float x, float y, String character, Color color) {
+        // TODO Auto-generated method stub
+    }
+}
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/PageDrawer.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/PageDrawer.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/PageDrawer.java	(revision 34609)
@@ -0,0 +1,251 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.openstreetmap.josm.plugins.pdfimport.pdfbox;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.geom.Area;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.Path2D;
+import java.awt.geom.Point2D;
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.pdfbox.cos.COSName;
+import org.apache.pdfbox.pdmodel.PDPage;
+import org.apache.pdfbox.pdmodel.PDResources;
+import org.apache.pdfbox.pdmodel.graphics.PDGraphicsState;
+import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotation;
+import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceDictionary;
+import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceStream;
+import org.apache.pdfbox.pdmodel.text.PDTextState;
+import org.apache.pdfbox.util.Matrix;
+import org.apache.pdfbox.util.PDFStreamEngine;
+import org.apache.pdfbox.util.ResourceLoader;
+import org.apache.pdfbox.util.TextPosition;
+import org.openstreetmap.josm.tools.Logging;
+
+
+/**
+ * This will paint a page in a PDF document to a graphics context.
+ *
+ * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
+ * @version $Revision: 1.22 $
+ */
+public class PageDrawer extends PDFStreamEngine {
+
+    private GraphicsProcessor graphics;
+    private BasicStroke stroke;
+    protected PDPage page;
+
+    private final GeneralPath linePath = new GeneralPath();
+
+    /**
+     * Default constructor, loads properties from file.
+     *
+     * @throws IOException If there is an error loading properties from the file.
+     */
+    public PageDrawer() throws IOException {
+        super(ResourceLoader.loadProperties(
+                "resources/org/openstreetmap/josm/plugins/pdfimport/pdfbox/PageDrawer.properties", true));
+    }
+
+    /**
+     * This will draw the page to the requested context.
+     *
+     * @param g The graphics context to draw onto.
+     * @param p The page to draw.
+     * @param pageDimension The size of the page to draw.
+     *
+     * @throws IOException If there is an IO error while drawing the page.
+     */
+    public void drawPage(GraphicsProcessor g, PDPage p) throws IOException {
+        graphics = g;
+        page = p;
+        // Only if there is some content, we have to process it.
+        // Otherwise we are done here and we will produce an empty page
+        if (page.getContents() != null) {
+            PDResources resources = page.findResources();
+            processStream(page, resources, page.getContents().getStream());
+        }
+
+        List<?> annotations = page.getAnnotations();
+        for (int i = 0; i < annotations.size(); i++) {
+            PDAnnotation annot = (PDAnnotation) annotations.get(i);
+            String appearanceName = annot.getAppearanceStream();
+            PDAppearanceDictionary appearDictionary = annot.getAppearance();
+            if (appearDictionary != null) {
+                if (appearanceName == null) {
+                    appearanceName = "default";
+                }
+                Map<?, ?> appearanceMap = appearDictionary.getNormalAppearance();
+                if (appearanceMap != null) {
+                    PDAppearanceStream appearance =
+                        (PDAppearanceStream) appearanceMap.get(appearanceName);
+                    if (appearance != null) {
+                        processSubStream(page, appearance.getResources(), appearance.getStream());
+                    }
+                }
+            }
+        }
+
+    }
+
+    /**
+     * You should override this method if you want to perform an action when a
+     * text is being processed.
+     *
+     * @param text The text to process
+     */
+    @Override
+    protected void processTextPosition(TextPosition text) {
+
+        Color color = null;
+
+        try {
+            switch(this.getGraphicsState().getTextState().getRenderingMode()) {
+            case PDTextState.RENDERING_MODE_FILL_TEXT:
+                color = this.getGraphicsState().getNonStrokingColor().getJavaColor();
+                break;
+            case PDTextState.RENDERING_MODE_STROKE_TEXT:
+                color = this.getGraphicsState().getStrokingColor().getJavaColor();
+                break;
+            case PDTextState.RENDERING_MODE_NEITHER_FILL_NOR_STROKE_TEXT:
+                //basic support for text rendering mode "invisible"
+                Color nsc = this.getGraphicsState().getStrokingColor().getJavaColor();
+                float[] components = {Color.black.getRed(), Color.black.getGreen(), Color.black.getBlue()};
+                color = new Color(nsc.getColorSpace(), components, 0f);
+                break;
+            default:
+                color = this.getGraphicsState().getNonStrokingColor().getJavaColor();
+            }
+
+            Matrix textPos = text.getTextPos().copy();
+            float x = textPos.getXPosition();
+            float y = textPos.getYPosition();
+            graphics.setClip(getGraphicsState().getCurrentClippingPath());
+            graphics.drawString(x, y, text.getCharacter(), color);
+        } catch (IOException e) {
+            Logging.error(e);
+        }
+    }
+
+    /**
+     * Get the page that is currently being drawn.
+     *
+     * @return The page that is being drawn.
+     */
+    public PDPage getPage() {
+        return page;
+    }
+
+    /**
+     * Get the current line path to be drawn.
+     *
+     * @return The current line path to be drawn.
+     */
+    public GeneralPath getLinePath() {
+        return linePath;
+    }
+
+    /**
+     * This will set the current stroke.
+     *
+     * @param newStroke The current stroke.
+     *
+     */
+    public void setStroke(BasicStroke newStroke) {
+        this.stroke = newStroke;
+    }
+
+    public BasicStroke getStroke() {
+        return this.stroke;
+    }
+
+    public void drawPath(boolean stroke, boolean fill, int windingRule) throws IOException {
+        graphics.setClip(getGraphicsState().getCurrentClippingPath());
+        GeneralPath path = getLinePath();
+
+        Color strokeColor = getGraphicsState().getStrokingColor().getJavaColor();
+        Color fillColor = getGraphicsState().getNonStrokingColor().getJavaColor();
+        graphics.drawPath(path, stroke ? strokeColor : null, fill ? fillColor : null, windingRule);
+
+        path.reset();
+    }
+
+
+    /**
+     * Draw the AWT image. Called by Invoke.
+     * Moved into PageDrawer so that Invoke doesn't have to reach in here for Graphics as that breaks extensibility.
+     *
+     * @param awtImage The image to draw.
+     * @param at The transformation to use when drawing.
+     *
+     */
+    public void drawImage() {
+        graphics.setClip(getGraphicsState().getCurrentClippingPath());
+        graphics.drawImage();
+    }
+
+    /**
+     * Fill with Shading.  Called by SHFill operator.
+     *
+     * @param ShadingName  The name of the Shading Dictionary to use for this fill instruction.
+     *
+     * @throws IOException If there is an IO error while shade-filling the path/clipping area.
+     */
+    public void SHFill(COSName ShadingName) throws IOException {
+        this.drawPath(false, true, Path2D.WIND_NON_ZERO);
+    }
+
+    //This code generalizes the code Jim Lynch wrote for AppendRectangleToPath
+    /**
+     * use the current transformation matrix to transform a single point.
+     * @param x x-coordinate of the point to be transform
+     * @param y y-coordinate of the point to be transform
+     * @return the transformed coordinates as Point2D.Double
+     */
+    public java.awt.geom.Point2D.Double transformedPoint(double x, double y) {
+        double[] position = {x, y};
+        getGraphicsState().getCurrentTransformationMatrix().createAffineTransform().transform(
+                position, 0, position, 0, 1);
+        return new Point2D.Double(position[0], position[1]);
+    }
+
+    /**
+     * Set the clipping Path.
+     *
+     * @param windingRule The winding rule this path will use.
+     *
+     */
+    public void setClippingPath(int windingRule) {
+        PDGraphicsState graphicsState = getGraphicsState();
+        GeneralPath clippingPath = (GeneralPath) getLinePath().clone();
+        clippingPath.setWindingRule(windingRule);
+        // If there is already set a clipping path, we have to intersect the new with the existing one
+        if (graphicsState.getCurrentClippingPath() != null) {
+            Area currentArea = new Area(getGraphicsState().getCurrentClippingPath());
+            Area newArea = new Area(clippingPath);
+            currentArea.intersect(newArea);
+            graphicsState.setCurrentClippingPath(currentArea);
+        } else {
+            graphicsState.setCurrentClippingPath(clippingPath);
+        }
+        getLinePath().reset();
+    }
+}
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/PdfBoxParser.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/PdfBoxParser.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/PdfBoxParser.java	(revision 34609)
@@ -0,0 +1,58 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.pdfimport.pdfbox;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.geom.Rectangle2D;
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.pdfbox.pdmodel.PDDocument;
+import org.apache.pdfbox.pdmodel.PDPage;
+import org.apache.pdfbox.pdmodel.common.PDRectangle;
+import org.apache.pdfbox.util.PDFStreamEngine;
+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
+import org.openstreetmap.josm.plugins.pdfimport.PathOptimizer;
+
+public class PdfBoxParser extends PDFStreamEngine {
+    private final PathOptimizer target;
+
+    public PdfBoxParser(PathOptimizer target) {
+        this.target = target;
+    }
+
+    public void parse(File file, int maxPaths, ProgressMonitor monitor) throws IOException {
+        monitor.beginTask(tr("Parsing PDF", 1));
+
+        try (PDDocument document = PDDocument.load(file)) {
+
+            if (document.isEncrypted()) {
+                throw new IllegalArgumentException(tr("Encrypted documents not supported."));
+            }
+
+            List<?> allPages = document.getDocumentCatalog().getAllPages();
+
+            if (allPages.size() != 1) {
+                throw new IllegalArgumentException(tr("The PDF file must have exactly one page."));
+            }
+
+            PDPage page = (PDPage) allPages.get(0);
+            PDRectangle pageSize = page.findMediaBox();
+            Integer rotationVal = page.getRotation();
+            int rotation = 0;
+            if (rotationVal != null) {
+                rotation = rotationVal.intValue();
+            }
+
+            new PageDrawer().drawPage(new GraphicsProcessor(target, rotation, maxPaths, monitor), page);
+            this.target.bounds = new Rectangle2D.Double(
+                    pageSize.getLowerLeftX(),
+                    pageSize.getLowerLeftY(),
+                    pageSize.getWidth(),
+                    pageSize.getHeight());
+        }
+
+        monitor.finishTask();
+    }
+}
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/AppendRectangleToPath.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/AppendRectangleToPath.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/AppendRectangleToPath.java	(revision 34609)
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.openstreetmap.josm.plugins.pdfimport.pdfbox.operators;
+
+import java.awt.geom.GeneralPath;
+import java.awt.geom.Point2D;
+import java.util.List;
+
+import org.apache.pdfbox.cos.COSBase;
+import org.apache.pdfbox.cos.COSNumber;
+import org.apache.pdfbox.util.PDFOperator;
+import org.apache.pdfbox.util.operator.OperatorProcessor;
+import org.openstreetmap.josm.plugins.pdfimport.pdfbox.PageDrawer;
+
+/**
+ * Implementation of content stream operator for page drawer.
+ *
+ * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
+ * @version $Revision: 1.3 $
+ */
+public class AppendRectangleToPath extends OperatorProcessor
+{
+
+
+    /**
+     * process : re : append rectangle to path.
+     * @param operator The operator that is being executed.
+     * @param arguments List
+     */
+    @Override
+    public void process(PDFOperator operator, List<COSBase> arguments)
+    {
+        PageDrawer drawer = (PageDrawer)context;
+
+        COSNumber x = (COSNumber)arguments.get( 0 );
+        COSNumber y = (COSNumber)arguments.get( 1 );
+        COSNumber w = (COSNumber)arguments.get( 2 );
+        COSNumber h = (COSNumber)arguments.get( 3 );
+
+        double x1 = x.doubleValue();
+        double y1 = y.doubleValue();
+        // create a pair of coordinates for the transformation
+        double x2 = w.doubleValue()+x1;
+        double y2 = h.doubleValue()+y1;
+
+        Point2D startCoords = drawer.transformedPoint(x1,y1);
+        Point2D endCoords = drawer.transformedPoint(x2,y2);
+
+        float width = (float)(endCoords.getX()-startCoords.getX());
+        float height = (float)(endCoords.getY()-startCoords.getY());
+        float xStart = (float)startCoords.getX();
+        float yStart = (float)startCoords.getY();
+
+        // To ensure that the path is created in the right direction,
+        // we have to create it by combining single lines instead of
+        // creating a simple rectangle
+        GeneralPath path = drawer.getLinePath();
+        path.moveTo(xStart, yStart);
+        path.lineTo(xStart+width, yStart);
+        path.lineTo(xStart+width, yStart+height);
+        path.lineTo(xStart, yStart+height);
+        path.lineTo(xStart, yStart);
+    }
+}
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/BeginInlineImage.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/BeginInlineImage.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/BeginInlineImage.java	(revision 34609)
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.openstreetmap.josm.plugins.pdfimport.pdfbox.operators;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.pdfbox.cos.COSBase;
+import org.apache.pdfbox.util.PDFOperator;
+import org.apache.pdfbox.util.operator.OperatorProcessor;
+import org.openstreetmap.josm.plugins.pdfimport.pdfbox.PageDrawer;
+
+/**
+ * Implementation of content stream operator for page drawer.
+ *
+ * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
+ * @version $Revision: 1.2 $
+ */
+public class BeginInlineImage extends OperatorProcessor
+{
+
+    /**
+     * process : BI : begin inline image.
+     * @param operator The operator that is being executed.
+     * @param arguments List
+     * @throws IOException If there is an error displaying the inline image.
+     */
+    @Override
+    public void process(PDFOperator operator, List<COSBase> arguments)  throws IOException
+    {
+        PageDrawer drawer = (PageDrawer)context;
+        drawer.drawImage();
+    }
+}
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/ClipEvenOddRule.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/ClipEvenOddRule.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/ClipEvenOddRule.java	(revision 34609)
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.openstreetmap.josm.plugins.pdfimport.pdfbox.operators;
+
+import java.awt.geom.GeneralPath;
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.pdfbox.cos.COSBase;
+import org.apache.pdfbox.util.PDFOperator;
+import org.apache.pdfbox.util.operator.OperatorProcessor;
+import org.openstreetmap.josm.plugins.pdfimport.pdfbox.PageDrawer;
+
+/**
+ * Implementation of content stream operator for page drawer.
+ *
+ * @author <a href="mailto:Daniel.Wilson@BlackLocustSoftware.com">Daniel Wilson</a>
+ * @version $Revision: 1.1 $
+ */
+public class ClipEvenOddRule extends OperatorProcessor
+{
+
+    /**
+     * Log instance.
+     */
+    private static final Log log = LogFactory.getLog(ClipEvenOddRule.class);
+
+    /**
+     * process : W* : set clipping path using even odd rule.
+     * @param operator The operator that is being executed.
+     * @param arguments List
+     *
+     * @throws IOException if there is an error during execution.
+     */
+    @Override
+    public void process(PDFOperator operator, List<COSBase> arguments) throws IOException
+    {
+
+        try
+        {
+            PageDrawer drawer = (PageDrawer)context;
+            drawer.setClippingPath(GeneralPath.WIND_EVEN_ODD);
+        }
+        catch (Exception e)
+        {
+            log.warn(e, e);
+        }
+    }
+}
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/ClipNonZeroRule.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/ClipNonZeroRule.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/ClipNonZeroRule.java	(revision 34609)
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.openstreetmap.josm.plugins.pdfimport.pdfbox.operators;
+
+import java.awt.geom.GeneralPath;
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.pdfbox.cos.COSBase;
+import org.apache.pdfbox.util.PDFOperator;
+import org.apache.pdfbox.util.operator.OperatorProcessor;
+import org.openstreetmap.josm.plugins.pdfimport.pdfbox.PageDrawer;
+
+/**
+ * Implementation of content stream operator for page drawer.
+ *
+ * @author <a href="mailto:Daniel.Wilson@BlackLocustSoftware.com">Daniel Wilson</a>
+ * @version $Revision: 1.1 $
+ */
+public class ClipNonZeroRule extends OperatorProcessor
+{
+
+    /**
+     * Log instance.
+     */
+    private static final Log log = LogFactory.getLog(ClipNonZeroRule.class);
+
+    /**
+     * process : W : Set the clipping path using non zero winding rule.
+     * @param operator The operator that is being executed.
+     * @param arguments List
+     *
+     * @throws IOException If there is an error during the processing.
+     */
+    @Override
+    public void process(PDFOperator operator, List<COSBase> arguments) throws IOException
+    {
+
+        try
+        {
+            PageDrawer drawer = (PageDrawer)context;
+            drawer.setClippingPath(GeneralPath.WIND_NON_ZERO);
+        }
+        catch (Exception e)
+        {
+            log.warn(e, e);
+        }
+    }
+}
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/CloseFillEvenOddAndStrokePath.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/CloseFillEvenOddAndStrokePath.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/CloseFillEvenOddAndStrokePath.java	(revision 34609)
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.openstreetmap.josm.plugins.pdfimport.pdfbox.operators;
+
+import java.awt.geom.Path2D;
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.pdfbox.cos.COSBase;
+import org.apache.pdfbox.util.PDFOperator;
+import org.apache.pdfbox.util.operator.OperatorProcessor;
+import org.openstreetmap.josm.plugins.pdfimport.pdfbox.PageDrawer;
+
+/**
+ * Implementation of content stream operator for page drawer.
+ *
+ * @author <a href="mailto:andreas@lehmi.de">Andreas Lehmkühler</a>
+ * @version $Revision: 1.0 $
+ */
+public class CloseFillEvenOddAndStrokePath extends OperatorProcessor
+{
+
+    /**
+     * fill and stroke the path.
+     * @param operator The operator that is being executed.
+     * @param arguments List
+     *
+     * @throws IOException If an error occurs while processing the font.
+     */
+    @Override
+    public void process(PDFOperator operator, List<COSBase> arguments) throws IOException
+    {
+        PageDrawer drawer = (PageDrawer)context;
+        drawer.getLinePath().closePath();
+        drawer.drawPath(true, true, Path2D.WIND_EVEN_ODD);
+    }
+}
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/CloseFillNonZeroAndStrokePath.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/CloseFillNonZeroAndStrokePath.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/CloseFillNonZeroAndStrokePath.java	(revision 34609)
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.openstreetmap.josm.plugins.pdfimport.pdfbox.operators;
+
+import java.awt.geom.Path2D;
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.pdfbox.cos.COSBase;
+import org.apache.pdfbox.util.PDFOperator;
+import org.apache.pdfbox.util.operator.OperatorProcessor;
+import org.openstreetmap.josm.plugins.pdfimport.pdfbox.PageDrawer;
+
+/**
+ * Implementation of content stream operator for page drawer.
+ *
+ * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
+ * @version $Revision: 1.1 $
+ */
+public class CloseFillNonZeroAndStrokePath extends OperatorProcessor
+{
+
+    /**
+     * fill and stroke the path.
+     * @param operator The operator that is being executed.
+     * @param arguments List
+     *
+     * @throws IOException If an error occurs while processing the font.
+     */
+    @Override
+    public void process(PDFOperator operator, List<COSBase> arguments) throws IOException
+    {
+        PageDrawer drawer = (PageDrawer)context;
+        drawer.getLinePath().closePath();
+        drawer.drawPath(true, true, Path2D.WIND_NON_ZERO);
+    }
+}
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/ClosePath.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/ClosePath.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/ClosePath.java	(revision 34609)
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.openstreetmap.josm.plugins.pdfimport.pdfbox.operators;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.pdfbox.cos.COSBase;
+import org.apache.pdfbox.util.PDFOperator;
+import org.apache.pdfbox.util.operator.OperatorProcessor;
+import org.openstreetmap.josm.plugins.pdfimport.pdfbox.PageDrawer;
+/**
+ * Implementation of content stream operator for page drawer.
+ *
+ * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
+ * @version $Revision: 1.3 $
+ */
+public class ClosePath extends OperatorProcessor
+{
+
+    /**
+     * process : h : Close path.
+     * @param operator The operator that is being executed.
+     * @param arguments List
+     *
+     * @throws IOException if something went wrong during logging
+     */
+    @Override
+    public void process(PDFOperator operator, List<COSBase> arguments) throws IOException
+    {
+        PageDrawer drawer = (PageDrawer)context;
+        drawer.getLinePath().closePath();
+    }
+}
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/CurveTo.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/CurveTo.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/CurveTo.java	(revision 34609)
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.openstreetmap.josm.plugins.pdfimport.pdfbox.operators;
+
+import java.awt.geom.Point2D;
+import java.util.List;
+
+import org.apache.pdfbox.cos.COSBase;
+import org.apache.pdfbox.cos.COSNumber;
+import org.apache.pdfbox.util.PDFOperator;
+import org.apache.pdfbox.util.operator.OperatorProcessor;
+import org.openstreetmap.josm.plugins.pdfimport.pdfbox.PageDrawer;
+
+/**
+ * Implementation of content stream operator for page drawer.
+ *
+ * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
+ * @version $Revision: 1.2 $
+ */
+public class CurveTo extends OperatorProcessor
+{
+
+
+    /**
+     * process : c : Append curved segment to path.
+     * @param operator The operator that is being executed.
+     * @param arguments List
+     */
+    @Override
+    public void process(PDFOperator operator, List<COSBase> arguments)
+    {
+        PageDrawer drawer = (PageDrawer)context;
+
+        COSNumber x1 = (COSNumber)arguments.get( 0 );
+        COSNumber y1 = (COSNumber)arguments.get( 1 );
+        COSNumber x2 = (COSNumber)arguments.get( 2 );
+        COSNumber y2 = (COSNumber)arguments.get( 3 );
+        COSNumber x3 = (COSNumber)arguments.get( 4 );
+        COSNumber y3 = (COSNumber)arguments.get( 5 );
+
+        Point2D point1 = drawer.transformedPoint(x1.doubleValue(), y1.doubleValue());
+        Point2D point2 = drawer.transformedPoint(x2.doubleValue(), y2.doubleValue());
+        Point2D point3 = drawer.transformedPoint(x3.doubleValue(), y3.doubleValue());
+
+        drawer.getLinePath().curveTo((float)point1.getX(), (float)point1.getY(),
+                (float)point2.getX(), (float)point2.getY(), (float)point3.getX(), (float)point3.getY());
+    }
+}
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/CurveToReplicateFinalPoint.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/CurveToReplicateFinalPoint.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/CurveToReplicateFinalPoint.java	(revision 34609)
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.openstreetmap.josm.plugins.pdfimport.pdfbox.operators;
+
+import java.awt.geom.Point2D;
+import java.util.List;
+
+import org.apache.pdfbox.cos.COSBase;
+import org.apache.pdfbox.cos.COSNumber;
+import org.apache.pdfbox.util.PDFOperator;
+import org.apache.pdfbox.util.operator.OperatorProcessor;
+import org.openstreetmap.josm.plugins.pdfimport.pdfbox.PageDrawer;
+
+/**
+ * Implementation of content stream operator for page drawer.
+ *
+ * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
+ * @version $Revision: 1.2 $
+ */
+public class CurveToReplicateFinalPoint extends OperatorProcessor
+{
+
+
+    /**
+     * process : y : Append curved segment to path (final point replicated).
+     * @param operator The operator that is being executed.
+     * @param arguments List
+     */
+    @Override
+    public void process(PDFOperator operator, List<COSBase> arguments)
+    {
+        PageDrawer drawer = (PageDrawer)context;
+
+        COSNumber x1 = (COSNumber)arguments.get( 0 );
+        COSNumber y1 = (COSNumber)arguments.get( 1 );
+        COSNumber x3 = (COSNumber)arguments.get( 2 );
+        COSNumber y3 = (COSNumber)arguments.get( 3 );
+
+        Point2D point1 = drawer.transformedPoint(x1.doubleValue(), y1.doubleValue());
+        Point2D point3 = drawer.transformedPoint(x3.doubleValue(), y3.doubleValue());
+
+        drawer.getLinePath().curveTo((float)point1.getX(), (float)point1.getY(),
+                (float)point3.getX(), (float)point3.getY(), (float)point3.getX(), (float)point3.getY());
+    }
+}
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/CurveToReplicateInitialPoint.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/CurveToReplicateInitialPoint.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/CurveToReplicateInitialPoint.java	(revision 34609)
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.openstreetmap.josm.plugins.pdfimport.pdfbox.operators;
+
+import java.awt.geom.GeneralPath;
+import java.awt.geom.Point2D;
+import java.util.List;
+
+import org.apache.pdfbox.cos.COSBase;
+import org.apache.pdfbox.cos.COSNumber;
+import org.apache.pdfbox.util.PDFOperator;
+import org.apache.pdfbox.util.operator.OperatorProcessor;
+import org.openstreetmap.josm.plugins.pdfimport.pdfbox.PageDrawer;
+
+/**
+ * Implementation of content stream operator for page drawer.
+ *
+ * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
+ * @version $Revision: 1.2 $
+ */
+public class CurveToReplicateInitialPoint extends OperatorProcessor
+{
+
+
+    /**
+     * process : v : Append curved segment to path (initial point replicated).
+     * @param operator The operator that is being executed.
+     * @param arguments List
+     */
+    @Override
+    public void process(PDFOperator operator, List<COSBase> arguments)
+    {
+        PageDrawer drawer = (PageDrawer)context;
+
+        COSNumber x2 = (COSNumber)arguments.get( 0 );
+        COSNumber y2 = (COSNumber)arguments.get( 1 );
+        COSNumber x3 = (COSNumber)arguments.get( 2 );
+        COSNumber y3 = (COSNumber)arguments.get( 3 );
+        GeneralPath path = drawer.getLinePath();
+        Point2D currentPoint = path.getCurrentPoint();
+
+        Point2D point2 = drawer.transformedPoint(x2.doubleValue(), y2.doubleValue());
+        Point2D point3 = drawer.transformedPoint(x3.doubleValue(), y3.doubleValue());
+
+        drawer.getLinePath().curveTo((float)currentPoint.getX(), (float)currentPoint.getY(),
+                (float)point2.getX(), (float)point2.getY(), (float)point3.getX(), (float)point3.getY());
+    }
+}
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/EndPath.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/EndPath.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/EndPath.java	(revision 34609)
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.openstreetmap.josm.plugins.pdfimport.pdfbox.operators;
+
+import java.util.List;
+
+import org.apache.pdfbox.cos.COSBase;
+import org.apache.pdfbox.util.PDFOperator;
+import org.apache.pdfbox.util.operator.OperatorProcessor;
+import org.openstreetmap.josm.plugins.pdfimport.pdfbox.PageDrawer;
+
+/**
+ * Implementation of content stream operator for page drawer.
+ *
+ * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
+ * @version $Revision: 1.2 $
+ */
+public class EndPath extends OperatorProcessor
+{
+
+
+    /**
+     * process : n : End path.
+     * @param operator The operator that is being executed.
+     * @param arguments List
+     */
+    @Override
+    public void process(PDFOperator operator, List<COSBase> arguments)
+    {
+        PageDrawer drawer = (PageDrawer)context;
+        drawer.getLinePath().reset();
+    }
+}
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/FillEvenOddAndStrokePath.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/FillEvenOddAndStrokePath.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/FillEvenOddAndStrokePath.java	(revision 34609)
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.openstreetmap.josm.plugins.pdfimport.pdfbox.operators;
+
+import java.awt.geom.Path2D;
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.pdfbox.cos.COSBase;
+import org.apache.pdfbox.util.PDFOperator;
+import org.apache.pdfbox.util.operator.OperatorProcessor;
+import org.openstreetmap.josm.plugins.pdfimport.pdfbox.PageDrawer;
+
+/**
+ * Implementation of content stream operator for page drawer.
+ *
+ * @author <a href="mailto:andreas@lehmi.de">Andreas Lehmkühler</a>
+ * @version $Revision: 101 $
+ */
+public class FillEvenOddAndStrokePath extends OperatorProcessor
+{
+
+    /**
+     * fill and stroke the path.
+     * @param operator The operator that is being executed.
+     * @param arguments List
+     *
+     * @throws IOException If an error occurs while processing the font.
+     */
+    @Override
+    public void process(PDFOperator operator, List<COSBase> arguments) throws IOException
+    {
+        PageDrawer drawer = (PageDrawer)context;
+        drawer.drawPath(true, true, Path2D.WIND_EVEN_ODD);
+    }
+}
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/FillEvenOddRule.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/FillEvenOddRule.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/FillEvenOddRule.java	(revision 34609)
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.openstreetmap.josm.plugins.pdfimport.pdfbox.operators;
+
+import java.awt.geom.GeneralPath;
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.pdfbox.cos.COSBase;
+import org.apache.pdfbox.util.PDFOperator;
+import org.apache.pdfbox.util.operator.OperatorProcessor;
+import org.openstreetmap.josm.plugins.pdfimport.pdfbox.PageDrawer;
+
+/**
+ * Implementation of content stream operator for page drawer.
+ *
+ * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
+ * @version $Revision: 1.5 $
+ */
+public class FillEvenOddRule extends OperatorProcessor
+{
+
+    /**
+     * Log instance.
+     */
+    private static final Log log = LogFactory.getLog(FillEvenOddRule.class);
+
+    /**
+     * process : f* : fill path using even odd rule.
+     * @param operator The operator that is being executed.
+     * @param arguments List
+     *
+     * @throws IOException if there is an error during execution.
+     */
+    @Override
+    public void process(PDFOperator operator, List<COSBase> arguments) throws IOException
+    {
+        try
+        {
+            ///dwilson refactoring
+            PageDrawer drawer = (PageDrawer)context;
+            drawer.drawPath(false, true, GeneralPath.WIND_EVEN_ODD);
+        }
+        catch (Exception e)
+        {
+            log.warn(e, e);
+        }
+    }
+}
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/FillNonZeroAndStrokePath.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/FillNonZeroAndStrokePath.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/FillNonZeroAndStrokePath.java	(revision 34609)
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.openstreetmap.josm.plugins.pdfimport.pdfbox.operators;
+
+import java.awt.geom.Path2D;
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.pdfbox.cos.COSBase;
+import org.apache.pdfbox.util.PDFOperator;
+import org.apache.pdfbox.util.operator.OperatorProcessor;
+import org.openstreetmap.josm.plugins.pdfimport.pdfbox.PageDrawer;
+
+/**
+ * Implementation of content stream operator for page drawer.
+ *
+ * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
+ * @version $Revision: 1.1 $
+ */
+public class FillNonZeroAndStrokePath extends OperatorProcessor
+{
+
+    /**
+     * fill and stroke the path.
+     * @param operator The operator that is being executed.
+     * @param arguments List
+     *
+     * @throws IOException If an error occurs while processing the font.
+     */
+    @Override
+    public void process(PDFOperator operator, List<COSBase> arguments) throws IOException
+    {
+        PageDrawer drawer = (PageDrawer)context;
+        drawer.drawPath(true, true, Path2D.WIND_NON_ZERO);
+    }
+}
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/FillNonZeroRule.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/FillNonZeroRule.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/FillNonZeroRule.java	(revision 34609)
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.openstreetmap.josm.plugins.pdfimport.pdfbox.operators;
+
+import java.awt.geom.GeneralPath;
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.pdfbox.cos.COSBase;
+import org.apache.pdfbox.util.PDFOperator;
+import org.apache.pdfbox.util.operator.OperatorProcessor;
+import org.openstreetmap.josm.plugins.pdfimport.pdfbox.PageDrawer;
+
+/**
+ * Implementation of content stream operator for page drawer.
+ *
+ * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
+ * @version $Revision: 1.5 $
+ */
+public class FillNonZeroRule extends OperatorProcessor
+{
+
+    /**
+     * process : F/f : fill path using non zero winding rule.
+     * @param operator The operator that is being executed.
+     * @param arguments List
+     *
+     * @throws IOException If there is an error during the processing.
+     */
+    @Override
+    public void process(PDFOperator operator, List<COSBase> arguments) throws IOException
+    {
+        PageDrawer drawer = (PageDrawer)context;
+        drawer.drawPath(false, true, GeneralPath.WIND_NON_ZERO);
+    }
+}
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/Invoke.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/Invoke.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/Invoke.java	(revision 34609)
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.openstreetmap.josm.plugins.pdfimport.pdfbox.operators;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.pdfbox.cos.COSBase;
+import org.apache.pdfbox.cos.COSName;
+import org.apache.pdfbox.cos.COSStream;
+import org.apache.pdfbox.pdmodel.PDPage;
+import org.apache.pdfbox.pdmodel.PDResources;
+import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObject;
+import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObjectForm;
+import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObjectImage;
+import org.apache.pdfbox.util.Matrix;
+import org.apache.pdfbox.util.PDFOperator;
+import org.apache.pdfbox.util.operator.OperatorProcessor;
+import org.openstreetmap.josm.plugins.pdfimport.pdfbox.PageDrawer;
+
+/**
+ * Implementation of content stream operator for page drawer.
+ *
+ * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
+ * @version $Revision: 1.4 $
+ */
+public class Invoke extends OperatorProcessor
+{
+
+
+    /**
+     * process : Do : Paint the specified XObject (section 4.7).
+     * @param operator The operator that is being executed.
+     * @param arguments List
+     * @throws IOException If there is an error invoking the sub object.
+     */
+    @Override
+    public void process(PDFOperator operator, List<COSBase> arguments) throws IOException
+    {
+        PageDrawer drawer = (PageDrawer)context;
+        PDPage page = drawer.getPage();
+        COSName objectName = (COSName)arguments.get( 0 );
+        Map<?, ?> xobjects = drawer.getResources().getXObjects();
+        PDXObject xobject = (PDXObject)xobjects.get( objectName.getName() );
+        if( xobject instanceof PDXObjectImage )
+        {
+            drawer.drawImage();
+        }
+        else if(xobject instanceof PDXObjectForm)
+        {
+            PDXObjectForm form = (PDXObjectForm)xobject;
+            COSStream invoke = (COSStream)form.getCOSObject();
+            PDResources pdResources = form.getResources();
+            if(pdResources == null)
+            {
+                pdResources = page.findResources();
+            }
+            // if there is an optional form matrix, we have to
+            // map the form space to the user space
+            Matrix matrix = form.getMatrix();
+            if (matrix != null)
+            {
+                Matrix xobjectCTM = matrix.multiply( context.getGraphicsState().getCurrentTransformationMatrix());
+                context.getGraphicsState().setCurrentTransformationMatrix(xobjectCTM);
+            }
+            getContext().processSubStream( page, pdResources, invoke );
+        }
+        else
+        {
+            //unknown xobject type
+        }
+
+
+        //invoke named object.
+    }
+}
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/LineTo.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/LineTo.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/LineTo.java	(revision 34609)
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.openstreetmap.josm.plugins.pdfimport.pdfbox.operators;
+
+import java.awt.geom.Point2D;
+import java.util.List;
+
+import org.apache.pdfbox.cos.COSBase;
+import org.apache.pdfbox.cos.COSNumber;
+import org.apache.pdfbox.util.PDFOperator;
+import org.apache.pdfbox.util.operator.OperatorProcessor;
+import org.openstreetmap.josm.plugins.pdfimport.pdfbox.PageDrawer;
+
+/**
+ * Implementation of content stream operator for page drawer.
+ *
+ * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
+ * @version $Revision: 1.2 $
+ */
+public class LineTo extends OperatorProcessor
+{
+
+
+    /**
+     * process : l : Append straight line segment to path.
+     * @param operator The operator that is being executed.
+     * @param arguments List
+     */
+    @Override
+    public void process(PDFOperator operator, List<COSBase> arguments)
+    {
+        PageDrawer drawer = (PageDrawer)context;
+
+        //append straight line segment from the current point to the point.
+        COSNumber x = (COSNumber)arguments.get( 0 );
+        COSNumber y = (COSNumber)arguments.get( 1 );
+
+        Point2D pos = drawer.transformedPoint(x.doubleValue(), y.doubleValue());
+        drawer.getLinePath().lineTo((float)pos.getX(), (float)pos.getY());
+    }
+}
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/MoveTo.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/MoveTo.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/MoveTo.java	(revision 34609)
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.openstreetmap.josm.plugins.pdfimport.pdfbox.operators;
+
+import java.awt.geom.Point2D;
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.pdfbox.cos.COSBase;
+import org.apache.pdfbox.cos.COSNumber;
+import org.apache.pdfbox.util.PDFOperator;
+import org.apache.pdfbox.util.operator.OperatorProcessor;
+import org.openstreetmap.josm.plugins.pdfimport.pdfbox.PageDrawer;
+
+/**
+ * Implementation of content stream operator for page drawer.
+ *
+ * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
+ * @version $Revision: 1.2 $
+ */
+public class MoveTo extends OperatorProcessor
+{
+
+    /**
+     * Log instance.
+     */
+    private static final Log log = LogFactory.getLog(MoveTo.class);
+
+    /**
+     * process : m : Begin new subpath.
+     * @param operator The operator that is being executed.
+     * @param arguments List
+     * @throws IOException If there is an error processing the operator.
+     */
+    @Override
+    public void process(PDFOperator operator, List<COSBase> arguments) throws IOException
+    {
+        try
+        {
+            PageDrawer drawer = (PageDrawer)context;
+            COSNumber x = (COSNumber)arguments.get( 0 );
+            COSNumber y = (COSNumber)arguments.get( 1 );
+            Point2D pos = drawer.transformedPoint(x.doubleValue(), y.doubleValue());
+            drawer.getLinePath().moveTo((float)pos.getX(), (float)pos.getY());
+        }
+        catch (Exception exception)
+        {
+            log.warn( exception, exception);
+        }
+    }
+}
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/SHFill.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/SHFill.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/SHFill.java	(revision 34609)
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.openstreetmap.josm.plugins.pdfimport.pdfbox.operators;
+
+import java.awt.geom.Path2D;
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.pdfbox.cos.COSBase;
+import org.apache.pdfbox.util.PDFOperator;
+import org.apache.pdfbox.util.operator.OperatorProcessor;
+import org.openstreetmap.josm.plugins.pdfimport.pdfbox.PageDrawer;
+
+/**
+ * Implementation of sh operator for page drawer.
+ *  See section 4.6.3 of the PDF 1.7 specification.
+ *
+ * @author <a href="mailto:Daniel.Wilson@BlackLocustSoftware.com">Daniel Wilson</a>
+ * @version $Revision: 1.0 $
+ */
+public class SHFill extends OperatorProcessor
+{
+
+    /**
+     * process : sh : shade fill the path or clipping area.
+     * @param operator The operator that is being executed.
+     * @param arguments List
+     *
+     * @throws IOException if there is an error during execution.
+     */
+    @Override
+    public void process(PDFOperator operator, List<COSBase> arguments) throws IOException
+    {
+        PageDrawer drawer = (PageDrawer)context;
+        drawer.drawPath(false, true, Path2D.WIND_NON_ZERO);
+    }
+}
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/SetLineCapStyle.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/SetLineCapStyle.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/SetLineCapStyle.java	(revision 34609)
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.openstreetmap.josm.plugins.pdfimport.pdfbox.operators;
+
+import java.awt.BasicStroke;
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.pdfbox.cos.COSBase;
+import org.apache.pdfbox.util.PDFOperator;
+import org.openstreetmap.josm.plugins.pdfimport.pdfbox.PageDrawer;
+
+/**
+ * Implementation of content stream operator for page drawer.
+ *
+ * @author <a href="mailto:andreas@lehmi.de>Andreas Lehmkühler</a>
+ * @version $Revision: 1.0 $
+ */
+public class SetLineCapStyle extends org.apache.pdfbox.util.operator.SetLineCapStyle
+{
+
+    /**
+     * Set the line cap style.
+     * @param operator The operator that is being executed.
+     * @param arguments List
+     *
+     * @throws IOException If an error occurs while processing the font.
+     */
+    @Override
+    public void process(PDFOperator operator, List<COSBase> arguments) throws IOException
+    {
+        super.process( operator, arguments );
+        int lineCapStyle = context.getGraphicsState().getLineCap();
+        PageDrawer drawer = (PageDrawer)context;
+        BasicStroke stroke = drawer.getStroke();
+        if (stroke == null)
+        {
+            drawer.setStroke( new BasicStroke(1,lineCapStyle,BasicStroke.JOIN_MITER) );
+        }
+        else
+        {
+            drawer.setStroke( new BasicStroke(stroke.getLineWidth(), lineCapStyle, stroke.getLineJoin(),
+                    stroke.getMiterLimit(), stroke.getDashArray(), stroke.getDashPhase()));
+        }
+    }
+}
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/SetLineDashPattern.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/SetLineDashPattern.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/SetLineDashPattern.java	(revision 34609)
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.openstreetmap.josm.plugins.pdfimport.pdfbox.operators;
+
+import java.awt.BasicStroke;
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.pdfbox.cos.COSBase;
+import org.apache.pdfbox.pdmodel.graphics.PDLineDashPattern;
+import org.apache.pdfbox.util.PDFOperator;
+import org.openstreetmap.josm.plugins.pdfimport.pdfbox.PageDrawer;
+
+/**
+ * Implementation of content stream operator for page drawer.
+ *
+ * @author <a href="mailto:andreas@lehmi.de">Andreas Lehmkühler</a>
+ * @version $Revision: 1.0 $
+ */
+public class SetLineDashPattern extends org.apache.pdfbox.util.operator.SetLineDashPattern
+{
+
+    /**
+     * Set the line dash pattern.
+     * @param operator The operator that is being executed.
+     * @param arguments List
+     *
+     * @throws IOException If an error occurs while processing the font.
+     */
+    @Override
+    public void process(PDFOperator operator, List<COSBase> arguments) throws IOException
+    {
+        super.process( operator, arguments );
+        PDLineDashPattern lineDashPattern = context.getGraphicsState().getLineDashPattern();
+        PageDrawer drawer = (PageDrawer)context;
+        BasicStroke stroke = drawer.getStroke();
+        if (stroke == null)
+        {
+            if (lineDashPattern.isDashPatternEmpty())
+            {
+                drawer.setStroke(new BasicStroke(1, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER, 10.0f) );
+            }
+            else
+            {
+                drawer.setStroke(new BasicStroke(1, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER, 10.0f,
+                        lineDashPattern.getCOSDashPattern().toFloatArray(), lineDashPattern.getPhaseStart()) );
+            }
+        }
+        else
+        {
+            if (lineDashPattern.isDashPatternEmpty())
+            {
+                drawer.setStroke( new BasicStroke(stroke.getLineWidth(), stroke.getEndCap(),
+                        stroke.getLineJoin(), stroke.getMiterLimit()) );
+            }
+            else
+            {
+                drawer.setStroke( new BasicStroke(stroke.getLineWidth(), stroke.getEndCap(), stroke.getLineJoin(),
+                        stroke.getMiterLimit(), lineDashPattern.getCOSDashPattern().toFloatArray(),
+                        lineDashPattern.getPhaseStart()) );
+            }
+        }
+    }
+
+}
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/SetLineJoinStyle.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/SetLineJoinStyle.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/SetLineJoinStyle.java	(revision 34609)
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.openstreetmap.josm.plugins.pdfimport.pdfbox.operators;
+
+import java.awt.BasicStroke;
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.pdfbox.cos.COSBase;
+import org.apache.pdfbox.util.PDFOperator;
+import org.openstreetmap.josm.plugins.pdfimport.pdfbox.PageDrawer;
+
+/**
+ * Implementation of content stream operator for page drawer.
+ *
+ * @author <a href="mailto:andreas@lehmi.de>Andreas Lehmkühler</a>
+ * @version $Revision: 1.0 $
+ */
+public class SetLineJoinStyle extends org.apache.pdfbox.util.operator.SetLineJoinStyle
+{
+
+    /**
+     * Set the line cap style.
+     * @param operator The operator that is being executed.
+     * @param arguments List
+     *
+     * @throws IOException If an error occurs while processing the font.
+     */
+    @Override
+    public void process(PDFOperator operator, List<COSBase> arguments) throws IOException
+    {
+        super.process( operator, arguments );
+        int lineJoinStyle = context.getGraphicsState().getLineJoin();
+        PageDrawer drawer = (PageDrawer)context;
+        BasicStroke stroke = drawer.getStroke();
+        if (stroke == null)
+        {
+            drawer.setStroke( new BasicStroke(1,BasicStroke.CAP_SQUARE,lineJoinStyle) );
+        }
+        else
+        {
+            drawer.setStroke( new BasicStroke(stroke.getLineWidth(), stroke.getEndCap(), lineJoinStyle,
+                    stroke.getMiterLimit(), stroke.getDashArray(), stroke.getDashPhase()) );
+        }
+    }
+}
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/SetLineMiterLimit.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/SetLineMiterLimit.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/SetLineMiterLimit.java	(revision 34609)
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.openstreetmap.josm.plugins.pdfimport.pdfbox.operators;
+
+import java.awt.BasicStroke;
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.pdfbox.cos.COSBase;
+import org.apache.pdfbox.util.PDFOperator;
+import org.openstreetmap.josm.plugins.pdfimport.pdfbox.PageDrawer;
+
+/**
+ * Implementation of content stream operator for page drawer.
+ *
+ * @author <a href="mailto:andreas@lehmi.de">Andreas Lehmkühler</a>
+ * @version $Revision: 1.0 $
+ */
+public class SetLineMiterLimit extends org.apache.pdfbox.util.operator.SetLineMiterLimit
+{
+
+    /**
+     * Set the line dash pattern.
+     * @param operator The operator that is being executed.
+     * @param arguments List
+     *
+     * @throws IOException If an error occurs while processing the font.
+     */
+    @Override
+    public void process(PDFOperator operator, List<COSBase> arguments) throws IOException
+    {
+        super.process(operator, arguments);
+        float miterLimit = (float)context.getGraphicsState().getMiterLimit();
+        PageDrawer drawer = (PageDrawer)context;
+        BasicStroke stroke = drawer.getStroke();
+        if (stroke == null)
+        {
+            drawer.setStroke(new BasicStroke(1, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER,
+                    miterLimit, null, 0.0f));
+        }
+        else
+        {
+            drawer.setStroke( new BasicStroke(stroke.getLineWidth(), stroke.getEndCap(), stroke.getLineJoin(),
+                    miterLimit, null, 0.0f));
+        }
+    }
+}
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/SetLineWidth.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/SetLineWidth.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/SetLineWidth.java	(revision 34609)
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.openstreetmap.josm.plugins.pdfimport.pdfbox.operators;
+
+import java.awt.BasicStroke;
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.pdfbox.cos.COSBase;
+import org.apache.pdfbox.util.PDFOperator;
+import org.openstreetmap.josm.plugins.pdfimport.pdfbox.PageDrawer;
+
+/**
+ * Implementation of content stream operator for page drawer.
+ *
+ * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
+ * @version $Revision: 1.2 $
+ */
+public class SetLineWidth extends org.apache.pdfbox.util.operator.SetLineWidth
+{
+
+    /**
+     * w Set line width.
+     * @param operator The operator that is being executed.
+     * @param arguments List
+     * @throws IOException If an error occurs while processing the font.
+     */
+    @Override
+    public void process(PDFOperator operator, List<COSBase> arguments) throws IOException
+    {
+        super.process( operator, arguments );
+        float lineWidth = (float)context.getGraphicsState().getLineWidth();
+        if (lineWidth == 0)
+        {
+            lineWidth = 1;
+        }
+        PageDrawer drawer = (PageDrawer)context;
+        BasicStroke stroke = drawer.getStroke();
+        if (stroke == null)
+        {
+            drawer.setStroke( new BasicStroke( lineWidth ) );
+        }
+        else
+        {
+            drawer.setStroke( new BasicStroke(lineWidth, stroke.getEndCap(), stroke.getLineJoin(),
+                    stroke.getMiterLimit(), stroke.getDashArray(), stroke.getDashPhase()) );
+        }
+    }
+}
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/StrokePath.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/StrokePath.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/StrokePath.java	(revision 34609)
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.openstreetmap.josm.plugins.pdfimport.pdfbox.operators;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.pdfbox.cos.COSBase;
+import org.apache.pdfbox.util.PDFOperator;
+import org.apache.pdfbox.util.operator.OperatorProcessor;
+import org.openstreetmap.josm.plugins.pdfimport.pdfbox.PageDrawer;
+
+/**
+ * Implementation of content stream operator for page drawer.
+ *
+ * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
+ * @version $Revision: 1.3 $
+ */
+public class StrokePath extends OperatorProcessor
+{
+
+    /**
+     * S stroke the path.
+     * @param operator The operator that is being executed.
+     * @param arguments List
+     *
+     * @throws IOException If an error occurs while processing the font.
+     */
+    @Override
+    public void process(PDFOperator operator, List<COSBase> arguments) throws IOException
+    {
+        PageDrawer drawer = (PageDrawer)context;
+        drawer.drawPath(true, false, 0);
+    }
+}
Index: /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/package.html
===================================================================
--- /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/package.html	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/src/org/openstreetmap/josm/plugins/pdfimport/pdfbox/operators/package.html	(revision 34609)
@@ -0,0 +1,25 @@
+<!--
+ ! Licensed to the Apache Software Foundation (ASF) under one or more
+ ! contributor license agreements.  See the NOTICE file distributed with
+ ! this work for additional information regarding copyright ownership.
+ ! The ASF licenses this file to You under the Apache License, Version 2.0
+ ! (the "License"); you may not use this file except in compliance with
+ ! the License.  You may obtain a copy of the License at
+ !
+ !      http://www.apache.org/licenses/LICENSE-2.0
+ !
+ ! Unless required by applicable law or agreed to in writing, software
+ ! distributed under the License is distributed on an "AS IS" BASIS,
+ ! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ! See the License for the specific language governing permissions and
+ ! limitations under the License.
+ !-->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+
+</head>
+<body>
+This package contains implementations of all of the PDF operators.
+</body>
+</html>
Index: /applications/editors/josm/plugins/pdfimport/test/unit/org/openstreetmap/josm/plugins/pdfimport/pdfbox/PDFParserTest.java
===================================================================
--- /applications/editors/josm/plugins/pdfimport/test/unit/org/openstreetmap/josm/plugins/pdfimport/pdfbox/PDFParserTest.java	(revision 34609)
+++ /applications/editors/josm/plugins/pdfimport/test/unit/org/openstreetmap/josm/plugins/pdfimport/pdfbox/PDFParserTest.java	(revision 34609)
@@ -0,0 +1,41 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.pdfimport.pdfbox;
+
+import static org.junit.Assert.assertEquals;
+
+import java.awt.Rectangle;
+import java.io.File;
+
+import org.junit.Test;
+import org.openstreetmap.josm.TestUtils;
+import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
+import org.openstreetmap.josm.plugins.pdfimport.PathOptimizer;
+
+public class PDFParserTest {
+
+    private PathOptimizer parse(String fileName) throws Exception {
+        PathOptimizer data = new PathOptimizer(0.0, null, false);
+        PdfBoxParser parser = new PdfBoxParser(data);
+        parser.parse(new File(fileName), Integer.MAX_VALUE, NullProgressMonitor.INSTANCE);
+        return data;
+    }
+
+    @Test
+    public void testParse9053() throws Exception {
+        PathOptimizer data = parse(TestUtils.getRegressionDataFile(9053, "testpdf.pdf"));
+        assertEquals(0, data.bounds.getMinX(), 0);
+        assertEquals(0, data.bounds.getMinY(), 0);
+        assertEquals(595.27557, data.bounds.getMaxX(), 0.00001);
+        assertEquals(841.88977, data.bounds.getMaxY(), 0.00001);
+        assertEquals(4, data.uniquePoints.size());
+        assertEquals(1, data.getLayers().size());
+    }
+
+    @Test
+    public void testParse12176() throws Exception {
+        PathOptimizer data = parse(TestUtils.getRegressionDataFile(12176, "LYD_Etage_0.pdf"));
+        assertEquals(new Rectangle(595, 842), data.bounds);
+        assertEquals(127300, data.uniquePoints.size());
+        assertEquals(34, data.getLayers().size());
+    }
+}
