diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetExport.java b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetExport.java
index 1f1e0d2dff1697c5f786bdb7926f4d16cd775284..8d46949ea194fead71a42248edc6e3ccbcc75025 100644
--- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetExport.java
+++ b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetExport.java
@@ -24,7 +24,6 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
 
 import java.io.Serializable;
-import java.util.List;
 import java.util.Map;
 
 @JsonObject("dss.dto.imaging.ImagingDataSetExport")
@@ -37,18 +36,9 @@ public class ImagingDataSetExport implements Serializable
     private Map<String, Serializable> config;
 
     @JsonProperty
-    private String format;
-
-    @JsonProperty
-    private String bytes;
-
-    @JsonProperty
-    private boolean show;
-
-    @JsonProperty
+    @JsonDeserialize(contentUsing = PropertiesDeserializer.class)
     private Map<String, String> metaData;
 
-
     @JsonIgnore
     public Map<String, Serializable> getConfig()
     {
@@ -60,39 +50,6 @@ public class ImagingDataSetExport implements Serializable
         this.config = config;
     }
 
-    @JsonIgnore
-    public String getFormat()
-    {
-        return format;
-    }
-
-    public void setFormat(String format)
-    {
-        this.format = format;
-    }
-
-    @JsonIgnore
-    public String getBytes()
-    {
-        return bytes;
-    }
-
-    public void setBytes(String bytes)
-    {
-        this.bytes = bytes;
-    }
-
-    @JsonIgnore
-    public boolean isShow()
-    {
-        return show;
-    }
-
-    public void setShow(boolean show)
-    {
-        this.show = show;
-    }
-
     @JsonIgnore
     public Map<String, String> getMetaData()
     {
diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetImage.java b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetImage.java
index 811b5b05ac48b350bce6ac4bf72654f01a508e2e..e726231d0e42141dd27912cffa0dd75b9e6b497c 100644
--- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetImage.java
+++ b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetImage.java
@@ -33,6 +33,9 @@ public class ImagingDataSetImage implements Serializable
     @JsonProperty
     private List<ImagingDataSetPreview> previews;
 
+    @JsonProperty
+    private Map<String, Serializable> config;
+
     @JsonProperty
     private Map<String, String> metaData;
 
@@ -48,6 +51,16 @@ public class ImagingDataSetImage implements Serializable
         this.previews = previews;
     }
 
+    public Map<String, Serializable> getConfig()
+    {
+        return config;
+    }
+
+    public void setConfig(Map<String, Serializable> config)
+    {
+        this.config = config;
+    }
+
     @JsonIgnore
     public Map<String, String> getMetaData()
     {
diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetMultiExport.java b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetMultiExport.java
new file mode 100644
index 0000000000000000000000000000000000000000..d46ced3b5a06b2cbf46a7bb28748ed7f6955d9fd
--- /dev/null
+++ b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetMultiExport.java
@@ -0,0 +1,97 @@
+/*
+ *  Copyright ETH 2023 Zürich, Scientific IT Services
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package ch.ethz.sis.openbis.generic.dssapi.v3.dto.imaging;
+
+
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.property.PropertiesDeserializer;
+import ch.systemsx.cisd.base.annotation.JsonObject;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+
+@JsonObject("dss.dto.imaging.ImagingDataSetMultiExport")
+public class ImagingDataSetMultiExport implements Serializable
+{
+    private static final long serialVersionUID = 1L;
+
+    @JsonProperty
+    private String permId;
+    @JsonProperty
+    private int index;
+
+    @JsonProperty
+    @JsonDeserialize(contentUsing = PropertiesDeserializer.class)
+    private Map<String, Serializable> config;
+
+    @JsonProperty
+    @JsonDeserialize(contentUsing = PropertiesDeserializer.class)
+    private Map<String, String> metaData;
+
+    @JsonIgnore
+    public String getPermId()
+    {
+        return permId;
+    }
+
+    public void setPermId(String permId) {
+        this.permId = permId;
+    }
+
+    @JsonIgnore
+    public int getIndex()
+    {
+        return index;
+    }
+
+    public void setIndex(int index) {
+        this.index = index;
+    }
+
+    @JsonIgnore
+    public Map<String, Serializable> getConfig()
+    {
+        return config;
+    }
+
+    public void setConfig(Map<String, Serializable> config)
+    {
+        this.config = config;
+    }
+
+    @JsonIgnore
+    public Map<String, String> getMetaData()
+    {
+        return metaData;
+    }
+
+    public void setMetaData(Map<String, String> metaData)
+    {
+        this.metaData = metaData;
+    }
+
+    @Override
+    public String toString()
+    {
+        return "ImagingDataSetMultiExport:" + permId;
+    }
+
+}
diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/ImagingArchiver.java b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/ImagingArchiver.java
new file mode 100644
index 0000000000000000000000000000000000000000..8974f7cccf8ada7dd318ca9711045e5f5c049165
--- /dev/null
+++ b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/ImagingArchiver.java
@@ -0,0 +1,153 @@
+/*
+ *  Copyright ETH 2023 Zürich, Scientific IT Services
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package ch.ethz.sis.openbis.generic.server.dss.plugins.imaging;
+
+import ch.systemsx.cisd.common.exceptions.UserFailureException;
+import ch.systemsx.cisd.openbis.dss.generic.server.AbstractDataSetPackager;
+import ch.systemsx.cisd.openbis.dss.generic.server.TarDataSetPackager;
+import ch.systemsx.cisd.openbis.dss.generic.server.ZipDataSetPackager;
+import ch.systemsx.cisd.openbis.dss.generic.shared.ServiceProvider;
+import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.ISessionWorkspaceProvider;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Serializable;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Map;
+import java.util.function.Function;
+
+class ImagingArchiver
+{
+    private final String sessionToken;
+    private final String exportDirName;
+    private final String exportArchiveName;
+    private final Function<InputStream, Long> checksumFunction;
+
+
+
+    private ArchiveBuilder archive;
+    
+    private final String archiveFormat;
+    
+    ImagingArchiver(String sessionToken, Map<String, Serializable> exportConfig) {
+        this.sessionToken = sessionToken;
+        archiveFormat = exportConfig.get("archive-format").toString();
+
+        String currentTimeMs = String.valueOf(System.currentTimeMillis());
+        exportDirName = "imaging_export_" + currentTimeMs;
+
+        if (archiveFormat.equalsIgnoreCase("zip"))
+        {
+            exportArchiveName = "export.zip";
+            checksumFunction = Util::getCRC32Checksum;
+        } else if (archiveFormat.equalsIgnoreCase("tar"))
+        {
+            exportArchiveName = "export.tar.gz";
+            checksumFunction = (x) -> 0L;
+        } else
+        {
+            throw new UserFailureException("Unknown archive format!");
+        }
+        
+        
+    }
+    
+    void prepare() {
+
+//        try
+//        {
+//            Path tempDir = Files.createDirectory(Path.of(tempDirectory.getAbsolutePath(), token));
+//            if (archiveFormat.equalsIgnoreCase("zip"))
+//            {
+//                File archiveFile =
+//                        Files.createFile(Path.of(tempDir.toAbsolutePath().toString(), "export.zip"))
+//                                .toFile();
+//                checksumFunction = Util::getCRC32Checksum;
+//                packager = new ZipDataSetPackager(archiveFile, true, null, null);
+//            } else if (archiveFormat.equalsIgnoreCase("tar"))
+//            {
+//                archiveFile =
+//                        Files.createFile(
+//                                        Path.of(tempDir.toAbsolutePath().toString(), "export.tar.gz"))
+//                                .toFile();
+//                checksumFunction = (x) -> 0L;
+//                packager = new TarDataSetPackager(archiveFile, null, null, DEFAULT_BUFFER_SIZE,
+//                        5L * DEFAULT_BUFFER_SIZE);
+//            } else
+//            {
+//                throw new UserFailureException("Unknown archive format!");
+//            }
+//
+//        } catch (IOException exception)
+//        {
+//            throw new UserFailureException("Could not export data!", exception);
+//        }
+        
+        
+    }
+
+    ArchiveBuilder newArchive() {
+        archive = new ArchiveBuilder();
+        return archive;
+    }
+
+    ArchiveBuilder addToArchive() {
+        if(archive == null) {
+            newArchive();
+        }
+        
+        
+//        File archiveFile;
+//        String token = "export_" + currentTimeMs;
+//
+//        ISessionWorkspaceProvider sessionWorkspaceProvider =
+//                getSessionWorkspaceProvider(sessionToken);
+//        File tempDirectory = sessionWorkspaceProvider.getSessionWorkspace();
+        
+        return new ArchiveBuilder("");
+    }
+
+
+    private ISessionWorkspaceProvider getSessionWorkspaceProvider(String sessionToken)
+    {
+        return ServiceProvider.getDataStoreService().getSessionWorkspaceProvider(sessionToken);
+    }
+    
+    
+    class ArchiveBuilder {
+
+        private AbstractDataSetPackager packager;
+
+        private ArchiveBuilder(String exportArchiveName) {
+            if(exportArchiveName.equalsIgnoreCase("export.zip")) {
+
+            } else if(exportArchiveName.equalsIgnoreCase("export.tar.gz")) {
+
+            }
+        }
+        
+        public String build() {
+            return "URL";
+        }
+        
+    }
+    
+    
+}
diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/ImagingService.java b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/ImagingService.java
index 0beb0960aee4891de964cd7913f3adde04aabff7..9290ddaf4751b14659eacabfd44153fa059f9e06 100644
--- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/ImagingService.java
+++ b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/ImagingService.java
@@ -23,8 +23,8 @@ import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.fetchoptions.DataSetFetc
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.id.DataSetPermId;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.id.IDataSetId;
 import ch.ethz.sis.openbis.generic.dssapi.v3.IDataStoreServerApi;
-import ch.ethz.sis.openbis.generic.dssapi.v3.dto.imaging.ImagingDataSetConfig;
 import ch.ethz.sis.openbis.generic.dssapi.v3.dto.imaging.ImagingDataSetImage;
+import ch.ethz.sis.openbis.generic.dssapi.v3.dto.imaging.ImagingDataSetPreview;
 import ch.ethz.sis.openbis.generic.dssapi.v3.dto.imaging.ImagingDataSetPropertyConfig;
 import ch.ethz.sis.openbis.generic.dssapi.v3.dto.service.CustomDSSServiceExecutionOptions;
 import ch.ethz.sis.openbis.generic.dssapi.v3.dto.service.id.ICustomDSSServiceId;
@@ -36,24 +36,28 @@ import ch.ethz.sis.openbis.generic.server.dss.plugins.imaging.container.ImagingP
 import ch.ethz.sis.openbis.generic.dssapi.v3.plugin.service.ICustomDSSServiceExecutor;
 import ch.systemsx.cisd.common.exceptions.UserFailureException;
 import ch.systemsx.cisd.common.logging.LogCategory;
-import ch.systemsx.cisd.common.properties.PropertyUtils;
 import ch.systemsx.cisd.common.reflection.ClassUtils;
 import ch.systemsx.cisd.openbis.common.io.hierarchical_content.api.IHierarchicalContent;
 import ch.systemsx.cisd.openbis.common.io.hierarchical_content.api.IHierarchicalContentNode;
+import ch.systemsx.cisd.openbis.dss.generic.server.AbstractDataSetPackager;
+import ch.systemsx.cisd.openbis.dss.generic.server.DataStoreServer;
+import ch.systemsx.cisd.openbis.dss.generic.server.TarDataSetPackager;
+import ch.systemsx.cisd.openbis.dss.generic.server.ZipDataSetPackager;
 import ch.systemsx.cisd.openbis.dss.generic.shared.IHierarchicalContentProvider;
 import ch.systemsx.cisd.openbis.dss.generic.shared.ServiceProvider;
+import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.ISessionWorkspaceProvider;
 import ch.systemsx.cisd.openbis.generic.shared.dto.OpenBISSessionHolder;
-import com.fasterxml.jackson.annotation.JsonIgnore;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.databind.JsonMappingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
 import ch.systemsx.cisd.common.logging.LogFactory;
+import org.apache.commons.io.FileUtils;
 import org.apache.log4j.Logger;
 
-import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.Serializable;
+import java.io.*;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.*;
+import java.util.function.Function;
 
 public class ImagingService implements ICustomDSSServiceExecutor
 {
@@ -65,6 +69,9 @@ public class ImagingService implements ICustomDSSServiceExecutor
     private static final Logger
             operationLog = LogFactory.getLogger(LogCategory.OPERATION, ImagingService.class);
 
+    private static final int DEFAULT_BUFFER_SIZE = (int) (10 * FileUtils.ONE_MB);
+
+    private static final String IMAGING_CONFIG_PROPERTY_NAME = "$IMAGING_DATA_CONFIG";
 
     public ImagingService(Properties properties)
     {
@@ -82,9 +89,15 @@ public class ImagingService implements ICustomDSSServiceExecutor
             if (data.getType().equalsIgnoreCase("preview"))
             {
                 return processPreviewFlow(sessionToken, (ImagingPreviewContainer) data);
+            } else if (data.getType().equalsIgnoreCase("export"))
+            {
+                return processExportFlow(sessionToken, (ImagingExportContainer) data);
+            } else if (data.getType().equalsIgnoreCase("multi-export"))
+            {
+                return processMultiExportFlow(sessionToken, (ImagingMultiExportContainer) data);
             } else
             {
-                return processExportFlow(sessionToken, data);
+                throw new UserFailureException("Unknown request type!");
             }
         } catch (Exception e)
         {
@@ -93,61 +106,184 @@ public class ImagingService implements ICustomDSSServiceExecutor
         return data;
     }
 
-    private ImagingPreviewContainer processPreviewFlow(String sessionToken,
-            ImagingPreviewContainer data)
+    private IImagingDataSetAdaptor getAdaptor(ImagingDataSetPropertyConfig config)
     {
-        DataSet dataSet = getDataSet(sessionToken, data);
-
-        ImagingDataSetPropertyConfig config =
-                readConfig(dataSet.getJsonProperty("$IMAGING_DATA_CONFIG"), ImagingDataSetPropertyConfig.class);
         final String adaptorName = config.getConfig().getAdaptor();
 
-        if(adaptorName == null || adaptorName.isBlank()) {
+        if (adaptorName == null || adaptorName.isBlank())
+        {
             throw new UserFailureException("Adaptor name is missing from the config!");
         }
-
-        IImagingDataSetAdaptor adaptor = null;
         try
         {
-            adaptor = ClassUtils.create(IImagingDataSetAdaptor.class, adaptorName, properties);
-        } catch(Exception e) {
+            return ClassUtils.create(IImagingDataSetAdaptor.class, adaptorName, properties);
+        } catch (Exception e)
+        {
             throw new UserFailureException("Could not load adapter: " + adaptorName, e);
         }
+    }
+
+    private File getRootFile(String sessionToken, DataSet dataSet)
+    {
         IHierarchicalContent content =
                 getHierarchicalContentProvider(sessionToken).asContent(
                         dataSet.getPermId().getPermId());
         IHierarchicalContentNode root = content.getRootNode();
+        return root.getFile();
+    }
+
+    private ImagingPreviewContainer processPreviewFlow(String sessionToken,
+            ImagingPreviewContainer data)
+    {
+        DataSet dataSet = getDataSet(sessionToken, data.getPermId());
+
+        ImagingDataSetPropertyConfig config =
+                Util.readConfig(dataSet.getJsonProperty("$IMAGING_DATA_CONFIG"),
+                        ImagingDataSetPropertyConfig.class);
 
-        File rootFile = root.getFile();
+        IImagingDataSetAdaptor adaptor = getAdaptor(config);
+        File rootFile = getRootFile(sessionToken, dataSet);
         Map<String, Serializable> previewParams = data.getPreview().getConfig();
         Map<String, String> meta = data.getPreview().getMetaData();
         String format = data.getPreview().getFormat();
 
-        ImagingServiceContext context = new ImagingServiceContext(sessionToken, getApplicationServerApi(), getDataStoreServerApi());
+        int index = data.getIndex();
+        if (config.getImages().size() <= index)
+        {
+            throw new UserFailureException("There is no image with index:" + index);
+        }
+        Map<String, Serializable> imageConfig = config.getImages().get(index).getConfig();
+
+        if (format == null || format.isBlank())
+        {
+            throw new UserFailureException("Format can not be empty!");
+        }
+
+        previewParams.put("$COMMAND_TYPE", "PREVIEW");
+
+        ImagingServiceContext context =
+                new ImagingServiceContext(sessionToken, getApplicationServerApi(),
+                        getDataStoreServerApi());
 
         data.getPreview().setBytes(
                 adaptor.process(context,
-                        rootFile, previewParams, meta, format).toString());
+                        rootFile, imageConfig, previewParams, meta, format).toString());
         return data;
     }
 
-    private Serializable processExportFlow(String sessionToken, ImagingDataContainer data)
+
+
+    private Serializable processExportFlow(String sessionToken, ImagingExportContainer data)
     {
-        DataSet dataSet = getDataSet(sessionToken, data);
-        if (data.getType().equalsIgnoreCase("export"))
+        // Get all parameters
+        final DataSet dataSet = getDataSet(sessionToken, data.getPermId());
+        final ImagingDataSetPropertyConfig config =
+                Util.readConfig(dataSet.getJsonProperty(IMAGING_CONFIG_PROPERTY_NAME),
+                        ImagingDataSetPropertyConfig.class);
+
+        final File rootFile = getRootFile(sessionToken, dataSet);
+        final int index = data.getIndex();
+        if (config.getImages().size() <= index)
         {
-            // Single export case
-            ImagingExportContainer export = (ImagingExportContainer) data;
+            throw new UserFailureException("There is no image with index:" + index);
+        }
+
+        final ImagingDataSetImage image = config.getImages().get(index);
+
+        Map<String, Serializable> exportConfig = data.getExport().getConfig();
+        Validator.validateExportConfig(exportConfig);
 
+        String archiveFormat = exportConfig.get("archive-format").toString();
+        Map<String, String> meta = data.getExport().getMetaData();
+        Serializable[] exportTypes = (Serializable[]) exportConfig.get("include");
+        String currentTimeMs = String.valueOf(System.currentTimeMillis());
+        AbstractDataSetPackager packager;
+        Function<InputStream, Long> checksumFunction;
+        File archiveFile;
+        String token = "export_" + currentTimeMs;
+        ISessionWorkspaceProvider sessionWorkspaceProvider = getSessionWorkspaceProvider(sessionToken);
+        File tempDirectory = sessionWorkspaceProvider.getSessionWorkspace();
+        String url = DataStoreServer.getConfigParameters().getDownloadURL() + "/datastore_server/session_workspace_file_download?sessionID=" + sessionToken + "&filePath=";
 
-        } else
+        // Prepare temp directory for archive
+        try
         {
-            // multi export case
-            ImagingMultiExportContainer multiExport = (ImagingMultiExportContainer) data;
+            Path tempDir = Files.createDirectory(Path.of(tempDirectory.getAbsolutePath(), token));
+            if (archiveFormat.equalsIgnoreCase("zip"))
+            {
+                archiveFile = Files.createFile(Path.of(tempDir.toAbsolutePath().toString(), "export.zip")).toFile();
+                checksumFunction = Util::getCRC32Checksum;
+                packager = new ZipDataSetPackager(archiveFile, true, null, null);
+            } else if (archiveFormat.equalsIgnoreCase("tar"))
+            {
+                archiveFile =
+                        Files.createFile(Path.of(tempDir.toAbsolutePath().toString(), "export.tar.gz")).toFile();
+                checksumFunction = (x) -> 0L;
+                packager = new TarDataSetPackager(archiveFile, null, null, DEFAULT_BUFFER_SIZE,
+                        5L * DEFAULT_BUFFER_SIZE);
+            } else
+            {
+                throw new UserFailureException("Unknown archive format!");
+            }
+
+        } catch (IOException exception)
+        {
+            throw new UserFailureException("Could not export data!", exception);
+        }
+
+        // For each export type, perform adequate action
+        for (Serializable exportType : exportTypes)
+        {
+            if (exportType.toString().equalsIgnoreCase("image"))
+            {
+                ImagingServiceContext context =
+                        new ImagingServiceContext(sessionToken, getApplicationServerApi(),
+                                getDataStoreServerApi());
+                IImagingDataSetAdaptor adaptor = getAdaptor(config);
+                archiveImage(context, adaptor, image, exportConfig, packager, rootFile, "", checksumFunction, dataSet);
+            } else if (exportType.toString().equalsIgnoreCase("raw data"))
+            {
+                archiveRawData(packager, rootFile, "", checksumFunction, dataSet);
+            } else
+            {
+                throw new UserFailureException("Unknown export type!");
+            }
+
         }
+
+        packager.close();
+        data.setUrl(url + Path.of(token, archiveFile.getName()));
+
         return data;
     }
 
+    private Serializable processMultiExportFlow(String sessionToken, ImagingMultiExportContainer data)
+    {
+
+        {
+            // multi export case
+//            String archiveFormat;
+//            for (ImagingDataSetExport export : data.getExport())
+//            {
+//                Map<String, Serializable> params = export.getConfig();
+//                Map<String, String> meta = export.getMetaData();
+//                String fullFormat = export.getFormat();
+//
+//                if (fullFormat == null || fullFormat.isBlank())
+//                {
+//                    throw new UserFailureException("Format can not be empty!");
+//                }
+//                String[] formats = fullFormat.split("/");
+//                archiveFormat = formats[0];
+//                String otherFormat = formats[1];
+//
+//            }
+
+        }
+        return null;
+    }
+
+
     private IHierarchicalContentProvider getHierarchicalContentProvider(String sessionToken)
     {
         if (contentProvider == null)
@@ -169,39 +305,12 @@ public class ImagingService implements ICustomDSSServiceExecutor
         return ServiceProvider.getV3DataStoreService();
     }
 
-    private ObjectMapper getObjectMapper()
-    {
-        return ServiceProvider.getObjectMapperV3();
-    }
-
-    private <T> T readConfig(String val, Class<T> clazz)
-    {
-        try
-        {
-            ObjectMapper objectMapper = getObjectMapper();
-            return objectMapper.readValue(new ByteArrayInputStream(val.getBytes()),
-                    clazz);
-        } catch (JsonMappingException mappingException) {
-            throw new UserFailureException(mappingException.toString(), mappingException);
-        } catch (Exception e)
-        {
-            throw new UserFailureException("Could not read the parameters!", e);
-        }
-    }
-
-    private String mapToJson(Map<String, Object> map)
+    private ISessionWorkspaceProvider getSessionWorkspaceProvider(String sessionToken)
     {
-        try
-        {
-            ObjectMapper objectMapper = getObjectMapper();
-            return objectMapper.writeValueAsString(map);
-        } catch (Exception e)
-        {
-            throw new UserFailureException("Could not serialize the input parameters!", e);
-        }
+        return ServiceProvider.getDataStoreService().getSessionWorkspaceProvider(sessionToken);
     }
 
-    private DataSet getDataSet(String sessionToken, ImagingDataContainer data)
+    private DataSet getDataSet(String sessionToken, String permId)
     {
         DataSetFetchOptions fetchOptions = new DataSetFetchOptions();
         fetchOptions.withProperties();
@@ -209,49 +318,78 @@ public class ImagingService implements ICustomDSSServiceExecutor
         fetchOptions.withDataStore();
         fetchOptions.withPhysicalData();
         Map<IDataSetId, DataSet> result = getApplicationServerApi()
-                .getDataSets(sessionToken, List.of(new DataSetPermId(data.getPermId())),
+                .getDataSets(sessionToken, List.of(new DataSetPermId(permId)),
                         fetchOptions);
         if (result.isEmpty())
         {
-            throw new UserFailureException("Could not find Dataset:" + data.getPermId());
+            throw new UserFailureException("Could not find Dataset:" + permId);
         }
-        return result.get(new DataSetPermId(data.getPermId()));
+        return result.get(new DataSetPermId(permId));
     }
 
-    private void validateInputParams(Map<String, Object> params)
-    {
-        if (!params.containsKey("permId"))
-        {
-            throw new UserFailureException("Missing dataset permId!");
-        }
-        if (!params.containsKey("type"))
-        {
-            throw new UserFailureException("Missing type!");
-        }
-        if (!params.containsKey("index"))
-        {
-            throw new UserFailureException("Missing index!");
-        }
-    }
+
 
     private ImagingDataContainer getDataFromParams(Map<String, Object> params)
     {
-        validateInputParams(params);
+        Validator.validateInputParams(params);
 
         String type = (String) params.get("type");
-        String json = mapToJson(params);
+        String json = Util.mapToJson(params);
 
         switch (type.toLowerCase())
         {
             case "preview":
-                return readConfig(json, ImagingPreviewContainer.class);
+                return Util.readConfig(json, ImagingPreviewContainer.class);
             case "export":
-                return readConfig(json, ImagingExportContainer.class);
+                return Util.readConfig(json, ImagingExportContainer.class);
             case "multi-export":
-                return readConfig(json, ImagingMultiExportContainer.class);
+                return Util.readConfig(json, ImagingMultiExportContainer.class);
             default:
                 throw new UserFailureException("Wrong type:" + type);
         }
     }
 
+    private void archiveRawData(AbstractDataSetPackager packager, File rootFile, String rootFolderName,
+            Function<InputStream, Long> checksumFunction,  DataSet dataSet)
+    {
+        //Add dataset files to archive
+        Util.archiveFiles(packager, rootFile, rootFolderName, checksumFunction);
+        //Add dataset properties to archive
+        Map<String, Serializable> properties = dataSet.getProperties();
+        properties.remove(IMAGING_CONFIG_PROPERTY_NAME);
+        byte[] json = Util.mapToJson(properties).getBytes(StandardCharsets.UTF_8);
+        packager.addEntry("properties.txt",
+                dataSet.getModificationDate().toInstant().toEpochMilli(),
+                json.length,
+                checksumFunction.apply(new ByteArrayInputStream(json)),
+                new ByteArrayInputStream(json));
+    }
+
+
+    private void archiveImage(ImagingServiceContext context, IImagingDataSetAdaptor adaptor,
+            ImagingDataSetImage image, Map<String, Serializable> exportConfig,
+            AbstractDataSetPackager packager, File rootFile, String rootFolderName,
+            Function<InputStream, Long> checksumFunction,  DataSet dataSet) {
+
+        String imageFormat = exportConfig.get("image-format").toString();
+        int previewIdx = 0;
+        for(ImagingDataSetPreview preview : image.getPreviews())
+        {
+            Map<String, Serializable> params = preview.getConfig();
+            params.put("resolution", exportConfig.get("resolution"));
+            Serializable img = adaptor.process(context,
+                    rootFile, image.getConfig(), params, image.getMetaData(), imageFormat);
+            String imgString = img.toString();
+            byte[] decoded = Base64.getDecoder().decode(imgString);
+            long size = decoded.length;
+            String name = "image" + previewIdx + "." + imageFormat;
+            packager.addEntry(Paths.get(rootFolderName, name).toString(),
+                    dataSet.getModificationDate().toInstant().toEpochMilli(),
+                    size,
+                    checksumFunction.apply(new ByteArrayInputStream(decoded)),
+                    new ByteArrayInputStream(decoded));
+            previewIdx++;
+        }
+    }
+
 }
diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/Util.java b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/Util.java
new file mode 100644
index 0000000000000000000000000000000000000000..f39f10af48cc54037c6bf6f1d10b37d4db0a1283
--- /dev/null
+++ b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/Util.java
@@ -0,0 +1,137 @@
+/*
+ *  Copyright ETH 2023 Zürich, Scientific IT Services
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package ch.ethz.sis.openbis.generic.server.dss.plugins.imaging;
+
+import ch.systemsx.cisd.common.exceptions.UserFailureException;
+import ch.systemsx.cisd.openbis.dss.generic.server.AbstractDataSetPackager;
+import ch.systemsx.cisd.openbis.dss.generic.shared.ServiceProvider;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import java.io.*;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Paths;
+import java.util.AbstractMap;
+import java.util.Deque;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.zip.CRC32;
+
+class Util
+{
+    private Util() {}
+
+    private static ObjectMapper getObjectMapper()
+    {
+        return ServiceProvider.getObjectMapperV3();
+    }
+
+    static long getCRC32Checksum(InputStream input)
+    {
+        if (input == null)
+            throw new UserFailureException("Can not compute crc32!");
+        CRC32 crc = new CRC32();
+        byte[] buffer = new byte[4096];
+        try
+        {
+            while (true)
+            {
+                int length = input.read(buffer);
+                if (length == -1)
+                    break;
+                crc.update(buffer, 0, length);
+            }
+        } catch (Exception ex)
+        {
+            try
+            {
+                input.close();
+            } catch (Exception ignored)
+            {
+            }
+        }
+        return crc.getValue();
+    }
+
+    static <T> T readConfig(String val, Class<T> clazz)
+    {
+        try
+        {
+            ObjectMapper objectMapper = getObjectMapper();
+            return objectMapper.readValue(new ByteArrayInputStream(val.getBytes()),
+                    clazz);
+        } catch (JsonMappingException mappingException)
+        {
+            throw new UserFailureException(mappingException.toString(), mappingException);
+        } catch (Exception e)
+        {
+            throw new UserFailureException("Could not read the parameters!", e);
+        }
+    }
+
+    static String mapToJson(Map<String, ?> map)
+    {
+        try
+        {
+            ObjectMapper objectMapper = getObjectMapper();
+            return objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(map);
+        } catch (Exception e)
+        {
+            throw new UserFailureException("Could not serialize the input parameters!", e);
+        }
+    }
+
+
+
+    static void archiveFiles(AbstractDataSetPackager packager, File rootFile, String rootFolderName,
+            Function<InputStream, Long> checksumFunction)
+    {
+        Deque<Map.Entry<String, File>> queue = new LinkedList<>();
+
+        queue.add(new AbstractMap.SimpleImmutableEntry<>(rootFolderName, rootFile));
+        while (!queue.isEmpty())
+        {
+            Map.Entry<String, File> element = queue.pollFirst();
+            String prefixPath = element.getKey();
+            File file = element.getValue();
+            String path = Paths.get(prefixPath, file.getName()).toString();
+            if (file.isDirectory())
+            {
+                for (File f : file.listFiles())
+                {
+                    queue.add(new AbstractMap.SimpleImmutableEntry<>(path, f));
+                }
+                packager.addDirectoryEntry(path);
+            } else
+            {
+                try
+                {
+                    FileInputStream fileStream = new FileInputStream(file);
+                    packager.addEntry(path, file.lastModified(), file.getTotalSpace(),
+                            checksumFunction.apply(fileStream), new FileInputStream(file));
+                } catch (IOException exc)
+                {
+                    throw new UserFailureException("Failed during export!", exc);
+                }
+            }
+        }
+
+    }
+
+}
diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/Validator.java b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/Validator.java
new file mode 100644
index 0000000000000000000000000000000000000000..6c94cbe70aaa751d1a8134537995171d5bd21ffc
--- /dev/null
+++ b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/Validator.java
@@ -0,0 +1,85 @@
+/*
+ *  Copyright ETH 2023 Zürich, Scientific IT Services
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package ch.ethz.sis.openbis.generic.server.dss.plugins.imaging;
+
+import ch.systemsx.cisd.common.exceptions.UserFailureException;
+
+import java.io.Serializable;
+import java.util.Map;
+
+class Validator
+{
+    private Validator() {}
+
+
+    static void validateInputParams(Map<String, Object> params)
+    {
+        if (!params.containsKey("permId"))
+        {
+            throw new UserFailureException("Missing dataset permId!");
+        }
+        if (!params.containsKey("type"))
+        {
+            throw new UserFailureException("Missing type!");
+        }
+        if (!params.containsKey("index"))
+        {
+            throw new UserFailureException("Missing index!");
+        }
+    }
+
+
+    static void validateExportConfig(Map<String, Serializable> exportConfig) {
+        if(exportConfig == null) {
+            throw new UserFailureException("Export config can not be empty!");
+        }
+        validateTag(exportConfig, "include", true);
+        validateTag(exportConfig, "image-format");
+        validateTag(exportConfig, "archive-format");
+        validateTag(exportConfig, "resolution");
+    }
+
+    private static void validateTag(Map<String, Serializable> config, String tagName)
+    {
+        validateTag(config, tagName, false);
+    }
+
+    private static void validateTag(Map<String, Serializable> config, String tagName, boolean isMultiValue)
+    {
+        if(!config.containsKey(tagName)){
+            throw new UserFailureException("Missing '"+tagName+"' in export config!");
+        }
+        Serializable include = config.get(tagName);
+        if(include == null){
+            throw new UserFailureException("'"+tagName+"' tag in export config can not be null!");
+        }
+        if(isMultiValue)
+        {
+            if (!include.getClass().isArray())
+            {
+                throw new UserFailureException("'include' tag in export config must be an array!");
+            }
+            if (((Serializable[]) include).length == 0)
+            {
+                throw new UserFailureException("'include' tag in export config can not be empty!");
+            }
+        }
+    }
+
+
+}
diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/IImagingDataSetAdaptor.java b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/IImagingDataSetAdaptor.java
index ea3b5ad6e14376c8023db65c17afb38b25bd6ce7..5aaefdeaa94e59057dd0156504dc6242b5349281 100644
--- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/IImagingDataSetAdaptor.java
+++ b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/IImagingDataSetAdaptor.java
@@ -25,7 +25,7 @@ import java.util.Map;
 
 public interface IImagingDataSetAdaptor
 {
-    Serializable process(ImagingServiceContext context, File rootFile,
+    Serializable process(ImagingServiceContext context, File rootFile, Map<String, Serializable> imageConfig,
             Map<String, Serializable> previewConfig, Map<String, String> metaData, String format);
 
 }
diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/ImagingDataSetExampleAdaptor.java b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/ImagingDataSetExampleAdaptor.java
index e553d1382d09354f6f82fbe4fd8b8341a7b2403d..536f083757128825e389b0966cf809fcc6c77305 100644
--- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/ImagingDataSetExampleAdaptor.java
+++ b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/ImagingDataSetExampleAdaptor.java
@@ -38,7 +38,7 @@ public final class ImagingDataSetExampleAdaptor implements IImagingDataSetAdapto
     }
 
     @Override
-    public Serializable process(ImagingServiceContext context, File rootFile,
+    public Serializable process(ImagingServiceContext context, File rootFile, Map<String, Serializable> imageConfig,
             Map<String, Serializable> previewConfig, Map<String, String> metaData, String format)
     {
         BufferedImage img = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_ARGB);
diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/ImagingDataSetJythonAdaptor.java b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/ImagingDataSetJythonAdaptor.java
index 51e5043ba32212f9b7e15a49cf35758776af7552..1a53bcd5c649ef0262d5cb142e1321b7556f82ef 100644
--- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/ImagingDataSetJythonAdaptor.java
+++ b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/ImagingDataSetJythonAdaptor.java
@@ -40,7 +40,7 @@ public class ImagingDataSetJythonAdaptor implements IImagingDataSetAdaptor
         }
     }
     @Override
-    public Serializable process(ImagingServiceContext context, File rootFile,
+    public Serializable process(ImagingServiceContext context, File rootFile, Map<String, Serializable> imageConfig,
             Map<String, Serializable> previewConfig, Map<String, String> metaData, String format)
     {
         CustomDSSServiceExecutionOptions options = new CustomDSSServiceExecutionOptions();
@@ -48,6 +48,7 @@ public class ImagingDataSetJythonAdaptor implements IImagingDataSetAdaptor
         options.withParameter("asApi", context.getAsApi());
         options.withParameter("dssApi", context.getDssApi());
         options.withParameter("file", rootFile);
+        options.withParameter("imageConfig", imageConfig);
         options.withParameter("config", previewConfig);
         options.withParameter("metaData", metaData);
             IDssServiceScriptRunner
diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/ImagingDataSetPythonAdaptor.java b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/ImagingDataSetPythonAdaptor.java
index 8c720261064f4fb676f5b798e79e0b274e026fa8..b616666b257ee6a3cae28f082b33c1f052cf1be6 100644
--- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/ImagingDataSetPythonAdaptor.java
+++ b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/ImagingDataSetPythonAdaptor.java
@@ -26,55 +26,67 @@ import java.io.File;
 import java.io.IOException;
 import java.io.Serializable;
 import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
 import java.util.Map;
 
 public abstract class ImagingDataSetPythonAdaptor implements IImagingDataSetAdaptor
 {
 
-
     protected String pythonPath;
 
     protected String scriptPath;
 
     @Override
-    public Serializable process(ImagingServiceContext context, File rootFile,
+    public Serializable process(ImagingServiceContext context, File rootFile, Map<String, Serializable> imageConfig,
             Map<String, Serializable> previewConfig, Map<String, String> metaData, String format)
     {
 
         ProcessBuilder processBuilder = new ProcessBuilder(pythonPath,
-                scriptPath, rootFile.getAbsolutePath(), convertMapToJson(previewConfig), convertMapToJson(metaData), format);
+                scriptPath, rootFile.getAbsolutePath(), convertMapToJson(imageConfig),
+                convertMapToJson(previewConfig), convertMapToJson(metaData), format);
         processBuilder.redirectErrorStream(false);
 
         String fullOutput;
-        try {
+        try
+        {
             Process process = processBuilder.start();
-            fullOutput = new String(process.getInputStream().readAllBytes(), StandardCharsets.UTF_8);
+            fullOutput =
+                    new String(process.getInputStream().readAllBytes(), StandardCharsets.UTF_8);
             int exitCode = process.waitFor();
-            if(exitCode != 0) {
-                String error = new String(process.getErrorStream().readAllBytes(), StandardCharsets.UTF_8);
+            if (exitCode != 0)
+            {
+                String error =
+                        new String(process.getErrorStream().readAllBytes(), StandardCharsets.UTF_8);
                 throw new UserFailureException("Script evaluation failed: " + error);
             }
-        } catch (IOException | InterruptedException e) {
+        } catch (IOException | InterruptedException e)
+        {
             throw new RuntimeException(e);
         }
 
-        if(fullOutput.isBlank()) {
+        if (fullOutput.isBlank())
+        {
             throw new UserFailureException("Script produced no results!");
         }
 
         String[] resultSplit = fullOutput.split("\n");
-        return resultSplit[resultSplit.length-1];
+        return resultSplit[resultSplit.length - 1];
     }
 
-    private String convertMapToJson(Map<String,?> map) {
-        try {
+    private String convertMapToJson(Map<String, ?> map)
+    {
+        Map<String, ?> mapToConvert = map;
+        if(map == null) {
+            mapToConvert = new HashMap<>();
+        }
+        try
+        {
             ObjectMapper objectMapper = new GenericObjectMapper();
-            return objectMapper.writeValueAsString(map);
-        }catch (Exception e) {
+            return objectMapper.writeValueAsString(mapToConvert);
+        } catch (Exception e)
+        {
             throw new UserFailureException("Couldn't convert map to string", e);
         }
     }
 
-
-
 }
diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/NanonisSxmAdaptor.java b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/NanonisSxmAdaptor.java
index a45e9c496b28c8827fe8b65b3317f6c31d0079a6..4f7601ec881634e0f4cb15aea41424c6d4f6e023 100644
--- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/NanonisSxmAdaptor.java
+++ b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/NanonisSxmAdaptor.java
@@ -37,7 +37,6 @@ public final class NanonisSxmAdaptor extends ImagingDataSetPythonAdaptor
 {
     private final String SXM_SCRIPT_PROPERTY = "nanonis-sxm";
 
-
     public NanonisSxmAdaptor(Properties properties)
     {
 
@@ -56,4 +55,24 @@ public final class NanonisSxmAdaptor extends ImagingDataSetPythonAdaptor
         this.pythonPath = properties.getProperty("python3-path", "python3");
     }
 
+    @Override
+    public Serializable process(ImagingServiceContext context, File rootFile, Map<String, Serializable> imageConfig,
+            Map<String, Serializable> previewConfig, Map<String, String> metaData, String format)
+    {
+        Serializable result = super.process(context, rootFile, imageConfig, previewConfig, metaData, format);
+        if (result == null)
+        {
+            return result;
+        }
+        String str = result.toString();
+        if (str.length() > 3)
+        {
+            return str.substring(2, str.length() - 1);
+        } else
+        {
+            return "";
+        }
+
+    }
+
 }
diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/container/ImagingDataContainer.java b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/container/ImagingDataContainer.java
index 3c1252484f38778b256b98e43ad5c70cbd442e1f..7c07d1c0b91e069e1ef724080a415d42e9d85731 100644
--- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/container/ImagingDataContainer.java
+++ b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/container/ImagingDataContainer.java
@@ -28,12 +28,9 @@ public abstract class ImagingDataContainer implements Serializable
 
     @JsonProperty
     private String type;
-    @JsonProperty
-    private String permId;
+
     @JsonProperty
     private String error;
-    @JsonProperty
-    private int index;
 
     @JsonIgnore
     public String getType()
@@ -45,16 +42,6 @@ public abstract class ImagingDataContainer implements Serializable
         this.type = type;
     }
 
-    @JsonIgnore
-    public String getPermId()
-    {
-        return permId;
-    }
-
-    public void setPermId(String permId) {
-        this.permId = permId;
-    }
-
     @JsonIgnore
     public String getError()
     {
@@ -66,14 +53,6 @@ public abstract class ImagingDataContainer implements Serializable
         this.error = error;
     }
 
-    @JsonIgnore
-    public int getIndex()
-    {
-        return index;
-    }
 
-    public void setIndex(int index) {
-        this.index = index;
-    }
 
 }
diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/container/ImagingExportContainer.java b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/container/ImagingExportContainer.java
index 9041716ddb4ef00770b5993bad01033ac0bc36d4..c1e5fed445dd53bd0180b554737cffabddf1e5eb 100644
--- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/container/ImagingExportContainer.java
+++ b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/container/ImagingExportContainer.java
@@ -24,9 +24,46 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 public final class ImagingExportContainer extends ImagingDataContainer
 {
 
+    @JsonProperty
+    private String permId;
+    @JsonProperty
+    private int index;
+    @JsonProperty
+    private String url;
     @JsonProperty
     private ImagingDataSetExport export = null;
 
+    @JsonIgnore
+    public String getPermId()
+    {
+        return permId;
+    }
+
+    public void setPermId(String permId) {
+        this.permId = permId;
+    }
+
+    @JsonIgnore
+    public int getIndex()
+    {
+        return index;
+    }
+
+    public void setIndex(int index) {
+        this.index = index;
+    }
+
+    @JsonIgnore
+    public String getUrl()
+    {
+        return url;
+    }
+
+    public void setUrl(String url)
+    {
+        this.url = url;
+    }
+
     @JsonIgnore
     public ImagingDataSetExport getExport()
     {
diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/container/ImagingMultiExportContainer.java b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/container/ImagingMultiExportContainer.java
index c5a342c9b25edbd5829fb70e0ead728bc5441834..183cb54dfd5fb69afa6cd336000f53d1713dc9e7 100644
--- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/container/ImagingMultiExportContainer.java
+++ b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/container/ImagingMultiExportContainer.java
@@ -17,7 +17,7 @@
 
 package ch.ethz.sis.openbis.generic.server.dss.plugins.imaging.container;
 
-import ch.ethz.sis.openbis.generic.dssapi.v3.dto.imaging.ImagingDataSetExport;
+import ch.ethz.sis.openbis.generic.dssapi.v3.dto.imaging.ImagingDataSetMultiExport;
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonProperty;
 
@@ -27,16 +27,30 @@ public class ImagingMultiExportContainer extends ImagingDataContainer
 {
 
     @JsonProperty
-    private List<ImagingDataSetExport> export = null;
+    private String url;
+
+    @JsonProperty
+    private List<ImagingDataSetMultiExport> exports = null;
+
+    @JsonIgnore
+    public String getUrl()
+    {
+        return url;
+    }
+
+    public void setUrl(String url)
+    {
+        this.url = url;
+    }
 
     @JsonIgnore
-    public List<ImagingDataSetExport> getExport()
+    public List<ImagingDataSetMultiExport> getExports()
     {
-        return export;
+        return exports;
     }
 
-    public void setExport(List<ImagingDataSetExport> export)
+    public void setExports(List<ImagingDataSetMultiExport> exports)
     {
-        this.export = export;
+        this.exports = exports;
     }
 }
diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/container/ImagingPreviewContainer.java b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/container/ImagingPreviewContainer.java
index 18c75f0c78b02b913f88a91598e8c0667ca441ad..d5d5e23973d6b1a1c328a3a11c96cef27e0687bc 100644
--- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/container/ImagingPreviewContainer.java
+++ b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/container/ImagingPreviewContainer.java
@@ -24,9 +24,33 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 public final class ImagingPreviewContainer extends ImagingDataContainer
 {
 
+    @JsonProperty
+    private String permId;
+    @JsonProperty
+    private int index;
     @JsonProperty
     private ImagingDataSetPreview preview = null;
 
+    @JsonIgnore
+    public String getPermId()
+    {
+        return permId;
+    }
+
+    public void setPermId(String permId) {
+        this.permId = permId;
+    }
+
+    @JsonIgnore
+    public int getIndex()
+    {
+        return index;
+    }
+
+    public void setIndex(int index) {
+        this.index = index;
+    }
+
     @JsonIgnore
     public ImagingDataSetPreview getPreview()
     {
diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/nanonis_dat.py b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/nanonis_dat.py
index b8b414bebe5c3972a4f7e5858ad35ccffeb5f75c..6b1c598587aa6ba994e31233e719ccbe49052e67 100644
--- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/nanonis_dat.py
+++ b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/nanonis_dat.py
@@ -31,9 +31,10 @@ def get_channel(img, channel_name = 'z'):
 
 
 file = sys.argv[1]
-params = json.loads(sys.argv[2])
-meta_data = json.loads(sys.argv[3])
-format = sys.argv[4]
+image_params = json.loads(sys.argv[2])
+params = json.loads(sys.argv[3])
+meta_data = json.loads(sys.argv[4])
+format = sys.argv[5]
 
 
 folder_dir = os.path.join(file, 'original')
diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/nanonis_sxm.py b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/nanonis_sxm.py
index 08d5711aab6dd3f9f192a76fd92a5d772c0fbe00..476d27f5a0a1b8e2499b30121a5bbd2aaf7ecc5f 100644
--- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/nanonis_sxm.py
+++ b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/nanonis_sxm.py
@@ -36,14 +36,14 @@ def get_channel(img, channel_name = 'z'):
 
 print("SYS.ARGV:" + str(sys.argv))
 file = sys.argv[1]
-params = json.loads(sys.argv[2])
-meta_data = json.loads(sys.argv[3])
-format = sys.argv[4]
+image_params = json.loads(sys.argv[2])
+params = json.loads(sys.argv[3])
+meta_data = json.loads(sys.argv[4])
+format = sys.argv[5]
 
 
 folder_dir = os.path.join(file, 'original')
 file_path = os.path.join(folder_dir, os.listdir(folder_dir)[0])
-# print(file_path)
 
 
 def generate_random_image(height, width):
@@ -56,90 +56,7 @@ def generate_random_image(height, width):
     return encoded
 
 
-def get_sxm_image():
-    img = load_image(file_path)
-    channel = get_channel(img, 'z')
-    img_byte_arr = io.BytesIO()
-
-    # im = plt.imshow(channel[0])
-    # plt.savefig(img_byte_arr, format="png")
-    fig = img.plot(show=False, show_params=False)
-    fig.frameon=False
-    # plt.title(None)
-    # plt.axis('off')
-    plt.savefig(img_byte_arr, format=format)
-
-    # print(img.header)
-    img_byte_arr = img_byte_arr.getvalue()
-    encoded = base64.b64encode(img_byte_arr)
-    print_params = img.print_params(show=False).split('\n')
-    print_params = {x: y for x, y in (s.split(':') for s in print_params)}
-    print_params = json.dumps(print_params)
-    print(f'PARAMS={print_params}')
-    header = json.dumps(img.header, cls=NumpyEncoder)
-    print(f'HEADER={header}')
-
-    return encoded
-
-
-def get_sxm_image2():
-    img_orig = load_image(file_path)
-    channel = get_channel(img_orig, 'z')[0]
-
-    min_val = numpy.min(channel)
-    max_val = numpy.max(channel)
-    scaled_data = (channel - min_val) / (max_val - min_val)
-    img = Image.fromarray(numpy.uint8(scaled_data * 255), 'L')
-
-    img_byte_arr = io.BytesIO()
-    img.save(img_byte_arr, format=format)
-    img_byte_arr = img_byte_arr.getvalue()
-    encoded = base64.b64encode(img_byte_arr)
-
-    print_params = img_orig.print_params(show=False).split('\n')
-    print_params = {x: y for x, y in (s.split(':') for s in print_params)}
-    print_params = json.dumps(print_params)
-    print(f'PARAMS={print_params}')
-    header = json.dumps(img_orig.header, cls=NumpyEncoder)
-    print(f'HEADER={header}')
-
-    return encoded
-
-
-def get_sxm_image3(channel_name, scaling, color_scale):
-    img = load_image(file_path)
-    # channel = get_channel(img, channel_name)
-    img_byte_arr = io.BytesIO()
-
-    log = False
-    if scaling == 'logarithmic':
-        log = True
-    fig = img.plot(show=False, show_params=False, hide=True, channel=channel_name, log=log)
-    fig.frameon=False
-    # plt.title('None')
-    plt.axis('off')
-    plt.savefig(img_byte_arr, format="png", bbox_inches='tight')
-
-    pilImg = Image.open(img_byte_arr)
-    print(f"SIZE={pilImg.size}")
-    im2 = pilImg.crop(pilImg.getbbox())
-    print(f"SIZE={im2.size}")
-    img_byte_arr = io.BytesIO()
-    im2.save(img_byte_arr, format='PNG')
-
-    # print(img.header)
-    img_byte_arr = img_byte_arr.getvalue()
-    encoded = base64.b64encode(img_byte_arr)
-    print_params = img.print_params(show=False).split('\n')
-    print_params = {x: y for x, y in (s.split(':') for s in print_params)}
-    print_params = json.dumps(print_params)
-    print(f'PARAMS={print_params}')
-    header = json.dumps(img.header, cls=NumpyEncoder)
-    print(f'HEADER={header}')
-
-    return encoded
-
-def get_sxm_image4(channel_name, x_axis, y_axis, scaling, color_scale, colormap, colormap_scaling):
+def get_sxm_image(channel_name, x_axis, y_axis, scaling, color_scale, colormap, colormap_scaling):
     img = load_image(file_path)
     img_byte_arr = io.BytesIO()
 
@@ -161,41 +78,23 @@ def get_sxm_image4(channel_name, x_axis, y_axis, scaling, color_scale, colormap,
 
     return encoded
 
+def sxm_mode(parameters):
+    channel = parameters['channel']
+    x_axis = [float(x) for x in parameters['x-axis']]
+    y_axis = [float(x) for x in parameters['y-axis']]
+    color_scale = [float(x) for x in parameters['color-scale']]
+    colormap = parameters['colormap']
+    scaling = parameters['scaling']
+    colormap_scaling = False
+    if "colormap_scaling" in parameters:
+        colormap_scaling = parameters['colormap_scaling'].upper() == "TRUE"
+    print(f'{get_sxm_image(channel, x_axis, y_axis, scaling, color_scale, colormap, colormap_scaling)}')
+
 print(params)
 if 'mode' in params:
-    if params['mode'] == '1':
-        # print(f'IMG={get_sxm_image()}')
-        print(f'{get_sxm_image()}')
-    elif params['mode'] == '2':
-        # print(f'IMG={get_sxm_image2()}')
-        print(f'{get_sxm_image2()}')
-    elif params['mode'] == '3':
-        # print(f'IMG={generate_random_image(320, 320)}')
+    if params['mode'] == '3':
         print(f'{generate_random_image(256, 256)}')
-    elif params['mode'] == '4':
-        channel = params['channel']
-        scaling = params['scaling']
-        color_scale = [float(x) for x in params['color-scale']]
-        print(f'{get_sxm_image3(channel, scaling, color_scale)}')
     elif params['mode'] == '5':
-        channel = params['channel']
-        x_axis = [float(x) for x in params['x-axis']]
-        y_axis = [float(x) for x in params['y-axis']]
-        color_scale = [float(x) for x in params['color-scale']]
-        colormap = params['colormap']
-        scaling = params['scaling']
-        colormap_scaling = False
-        if "colormap_scaling" in params:
-            colormap_scaling = params['colormap_scaling'].upper() == "TRUE"
-        print(f'{get_sxm_image4(channel, x_axis, y_axis, scaling, color_scale, colormap, colormap_scaling)}')
+        sxm_mode(params)
 else:
-    channel = params['channel']
-    x_axis = [float(x) for x in params['x-axis']]
-    y_axis = [float(x) for x in params['y-axis']]
-    color_scale = [float(x) for x in params['color-scale']]
-    colormap = params['colormap']
-    scaling = params['scaling']
-    colormap_scaling = False
-    if "colormap_scaling" in params:
-        colormap_scaling = params['colormap_scaling'].upper() == "TRUE"
-    print(f'{get_sxm_image4(channel, x_axis, y_axis, scaling, color_scale, colormap, colormap_scaling)}')
\ No newline at end of file
+    sxm_mode(params)
\ No newline at end of file