diff --git a/frontend-js/src/main/js/ServerConnector.js b/frontend-js/src/main/js/ServerConnector.js
index ae6de2653f56a887a2917c84be3e55616535e267..01b15bbea04f35ae7e9b73a9cf86eb5da8760bf3 100644
--- a/frontend-js/src/main/js/ServerConnector.js
+++ b/frontend-js/src/main/js/ServerConnector.js
@@ -1937,6 +1937,20 @@ ServerConnector.getImageDownloadUrl = function (params) {
   });
 };
 
+/**
+ *
+ * @param {Object} params
+ * @param {string} [params.projectId]
+ * @param {number} params.modelId
+ * @param {string} [params.polygonString]
+ * @param {string} params.handlerClass
+ * @param {number} [params.backgroundOverlayId]
+ * @param {number} [params.zoomLevel]
+ * @param {number[]} [params.overlayIds]
+ * @param {number[]} [params.elementIds]
+ * @param {number[]} [params.reactionIds]
+ * @returns {Promise}
+ */
 ServerConnector.getModelDownloadUrl = function (params) {
   var self = this;
   var queryParams = {
@@ -1944,12 +1958,13 @@ ServerConnector.getModelDownloadUrl = function (params) {
     modelId: params.modelId
   };
   var filterParams = {
-    token: params.token,
     polygonString: params.polygonString,
     handlerClass: params.handlerClass,
     backgroundOverlayId: params.backgroundOverlayId,
     zoomLevel: params.zoomLevel,
-    overlayIds: this.idsToString(params.overlayIds)
+    overlayIds: this.idsToString(params.overlayIds),
+    elementIds: this.idsToString(params.elementIds),
+    reactionIds: this.idsToString(params.reactionIds)
   };
   return self.getProjectId(params.projectId).then(function (result) {
     queryParams.projectId = result;
@@ -1957,6 +1972,41 @@ ServerConnector.getModelDownloadUrl = function (params) {
   });
 };
 
+/**
+ *
+ * @param {Object} params
+ * @param {string} [params.projectId]
+ * @param {number} params.modelId
+ * @param {string} [params.polygonString]
+ * @param {string} params.handlerClass
+ * @param {number} [params.backgroundOverlayId]
+ * @param {number} [params.zoomLevel]
+ * @param {number[]} [params.overlayIds]
+ * @param {number[]} [params.elementIds]
+ * @param {number[]} [params.reactionIds]
+ * @returns {Promise}
+ */
+ServerConnector.getPartOfModelInExportFormat = function (params) {
+  var self = this;
+  var queryParams = {
+    projectId: params.projectId,
+    modelId: params.modelId
+  };
+  var filterParams = {
+    polygonString: params.polygonString,
+    handlerClass: params.handlerClass,
+    backgroundOverlayId: params.backgroundOverlayId,
+    zoomLevel: params.zoomLevel,
+    overlayIds: this.idsToString(params.overlayIds),
+    elementIds: this.idsToString(params.elementIds),
+    reactionIds: this.idsToString(params.reactionIds)
+  };
+  return self.getProjectId(params.projectId).then(function (result) {
+    queryParams.projectId = result;
+    return self.sendPostRequest(self.getModelPartUrl(queryParams), filterParams);
+  });
+};
+
 ServerConnector.getImageConverters = function () {
   var self = this;
   return self.getConfiguration().then(function (configuration) {
diff --git a/frontend-js/src/main/js/plugin/MinervaPluginProxy.js b/frontend-js/src/main/js/plugin/MinervaPluginProxy.js
index 6a30568a937a07888ecc4bd7b106fbfde43e8a02..15fbc9e6587bbb7ce763ac7e7200e7bfbd206cf5 100644
--- a/frontend-js/src/main/js/plugin/MinervaPluginProxy.js
+++ b/frontend-js/src/main/js/plugin/MinervaPluginProxy.js
@@ -137,6 +137,38 @@ function createProjectData(options) {
         }
       });
     },
+    /**
+     * Export part of the map that includes bioEntities into a known format.
+     *
+     * @param {Object} param
+     * @param {string} param.handlerClass format defined in {Configuration#getModelConverters}
+     * @param {number} param.modelId id of the model
+     * @param {Array} param.bioEntities
+     * @returns {Promise}
+     */
+    exportToMapFormat: function (param) {
+      var exportParams = {
+        projectId: map.getProject().getProjectId(),
+        modelId: param.modelId,
+        handlerClass: param.handlerClass,
+        elementIds: [],
+        reactionIds: []
+      };
+      for (var i = 0; i < param.bioEntities.length; i++) {
+        var ie = new IdentifiedElement(param.bioEntities[i]);
+        if (ie.getType() === "ALIAS") {
+          exportParams.elementIds.push(ie.getId());
+        } else if (ie.getType() === "REACTION") {
+          exportParams.reactionIds.push(ie.getId());
+        } else {
+          return Promise.reject(new Error("Unsupported bioentity type: " + ie.getType()));
+        }
+        if (ie.getModelId() !== param.modelId) {
+          return Promise.reject(new Error("Export of bioEntities from few maps is not supported. ModelId: " + param.modelId + "; element modelId: " + ie.getModelId()));
+        }
+      }
+      return options.map.getServerConnector().getPartOfModelInExportFormat(exportParams);
+    },
     getAllBioEntities: function () {
       var models = map.getProject().getModels();
       var result = [];
@@ -312,7 +344,7 @@ function createWrapperFunctionForDialogGuiUpdate(param) {
  * @param {CustomMap} options.map
  * @param {Plugin} options.plugin
  * @param {string} options.pluginId
- * @returns {{getVisibleDataOverlays: function(): (Promise<DataOverlay[]>|*), addListener: addListener, removeListener: removeListener, removeAllListeners: function(): Array, getHighlightedBioEntities: function(*=): *, showBioEntity: function(*=): *, hideBioEntity: function(*=): Promise<T>, setCenter: function(*): PromiseLike, getCenter: function(*): Point, getBounds: function(*): Bounds, fitBounds: function(*): void, setZoom: function(*): *, getZoom: function(*): number, openMap: function(*): PromiseLike}}
+ * @returns {{getVisibleDataOverlays: (function(): (Promise<DataOverlay[]>|*)), addListener: addListener, removeListener: removeListener, removeAllListeners: (function(): Array), getHighlightedBioEntities: (function(*=): Promise<Array | never>), showBioEntity: (function(*=): *), hideBioEntity: (function(*=): Promise<any | never>), setCenter: (function(*): PromiseLike), getCenter: (function(*): Point), getBounds: (function(*): Bounds), fitBounds: (function(*): void), setZoom: (function(*): *), getZoom: (function(*): number), openMap: (function(*): PromiseLike)}}
  */
 function createProjectMap(options) {
   var map = options.map;
@@ -569,7 +601,7 @@ function createProjectMap(options) {
  * @param {CustomMap} options.map
  * @param {Plugin} options.plugin
  * @param {string} options.pluginId
- * @returns {{data: {getBioEntityById: function(*=): Promise<any>, getAllBioEntities: function(): *, getReactionsWithElement: function(*=): *, getProjectId: function(): string, getName: function(): string, getVersion: function(): string, getDisease: getDisease, getOrganism: getOrganism, getModels: function(): *[]}, map: {getVisibleDataOverlays: function(): (Promise<DataOverlay[]>|*), addListener: addListener, removeListener: removeListener, removeAllListeners: function(): Array, getHighlightedBioEntities: function(*=): *, showBioEntity: function(*=): *, hideBioEntity: function(*=): Promise<T>, setCenter: function(*): PromiseLike, getCenter: function(*): Point, getBounds: function(*): Bounds, fitBounds: function(*): void, setZoom: function(*): *, getZoom: function(*): number, openMap: function(*): PromiseLike}}}
+ * @returns {{data: {getBioEntityById: (function(*=): Promise<any>), getAllBioEntities: (function(): *), getReactionsWithElement: (function(*=): *), getProjectId: (function(): string), getName: (function(): string), getVersion: (function(): string), getDisease: getDisease, getOrganism: getOrganism, getModels: (function(): *[])}, map: {getVisibleDataOverlays: (function(): (Promise<DataOverlay[]>|*)), addListener: addListener, removeListener: removeListener, removeAllListeners: (function(): Array), getHighlightedBioEntities: (function(*=): Promise<Array|never>), showBioEntity: (function(*=): *), hideBioEntity: (function(*=): Promise<any|never>), setCenter: (function(*): PromiseLike), getCenter: (function(*): Point), getBounds: (function(*): Bounds), fitBounds: (function(*): void), setZoom: (function(*): *), getZoom: (function(*): number), openMap: (function(*): PromiseLike)}}}
  */
 function createProject(options) {
   return {
@@ -635,17 +667,16 @@ function createPluginData(options) {
  * @param {HTMLElement} options.element
  * @param {Configuration} options.configuration
  * @param {ServerConnector} options.serverConnector
- * @returns {{pluginId: string|string, element: *, project: {data: {getBioEntityById: function(*=): Promise<any>, getAllBioEntities: function(): *, getReactionsWithElement: function(*=): *, getProjectId: function(): string, getName: function(): string, getVersion: function(): string, getDisease: getDisease, getOrganism: getOrganism, getModels: function(): *[]}, map: {getVisibleDataOverlays: function(): (Promise<DataOverlay[]>|*), addListener: addListener, removeListener: removeListener, removeAllListeners: function(): Array, getHighlightedBioEntities: function(*=): *, showBioEntity: function(*=): *, hideBioEntity: function(*=): Promise<T>, setCenter: function(*): PromiseLike, getCenter: function(*): Point, getBounds: function(*): Bounds, fitBounds: function(*): void, setZoom: function(*): *, getZoom: function(*): number, openMap: function(*): PromiseLike}}, configuration: {options: ConfigurationOption[], overlayTypes: string[], imageConverters: ImageConverter[], modelConverters: ModelConverter[], elementTypes: BioEntityType[], reactionTypes: BioEntityType[], miriamTypes: MiriamType[], mapTypes: MapType[], modificationStateTypes: ModificationStateType[], privilegeTypes: PrivilegeType[], annotators: Annotator[]}, pluginData: {setGlobalParam: function(*=, *=): *, getGlobalParam: function(*=): *, setUserParam: function(*=, *=): *, getUserParam: function(*=): *}}}
+ * @returns {{pluginId: (string|string), element: HTMLElement, project: {data: {getBioEntityById: (function(*=): Promise<any>), getAllBioEntities: (function(): *), getReactionsWithElement: (function(*=): *), getProjectId: (function(): string), getName: (function(): string), getVersion: (function(): string), getDisease: getDisease, getOrganism: getOrganism, getModels: (function(): *[])}, map: {getVisibleDataOverlays: (function(): (Promise<DataOverlay[]>|*)), addListener: addListener, removeListener: removeListener, removeAllListeners: (function(): Array), getHighlightedBioEntities: (function(*=): Promise<Array|never>), showBioEntity: (function(*=): *), hideBioEntity: (function(*=): Promise<any|never>), setCenter: (function(*): PromiseLike), getCenter: (function(*): Point), getBounds: (function(*): Bounds), fitBounds: (function(*): void), setZoom: (function(*): *), getZoom: (function(*): number), openMap: (function(*): PromiseLike)}}, configuration: {options: ConfigurationOption[], overlayTypes: string[], imageConverters: ImageConverter[], modelConverters: ModelConverter[], elementTypes: BioEntityType[], reactionTypes: BioEntityType[], miriamTypes: MiriamType[], mapTypes: MapType[], modificationStateTypes: ModificationStateType[], privilegeTypes: PrivilegeType[], annotators: Annotator[]}, pluginData: {setGlobalParam: (function(*=, *=): *), getGlobalParam: (function(*=): *), setUserParam: (function(*=, *=): *), getUserParam: (function(*=): *)}}}
  * @constructor
  */
 function MinervaPluginProxy(options) {
-  return {
-    pluginId: options.pluginId,
-    element: options.element,
-    project: createProject(options),
-    configuration: createConfiguration(options),
-    pluginData: createPluginData(options)
-  };
+  this.pluginId = options.pluginId;
+  this.element = options.element;
+  this.project = createProject(options);
+  this.configuration = createConfiguration(options);
+  this.pluginData = createPluginData(options);
+
 }
 
 module.exports = MinervaPluginProxy;
diff --git a/frontend-js/src/test/js/plugin/MinervaPluginProxy-test.js b/frontend-js/src/test/js/plugin/MinervaPluginProxy-test.js
index 4715ed3b0fed6036022550d246f856fe9a689e75..116e8d8537e7e2190081c191c07ee9c6a2910d54 100644
--- a/frontend-js/src/test/js/plugin/MinervaPluginProxy-test.js
+++ b/frontend-js/src/test/js/plugin/MinervaPluginProxy-test.js
@@ -181,10 +181,10 @@ describe('MinervaPluginProxy', function () {
 
   describe("getBioEntityById", function () {
     it("for alias", function () {
-      var map, proxy;
+      var map;
       return ServerConnector.getProject().then(function (project) {
         map = helper.createCustomMap(project);
-        proxy = createProxy(map);
+        var proxy = createProxy(map);
         return proxy.project.data.getBioEntityById({
           id: 329177,
           modelId: 15781,
@@ -198,10 +198,10 @@ describe('MinervaPluginProxy', function () {
     });
 
     it("for reaction", function () {
-      var map, proxy;
+      var map;
       return ServerConnector.getProject().then(function (project) {
         map = helper.createCustomMap(project);
-        proxy = createProxy(map);
+        var proxy = createProxy(map);
         return proxy.project.data.getBioEntityById({
           id: 153508,
           modelId: 15781,
@@ -216,6 +216,26 @@ describe('MinervaPluginProxy', function () {
     });
   });
 
+  describe("exportToMapFormat", function () {
+    it("for alias", function () {
+      var map;
+      return ServerConnector.getProject().then(function (project) {
+        map = helper.createCustomMap(project);
+        var proxy = createProxy(map);
+        return proxy.project.data.exportToMapFormat({
+          modelId: 15781,
+          bioEntities: [{id: 329177, modelId: 15781, type: "ALIAS"}],
+          handlerClass: helper.getConfiguration().getModelConverters()[0].handler
+        });
+      }).then(function (result) {
+        assert.ok(result);
+      }).then(function () {
+        map.destroy();
+      });
+    });
+
+  });
+
   describe("showElement", function () {
     it("alias", function () {
       var elementToShow = {
@@ -238,7 +258,8 @@ describe('MinervaPluginProxy', function () {
           color: "#FF0000"
         }
       };
-      var map, proxy;
+      var map;
+      var proxy;
       return ServerConnector.getProject().then(function (project) {
         map = helper.createCustomMap(project);
         proxy = createProxy(map);
diff --git a/frontend-js/testFiles/apiCalls/projects/sample/models/15781.downloadModel/POST_elementIds=329177&handlerClass=lcsb.mapviewer.converter.model.celldesigner.CellDesignerXmlParser&token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/projects/sample/models/15781.downloadModel/POST_elementIds=329177&handlerClass=lcsb.mapviewer.converter.model.celldesigner.CellDesignerXmlParser&token=MOCK_TOKEN_ID&
new file mode 100644
index 0000000000000000000000000000000000000000..c83f0983baeb47529744650af680789d24fa844e
--- /dev/null
+++ b/frontend-js/testFiles/apiCalls/projects/sample/models/15781.downloadModel/POST_elementIds=329177&handlerClass=lcsb.mapviewer.converter.model.celldesigner.CellDesignerXmlParser&token=MOCK_TOKEN_ID&
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<sbml xmlns="http://www.sbml.org/sbml/level2/version4" xmlns:celldesigner="http://www.sbml.org/2001/ns/celldesigner" level="2" version="4">
+<model metaid="untitled" id="untitled">
+<listOfUnitDefinitions>
+</listOfUnitDefinitions>
+<listOfFunctionDefinitions>
+</listOfFunctionDefinitions>
+<annotation>
+<celldesigner:extension>
+<celldesigner:modelVersion>4.0</celldesigner:modelVersion>
+<celldesigner:modelDisplay sizeX="1305" sizeY="473"/>
+<celldesigner:listOfIncludedSpecies>
+</celldesigner:listOfIncludedSpecies>
+<celldesigner:listOfCompartmentAliases>
+</celldesigner:listOfCompartmentAliases>
+<celldesigner:listOfComplexSpeciesAliases>
+</celldesigner:listOfComplexSpeciesAliases>
+<celldesigner:listOfSpeciesAliases>
+<celldesigner:speciesAlias id="sa10" species="s_id_sa10" >
+<celldesigner:activity>inactive</celldesigner:activity>
+<celldesigner:bounds x="0.0" y="186.0" w="80.0" h="30.0" />
+<celldesigner:font size="12.0"/>
+<celldesigner:view state="usual"/>
+<celldesigner:usualView><celldesigner:innerPosition x="0.0" y="186.0"/><celldesigner:boxSize width="80.0" height="30.0"/><celldesigner:singleLine width="1.0"/><celldesigner:paint color="FFFF00FF" scheme="Color"/></celldesigner:usualView>
+<celldesigner:briefView><celldesigner:innerPosition x="0.0" y="186.0"/><celldesigner:boxSize width="80.0" height="30.0"/><celldesigner:singleLine width="1.0"/><celldesigner:paint color="FFFF00FF" scheme="Color"/></celldesigner:briefView>
+</celldesigner:speciesAlias>
+</celldesigner:listOfSpeciesAliases>
+<celldesigner:listOfProteins></celldesigner:listOfProteins>
+<celldesigner:listOfGenes></celldesigner:listOfGenes>
+<celldesigner:listOfRNAs></celldesigner:listOfRNAs>
+<celldesigner:listOfAntisenseRNAs></celldesigner:listOfAntisenseRNAs>
+<celldesigner:listOfLayers></celldesigner:listOfLayers>
+</celldesigner:extension>
+</annotation>
+<listOfCompartments>
+<compartment metaid="default" id="default" name="" size="1" units="volume" >
+<annotation>
+<celldesigner:extension>
+<celldesigner:name></celldesigner:name>
+</celldesigner:extension>
+<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:vCard="http://www.w3.org/2001/vcard-rdf/3.0#" xmlns:bqbiol="http://biomodels.net/biology-qualifiers/" xmlns:bqmodel="http://biomodels.net/model-qualifiers/">
+<rdf:Description rdf:about="#">
+</rdf:Description>
+</rdf:RDF>
+</annotation>
+<notes><html xmlns="http://www.w3.org/1999/xhtml"><head><title/></head><body>
+</body></html></notes>
+</compartment>
+</listOfCompartments>
+<listOfSpecies><species  name="s10" id="s_id_sa10" metaid="s_id_sa10" initialAmount="0.0" compartment="default"><annotation><celldesigner:extension><celldesigner:positionToCompartment>inside</celldesigner:positionToCompartment><celldesigner:speciesIdentity><celldesigner:class>DRUG</celldesigner:class>
+<celldesigner:name>s10</celldesigner:name>
+</celldesigner:speciesIdentity>
+</celldesigner:extension>
+<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:vCard="http://www.w3.org/2001/vcard-rdf/3.0#" xmlns:bqbiol="http://biomodels.net/biology-qualifiers/" xmlns:bqmodel="http://biomodels.net/model-qualifiers/">
+<rdf:Description rdf:about="#">
+</rdf:Description>
+</rdf:RDF>
+</annotation>
+</species>
+</listOfSpecies>
+<listOfReactions>
+</listOfReactions>
+<notes></notes></model></sbml>
\ No newline at end of file
diff --git a/model-command/src/main/java/lcsb/mapviewer/commands/SubModelCommand.java b/model-command/src/main/java/lcsb/mapviewer/commands/SubModelCommand.java
index 0ab7ea8d342d85d8b1df2ed67da5d0511292b20a..b1e301093a37e90c7e003adfb607acfadd20ca73 100644
--- a/model-command/src/main/java/lcsb/mapviewer/commands/SubModelCommand.java
+++ b/model-command/src/main/java/lcsb/mapviewer/commands/SubModelCommand.java
@@ -6,14 +6,15 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
+import org.apache.log4j.Logger;
+
 import lcsb.mapviewer.model.map.layout.graphics.Layer;
 import lcsb.mapviewer.model.map.layout.graphics.LayerText;
 import lcsb.mapviewer.model.map.model.Model;
-import lcsb.mapviewer.model.map.reaction.AbstractNode;
 import lcsb.mapviewer.model.map.reaction.Reaction;
 import lcsb.mapviewer.model.map.reaction.ReactionNode;
-import lcsb.mapviewer.model.map.species.Element;
 import lcsb.mapviewer.model.map.species.Complex;
+import lcsb.mapviewer.model.map.species.Element;
 import lcsb.mapviewer.model.map.species.Species;
 
 /**
@@ -24,118 +25,160 @@ import lcsb.mapviewer.model.map.species.Species;
  * 
  */
 public class SubModelCommand extends NewModelCommand {
-	
-	/**
-	 * Polygon that limits the area for the new model.
-	 * 
-	 */
-	private Path2D polygon;
-
-	/**
-	 * Default constructor.
-	 * 
-	 * @param model
-	 *          original {@link NewModelCommand#model}
-	 * @param polygon
-	 *          #polygon that limits the area for the new model
-	 */
-	public SubModelCommand(Model model, Path2D polygon) {
-		super(model);
-		this.polygon = polygon;
-	}
-
-	@Override
-	public Model execute() {
-		CopyCommand copy = new CopyCommand(getModel());
-		Model result = copy.execute();
-
-		Set<Element> aliasNotToRemove = new HashSet<Element>();
-
-		for (Element alias : result.getElements()) {
-			if (polygon.intersects(alias.getBorder())) {
-				aliasNotToRemove.add(alias);
-			}
-		}
-		boolean added = false;
-		do {
-			Set<Element> iterativeAliasNotToRemove = new HashSet<>();
-			for (Element alias : aliasNotToRemove) {
-				Element parent = alias.getCompartment();
-				if (parent != null) {
-					if (!aliasNotToRemove.contains(parent)) {
-						iterativeAliasNotToRemove.add(parent);
-					}
-				}
-				if (alias instanceof Species) {
-					parent = ((Species) alias).getComplex();
-					if (parent != null) {
-						if (!aliasNotToRemove.contains(parent)) {
-							iterativeAliasNotToRemove.add(parent);
-						}
-					}
-				}
-			}
-
-			added = iterativeAliasNotToRemove.size() != 0;
-			aliasNotToRemove.addAll(iterativeAliasNotToRemove);
-		} while (added);
-
-		List<Element> aliasToRemove = new ArrayList<Element>();
-		for (Element alias : result.getElements()) {
-			if (!(polygon.intersects(alias.getBorder()))) {
-				boolean remove = true;
-				if (alias instanceof Species) {
-					remove = ((Species) alias).getComplex() == null;
-				}
-				if (aliasNotToRemove.contains(alias)) {
-					remove = false;
-				}
-				if (remove) {
-					aliasToRemove.add(alias);
-					if (alias instanceof Complex) {
-						List<Species> aliases = ((Complex) alias).getAllChildren();
-						aliasToRemove.addAll(aliases);
-					}
-				}
-			}
-
-		}
-		for (Element alias : aliasToRemove) {
-			result.removeElement(alias);
-		}
-
-		List<Reaction> reactionsToRemove = new ArrayList<Reaction>();
-		for (Reaction reaction : result.getReactions()) {
-			boolean remove = false;
-			for (AbstractNode node : reaction.getNodes()) {
-				if (node instanceof ReactionNode) {
-					if (!result.getElements().contains(((ReactionNode) node).getElement())) {
-						remove = true;
-						break;
-					}
-				}
-			}
-			if (remove) {
-				reactionsToRemove.add(reaction);
-			}
-		}
-		for (Reaction reaction : reactionsToRemove) {
-			result.removeReaction(reaction);
-		}
-
-		for (Layer layer : result.getLayers()) {
-			List<LayerText> textToRemove = new ArrayList<LayerText>();
-			for (LayerText text : layer.getTexts()) {
-				if (!(polygon.intersects(text.getBorder()))) {
-					textToRemove.add(text);
-				}
-			}
-			for (LayerText text : textToRemove) {
-				layer.removeLayerText(text);
-			}
-		}
-
-		return result;
-	}
+
+  Logger logger = Logger.getLogger(SubModelCommand.class);
+
+  /**
+   * Polygon that limits the area for the new model.
+   * 
+   */
+  private Path2D polygon;
+
+  private Set<Integer> elementIds;
+
+  private Set<Integer> reactionIds;
+
+  /**
+   * Default constructor.
+   * 
+   * @param model
+   *          original {@link NewModelCommand#model}
+   * @param polygon
+   *          #polygon that limits the area for the new model
+   */
+  public SubModelCommand(Model model, Path2D polygon) {
+    this(model, polygon, new HashSet<>(), new HashSet<>());
+  }
+
+  /**
+   * Default constructor.
+   * 
+   * @param model
+   *          original {@link NewModelCommand#model}
+   * @param polygon
+   *          #polygon that limits the area for the new model
+   */
+  public SubModelCommand(Model model, Path2D polygon, Set<Integer> elementIds, Set<Integer> reactionIds) {
+    super(model);
+    this.polygon = polygon;
+    this.elementIds = elementIds;
+    this.reactionIds = reactionIds;
+  }
+
+  @Override
+  public Model execute() {
+    CopyCommand copy = new CopyCommand(getModel());
+    Model result = copy.execute();
+
+    Set<Element> inputElements = new HashSet<>();
+    if (elementIds.size() == 0) {
+      inputElements.addAll(result.getElements());
+    } else {
+      for (Element element : getModel().getElements()) {
+        if (elementIds.contains(element.getId())) {
+          inputElements.add(result.getElementByElementId(element.getElementId()));
+        }
+      }
+    }
+
+    Set<Element> aliasNotToRemove = new HashSet<>();
+
+    for (Element alias : result.getElements()) {
+      if (polygon.intersects(alias.getBorder())) {
+        aliasNotToRemove.add(alias);
+      }
+    }
+    aliasNotToRemove.retainAll(inputElements);
+
+    boolean added = false;
+    do {
+      Set<Element> iterativeAliasNotToRemove = new HashSet<>();
+      for (Element alias : aliasNotToRemove) {
+        Element parent = alias.getCompartment();
+        if (parent != null) {
+          if (!aliasNotToRemove.contains(parent)) {
+            iterativeAliasNotToRemove.add(parent);
+          }
+        }
+        if (alias instanceof Species) {
+          parent = ((Species) alias).getComplex();
+          if (parent != null) {
+            if (!aliasNotToRemove.contains(parent)) {
+              iterativeAliasNotToRemove.add(parent);
+            }
+          }
+        }
+      }
+
+      added = iterativeAliasNotToRemove.size() != 0;
+      aliasNotToRemove.addAll(iterativeAliasNotToRemove);
+    } while (added);
+
+    List<Element> aliasToRemove = new ArrayList<>();
+    for (Element element : result.getElements()) {
+      if (!(polygon.intersects(element.getBorder())) || !inputElements.contains(element)) {
+        boolean remove = true;
+        if (element instanceof Species) {
+          remove = ((Species) element).getComplex() == null;
+        }
+        if (aliasNotToRemove.contains(element)) {
+          remove = false;
+        }
+        if (remove) {
+          aliasToRemove.add(element);
+          if (element instanceof Complex) {
+            List<Species> aliases = ((Complex) element).getAllChildren();
+            aliasToRemove.addAll(aliases);
+          }
+        }
+      }
+
+    }
+    for (Element alias : aliasToRemove) {
+      result.removeElement(alias);
+    }
+
+    Set<String> reactionStringIds = new HashSet<>();
+    for (Reaction reaction : getModel().getReactions()) {
+      if (reactionIds.size() == 0 || reactionIds.contains(reaction.getId())) {
+        reactionStringIds.add(reaction.getElementId());
+      }
+    }
+
+    List<Reaction> reactionsToRemove = new ArrayList<>();
+    for (Reaction reaction : result.getReactions()) {
+      boolean remove = false;
+      if (!reactionStringIds.contains(reaction.getElementId())) {
+        remove = true;
+      } else {
+        for (ReactionNode node : reaction.getReactionNodes()) {
+          if (!result.getElements().contains(node.getElement())) {
+            remove = true;
+            break;
+          }
+        }
+      }
+      if (remove) {
+        reactionsToRemove.add(reaction);
+      }
+    }
+    for (Reaction reaction : reactionsToRemove) {
+      result.removeReaction(reaction);
+    }
+
+    for (Layer layer : result.getLayers()) {
+      List<LayerText> textToRemove = new ArrayList<>();
+      for (LayerText text : layer.getTexts()) {
+        if (!(polygon.intersects(text.getBorder()))) {
+          textToRemove.add(text);
+        }
+      }
+      for (LayerText text : textToRemove) {
+        layer.removeLayerText(text);
+      }
+    }
+
+    return result;
+  }
 
 }
diff --git a/model-command/src/test/java/lcsb/mapviewer/commands/SubModelCommandTest.java b/model-command/src/test/java/lcsb/mapviewer/commands/SubModelCommandTest.java
index ccfb0bb1adb1959a048126a8de13f1522eabff26..d4e7f30e6ed84db9ffad7a6caa4a5ebdacddf562 100644
--- a/model-command/src/test/java/lcsb/mapviewer/commands/SubModelCommandTest.java
+++ b/model-command/src/test/java/lcsb/mapviewer/commands/SubModelCommandTest.java
@@ -2,167 +2,245 @@ package lcsb.mapviewer.commands;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
 import java.awt.geom.Path2D;
 import java.io.ByteArrayInputStream;
 import java.io.InputStream;
 import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.HashSet;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
 
 import lcsb.mapviewer.converter.ConverterParams;
 import lcsb.mapviewer.converter.model.celldesigner.CellDesignerXmlParser;
 import lcsb.mapviewer.model.map.model.Model;
 import lcsb.mapviewer.model.map.model.ModelComparator;
 
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
 public class SubModelCommandTest extends CommandTestFunctions {
 
-	@Before
-	public void setUp() throws Exception {
-	}
-
-	@After
-	public void tearDown() throws Exception {
-	}
-
-	@Test
-	public void testGetSubmodel1() throws Exception {
-		try {
-			Model model = getModelForFile("testFiles/spliting_test_Case.xml", true);
-
-			Path2D polygon = new Path2D.Double();
-			polygon.moveTo(0, 0);
-			polygon.lineTo(0, 100);
-			polygon.lineTo(100, 100);
-			polygon.lineTo(100, 0);
-			polygon.closePath();
-
-			Model copy = new SubModelCommand(model, polygon).execute();
-
-			assertEquals(2, copy.getElements().size());
-			assertEquals(0, copy.getReactions().size());
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testGetSubmodel2() throws Exception {
-		try {
-			Model model = getModelForFile("testFiles/spliting_test_Case.xml", true);
-
-			Path2D polygon = new Path2D.Double();
-			polygon.moveTo(50, 50);
-			polygon.lineTo(350, 50);
-			polygon.lineTo(350, 200);
-			polygon.lineTo(50, 200);
-			polygon.closePath();
-
-			Model copy = new SubModelCommand(model, polygon).execute();
-
-			assertEquals(9, copy.getElements().size());
-			assertEquals(1, copy.getReactions().size());
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testGetSubmodel3() throws Exception {
-		try {
-			Model model = getModelForFile("testFiles/spliting_test_Case.xml", true);
-
-			Path2D polygon = new Path2D.Double();
-			polygon.moveTo(0, 200);
-			polygon.lineTo(350, 200);
-			polygon.lineTo(350, 400);
-			polygon.lineTo(0, 400);
-			polygon.closePath();
-
-			Model copy = new SubModelCommand(model, polygon).execute();
-
-			double dx = 10;
-			double dy = -10;
-
-			new MoveCommand(copy, dx, dy).execute();
-
-			assertEquals(model.getElementByElementId("sa3").getCenterX(), copy.getElementByElementId("sa3").getCenterX() - dx, EPSILON);
-			assertEquals(model.getElementByElementId("sa3").getCenterY(), copy.getElementByElementId("sa3").getCenterY() - dy, EPSILON);
-
-			assertEquals(model.getReactionByReactionId("re3").getLines().get(0).getX2(), copy.getReactionByReactionId("re3").getLines().get(0).getX2() - dx, EPSILON);
-			assertEquals(model.getReactionByReactionId("re3").getLines().get(0).getY2(), copy.getReactionByReactionId("re3").getLines().get(0).getY2() - dy, EPSILON);
-
-			CellDesignerXmlParser parser = new CellDesignerXmlParser();
-			String xml = parser.toXml(copy);
-
-			InputStream stream = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
-			Model copy2 = parser.createModel(new ConverterParams().inputStream(stream).sizeAutoAdjust(false));
-			ModelComparator comparator = new ModelComparator();
-
-			// check if after conversion to xml everything works
-			assertEquals(0, comparator.compare(copy, copy2));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testGetSubmodelWithoutCompartments() throws Exception {
-		try {
-			Model model = getModelForFile("testFiles/compartments.xml", true);
-
-			Path2D polygon = new Path2D.Double();
-			polygon.moveTo(0, 10);
-			polygon.lineTo(10, 10);
-			polygon.lineTo(10, 0);
-			polygon.lineTo(0, 0);
-			polygon.closePath();
-
-			Model copy = new SubModelCommand(model, polygon).execute();
-
-			// we should cut off some of compartmets
-			assertFalse(model.getLayers().iterator().next().getTexts().size() == copy.getLayers().iterator().next().getTexts().size());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testGetSubmodelWithoutCompartments2() throws Exception {
-		try {
-			Model model = getModelForFile("testFiles/problematic/cutting_without_compartment.xml", true);
-
-			Path2D polygon = new Path2D.Double();
-			polygon.moveTo(0, 0);
-			polygon.lineTo(0, 500);
-			polygon.lineTo(300, 500);
-			polygon.lineTo(300, 0);
-			polygon.closePath();
-
-			Model copy = new SubModelCommand(model, polygon).execute();
-
-			CellDesignerXmlParser parser = new CellDesignerXmlParser();
-			String xmlString = parser.toXml(copy);
-
-			InputStream stream = new ByteArrayInputStream(xmlString.getBytes(StandardCharsets.UTF_8));
-
-			Model model2 = parser.createModel(new ConverterParams().inputStream(stream).sizeAutoAdjust(false));
-
-			ModelComparator mc = new ModelComparator();
-			assertEquals(0, mc.compare(copy, model2));
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
+  @Before
+  public void setUp() throws Exception {
+  }
+
+  @After
+  public void tearDown() throws Exception {
+  }
+
+  @Test
+  public void testGetSubmodel1() throws Exception {
+    try {
+      Model model = getModelForFile("testFiles/spliting_test_Case.xml", true);
+
+      Path2D polygon = new Path2D.Double();
+      polygon.moveTo(0, 0);
+      polygon.lineTo(0, 100);
+      polygon.lineTo(100, 100);
+      polygon.lineTo(100, 0);
+      polygon.closePath();
+
+      Model copy = new SubModelCommand(model, polygon).execute();
+
+      assertEquals(2, copy.getElements().size());
+      assertEquals(0, copy.getReactions().size());
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetSubmodel2() throws Exception {
+    try {
+      Model model = getModelForFile("testFiles/spliting_test_Case.xml", true);
+
+      Path2D polygon = new Path2D.Double();
+      polygon.moveTo(50, 50);
+      polygon.lineTo(350, 50);
+      polygon.lineTo(350, 200);
+      polygon.lineTo(50, 200);
+      polygon.closePath();
+
+      Model copy = new SubModelCommand(model, polygon).execute();
+
+      assertEquals(9, copy.getElements().size());
+      assertEquals(1, copy.getReactions().size());
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetSubmodel3() throws Exception {
+    try {
+      Model model = getModelForFile("testFiles/spliting_test_Case.xml", true);
+
+      Path2D polygon = new Path2D.Double();
+      polygon.moveTo(0, 200);
+      polygon.lineTo(350, 200);
+      polygon.lineTo(350, 400);
+      polygon.lineTo(0, 400);
+      polygon.closePath();
+
+      Model copy = new SubModelCommand(model, polygon).execute();
+
+      double dx = 10;
+      double dy = -10;
+
+      new MoveCommand(copy, dx, dy).execute();
+
+      assertEquals(model.getElementByElementId("sa3").getCenterX(), copy.getElementByElementId("sa3").getCenterX() - dx,
+          EPSILON);
+      assertEquals(model.getElementByElementId("sa3").getCenterY(), copy.getElementByElementId("sa3").getCenterY() - dy,
+          EPSILON);
+
+      assertEquals(model.getReactionByReactionId("re3").getLines().get(0).getX2(),
+          copy.getReactionByReactionId("re3").getLines().get(0).getX2() - dx, EPSILON);
+      assertEquals(model.getReactionByReactionId("re3").getLines().get(0).getY2(),
+          copy.getReactionByReactionId("re3").getLines().get(0).getY2() - dy, EPSILON);
+
+      CellDesignerXmlParser parser = new CellDesignerXmlParser();
+      String xml = parser.toXml(copy);
+
+      InputStream stream = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
+      Model copy2 = parser.createModel(new ConverterParams().inputStream(stream).sizeAutoAdjust(false));
+      ModelComparator comparator = new ModelComparator();
+
+      // check if after conversion to xml everything works
+      assertEquals(0, comparator.compare(copy, copy2));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetSubmodelWithoutCompartments() throws Exception {
+    try {
+      Model model = getModelForFile("testFiles/compartments.xml", true);
+
+      Path2D polygon = new Path2D.Double();
+      polygon.moveTo(0, 10);
+      polygon.lineTo(10, 10);
+      polygon.lineTo(10, 0);
+      polygon.lineTo(0, 0);
+      polygon.closePath();
+
+      Model copy = new SubModelCommand(model, polygon).execute();
+
+      // we should cut off some of compartmets
+      assertFalse(model.getLayers().iterator().next().getTexts().size() == copy.getLayers().iterator().next().getTexts()
+          .size());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetSubmodelWithoutCompartments2() throws Exception {
+    try {
+      Model model = getModelForFile("testFiles/problematic/cutting_without_compartment.xml", true);
+
+      Path2D polygon = new Path2D.Double();
+      polygon.moveTo(0, 0);
+      polygon.lineTo(0, 500);
+      polygon.lineTo(300, 500);
+      polygon.lineTo(300, 0);
+      polygon.closePath();
+
+      Model copy = new SubModelCommand(model, polygon).execute();
+
+      CellDesignerXmlParser parser = new CellDesignerXmlParser();
+      String xmlString = parser.toXml(copy);
+
+      InputStream stream = new ByteArrayInputStream(xmlString.getBytes(StandardCharsets.UTF_8));
+
+      Model model2 = parser.createModel(new ConverterParams().inputStream(stream).sizeAutoAdjust(false));
+
+      ModelComparator mc = new ModelComparator();
+      assertEquals(0, mc.compare(copy, model2));
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetSubmodelWithElementIds() throws Exception {
+    try {
+      Model model = getModelForFile("testFiles/spliting_test_Case.xml", false);
+
+      Path2D polygon = new Path2D.Double();
+      polygon.moveTo(0, 0);
+      polygon.lineTo(0, 1000);
+      polygon.lineTo(1000, 1000);
+      polygon.lineTo(1000, 0);
+      polygon.closePath();
+      model.getElementByElementId("sa2").setId(-2);
+
+      Model copy = new SubModelCommand(model, polygon, new HashSet<>(Arrays.asList(-2)), new HashSet<>()).execute();
+
+      assertEquals(1, copy.getElements().size());
+      assertEquals(0, copy.getReactions().size());
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetSubmodelWithEmptyElementIds() throws Exception {
+    try {
+      Model model = getModelForFile("testFiles/spliting_test_Case.xml", true);
+
+      Path2D polygon = new Path2D.Double();
+      polygon.moveTo(0, 0);
+      polygon.lineTo(0, 1000);
+      polygon.lineTo(1000, 1000);
+      polygon.lineTo(1000, 0);
+      polygon.closePath();
+
+      Model copy = new SubModelCommand(model, polygon, new HashSet<>(), new HashSet<>()).execute();
+
+      assertEquals(12, copy.getElements().size());
+      assertEquals(3, copy.getReactions().size());
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetSubmodelWithReactionIds() throws Exception {
+    try {
+      Model model = getModelForFile("testFiles/spliting_test_Case.xml", false);
+
+      Path2D polygon = new Path2D.Double();
+      polygon.moveTo(0, 0);
+      polygon.lineTo(0, 1000);
+      polygon.lineTo(1000, 1000);
+      polygon.lineTo(1000, 0);
+      polygon.closePath();
+      model.getReactions().iterator().next().setId(-2);
+
+      Model copy = new SubModelCommand(model, polygon, new HashSet<>(), new HashSet<>(Arrays.asList(-2))).execute();
+
+      assertEquals(1, copy.getReactions().size());
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
 
 }
diff --git a/rest-api/src/main/java/lcsb/mapviewer/api/projects/ProjectController.java b/rest-api/src/main/java/lcsb/mapviewer/api/projects/ProjectController.java
index c2171f9fb93d19d327cf7e73f3fde0e92724ce88..974a5950987f032f73315b455f72e281681ed551 100644
--- a/rest-api/src/main/java/lcsb/mapviewer/api/projects/ProjectController.java
+++ b/rest-api/src/main/java/lcsb/mapviewer/api/projects/ProjectController.java
@@ -22,13 +22,8 @@ import org.springframework.web.bind.annotation.RestController;
 import lcsb.mapviewer.api.BaseController;
 import lcsb.mapviewer.api.ObjectNotFoundException;
 import lcsb.mapviewer.api.QueryException;
-import lcsb.mapviewer.commands.CommandExecutionException;
 import lcsb.mapviewer.common.Configuration;
-import lcsb.mapviewer.converter.ConverterException;
-import lcsb.mapviewer.converter.graphics.DrawingException;
 import lcsb.mapviewer.model.cache.FileEntry;
-import lcsb.mapviewer.model.map.InconsistentModelException;
-import lcsb.mapviewer.model.map.layout.InvalidColorSchemaException;
 import lcsb.mapviewer.services.SecurityException;
 
 @RestController
@@ -120,50 +115,6 @@ public class ProjectController extends BaseController {
         .body(file.getFileContent());
   }
 
-  @RequestMapping(value = "/projects/{projectId}/models/{modelId}:downloadImage", method = {
-      RequestMethod.GET }, produces = { MediaType.APPLICATION_JSON_VALUE })
-  public ResponseEntity<byte[]> getModelAsImage(//
-      @CookieValue(value = Configuration.AUTH_TOKEN) String token, //
-      @PathVariable(value = "projectId") String projectId, //
-      @PathVariable(value = "modelId") String modelId, //
-      @RequestParam(value = "handlerClass") String handlerClass, //
-      @RequestParam(value = "backgroundOverlayId", defaultValue = "") String backgroundOverlayId, //
-      @RequestParam(value = "overlayIds", defaultValue = "") String overlayIds, //
-      @RequestParam(value = "zoomLevel", defaultValue = "") String zoomLevel, //
-      @RequestParam(value = "polygonString", defaultValue = "") String polygonString//
-  ) throws SecurityException, QueryException, IOException, InvalidColorSchemaException, CommandExecutionException,
-      DrawingException {
-
-    FileEntry file = projectController.getModelAsImage(token, projectId, modelId, handlerClass, backgroundOverlayId,
-        overlayIds, zoomLevel, polygonString);
-    MediaType type = MediaType.APPLICATION_OCTET_STREAM;
-    return ResponseEntity.ok().contentLength(file.getFileContent().length).contentType(type)
-        .header("Content-Disposition", "attachment; filename=" + file.getOriginalFileName())
-        .body(file.getFileContent());
-  }
-
-  @RequestMapping(value = "/projects/{projectId}/models/{modelId}:downloadModel", method = {
-      RequestMethod.GET }, produces = { MediaType.APPLICATION_JSON_VALUE })
-  public ResponseEntity<byte[]> getModelAsModelFile(//
-      @CookieValue(value = Configuration.AUTH_TOKEN) String token, //
-      @PathVariable(value = "projectId") String projectId, //
-      @PathVariable(value = "modelId") String modelId, //
-      @RequestParam(value = "handlerClass") String handlerClass, //
-      @RequestParam(value = "backgroundOverlayId", defaultValue = "") String backgroundOverlayId, //
-      @RequestParam(value = "overlayIds", defaultValue = "") String overlayIds, //
-      @RequestParam(value = "zoomLevel", defaultValue = "") String zoomLevel, //
-      @RequestParam(value = "polygonString", defaultValue = "") String polygonString//
-  ) throws SecurityException, QueryException, IOException, InvalidColorSchemaException, CommandExecutionException,
-      ConverterException, InconsistentModelException {
-
-    FileEntry file = projectController.getModelAsModelFile(token, projectId, modelId, handlerClass, backgroundOverlayId,
-        overlayIds, zoomLevel, polygonString);
-    MediaType type = MediaType.APPLICATION_OCTET_STREAM;
-    return ResponseEntity.ok().contentLength(file.getFileContent().length).contentType(type)
-        .header("Content-Disposition", "attachment; filename=" + file.getOriginalFileName())
-        .body(file.getFileContent());
-  }
-
   @RequestMapping(value = "/projects/{projectId}/logs/", method = { RequestMethod.GET }, produces = {
       MediaType.APPLICATION_JSON_VALUE })
   public Map<String, Object> getLogs(//
diff --git a/rest-api/src/main/java/lcsb/mapviewer/api/projects/ProjectRestImpl.java b/rest-api/src/main/java/lcsb/mapviewer/api/projects/ProjectRestImpl.java
index b0d4cee6b5a1daaa65835f322cb113bcb8e89719..528c189b5d01beacf58f447900357a3f34efa075 100644
--- a/rest-api/src/main/java/lcsb/mapviewer/api/projects/ProjectRestImpl.java
+++ b/rest-api/src/main/java/lcsb/mapviewer/api/projects/ProjectRestImpl.java
@@ -1,19 +1,12 @@
 package lcsb.mapviewer.api.projects;
 
-import java.awt.Color;
-import java.awt.geom.Path2D;
-import java.awt.geom.PathIterator;
 import java.awt.geom.Point2D;
 import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.FileInputStream;
 import java.io.IOException;
-import java.io.InputStream;
 import java.io.Serializable;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Comparator;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
@@ -22,7 +15,6 @@ import java.util.Map;
 import java.util.Set;
 import java.util.TreeMap;
 
-import org.apache.commons.io.IOUtils;
 import org.apache.log4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.transaction.annotation.Transactional;
@@ -34,21 +26,9 @@ import lcsb.mapviewer.api.ObjectNotFoundException;
 import lcsb.mapviewer.api.OperationNotAllowedException;
 import lcsb.mapviewer.api.QueryException;
 import lcsb.mapviewer.api.projects.models.publications.PublicationsRestImpl;
-import lcsb.mapviewer.commands.ClearColorModelCommand;
-import lcsb.mapviewer.commands.ColorExtractor;
-import lcsb.mapviewer.commands.ColorModelCommand;
-import lcsb.mapviewer.commands.CommandExecutionException;
-import lcsb.mapviewer.commands.CopyCommand;
-import lcsb.mapviewer.commands.SetFixedHierarchyLevelCommand;
-import lcsb.mapviewer.commands.SubModelCommand;
-import lcsb.mapviewer.common.Configuration;
 import lcsb.mapviewer.common.exception.InvalidArgumentException;
 import lcsb.mapviewer.common.exception.NotImplementedException;
-import lcsb.mapviewer.converter.ConverterException;
 import lcsb.mapviewer.converter.IConverter;
-import lcsb.mapviewer.converter.graphics.AbstractImageGenerator.Params;
-import lcsb.mapviewer.converter.graphics.DrawingException;
-import lcsb.mapviewer.converter.graphics.ImageGenerators;
 import lcsb.mapviewer.converter.zip.ImageZipEntryFile;
 import lcsb.mapviewer.converter.zip.LayoutZipEntryFile;
 import lcsb.mapviewer.converter.zip.ModelZipEntryFile;
@@ -58,7 +38,6 @@ import lcsb.mapviewer.model.cache.FileEntry;
 import lcsb.mapviewer.model.cache.UploadedFileEntry;
 import lcsb.mapviewer.model.graphics.MapCanvasType;
 import lcsb.mapviewer.model.map.BioEntity;
-import lcsb.mapviewer.model.map.InconsistentModelException;
 import lcsb.mapviewer.model.map.MiriamData;
 import lcsb.mapviewer.model.map.MiriamType;
 import lcsb.mapviewer.model.map.OverviewImage;
@@ -66,9 +45,6 @@ import lcsb.mapviewer.model.map.OverviewImageLink;
 import lcsb.mapviewer.model.map.OverviewLink;
 import lcsb.mapviewer.model.map.OverviewModelLink;
 import lcsb.mapviewer.model.map.OverviewSearchLink;
-import lcsb.mapviewer.model.map.layout.ColorSchema;
-import lcsb.mapviewer.model.map.layout.InvalidColorSchemaException;
-import lcsb.mapviewer.model.map.layout.Layout;
 import lcsb.mapviewer.model.map.model.Model;
 import lcsb.mapviewer.model.map.model.SubmodelType;
 import lcsb.mapviewer.model.map.reaction.Reaction;
@@ -79,24 +55,12 @@ import lcsb.mapviewer.model.user.User;
 import lcsb.mapviewer.persist.dao.ProjectDao;
 import lcsb.mapviewer.persist.dao.cache.UploadedFileEntryDao;
 import lcsb.mapviewer.services.SecurityException;
-import lcsb.mapviewer.services.interfaces.ILayoutService;
 import lcsb.mapviewer.services.interfaces.IProjectService;
-import lcsb.mapviewer.services.utils.ColorSchemaReader;
 import lcsb.mapviewer.services.utils.CreateProjectParams;
-import lcsb.mapviewer.services.utils.data.BuildInLayout;
 
 @Transactional(value = "txManager")
 public class ProjectRestImpl extends BaseRestImpl {
 
-  /**
-   * Constant defining size of the array returned by
-   * {@link PathIterator#currentSegment(double[])} method. More information can be
-   * found <a href=
-   * "http://docs.oracle.com/javase/7/docs/api/java/awt/geom/PathIterator.html#currentSegment(double[])"
-   * >here</a>
-   */
-  private static final int PATH_ITERATOR_SEGMENT_SIZE = 6;
-
   /**
    * Default class logger.
    */
@@ -105,9 +69,6 @@ public class ProjectRestImpl extends BaseRestImpl {
   @Autowired
   private PublicationsRestImpl publicationsRestImpl;
 
-  @Autowired
-  private ILayoutService layoutService;
-
   @Autowired
   private IProjectService projectService;
 
@@ -240,224 +201,6 @@ public class ProjectRestImpl extends BaseRestImpl {
     return project.getInputData();
   }
 
-  public FileEntry getModelAsImage(String token, String projectId, String modelId, String handlerClass,
-      String backgroundOverlayId, String overlayIds, String zoomLevel, String polygonString) throws SecurityException,
-      QueryException, IOException, InvalidColorSchemaException, CommandExecutionException, DrawingException {
-    User user = getUserService().getUserByToken(token);
-
-    Model topModel = getModelService().getLastModelByProjectId(projectId, token);
-    if (topModel == null) {
-      throw new ObjectNotFoundException("Project with given id doesn't exist");
-    }
-
-    Model originalModel = topModel.getSubmodelById(modelId);
-
-    if (originalModel == null) {
-      throw new ObjectNotFoundException("Model with given id doesn't exist");
-    }
-
-    Layout overlay = null;
-    if (!backgroundOverlayId.equals("")) {
-      overlay = topModel.getLayoutByIdentifier(Integer.valueOf(backgroundOverlayId));
-
-      if (overlay == null) {
-        throw new ObjectNotFoundException("Unknown overlay in model. Layout.id=" + backgroundOverlayId);
-      }
-    } else {
-      if (topModel.getLayouts().size() > 0) {
-        overlay = topModel.getLayouts().get(0);
-      }
-    }
-
-    Model colorModel = new CopyCommand(originalModel).execute();
-    if (overlay != null) {
-      if (overlay.getInputData() != null) {
-        ColorSchemaReader reader = new ColorSchemaReader();
-        Collection<ColorSchema> schemas = reader.readColorSchema(overlay.getInputData().getFileContent());
-
-        new ColorModelCommand(colorModel, schemas, getUserService().getColorExtractorForUser(user)).execute();
-      } else if (overlay.getTitle().equals(BuildInLayout.CLEAN.getTitle())) {
-        // this might not return true if we change CLEAN.title in future...
-
-        // if it's clean then remove coloring
-        new ClearColorModelCommand(colorModel).execute();
-      } else if (overlay.isHierarchicalView()) {
-        new SetFixedHierarchyLevelCommand(colorModel, overlay.getHierarchyViewLevel()).execute();
-      }
-    }
-
-    Integer level = Configuration.MIN_ZOOM_LEVEL;
-    if (!zoomLevel.equals("")) {
-      level = Integer.valueOf(zoomLevel);
-    }
-
-    Path2D polygon = stringToPolygon(polygonString, colorModel);
-
-    Double minX = originalModel.getWidth();
-    Double minY = originalModel.getHeight();
-    Double maxX = 0.0;
-    Double maxY = 0.0;
-
-    PathIterator pathIter = polygon.getPathIterator(null);
-    while (!pathIter.isDone()) {
-      final double[] segment = new double[PATH_ITERATOR_SEGMENT_SIZE];
-      if (pathIter.currentSegment(segment) != PathIterator.SEG_CLOSE) {
-        minX = Math.min(minX, segment[0]);
-        maxX = Math.max(maxX, segment[0]);
-        minY = Math.min(minY, segment[1]);
-        maxY = Math.max(maxY, segment[1]);
-      }
-      pathIter.next();
-    }
-
-    maxX = Math.min(originalModel.getWidth(), maxX);
-    maxY = Math.min(originalModel.getHeight(), maxY);
-    minX = Math.max(0.0, minX);
-    minY = Math.max(0.0, minY);
-
-    Double scale = Math.max(originalModel.getHeight(), originalModel.getWidth()) / (originalModel.getTileSize());
-
-    for (int i = level; i > Configuration.MIN_ZOOM_LEVEL; i--) {
-      scale /= 2;
-    }
-
-    ColorExtractor colorExtractor = getUserService().getColorExtractorForUser(user);
-
-    Params params = new Params().//
-        x(minX).//
-        y(minY).//
-        height((maxY - minY) / scale).//
-        width((maxX - minX) / scale).//
-        level(level - Configuration.MIN_ZOOM_LEVEL).//
-        nested(false).// automatically set nested view as invalid
-        scale(scale).//
-        colorExtractor(colorExtractor).//
-        sbgn(topModel.getProject().isSbgnFormat()).//
-        model(colorModel);
-    if (overlay != null) {
-      params.nested(overlay.isHierarchicalView());
-    }
-    List<Integer> visibleLayoutIds = deserializeIdList(overlayIds);
-    for (Integer integer : visibleLayoutIds) {
-      Map<Object, ColorSchema> map = layoutService.getElementsForLayout(colorModel, integer, token);
-      params.addVisibleLayout(map);
-    }
-
-    ImageGenerators imageGenerator = new ImageGenerators();
-    String extension = imageGenerator.getExtension(handlerClass);
-    File file = File.createTempFile("map", "." + extension);
-
-    imageGenerator.generate(handlerClass, params, file.getAbsolutePath());
-
-    UploadedFileEntry entry = new UploadedFileEntry();
-    entry.setOriginalFileName("map." + extension);
-    entry.setFileContent(IOUtils.toByteArray(new FileInputStream(file)));
-    entry.setLength(entry.getFileContent().length);
-    file.delete();
-    return entry;
-
-  }
-
-  private Path2D stringToPolygon(String polygonString, Model colorModel) {
-    String[] stringPointArray = polygonString.split(";");
-
-    List<Point2D> points = new ArrayList<>();
-    for (String string : stringPointArray) {
-      if (!string.trim().equals("")) {
-        double x = Double.valueOf(string.split(",")[0]);
-        double y = Double.valueOf(string.split(",")[1]);
-        points.add(new Point2D.Double(x, y));
-      }
-    }
-
-    if (points.size() <= 2) {
-      points.clear();
-      points.add(new Point2D.Double(0, 0));
-      points.add(new Point2D.Double(colorModel.getWidth(), 0));
-      points.add(new Point2D.Double(colorModel.getWidth(), colorModel.getHeight()));
-      points.add(new Point2D.Double(0, colorModel.getHeight()));
-    }
-
-    Path2D polygon = new Path2D.Double();
-    polygon.moveTo(points.get(0).getX(), points.get(0).getY());
-    for (int i = 1; i < points.size(); i++) {
-      Point2D point = points.get(i);
-      polygon.lineTo(point.getX(), point.getY());
-    }
-    polygon.closePath();
-    return polygon;
-  }
-
-  private List<Integer> deserializeIdList(String overlayIds) {
-    List<Integer> result = new ArrayList<>();
-    String[] tmp = overlayIds.split(",");
-    for (String string : tmp) {
-      if (!string.equals("")) {
-        result.add(Integer.valueOf(string));
-      }
-    }
-    return result;
-  }
-
-  public FileEntry getModelAsModelFile(String token, String projectId, String modelId, String handlerClass,
-      String backgroundOverlayId, String overlayIds, String zoomLevel, String polygonString)
-      throws SecurityException, QueryException, IOException, InvalidColorSchemaException, CommandExecutionException,
-      ConverterException, InconsistentModelException {
-    User user = getUserService().getUserByToken(token);
-    Model topModel = getModelService().getLastModelByProjectId(projectId, token);
-    if (topModel == null) {
-      throw new ObjectNotFoundException("Project with given id doesn't exist");
-    }
-
-    Model originalModel = topModel.getSubmodelById(modelId);
-
-    if (originalModel == null) {
-      throw new ObjectNotFoundException("Model with given id doesn't exist");
-    }
-
-    Path2D polygon = stringToPolygon(polygonString, originalModel);
-
-    // create model bounded by the polygon
-    SubModelCommand subModelCommand = new SubModelCommand(originalModel, polygon);
-    Model part = subModelCommand.execute();
-
-    // Get list of overlay ids
-    String[] overlayIdsList;
-    if (overlayIds == null || overlayIds.trim().isEmpty()) {
-      overlayIdsList = new String[0];
-    } else {
-      overlayIdsList = overlayIds.split(",");
-    }
-    // Remove all colors
-    if (overlayIdsList.length > 0) {
-
-      for (Element element : part.getElements()) {
-        element.setColor(Color.WHITE);
-      }
-    }
-    // Color with overlays
-    for (String overlayId : overlayIdsList) {
-      Layout overlay = layoutService.getLayoutById(Integer.parseInt(overlayId.trim()), token);
-
-      ColorSchemaReader reader = new ColorSchemaReader();
-      Collection<ColorSchema> schemas = reader.readColorSchema(overlay.getInputData().getFileContent());
-
-      new ColorModelCommand(part, schemas, getUserService().getColorExtractorForUser(user)).execute();
-    }
-
-    IConverter parser = getModelParser(handlerClass);
-    InputStream is = parser.exportModelToInputStream(part);
-
-    String fileExtension = parser.getFileExtension();
-
-    UploadedFileEntry entry = new UploadedFileEntry();
-    entry.setOriginalFileName("model." + fileExtension);
-    entry.setFileContent(IOUtils.toByteArray(is));
-    entry.setLength(entry.getFileContent().length);
-    return entry;
-
-  }
-
   public Map<String, Object> getStatistics(String projectId, String token)
       throws SecurityException, ObjectNotFoundException {
     Map<String, Object> result = new TreeMap<>();
@@ -740,7 +483,8 @@ public class ProjectRestImpl extends BaseRestImpl {
   public Map<String, Object> removeProject(String token, String projectId, String path)
       throws SecurityException, QueryException {
     Project project = getProjectService().getProjectByProjectId(projectId, token);
-    if (getConfigurationService().getConfigurationValue(ConfigurationElementType.DEFAULT_MAP).equals(project.getProjectId())) {
+    if (getConfigurationService().getConfigurationValue(ConfigurationElementType.DEFAULT_MAP)
+        .equals(project.getProjectId())) {
       throw new OperationNotAllowedException("You cannot remove default map");
     }
     getProjectService().removeProject(project, path, true, token);
diff --git a/rest-api/src/main/java/lcsb/mapviewer/api/projects/models/ModelController.java b/rest-api/src/main/java/lcsb/mapviewer/api/projects/models/ModelController.java
index aa9b1dbe903dcf34c32f13e835d5ec62cb9d3841..c72604753660d2bfb4462e08e3271b41e277a4a7 100644
--- a/rest-api/src/main/java/lcsb/mapviewer/api/projects/models/ModelController.java
+++ b/rest-api/src/main/java/lcsb/mapviewer/api/projects/models/ModelController.java
@@ -6,11 +6,13 @@ import java.util.Map;
 
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.CookieValue;
 import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
 import com.fasterxml.jackson.core.JsonParseException;
@@ -19,7 +21,13 @@ import com.fasterxml.jackson.databind.JsonMappingException;
 import lcsb.mapviewer.api.BaseController;
 import lcsb.mapviewer.api.ObjectNotFoundException;
 import lcsb.mapviewer.api.QueryException;
+import lcsb.mapviewer.commands.CommandExecutionException;
 import lcsb.mapviewer.common.Configuration;
+import lcsb.mapviewer.converter.ConverterException;
+import lcsb.mapviewer.converter.graphics.DrawingException;
+import lcsb.mapviewer.model.cache.FileEntry;
+import lcsb.mapviewer.model.map.InconsistentModelException;
+import lcsb.mapviewer.model.map.layout.InvalidColorSchemaException;
 import lcsb.mapviewer.services.SecurityException;
 
 @RestController
@@ -63,4 +71,50 @@ public class ModelController extends BaseController {
     return modelController.updateModel(projectId, modelId, data, token);
   }
 
+  @RequestMapping(value = "/projects/{projectId}/models/{modelId}:downloadImage", method = {
+      RequestMethod.GET }, produces = { MediaType.APPLICATION_JSON_VALUE })
+  public ResponseEntity<byte[]> getModelAsImage(//
+      @CookieValue(value = Configuration.AUTH_TOKEN) String token, //
+      @PathVariable(value = "projectId") String projectId, //
+      @PathVariable(value = "modelId") String modelId, //
+      @RequestParam(value = "handlerClass") String handlerClass, //
+      @RequestParam(value = "backgroundOverlayId", defaultValue = "") String backgroundOverlayId, //
+      @RequestParam(value = "overlayIds", defaultValue = "") String overlayIds, //
+      @RequestParam(value = "zoomLevel", defaultValue = "") String zoomLevel, //
+      @RequestParam(value = "polygonString", defaultValue = "") String polygonString//
+  ) throws SecurityException, QueryException, IOException, InvalidColorSchemaException, CommandExecutionException,
+      DrawingException {
+
+    FileEntry file = modelController.getModelAsImage(token, projectId, modelId, handlerClass, backgroundOverlayId,
+        overlayIds, zoomLevel, polygonString);
+    MediaType type = MediaType.APPLICATION_OCTET_STREAM;
+    return ResponseEntity.ok().contentLength(file.getFileContent().length).contentType(type)
+        .header("Content-Disposition", "attachment; filename=" + file.getOriginalFileName())
+        .body(file.getFileContent());
+  }
+
+  @RequestMapping(value = "/projects/{projectId}/models/{modelId}:downloadModel", method = { RequestMethod.GET,
+      RequestMethod.POST }, produces = { MediaType.APPLICATION_JSON_VALUE })
+  public ResponseEntity<byte[]> getModelAsModelFile(//
+      @CookieValue(value = Configuration.AUTH_TOKEN) String token, //
+      @PathVariable(value = "projectId") String projectId, //
+      @PathVariable(value = "modelId") String modelId, //
+      @RequestParam(value = "handlerClass") String handlerClass, //
+      @RequestParam(value = "backgroundOverlayId", defaultValue = "") String backgroundOverlayId, //
+      @RequestParam(value = "overlayIds", defaultValue = "") String overlayIds, //
+      @RequestParam(value = "zoomLevel", defaultValue = "") String zoomLevel, //
+      @RequestParam(value = "polygonString", defaultValue = "") String polygonString, //
+      @RequestParam(value = "elementIds", defaultValue = "") String elementIds, //
+      @RequestParam(value = "reactionIds", defaultValue = "") String reactionIds //
+  ) throws SecurityException, QueryException, IOException, InvalidColorSchemaException, CommandExecutionException,
+      ConverterException, InconsistentModelException {
+
+    FileEntry file = modelController.getModelAsModelFile(token, projectId, modelId, handlerClass, backgroundOverlayId,
+        overlayIds, zoomLevel, polygonString, elementIds, reactionIds);
+    MediaType type = MediaType.APPLICATION_OCTET_STREAM;
+    return ResponseEntity.ok().contentLength(file.getFileContent().length).contentType(type)
+        .header("Content-Disposition", "attachment; filename=" + file.getOriginalFileName())
+        .body(file.getFileContent());
+  }
+
 }
\ No newline at end of file
diff --git a/rest-api/src/main/java/lcsb/mapviewer/api/projects/models/ModelRestImpl.java b/rest-api/src/main/java/lcsb/mapviewer/api/projects/models/ModelRestImpl.java
index 5e3659dbc1a4d3ece5da1918825bc07267448108..bf5adaf6922b73d6f059e71c5b02f80309e6466d 100644
--- a/rest-api/src/main/java/lcsb/mapviewer/api/projects/models/ModelRestImpl.java
+++ b/rest-api/src/main/java/lcsb/mapviewer/api/projects/models/ModelRestImpl.java
@@ -1,29 +1,76 @@
 package lcsb.mapviewer.api.projects.models;
 
+import java.awt.Color;
+import java.awt.geom.Path2D;
+import java.awt.geom.PathIterator;
+import java.awt.geom.Point2D;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
 import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import org.apache.commons.io.IOUtils;
 import org.apache.log4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.transaction.annotation.Transactional;
 
 import lcsb.mapviewer.api.BaseRestImpl;
 import lcsb.mapviewer.api.ObjectNotFoundException;
 import lcsb.mapviewer.api.QueryException;
+import lcsb.mapviewer.commands.ClearColorModelCommand;
+import lcsb.mapviewer.commands.ColorExtractor;
+import lcsb.mapviewer.commands.ColorModelCommand;
+import lcsb.mapviewer.commands.CommandExecutionException;
+import lcsb.mapviewer.commands.CopyCommand;
+import lcsb.mapviewer.commands.SetFixedHierarchyLevelCommand;
+import lcsb.mapviewer.commands.SubModelCommand;
 import lcsb.mapviewer.common.Configuration;
 import lcsb.mapviewer.common.exception.InvalidArgumentException;
+import lcsb.mapviewer.converter.ConverterException;
+import lcsb.mapviewer.converter.IConverter;
+import lcsb.mapviewer.converter.graphics.AbstractImageGenerator.Params;
+import lcsb.mapviewer.converter.graphics.DrawingException;
+import lcsb.mapviewer.converter.graphics.ImageGenerators;
 import lcsb.mapviewer.model.Project;
+import lcsb.mapviewer.model.cache.FileEntry;
+import lcsb.mapviewer.model.cache.UploadedFileEntry;
+import lcsb.mapviewer.model.map.InconsistentModelException;
+import lcsb.mapviewer.model.map.layout.ColorSchema;
+import lcsb.mapviewer.model.map.layout.InvalidColorSchemaException;
+import lcsb.mapviewer.model.map.layout.Layout;
 import lcsb.mapviewer.model.map.model.Model;
 import lcsb.mapviewer.model.map.model.ModelData;
 import lcsb.mapviewer.model.map.model.SubmodelType;
+import lcsb.mapviewer.model.map.species.Element;
 import lcsb.mapviewer.model.user.PrivilegeType;
+import lcsb.mapviewer.model.user.User;
 import lcsb.mapviewer.services.SecurityException;
+import lcsb.mapviewer.services.interfaces.ILayoutService;
+import lcsb.mapviewer.services.utils.ColorSchemaReader;
+import lcsb.mapviewer.services.utils.data.BuildInLayout;
 
 @Transactional(value = "txManager")
 public class ModelRestImpl extends BaseRestImpl {
 
+  /**
+   * Constant defining size of the array returned by
+   * {@link PathIterator#currentSegment(double[])} method. More information can be
+   * found <a href=
+   * "http://docs.oracle.com/javase/7/docs/api/java/awt/geom/PathIterator.html#currentSegment(double[])"
+   * >here</a>
+   */
+  private static final int PATH_ITERATOR_SEGMENT_SIZE = 6;
+
+  @Autowired
+  private ILayoutService layoutService;
+
   /**
    * Default class logger.
    */
@@ -132,7 +179,6 @@ public class ModelRestImpl extends BaseRestImpl {
     } else {
       throw new InvalidArgumentException();
     }
-
   }
 
   private Double parseDouble(Object value) throws QueryException {
@@ -156,4 +202,249 @@ public class ModelRestImpl extends BaseRestImpl {
       throw new QueryException("Don't know how to change " + value.getClass() + " into Double");
     }
   }
+
+  public FileEntry getModelAsModelFile(String token, String projectId, String modelId, String handlerClass,
+      String backgroundOverlayId, String overlayIds, String zoomLevel, String polygonString, String elementIds,
+      String reactionIds) throws SecurityException, QueryException, IOException, InvalidColorSchemaException,
+      CommandExecutionException, ConverterException, InconsistentModelException {
+    User user = getUserService().getUserByToken(token);
+    Model originalModel = getModelByModelId(token, projectId, modelId);
+
+    Path2D polygon = stringToPolygon(polygonString, originalModel);
+
+    Set<Integer> elementIdsList = stringListToIntegerSet(elementIds);
+    Set<Integer> reactionIdsList = stringListToIntegerSet(reactionIds);
+
+    // create model bounded by the polygon
+    SubModelCommand subModelCommand = new SubModelCommand(originalModel, polygon, elementIdsList, reactionIdsList);
+    Model part = subModelCommand.execute();
+
+    // Get list of overlay ids
+    String[] overlayIdsList = stringListToArray(overlayIds);
+    // Remove all colors
+    if (overlayIdsList.length > 0) {
+      for (Element element : part.getElements()) {
+        element.setColor(Color.WHITE);
+      }
+    }
+    // Color with overlays
+    for (String overlayId : overlayIdsList) {
+      Layout overlay = layoutService.getLayoutById(Integer.parseInt(overlayId.trim()), token);
+
+      ColorSchemaReader reader = new ColorSchemaReader();
+      Collection<ColorSchema> schemas = reader.readColorSchema(overlay.getInputData().getFileContent());
+
+      new ColorModelCommand(part, schemas, getUserService().getColorExtractorForUser(user)).execute();
+    }
+
+    IConverter parser = getModelParser(handlerClass);
+    InputStream is = parser.exportModelToInputStream(part);
+
+    String fileExtension = parser.getFileExtension();
+
+    UploadedFileEntry entry = new UploadedFileEntry();
+    entry.setOriginalFileName("model." + fileExtension);
+    entry.setFileContent(IOUtils.toByteArray(is));
+    entry.setLength(entry.getFileContent().length);
+    return entry;
+
+  }
+
+  protected Set<Integer> stringListToIntegerSet(String elementIds) {
+    Set<Integer> result = new HashSet<>();
+    if (elementIds != null) {
+      String[] stringIds = elementIds.split(",");
+      for (String string : stringIds) {
+        if (!string.trim().isEmpty()) {
+          result.add(Integer.valueOf(string));
+        }
+      }
+    }
+    return result;
+  }
+
+  private Model getModelByModelId(String token, String projectId, String modelId)
+      throws SecurityException, ObjectNotFoundException {
+    Model topModel = getModelService().getLastModelByProjectId(projectId, token);
+    if (topModel == null) {
+      throw new ObjectNotFoundException("Project with given id doesn't exist");
+    }
+
+    Model originalModel = topModel.getSubmodelById(modelId);
+
+    if (originalModel == null) {
+      throw new ObjectNotFoundException("Model with given id doesn't exist");
+    }
+    return originalModel;
+  }
+
+  private String[] stringListToArray(String overlayIds) {
+    String[] overlayIdsList;
+    if (overlayIds == null || overlayIds.trim().isEmpty()) {
+      overlayIdsList = new String[0];
+    } else {
+      overlayIdsList = overlayIds.split(",");
+    }
+    return overlayIdsList;
+  }
+
+  public FileEntry getModelAsImage(String token, String projectId, String modelId, String handlerClass,
+      String backgroundOverlayId, String overlayIds, String zoomLevel, String polygonString) throws SecurityException,
+      QueryException, IOException, InvalidColorSchemaException, CommandExecutionException, DrawingException {
+    User user = getUserService().getUserByToken(token);
+
+    Model topModel = getModelService().getLastModelByProjectId(projectId, token);
+    if (topModel == null) {
+      throw new ObjectNotFoundException("Project with given id doesn't exist");
+    }
+
+    Model originalModel = topModel.getSubmodelById(modelId);
+
+    if (originalModel == null) {
+      throw new ObjectNotFoundException("Model with given id doesn't exist");
+    }
+
+    Layout overlay = null;
+    if (!backgroundOverlayId.equals("")) {
+      overlay = topModel.getLayoutByIdentifier(Integer.valueOf(backgroundOverlayId));
+
+      if (overlay == null) {
+        throw new ObjectNotFoundException("Unknown overlay in model. Layout.id=" + backgroundOverlayId);
+      }
+    } else {
+      if (topModel.getLayouts().size() > 0) {
+        overlay = topModel.getLayouts().get(0);
+      }
+    }
+
+    Model colorModel = new CopyCommand(originalModel).execute();
+    if (overlay != null) {
+      if (overlay.getInputData() != null) {
+        ColorSchemaReader reader = new ColorSchemaReader();
+        Collection<ColorSchema> schemas = reader.readColorSchema(overlay.getInputData().getFileContent());
+
+        new ColorModelCommand(colorModel, schemas, getUserService().getColorExtractorForUser(user)).execute();
+      } else if (overlay.getTitle().equals(BuildInLayout.CLEAN.getTitle())) {
+        // this might not return true if we change CLEAN.title in future...
+
+        // if it's clean then remove coloring
+        new ClearColorModelCommand(colorModel).execute();
+      } else if (overlay.isHierarchicalView()) {
+        new SetFixedHierarchyLevelCommand(colorModel, overlay.getHierarchyViewLevel()).execute();
+      }
+    }
+
+    Integer level = Configuration.MIN_ZOOM_LEVEL;
+    if (!zoomLevel.equals("")) {
+      level = Integer.valueOf(zoomLevel);
+    }
+
+    Path2D polygon = stringToPolygon(polygonString, colorModel);
+
+    Double minX = originalModel.getWidth();
+    Double minY = originalModel.getHeight();
+    Double maxX = 0.0;
+    Double maxY = 0.0;
+
+    PathIterator pathIter = polygon.getPathIterator(null);
+    while (!pathIter.isDone()) {
+      final double[] segment = new double[PATH_ITERATOR_SEGMENT_SIZE];
+      if (pathIter.currentSegment(segment) != PathIterator.SEG_CLOSE) {
+        minX = Math.min(minX, segment[0]);
+        maxX = Math.max(maxX, segment[0]);
+        minY = Math.min(minY, segment[1]);
+        maxY = Math.max(maxY, segment[1]);
+      }
+      pathIter.next();
+    }
+
+    maxX = Math.min(originalModel.getWidth(), maxX);
+    maxY = Math.min(originalModel.getHeight(), maxY);
+    minX = Math.max(0.0, minX);
+    minY = Math.max(0.0, minY);
+
+    Double scale = Math.max(originalModel.getHeight(), originalModel.getWidth()) / (originalModel.getTileSize());
+
+    for (int i = level; i > Configuration.MIN_ZOOM_LEVEL; i--) {
+      scale /= 2;
+    }
+
+    ColorExtractor colorExtractor = getUserService().getColorExtractorForUser(user);
+
+    Params params = new Params().//
+        x(minX).//
+        y(minY).//
+        height((maxY - minY) / scale).//
+        width((maxX - minX) / scale).//
+        level(level - Configuration.MIN_ZOOM_LEVEL).//
+        nested(false).// automatically set nested view as invalid
+        scale(scale).//
+        colorExtractor(colorExtractor).//
+        sbgn(topModel.getProject().isSbgnFormat()).//
+        model(colorModel);
+    if (overlay != null) {
+      params.nested(overlay.isHierarchicalView());
+    }
+    List<Integer> visibleLayoutIds = deserializeIdList(overlayIds);
+    for (Integer integer : visibleLayoutIds) {
+      Map<Object, ColorSchema> map = layoutService.getElementsForLayout(colorModel, integer, token);
+      params.addVisibleLayout(map);
+    }
+
+    ImageGenerators imageGenerator = new ImageGenerators();
+    String extension = imageGenerator.getExtension(handlerClass);
+    File file = File.createTempFile("map", "." + extension);
+
+    imageGenerator.generate(handlerClass, params, file.getAbsolutePath());
+
+    UploadedFileEntry entry = new UploadedFileEntry();
+    entry.setOriginalFileName("map." + extension);
+    entry.setFileContent(IOUtils.toByteArray(new FileInputStream(file)));
+    entry.setLength(entry.getFileContent().length);
+    file.delete();
+    return entry;
+
+  }
+
+  private Path2D stringToPolygon(String polygonString, Model colorModel) {
+    String[] stringPointArray = polygonString.split(";");
+
+    List<Point2D> points = new ArrayList<>();
+    for (String string : stringPointArray) {
+      if (!string.trim().equals("")) {
+        double x = Double.valueOf(string.split(",")[0]);
+        double y = Double.valueOf(string.split(",")[1]);
+        points.add(new Point2D.Double(x, y));
+      }
+    }
+
+    if (points.size() <= 2) {
+      points.clear();
+      points.add(new Point2D.Double(0, 0));
+      points.add(new Point2D.Double(colorModel.getWidth(), 0));
+      points.add(new Point2D.Double(colorModel.getWidth(), colorModel.getHeight()));
+      points.add(new Point2D.Double(0, colorModel.getHeight()));
+    }
+
+    Path2D polygon = new Path2D.Double();
+    polygon.moveTo(points.get(0).getX(), points.get(0).getY());
+    for (int i = 1; i < points.size(); i++) {
+      Point2D point = points.get(i);
+      polygon.lineTo(point.getX(), point.getY());
+    }
+    polygon.closePath();
+    return polygon;
+  }
+
+  private List<Integer> deserializeIdList(String overlayIds) {
+    List<Integer> result = new ArrayList<>();
+    String[] tmp = overlayIds.split(",");
+    for (String string : tmp) {
+      if (!string.equals("")) {
+        result.add(Integer.valueOf(string));
+      }
+    }
+    return result;
+  }
+
 }
diff --git a/rest-api/src/test/java/lcsb/mapviewer/api/convert/ConvertRestImplTest.java b/rest-api/src/test/java/lcsb/mapviewer/api/convert/ConvertRestImplTest.java
index 047dc151eb97251d2100ffab99867fed5b30afa5..195a8d73a56c803e0253ebcd57f1a73c9e012b71 100644
--- a/rest-api/src/test/java/lcsb/mapviewer/api/convert/ConvertRestImplTest.java
+++ b/rest-api/src/test/java/lcsb/mapviewer/api/convert/ConvertRestImplTest.java
@@ -187,9 +187,13 @@ public class ConvertRestImplTest extends RestTestFunctions {
         String result = convertRestImpl.convert(token, "CellDesigner_SBML", "SBML", content);
         ByteArrayOutputStream result1 = convertRestImpl.converToImage(token, "SBML", "svg", result);
         
-        FileOutputStream outputStream = new FileOutputStream("testFiles/convert/glycolysis2.svg");
+        File output = new File("testFiles/convert/glycolysis2.svg");
+            
+        FileOutputStream outputStream = new FileOutputStream(output);
         outputStream.write(result1.toByteArray());
         outputStream.close();
+        assertTrue(output.exists());
+        output.delete();
     	
             	
     } catch (Exception e) {
diff --git a/rest-api/src/test/java/lcsb/mapviewer/api/projects/ProjectRestImplTest.java b/rest-api/src/test/java/lcsb/mapviewer/api/projects/ProjectRestImplTest.java
index 79afcc01ea2719718cb3cd963afb71ac545c066d..60688c8ccacebe8141366abac7056c762baf23ea 100644
--- a/rest-api/src/test/java/lcsb/mapviewer/api/projects/ProjectRestImplTest.java
+++ b/rest-api/src/test/java/lcsb/mapviewer/api/projects/ProjectRestImplTest.java
@@ -4,9 +4,8 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyString;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.times;
 
 import java.util.ArrayList;
@@ -28,17 +27,12 @@ import org.springframework.util.MultiValueMap;
 import com.google.gson.Gson;
 
 import lcsb.mapviewer.api.ObjectNotFoundException;
-import lcsb.mapviewer.api.QueryException;
 import lcsb.mapviewer.api.RestTestFunctions;
-import lcsb.mapviewer.common.exception.InvalidArgumentException;
-import lcsb.mapviewer.converter.graphics.PdfImageGenerator;
-import lcsb.mapviewer.converter.model.celldesigner.CellDesignerXmlParser;
 import lcsb.mapviewer.converter.zip.ImageZipEntryFile;
 import lcsb.mapviewer.converter.zip.LayoutZipEntryFile;
 import lcsb.mapviewer.converter.zip.ModelZipEntryFile;
 import lcsb.mapviewer.converter.zip.ZipEntryFile;
 import lcsb.mapviewer.model.Project;
-import lcsb.mapviewer.model.cache.FileEntry;
 import lcsb.mapviewer.model.map.MiriamType;
 import lcsb.mapviewer.model.map.model.Model;
 import lcsb.mapviewer.persist.dao.ProjectDao;
@@ -71,32 +65,6 @@ public class ProjectRestImplTest extends RestTestFunctions {
   public void tearDown() throws Exception {
   }
 
-  @Test
-  public void testGetModelAsImageForInvalidConverter() throws Exception {
-    try {
-      ProjectRestImpl projectRest = createMockProjectRest("testFiles/model/sample.xml");
-      projectRest.getModelAsImage(token, "sample", "0", "", "", "", "", "");
-      fail("Exception expected");
-    } catch (InvalidArgumentException e) {
-    } catch (Exception e) {
-      e.printStackTrace();
-      throw e;
-    }
-  }
-
-  @Test
-  public void testGetModelAsImage() throws Exception {
-    try {
-      ProjectRestImpl projectRest = createMockProjectRest("testFiles/model/sample.xml");
-      FileEntry result = projectRest.getModelAsImage(token, "sample", "0", PdfImageGenerator.class.getCanonicalName(),
-          "", "", "", "");
-      assertNotNull(result);
-    } catch (Exception e) {
-      e.printStackTrace();
-      throw e;
-    }
-  }
-
   @Test
   public void testGetModelDataDependencies() throws Exception {
     try {
@@ -117,55 +85,6 @@ public class ProjectRestImplTest extends RestTestFunctions {
     projectRest.getProject("unknown_model_id", token);
   }
 
-  @Test
-  public void testGetModelAsImage2() throws Exception {
-    try {
-      ProjectRestImpl projectRest = createMockProjectRest("testFiles/model/sample.xml");
-      projectRest.getModelAsImage(token, "sample", "0", PdfImageGenerator.class.getCanonicalName(), "", "", "", "");
-    } catch (Exception e) {
-      e.printStackTrace();
-      throw e;
-    }
-  }
-
-  @Test
-  public void testGetModelAsFileModel() throws Exception {
-    try {
-      ProjectRestImpl projectRest = createMockProjectRest("testFiles/model/sample.xml");
-      projectRest.getModelAsModelFile(token, "sample", "0", "", "", "", "", "");
-      fail("Exception expected");
-    } catch (QueryException e) {
-    } catch (Exception e) {
-      e.printStackTrace();
-      throw e;
-    }
-  }
-
-  @Test
-  public void testGetModelAsFileModel2() throws Exception {
-    try {
-      ProjectRestImpl projectRest = createMockProjectRest("testFiles/model/sample.xml");
-      projectRest.getModelAsModelFile(token, "sample", "0", CellDesignerXmlParser.class.getCanonicalName(), "", "", "",
-          "0,0;90,0;90,90;90,0");
-    } catch (Exception e) {
-      e.printStackTrace();
-      throw e;
-    }
-  }
-
-  @Test
-  public void testGetModelAsFileModel3() throws Exception {
-    try {
-      ProjectRestImpl projectRest = createMockProjectRest("testFiles/model/sample.xml");
-      projectRest.getModelAsModelFile(token, "sample", "0", "", "", "", "", "0,0;90,0;90,90;90,0");
-      fail("Exception expected");
-    } catch (QueryException e) {
-    } catch (Exception e) {
-      e.printStackTrace();
-      throw e;
-    }
-  }
-
   @Test
   public void testGetProject() throws Exception {
     try {
diff --git a/rest-api/src/test/java/lcsb/mapviewer/api/projects/models/ModelRestImplTest.java b/rest-api/src/test/java/lcsb/mapviewer/api/projects/models/ModelRestImplTest.java
index d3435cc35db0867789a427c34393ba3d98e1d809..80fe6f15bc32b675e78678324bae8452893aef32 100644
--- a/rest-api/src/test/java/lcsb/mapviewer/api/projects/models/ModelRestImplTest.java
+++ b/rest-api/src/test/java/lcsb/mapviewer/api/projects/models/ModelRestImplTest.java
@@ -1,12 +1,15 @@
 package lcsb.mapviewer.api.projects.models;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.nullable;
 import static org.mockito.ArgumentMatchers.refEq;
 
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import org.junit.After;
 import org.junit.Before;
@@ -14,8 +17,13 @@ import org.junit.Test;
 import org.mockito.Mockito;
 import org.springframework.beans.factory.annotation.Autowired;
 
+import lcsb.mapviewer.api.QueryException;
 import lcsb.mapviewer.api.RestTestFunctions;
+import lcsb.mapviewer.common.exception.InvalidArgumentException;
+import lcsb.mapviewer.converter.graphics.PdfImageGenerator;
+import lcsb.mapviewer.converter.model.celldesigner.CellDesignerXmlParser;
 import lcsb.mapviewer.model.Project;
+import lcsb.mapviewer.model.cache.FileEntry;
 import lcsb.mapviewer.model.map.model.Model;
 import lcsb.mapviewer.services.interfaces.IModelService;
 import lcsb.mapviewer.services.interfaces.IProjectService;
@@ -93,4 +101,101 @@ public class ModelRestImplTest extends RestTestFunctions {
     return _modelRestImpl;
   }
 
+  @Test
+  public void testGetModelAsImageForInvalidConverter() throws Exception {
+    try {
+      ModelRestImpl modelRest = createMockProjectRest("testFiles/model/sample.xml");
+      modelRest.getModelAsImage(token, "sample", "0", "", "", "", "", "");
+      fail("Exception expected");
+    } catch (InvalidArgumentException e) {
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetModelAsImage() throws Exception {
+    try {
+      ModelRestImpl modelRest = createMockProjectRest("testFiles/model/sample.xml");
+      FileEntry result = modelRest.getModelAsImage(token, "sample", "0", PdfImageGenerator.class.getCanonicalName(), "",
+          "", "", "");
+      assertNotNull(result);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetModelAsImage2() throws Exception {
+    try {
+      ModelRestImpl modelRest = createMockProjectRest("testFiles/model/sample.xml");
+      modelRest.getModelAsImage(token, "sample", "0", PdfImageGenerator.class.getCanonicalName(), "", "", "", "");
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetModelAsFileModel() throws Exception {
+    try {
+      ModelRestImpl modelRest = createMockProjectRest("testFiles/model/sample.xml");
+      modelRest.getModelAsModelFile(token, "sample", "0", "", "", "", "", "", null, null);
+      fail("Exception expected");
+    } catch (QueryException e) {
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetModelAsFileModel2() throws Exception {
+    try {
+      ModelRestImpl modelRest = createMockProjectRest("testFiles/model/sample.xml");
+      modelRest.getModelAsModelFile(token, "sample", "0", CellDesignerXmlParser.class.getCanonicalName(), "", "", "",
+          "0,0;90,0;90,90;90,0", null, null);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetModelAsFileModel3() throws Exception {
+    try {
+      ModelRestImpl modelRest = createMockProjectRest("testFiles/model/sample.xml");
+      modelRest.getModelAsModelFile(token, "sample", "0", "", "", "", "", "0,0;90,0;90,90;90,0", null, null);
+      fail("Exception expected");
+    } catch (QueryException e) {
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testEmptyStringListToIntegerList() throws Exception {
+    try {
+      Set<Integer> ids = _modelRestImpl.stringListToIntegerSet("");
+      assertNotNull(ids);
+      assertEquals(0, ids.size());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+  @Test
+  public void testStringListToIntegerArray() throws Exception {
+    try {
+      Set<Integer> ids = _modelRestImpl.stringListToIntegerSet("12,3");
+      assertNotNull(ids);
+      assertEquals(2, ids.size());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
 }