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..d350d59b6131c28a72bc47bb2f8ba281a0018a74 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,48 @@ 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 }, 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 = modelController.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());
+  }
+
 }
\ 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..f735bb5937aa81e1c578ebfb0d15a1142caa8d6e 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,77 @@
 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.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.
    */
@@ -156,4 +204,225 @@ 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)
+      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 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/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..75e4f09a45a7bffdb355311eaf3b0e8891a6f6e1 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,6 +1,8 @@
 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;
@@ -14,8 +16,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 +100,80 @@ 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", "", "", "", "", "");
+      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");
+    } 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");
+      fail("Exception expected");
+    } catch (QueryException e) {
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+
 }