From 8f8a1354c12cf624d0230149d03cdffefb2d97c5 Mon Sep 17 00:00:00 2001
From: gpawel <gpawel>
Date: Wed, 29 Aug 2012 10:15:30 +0000
Subject: [PATCH] SP-235 BIS-19: Processing plugin to generate and register
 overview images

SVN: 26476
---
 .../dss/etl/AbstractImageFileExtractor.java   |  13 +-
 .../dss/etl/Hdf5ThumbnailGenerator.java       |  70 +++---
 .../dss/etl/dto/RelativeImageFile.java        |   7 +-
 .../dto/api/impl/ImageDataSetInformation.java |  14 ++
 .../dss/etl/dto/api/v1/ImageFileInfo.java     |  31 ++-
 .../api/v1/SimpleOverviewImageDataConfig.java |  14 ++
 ...ImagingDataSetRegistrationTransaction.java | 135 ++++++++---
 .../etl/jython/JythonPlateDataSetHandler.java |   1 -
 .../jython/SimpleImageDataSetRegistrator.java | 158 ++++++++++---
 .../MarkerFileCreatingProcessingPlugin.java   |  83 +++++++
 .../dataaccess/IImagingReadonlyQueryDAO.java  |  13 ++
 .../ImgAcquiredImageEnrichedDTO.java          | 213 ++++++++++++++++++
 12 files changed, 650 insertions(+), 102 deletions(-)
 create mode 100644 screening/source/java/ch/systemsx/cisd/openbis/dss/screening/server/plugins/MarkerFileCreatingProcessingPlugin.java
 create mode 100644 screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/dataaccess/ImgAcquiredImageEnrichedDTO.java

diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/AbstractImageFileExtractor.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/AbstractImageFileExtractor.java
index 517facb2e2e..145289ca196 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/AbstractImageFileExtractor.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/AbstractImageFileExtractor.java
@@ -44,7 +44,6 @@ import ch.systemsx.cisd.openbis.dss.etl.dto.RelativeImageFile;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.ThumbnailsInfo;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.Channel;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ImageFileInfo;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ImageIdentifier;
 import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.ChannelDescription;
@@ -472,8 +471,7 @@ abstract public class AbstractImageFileExtractor implements IImageFileExtractor
     {
         RelativeImageReference relativeImageRef =
                 new RelativeImageReference(imageInfo.getImageRelativePath(),
-                        getUniqueStringIdentifier(imageInfo.tryGetImageIdentifier()),
-                        colorComponentOrNull);
+                        imageInfo.tryGetUniqueStringIdentifier(), colorComponentOrNull);
 
         RelativeImageReference relativeThumbnailRef = null;
         if (thumbnailFilePathsOrNull != null)
@@ -499,15 +497,6 @@ abstract public class AbstractImageFileExtractor implements IImageFileExtractor
                 relativeThumbnailRef);
     }
 
-    private static String getUniqueStringIdentifier(ImageIdentifier identifier)
-    {
-        if (identifier == null)
-        {
-            return null;
-        }
-        return identifier.getUniqueStringIdentifier();
-    }
-
     protected static Integer tryAsInt(String valueOrNull)
     {
         if (valueOrNull == null)
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/Hdf5ThumbnailGenerator.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/Hdf5ThumbnailGenerator.java
index 5b2ba043d3f..53344e76af1 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/Hdf5ThumbnailGenerator.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/Hdf5ThumbnailGenerator.java
@@ -44,6 +44,7 @@ import ch.systemsx.cisd.common.hdf5.HDF5Container.IHDF5WriterClient;
 import ch.systemsx.cisd.common.hdf5.IHDF5ContainerWriter;
 import ch.systemsx.cisd.common.io.ByteArrayBasedContentNode;
 import ch.systemsx.cisd.common.io.FileBasedContentNode;
+import ch.systemsx.cisd.common.io.hierarchical_content.api.IHierarchicalContent;
 import ch.systemsx.cisd.common.logging.LogCategory;
 import ch.systemsx.cisd.common.logging.LogFactory;
 import ch.systemsx.cisd.common.process.ProcessExecutionHelper;
@@ -56,7 +57,6 @@ import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.ThumbnailsInfo;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.Channel;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ChannelColorComponent;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ImageFileInfo;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ImageIdentifier;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ImageStorageConfiguraton;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ThumbnailsStorageFormat;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.transformations.ImageTransformation;
@@ -99,13 +99,14 @@ public class Hdf5ThumbnailGenerator implements IHDF5WriterClient
      *            imagesParentDirectory
      * @param thumbnailFilePath absolute path to the file where thumbnails will be saved
      * @param imageStorageConfiguraton describes how the thumbnails should be generated
+     * @param content
      */
     public static void tryGenerateThumbnails(ImageDataSetStructure imageDataSetStructure,
             File imagesParentDirectory, String thumbnailFilePath,
             ImageStorageConfiguraton imageStorageConfiguraton,
             String thumbnailPhysicalDatasetPermId,
             ThumbnailsStorageFormat thumbnailsStorageFormatOrNull, ThumbnailsInfo thumbnailPaths,
-            boolean registerOriginalImageAsThumbnail)
+            boolean registerOriginalImageAsThumbnail, IHierarchicalContent content)
     {
         if (thumbnailsStorageFormatOrNull != null)
         {
@@ -121,7 +122,7 @@ public class Hdf5ThumbnailGenerator implements IHDF5WriterClient
                     new Hdf5ThumbnailGenerator(imageDataSetStructure, imagesParentDirectory,
                             thumbnailPhysicalDatasetPermId, thumbnailsStorageFormatOrNull,
                             imageLibrary, thumbnailPaths, registerOriginalImageAsThumbnail,
-                            operationLog);
+                            content, operationLog);
             container.runWriterClient(thumbnailsStorageFormatOrNull.isStoreCompressed(),
                     thumbnailsGenerator);
         }
@@ -158,11 +159,13 @@ public class Hdf5ThumbnailGenerator implements IHDF5WriterClient
 
     private final boolean registerOriginalImageAsThumbnail;
 
+    private IHierarchicalContent contentOrNull;
+
     private Hdf5ThumbnailGenerator(ImageDataSetStructure imageDataSetStructure,
             File imagesParentDirectory, String thumbnailPhysicalDatasetPermId,
             ThumbnailsStorageFormat thumbnailsStorageFormat, ImageLibraryInfo imageLibraryOrNull,
             ThumbnailsInfo thumbnailPathCollector, boolean registerOriginalImageAsThumbnail,
-            Logger operationLog)
+            IHierarchicalContent contentOrNull, Logger operationLog)
     {
         this.imageDataSetStructure = imageDataSetStructure;
         this.imagesParentDirectory = imagesParentDirectory;
@@ -171,6 +174,7 @@ public class Hdf5ThumbnailGenerator implements IHDF5WriterClient
         this.imageLibraryOrNull = imageLibraryOrNull;
         this.thumbnailPathCollector = thumbnailPathCollector;
         this.registerOriginalImageAsThumbnail = registerOriginalImageAsThumbnail;
+        this.contentOrNull = contentOrNull;
         this.logger = operationLog;
 
         for (Channel ch : imageDataSetStructure.getChannels())
@@ -216,7 +220,7 @@ public class Hdf5ThumbnailGenerator implements IHDF5WriterClient
         try
         {
             long start = System.currentTimeMillis();
-            String imageIdOrNull = tryExtractImageID(image);
+            String imageIdOrNull = image.tryGetUniqueStringIdentifier();
 
             List<ThumbnailData> thumbnailData =
                     generateThumbnail(bufferOutputStream, image, imageIdOrNull);
@@ -282,7 +286,7 @@ public class Hdf5ThumbnailGenerator implements IHDF5WriterClient
         }
         newImagePath.append("_c").append(channelCode);
 
-        String imageIdOrNull = tryExtractImageID(plateImage);
+        String imageIdOrNull = plateImage.tryGetUniqueStringIdentifier();
         if (imageIdOrNull != null)
         {
             newImagePath.append(imageIdOrNull);
@@ -295,12 +299,6 @@ public class Hdf5ThumbnailGenerator implements IHDF5WriterClient
         return sb.length() > 0 ? "_" : "";
     }
 
-    private static String tryExtractImageID(ImageFileInfo image)
-    {
-        ImageIdentifier imageIdentifier = image.tryGetImageIdentifier();
-        return imageIdentifier == null ? null : imageIdentifier.getUniqueStringIdentifier();
-    }
-
     private List<ThumbnailData> generateThumbnail(ByteArrayOutputStream bufferOutputStream,
             ImageFileInfo img, String imageIdOrNull) throws IOException
     {
@@ -323,7 +321,7 @@ public class Hdf5ThumbnailGenerator implements IHDF5WriterClient
     {
         final File imageFile =
                 new File(imagesParentDirectory, imageFileInfo.getImageRelativePath());
-        Size originalSize = loadUnchangedImageDimension(imageFile, null);
+        Size originalSize = loadUnchangedImageDimension(imageFileInfo.getImageRelativePath(), null);
 
         return Collections.singletonList(new ThumbnailData(
                 FileUtilities.loadToByteArray(imageFile), originalSize.getWidth(), originalSize
@@ -333,21 +331,29 @@ public class Hdf5ThumbnailGenerator implements IHDF5WriterClient
     private List<ThumbnailData> generateThumbnailWithImageMagic(ImageFileInfo imageFileInfo)
             throws IOException
     {
-        final File imageFile =
-                new File(imagesParentDirectory, imageFileInfo.getImageRelativePath());
         int width = thumbnailsStorageFormat.getMaxWidth();
         int height = thumbnailsStorageFormat.getMaxHeight();
 
         if (thumbnailsStorageFormat.getZoomLevel() != null)
         {
-            Size originalSize = loadUnchangedImageDimension(imageFile, null);
+            Size originalSize =
+                    loadUnchangedImageDimension(imageFileInfo.getImageRelativePath(), null);
             double zoomLevel = thumbnailsStorageFormat.getZoomLevel();
             width = (int) Math.round(zoomLevel * originalSize.getWidth());
             height = (int) Math.round(zoomLevel * originalSize.getHeight());
         }
         String size = width + "x" + height;
 
-        String imageFilePath = imageFile.getPath();
+        String imageFilePath = null;
+        if (contentOrNull == null)
+        {
+            imageFilePath = new File(imageFilePath, imageFileInfo.getImageRelativePath()).getPath();
+        } else
+        {
+            imageFilePath =
+                    contentOrNull.getNode(imageFileInfo.getImageRelativePath()).getFile().getPath();
+        }
+
         List<String> params = new ArrayList<String>();
         params.addAll(Arrays.asList(convertUtilityOrNull.getPath(), imageFilePath, "-scale", size));
         List<String> additionalParams = thumbnailsStorageFormat.getImageMagicParams();
@@ -413,9 +419,7 @@ public class Hdf5ThumbnailGenerator implements IHDF5WriterClient
             String imageIdOrNull, ByteArrayOutputStream bufferOutputStream) throws IOException
     {
         BufferedImage image =
-                loadUnchangedImage(
-                        new File(imagesParentDirectory, imageFileInfo.getImageRelativePath()),
-                        imageIdOrNull);
+                loadUnchangedImage(imageFileInfo.getImageRelativePath(), imageIdOrNull);
 
         int widht = thumbnailsStorageFormat.getMaxWidth();
         int height = thumbnailsStorageFormat.getMaxHeight();
@@ -512,16 +516,30 @@ public class Hdf5ThumbnailGenerator implements IHDF5WriterClient
         return null;
     }
 
-    private BufferedImage loadUnchangedImage(File imageFile, String imageIdOrNull)
+    private BufferedImage loadUnchangedImage(String imageRelativePath, String imageIdOrNull)
     {
-        return Utils.loadUnchangedImage(new FileBasedContentNode(imageFile), imageIdOrNull,
-                imageLibraryOrNull);
+        if (contentOrNull == null)
+        {
+            return Utils.loadUnchangedImage(new FileBasedContentNode(new File(
+                    imagesParentDirectory, imageRelativePath)), imageIdOrNull, imageLibraryOrNull);
+        } else
+        {
+            return Utils.loadUnchangedImage(contentOrNull.getNode(imageRelativePath),
+                    imageIdOrNull, imageLibraryOrNull);
+        }
     }
 
-    private Size loadUnchangedImageDimension(File imageFile, String imageIdOrNull)
+    private Size loadUnchangedImageDimension(String imageRelativePath, String imageIdOrNull)
     {
-        return Utils.loadUnchangedImageSize(new FileBasedContentNode(imageFile), imageIdOrNull,
-                imageLibraryOrNull);
+        if (contentOrNull == null)
+        {
+            return Utils.loadUnchangedImageSize(new FileBasedContentNode(new File(
+                    imagesParentDirectory, imageRelativePath)), imageIdOrNull, imageLibraryOrNull);
+        } else
+        {
+            return Utils.loadUnchangedImageSize(contentOrNull.getNode(imageRelativePath),
+                    imageIdOrNull, imageLibraryOrNull);
+        }
     }
 
     private Status createStatus(String thumbnailPath, IOException ex)
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/RelativeImageFile.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/RelativeImageFile.java
index 051161ecac4..652abe2ac77 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/RelativeImageFile.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/RelativeImageFile.java
@@ -20,7 +20,6 @@ import java.io.Serializable;
 
 import ch.systemsx.cisd.common.utilities.AbstractHashable;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ImageFileInfo;
-import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ImageIdentifier;
 
 /**
  * Points to one image on the file system.
@@ -37,10 +36,8 @@ public class RelativeImageFile extends AbstractHashable implements Serializable
 
     public static RelativeImageFile create(ImageFileInfo imageFileInfo)
     {
-        ImageIdentifier imageIdentifier = imageFileInfo.tryGetImageIdentifier();
-        String imageIDOrNull =
-                (imageIdentifier == null) ? null : imageIdentifier.getUniqueStringIdentifier();
-        return new RelativeImageFile(imageFileInfo.getImageRelativePath(), imageIDOrNull);
+        return new RelativeImageFile(imageFileInfo.getImageRelativePath(),
+                imageFileInfo.tryGetUniqueStringIdentifier());
     }
 
     public RelativeImageFile(String imageRelativePath, String imageIDOrNull)
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/ImageDataSetInformation.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/ImageDataSetInformation.java
index 3171778eced..a4f686564d2 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/ImageDataSetInformation.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/ImageDataSetInformation.java
@@ -51,6 +51,8 @@ public class ImageDataSetInformation extends BasicDataSetInformation
 
     private boolean registerAsOverviewImageDataSet;
 
+    private boolean generateOverviewImagesFromRegisteredImages;
+
     private int maximumImageWidth;
 
     private int maximumImageHeight;
@@ -160,6 +162,18 @@ public class ImageDataSetInformation extends BasicDataSetInformation
         this.registerAsOverviewImageDataSet = registerAsOverviewImageDataSet;
     }
 
+    public boolean isGenerateOverviewImagesFromRegisteredImages()
+    {
+        return generateOverviewImagesFromRegisteredImages;
+    }
+
+    public void setGenerateOverviewImagesFromRegisteredImages(
+            boolean generateOverviewImagesFromRegisteredImages)
+    {
+        this.generateOverviewImagesFromRegisteredImages =
+                generateOverviewImagesFromRegisteredImages;
+    }
+
     @Override
     public String toString()
     {
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ImageFileInfo.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ImageFileInfo.java
index 85c50c1d893..30ad9846389 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ImageFileInfo.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ImageFileInfo.java
@@ -30,6 +30,10 @@ public final class ImageFileInfo implements Serializable
 
     private ImageIdentifier imageIdentifier;
 
+    private String uniqueImageIdentifier;
+
+    private String containerDataSetCode;
+
     public ImageFileInfo(String channelCode, int tileRow, int tileColumn, String imageRelativePath)
     {
         assert channelCode != null;
@@ -40,10 +44,17 @@ public final class ImageFileInfo implements Serializable
         setTile(tileRow, tileColumn);
     }
 
-    public ImageIdentifier tryGetImageIdentifier()
+    public String tryGetUniqueStringIdentifier()
     {
-        return imageIdentifier;
+        if (imageIdentifier != null)
+        {
+            return imageIdentifier.getUniqueStringIdentifier();
+        } else if (uniqueImageIdentifier != null)
+        {
+            return uniqueImageIdentifier;
+        }
 
+        return null;
     }
 
     public Integer tryGetWellRow()
@@ -146,6 +157,21 @@ public final class ImageFileInfo implements Serializable
         this.seriesNumberOrNull = value;
     }
 
+    public void setUniqueImageIdentifier(String uniqueImageIdentifier)
+    {
+        this.uniqueImageIdentifier = uniqueImageIdentifier;
+    }
+
+    public String getContainerDataSetCode()
+    {
+        return containerDataSetCode;
+    }
+
+    public void setContainerDataSetCode(String containerDataSetCode)
+    {
+        this.containerDataSetCode = containerDataSetCode;
+    }
+
     @Override
     public String toString()
     {
@@ -154,5 +180,4 @@ public final class ImageFileInfo implements Serializable
                 + timepointOrNull + ", depth=" + depthOrNull + ", seriesNumber="
                 + seriesNumberOrNull + "]";
     }
-
 }
\ No newline at end of file
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/SimpleOverviewImageDataConfig.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/SimpleOverviewImageDataConfig.java
index f57b0ab05cb..3fe34cf6129 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/SimpleOverviewImageDataConfig.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/SimpleOverviewImageDataConfig.java
@@ -25,6 +25,8 @@ public class SimpleOverviewImageDataConfig extends SimpleImageDataConfig
 {
     private String containerDataSetCode;
 
+    private boolean generateOverviewImagesFromRegisteredImages;
+
     public String getContainerDataSetCode()
     {
         return containerDataSetCode;
@@ -34,4 +36,16 @@ public class SimpleOverviewImageDataConfig extends SimpleImageDataConfig
     {
         this.containerDataSetCode = containerDataSetCode;
     }
+
+    public boolean isGenerateOverviewImagesFromRegisteredImages()
+    {
+        return generateOverviewImagesFromRegisteredImages;
+    }
+
+    public void setGenerateOverviewImagesFromRegisteredImages(
+            boolean generateOverviewImagesFromRegisteredImages)
+    {
+        this.generateOverviewImagesFromRegisteredImages =
+                generateOverviewImagesFromRegisteredImages;
+    }
 }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/ImagingDataSetRegistrationTransaction.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/ImagingDataSetRegistrationTransaction.java
index ea1943f1aff..3e5f727c8d4 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/ImagingDataSetRegistrationTransaction.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/ImagingDataSetRegistrationTransaction.java
@@ -30,6 +30,7 @@ import java.util.Properties;
 import ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnel;
 import ch.systemsx.cisd.common.exceptions.UserFailureException;
 import ch.systemsx.cisd.common.io.FileBasedContentNode;
+import ch.systemsx.cisd.common.io.hierarchical_content.api.IHierarchicalContent;
 import ch.systemsx.cisd.etlserver.registrator.DataSetRegistrationDetails;
 import ch.systemsx.cisd.etlserver.registrator.DataSetRegistrationService;
 import ch.systemsx.cisd.etlserver.registrator.IDataSetRegistrationDetailsFactory;
@@ -59,6 +60,7 @@ import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ThumbnailsStorageFormat;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.v2.IFeatureVectorDataSet;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.v2.SimpleFeatureVectorDataConfig;
 import ch.systemsx.cisd.openbis.dss.etl.featurevector.CsvFeatureVectorParser;
+import ch.systemsx.cisd.openbis.dss.generic.shared.ServiceProvider;
 import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.v1.IDataSetImmutable;
 import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation;
 import ch.systemsx.cisd.openbis.dss.generic.shared.dto.Size;
@@ -242,7 +244,7 @@ public class ImagingDataSetRegistrationTransaction extends DataSetRegistrationTr
                 thumbnailDatasets.add(thumbnailDataset);
 
                 generateThumbnails(imageDataSetStructure, incomingDirectory, thumbnailDataset,
-                        thumbnailsStorageFormat, thumbnailsInfo, false);
+                        thumbnailsStorageFormat, thumbnailsInfo, false, null);
                 containedDataSetCodes.add(thumbnailDataset.getDataSetCode());
             }
             imageDataSetInformation.setThumbnailsInfo(thumbnailsInfo);
@@ -271,7 +273,7 @@ public class ImagingDataSetRegistrationTransaction extends DataSetRegistrationTr
         return containerDataset;
     }
 
-    public IDataSet createNewOverviewImageDataSet(
+    private IDataSet createNewOverviewImageDataSet(
             DataSetRegistrationDetails<ImageDataSetInformation> imageRegistrationDetails)
     {
         ImageDataSetInformation imageDataSetInformation =
@@ -290,6 +292,8 @@ public class ImagingDataSetRegistrationTransaction extends DataSetRegistrationTr
                     container);
         }
 
+        calculateBoundingBox(imageDataSetInformation, imageDataSetStructure, incomingDirectory);
+
         SearchCriteria searchCriteria = new SearchCriteria();
         SearchCriteria searchSubCriteria = new SearchCriteria();
         searchSubCriteria.addMatchClause(MatchClause.createAttributeMatch(
@@ -302,8 +306,6 @@ public class ImagingDataSetRegistrationTransaction extends DataSetRegistrationTr
 
         IDataSetImmutable exampleDataSet = containedDataSets.iterator().next();
 
-        calculateBoundingBox(imageDataSetInformation, imageDataSetStructure, incomingDirectory);
-
         imageDataSetStructure
                 .validateImageRepresentationGenerationParameters(imageDataSetInformation);
 
@@ -311,23 +313,73 @@ public class ImagingDataSetRegistrationTransaction extends DataSetRegistrationTr
         List<String> containedDataSetCodes = new ArrayList<String>();
         containedDataSetCodes.addAll(container.getContainedDataSetCodes());
 
-        @SuppressWarnings("unchecked")
-        DataSet<ImageDataSetInformation> thumbnailDataset =
-                (DataSet<ImageDataSetInformation>) super.createNewDataSet(imageRegistrationDetails);
-        thumbnailDataset.setFileFormatType(imageDataSetInformation.getFileFormatTypeCode());
-        thumbnailDataset.setMeasuredData(false);
-
-        generateThumbnails(imageDataSetStructure, incomingDirectory, thumbnailDataset,
-                createThumbnailsStorageFormat(imageDataSetInformation), thumbnailsInfo, true);
-        containedDataSetCodes.add(thumbnailDataset.getDataSetCode());
+        List<IDataSet> thumbnailDatasets = new ArrayList<IDataSet>();
+        if (imageDataSetInformation.isGenerateOverviewImagesFromRegisteredImages())
+        {
+            IHierarchicalContent content =
+                    ServiceProvider.getHierarchicalContentProvider().asContent(containerCode);
+            try
+            {
+                imageDataSetStructure
+                        .validateImageRepresentationGenerationParameters(imageDataSetInformation);
+
+                List<ThumbnailsStorageFormat> thumbnailsStorageFormatList =
+                        imageDataSetStructure.getImageStorageConfiguraton()
+                                .getThumbnailsStorageFormat();
+
+                boolean isFirst = true;
+                for (ThumbnailsStorageFormat thumbnailsStorageFormat : thumbnailsStorageFormatList)
+                {
+                    IDataSet thumbnailDataset = null;
+                    if (isFirst)
+                    {
+                        thumbnailDataset = super.createNewDataSet(imageRegistrationDetails);
+                        isFirst = false;
+                    } else
+                    {
+                        thumbnailDataset =
+                                createThumbnailDataset(imageDataSetInformation,
+                                        thumbnailsStorageFormat);
+                    }
+                    thumbnailDatasets.add(thumbnailDataset);
+
+                    generateThumbnails(imageDataSetStructure, incomingDirectory, thumbnailDataset,
+                            thumbnailsStorageFormat, thumbnailsInfo, false, content);
+                    containedDataSetCodes.add(thumbnailDataset.getDataSetCode());
+                }
+            } finally
+            {
+                if (content != null)
+                {
+                    content.close();
+                }
+            }
+        } else
+        {
+            @SuppressWarnings("unchecked")
+            DataSet<ImageDataSetInformation> thumbnailDataset =
+                    (DataSet<ImageDataSetInformation>) super
+                            .createNewDataSet(imageRegistrationDetails);
+            thumbnailDataset.setFileFormatType(imageDataSetInformation.getFileFormatTypeCode());
+            thumbnailDataset.setMeasuredData(false);
+            thumbnailDatasets.add(thumbnailDataset);
+
+            generateThumbnails(imageDataSetStructure, incomingDirectory, thumbnailDataset,
+                    createThumbnailsStorageFormat(imageDataSetInformation), thumbnailsInfo, true,
+                    null);
+            containedDataSetCodes.add(thumbnailDataset.getDataSetCode());
+        }
 
         imageDataSetInformation.setThumbnailsInfo(thumbnailsInfo);
 
-        setSameDatasetOwner(exampleDataSet, thumbnailDataset);
+        for (IDataSet thumbnailDataset : thumbnailDatasets)
+        {
+            setSameDatasetOwner(exampleDataSet, thumbnailDataset);
+        }
 
         container.setContainedDataSetCodes(containedDataSetCodes);
 
-        return thumbnailDataset;
+        return thumbnailDatasets.iterator().next();
     }
 
     private static ThumbnailsStorageFormat createThumbnailsStorageFormat(
@@ -349,15 +401,45 @@ public class ImagingDataSetRegistrationTransaction extends DataSetRegistrationTr
         ImageLibraryInfo imageLibrary =
                 imageDataSetStructure.getImageStorageConfiguraton().tryGetImageLibrary();
         List<ImageFileInfo> images = imageDataSetStructure.getImages();
-        for (ImageFileInfo imageFileInfo : images)
-        {
-            File file = new File(incomingDirectory, imageFileInfo.getImageRelativePath());
-            Size size =
-                    Utils.loadUnchangedImageSize(new FileBasedContentNode(file), null, imageLibrary);
-            imageDataSetInformation.setMaximumImageWidth(Math.max(
-                    imageDataSetInformation.getMaximumImageWidth(), size.getWidth()));
-            imageDataSetInformation.setMaximumImageHeight(Math.max(
-                    imageDataSetInformation.getMaximumImageHeight(), size.getHeight()));
+
+        if (imageDataSetInformation.isGenerateOverviewImagesFromRegisteredImages())
+        {
+            IHierarchicalContent content =
+                    ServiceProvider.getHierarchicalContentProvider().asContent(
+                            imageDataSetInformation.getContainerDatasetPermId());
+            try
+            {
+                for (ImageFileInfo imageFileInfo : images)
+                {
+                    Size size =
+                            Utils.loadUnchangedImageSize(
+                                    content.getNode(imageFileInfo.getImageRelativePath()), null,
+                                    imageLibrary);
+                    imageDataSetInformation.setMaximumImageWidth(Math.max(
+                            imageDataSetInformation.getMaximumImageWidth(), size.getWidth()));
+                    imageDataSetInformation.setMaximumImageHeight(Math.max(
+                            imageDataSetInformation.getMaximumImageHeight(), size.getHeight()));
+                }
+            } finally
+            {
+                if (content != null)
+                {
+                    content.close();
+                }
+            }
+        } else
+        {
+            for (ImageFileInfo imageFileInfo : images)
+            {
+                File file = new File(incomingDirectory, imageFileInfo.getImageRelativePath());
+                Size size =
+                        Utils.loadUnchangedImageSize(new FileBasedContentNode(file), null,
+                                imageLibrary);
+                imageDataSetInformation.setMaximumImageWidth(Math.max(
+                        imageDataSetInformation.getMaximumImageWidth(), size.getWidth()));
+                imageDataSetInformation.setMaximumImageHeight(Math.max(
+                        imageDataSetInformation.getMaximumImageHeight(), size.getHeight()));
+            }
         }
     }
 
@@ -369,7 +451,7 @@ public class ImagingDataSetRegistrationTransaction extends DataSetRegistrationTr
     private void generateThumbnails(ImageDataSetStructure imageDataSetStructure,
             File incomingDirectory, IDataSet thumbnailDataset,
             ThumbnailsStorageFormat thumbnailsStorageFormatOrNull, ThumbnailsInfo thumbnailPaths,
-            boolean registerOriginalImageAsThumbnail)
+            boolean registerOriginalImageAsThumbnail, IHierarchicalContent content)
     {
         String thumbnailFile;
         if (thumbnailsStorageFormatOrNull == null)
@@ -386,7 +468,7 @@ public class ImagingDataSetRegistrationTransaction extends DataSetRegistrationTr
         Hdf5ThumbnailGenerator.tryGenerateThumbnails(imageDataSetStructure, incomingDirectory,
                 thumbnailFile, imageDataSetStructure.getImageStorageConfiguraton(),
                 thumbnailDataset.getDataSetCode(), thumbnailsStorageFormatOrNull, thumbnailPaths,
-                registerOriginalImageAsThumbnail);
+                registerOriginalImageAsThumbnail, content);
         enhanceWithResolution(thumbnailDataset, thumbnailPaths);
     }
 
@@ -643,5 +725,4 @@ public class ImagingDataSetRegistrationTransaction extends DataSetRegistrationTr
             return null;
         }
     }
-
 }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/JythonPlateDataSetHandler.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/JythonPlateDataSetHandler.java
index 045573b617b..6a3c1368dfe 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/JythonPlateDataSetHandler.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/JythonPlateDataSetHandler.java
@@ -21,7 +21,6 @@ import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation;
  */
 public class JythonPlateDataSetHandler extends JythonTopLevelDataSetHandler<DataSetInformation>
 {
-
     private final String originalDirName;
 
     public JythonPlateDataSetHandler(TopLevelDataSetRegistratorGlobalState globalState)
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/SimpleImageDataSetRegistrator.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/SimpleImageDataSetRegistrator.java
index f40870e744f..1b7f57f4531 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/SimpleImageDataSetRegistrator.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/SimpleImageDataSetRegistrator.java
@@ -52,6 +52,7 @@ import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.ImageDataSetInformation;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.ImageDataSetStructure;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.Channel;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ChannelColorComponent;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ChannelColorRGB;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ImageFileInfo;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ImageIdentifier;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ImageMetadata;
@@ -63,10 +64,16 @@ import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.transformations.ImageTransfor
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.transformations.ImageTransformationBuffer;
 import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation;
 import ch.systemsx.cisd.openbis.dss.generic.shared.utils.ImageUtil;
+import ch.systemsx.cisd.openbis.dss.shared.DssScreeningUtils;
 import ch.systemsx.cisd.openbis.generic.shared.basic.CodeNormalizer;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetType;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.FileFormatType;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.Geometry;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.IImagingReadonlyQueryDAO;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ImgAcquiredImageEnrichedDTO;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ImgChannelDTO;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ImgImageDatasetDTO;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ImgImageTransformationDTO;
 
 /**
  * Allows to prepare the image dataset which should be registered easily using the specified
@@ -166,6 +173,19 @@ public class SimpleImageDataSetRegistrator
         DataSetRegistrationDetails<ImageDataSetInformation> registrationDetails =
                 imageDatasetFactory.createDataSetRegistrationDetails();
         ImageDataSetInformation imageDataset = registrationDetails.getDataSetInformation();
+
+        if (simpleImageConfig instanceof SimpleOverviewImageDataConfig)
+        {
+            SimpleOverviewImageDataConfig simpleOverviewImageConfig =
+                    (SimpleOverviewImageDataConfig) simpleImageConfig;
+
+            imageDataset.setContainerDatasetPermId(simpleOverviewImageConfig
+                    .getContainerDataSetCode());
+            imageDataset.setGenerateOverviewImagesFromRegisteredImages(simpleOverviewImageConfig
+                    .isGenerateOverviewImagesFromRegisteredImages());
+            imageDataset.setRegisterAsOverviewImageDataSet(true);
+        }
+
         setImageDataset(incoming, imageDataset);
         List<Channel> channels = simpleImageConfig.getChannels();
         if (channels != null)
@@ -181,16 +201,6 @@ public class SimpleImageDataSetRegistrator
             }
         }
 
-        if (simpleImageConfig instanceof SimpleOverviewImageDataConfig)
-        {
-            SimpleOverviewImageDataConfig simpleOverviewImageConfig =
-                    (SimpleOverviewImageDataConfig) simpleImageConfig;
-
-            imageDataset.setContainerDatasetPermId(simpleOverviewImageConfig
-                    .getContainerDataSetCode());
-            imageDataset.setRegisterAsOverviewImageDataSet(true);
-        }
-
         setRegistrationDetails(registrationDetails, imageDataset);
         return registrationDetails;
     }
@@ -620,30 +630,43 @@ public class SimpleImageDataSetRegistrator
         dataset.setSample(simpleImageConfig.getPlateSpace(), simpleImageConfig.getPlateCode());
         dataset.setIncomingDirectory(incoming);
 
-        ImageDataSetStructure imageStruct = createImageDataSetStructure(incoming);
+        ImageDataSetStructure imageStruct = createImageDataSetStructure(incoming, dataset);
         dataset.setImageDataSetStructure(imageStruct);
     }
 
-    private ImageDataSetStructure createImageDataSetStructure(File incoming)
+    private ImageDataSetStructure createImageDataSetStructure(File incoming,
+            ImageDataSetInformation dataset)
     {
-        List<File> imageFiles = extractImageFiles(incoming);
-        IImageReader imageReaderOrNull = tryCreateAndSaveImageReader(imageFiles);
-        List<ImageTokensWithPath> imageTokensList =
-                parseImageTokens(imageFiles, incoming, imageReaderOrNull);
-
-        int maxTileNumber = getMaxTileNumber(imageTokensList);
-        Geometry tileGeometry = simpleImageConfig.getTileGeometry(imageTokensList, maxTileNumber);
-        List<ImageFileInfo> images = createImageInfos(imageTokensList, tileGeometry);
-        List<Channel> channels = getAvailableChannels(images);
-
-        if (simpleImageConfig.isFixedIntensityRangeForAllImagesDefined())
-        {
-            computeAndAppendCommonFixedIntensityRangeTransformation(images, incoming, channels,
-                    imageReaderOrNull);
+        List<ImageFileInfo> images = null;
+        List<Channel> channels = null;
+        Geometry tileGeometry = null;
+        if (dataset.isGenerateOverviewImagesFromRegisteredImages())
+        {
+            images = new ArrayList<ImageFileInfo>();
+            channels = new ArrayList<Channel>();
+            tileGeometry = extractImageFileInfos(dataset, images, channels);
         } else
         {
-            computeAndAppendCommonIntensityRangeTransformation(images, incoming, channels,
-                    imageReaderOrNull);
+            List<File> imageFiles = extractImageFiles(incoming);
+            IImageReader imageReaderOrNull = tryCreateAndSaveImageReader(imageFiles);
+            List<ImageTokensWithPath> imageTokensList =
+                    parseImageTokens(imageFiles, incoming, imageReaderOrNull);
+
+            int maxTileNumber = getMaxTileNumber(imageTokensList);
+            tileGeometry = simpleImageConfig.getTileGeometry(imageTokensList, maxTileNumber);
+
+            images = createImageInfos(imageTokensList, tileGeometry);
+            channels = getAvailableChannels(images);
+
+            if (simpleImageConfig.isFixedIntensityRangeForAllImagesDefined())
+            {
+                computeAndAppendCommonFixedIntensityRangeTransformation(images, incoming, channels,
+                        imageReaderOrNull);
+            } else
+            {
+                computeAndAppendCommonIntensityRangeTransformation(images, incoming, channels,
+                        imageReaderOrNull);
+            }
         }
 
         ImageDataSetStructure imageStruct = new ImageDataSetStructure();
@@ -656,6 +679,85 @@ public class SimpleImageDataSetRegistrator
         return imageStruct;
     }
 
+    private Geometry extractImageFileInfos(ImageDataSetInformation dataset,
+            List<ImageFileInfo> images, List<Channel> channels)
+    {
+        IImagingReadonlyQueryDAO query = DssScreeningUtils.getQuery();
+
+        List<ImgImageDatasetDTO> containers =
+                DssScreeningUtils.getQuery().listImageDatasetsByPermId(
+                        dataset.getContainerDatasetPermId());
+
+        for (ImgImageDatasetDTO container : containers)
+        {
+            List<ImgAcquiredImageEnrichedDTO> acquiredImages =
+                    query.listAllEnrichedAcquiredImagesForDataSet(container.getId());
+            for (ImgAcquiredImageEnrichedDTO acquiredImage : acquiredImages)
+            {
+                images.add(createImageFileInfo(container, acquiredImage));
+            }
+
+            List<ImgChannelDTO> channelDTOs = query.getChannelsByDatasetId(container.getId());
+            for (ImgChannelDTO channelDTO : channelDTOs)
+            {
+                Channel channel = createChannel(query, channelDTO);
+
+                channels.add(channel);
+            }
+
+            return Geometry.createFromRowColDimensions(container.getFieldNumberOfRows(),
+                    container.getFieldNumberOfColumns());
+        }
+
+        return null;
+    }
+
+    private Channel createChannel(IImagingReadonlyQueryDAO query, ImgChannelDTO channelDTO)
+    {
+        Channel channel =
+                new Channel(channelDTO.getCode(), channelDTO.getLabel(), new ChannelColorRGB(
+                        channelDTO.getRedColorComponent(), channelDTO.getGreenColorComponent(),
+                        channelDTO.getBlueColorComponent()));
+        channel.setDescription(channelDTO.getDescription());
+        channel.setWavelength(channelDTO.getWavelength());
+
+        List<ImgImageTransformationDTO> transformationDTOs =
+                query.listImageTransformations(channelDTO.getId());
+        ImageTransformation[] transformations = new ImageTransformation[transformationDTOs.size()];
+        int counter = 0;
+        for (ImgImageTransformationDTO transformationDTO : transformationDTOs)
+        {
+            ImageTransformation transformation =
+                    new ImageTransformation(transformationDTO.getCode(),
+                            transformationDTO.getLabel(), transformationDTO.getDescription(),
+                            transformationDTO.getImageTransformerFactory());
+            transformations[counter++] = transformation;
+        }
+        channel.setAvailableTransformations(transformations);
+
+        return channel;
+    }
+
+    private ImageFileInfo createImageFileInfo(ImgImageDatasetDTO container,
+            ImgAcquiredImageEnrichedDTO acquiredImage)
+    {
+        ImageFileInfo img =
+                new ImageFileInfo(acquiredImage.getChannelCode(), acquiredImage.getTileRow(),
+                        acquiredImage.getTileColumn(), acquiredImage.getImageFilePath());
+        img.setTimepoint(acquiredImage.getT());
+        img.setDepth(acquiredImage.getZ());
+        img.setSeriesNumber(acquiredImage.getSeriesNumber());
+
+        if (acquiredImage.getSpotRow() != null && acquiredImage.getSpotColumn() != null)
+        {
+            img.setWell(acquiredImage.getSpotRow(), acquiredImage.getSpotColumn());
+        }
+        img.setUniqueImageIdentifier(acquiredImage.getImageIdOrNull());
+        img.setContainerDataSetCode(container.getPermId());
+
+        return img;
+    }
+
     private <T extends DataSetInformation> void setRegistrationDetails(
             DataSetRegistrationDetails<T> registrationDetails, T dataset)
     {
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/server/plugins/MarkerFileCreatingProcessingPlugin.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/server/plugins/MarkerFileCreatingProcessingPlugin.java
new file mode 100644
index 00000000000..6d6e826fac3
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/server/plugins/MarkerFileCreatingProcessingPlugin.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2012 ETH Zuerich, CISD
+ *
+ * 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.systemsx.cisd.openbis.dss.screening.server.plugins;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.log4j.Logger;
+
+import ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnel;
+import ch.systemsx.cisd.common.exceptions.ConfigurationFailureException;
+import ch.systemsx.cisd.common.logging.LogCategory;
+import ch.systemsx.cisd.common.logging.LogFactory;
+import ch.systemsx.cisd.common.utilities.PropertyUtils;
+import ch.systemsx.cisd.openbis.dss.generic.server.plugins.tasks.IProcessingPluginTask;
+import ch.systemsx.cisd.openbis.dss.generic.shared.DataSetProcessingContext;
+import ch.systemsx.cisd.openbis.dss.generic.shared.ProcessingStatus;
+import ch.systemsx.cisd.openbis.generic.shared.dto.DatasetDescription;
+
+/**
+ * A processing plugin that create a marker file (named with the dataset code) in specified
+ * location.
+ * 
+ * @author Pawel Glyzewski
+ */
+public class MarkerFileCreatingProcessingPlugin implements IProcessingPluginTask
+{
+    private static final String OUTPUT_DIR = "output-dir";
+
+    private static final long serialVersionUID = 1L;
+
+    private static final Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION,
+            MarkerFileCreatingProcessingPlugin.class);
+
+    private final File outputDirectory;
+
+    public MarkerFileCreatingProcessingPlugin(Properties properties, File storeRoot)
+    {
+        String directoryPath = PropertyUtils.getMandatoryProperty(properties, OUTPUT_DIR);
+        this.outputDirectory = new File(directoryPath);
+        if (false == outputDirectory.exists() || false == outputDirectory.isDirectory())
+        {
+            throw new ConfigurationFailureException("'" + OUTPUT_DIR + "' (" + directoryPath
+                    + ") should point to an existing directory.");
+        }
+    }
+
+    @Override
+    public ProcessingStatus process(List<DatasetDescription> datasets,
+            DataSetProcessingContext context)
+    {
+        for (DatasetDescription dataset : datasets)
+        {
+            File markerFile = new File(outputDirectory, dataset.getDataSetCode());
+            try
+            {
+                markerFile.createNewFile();
+            } catch (IOException ex)
+            {
+                CheckedExceptionTunnel.unwrapIfNecessary(ex);
+            }
+        }
+
+        operationLog.info("Processing done.");
+        return null;
+    }
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/dataaccess/IImagingReadonlyQueryDAO.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/dataaccess/IImagingReadonlyQueryDAO.java
index b0913373434..a9d7027bdc2 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/dataaccess/IImagingReadonlyQueryDAO.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/dataaccess/IImagingReadonlyQueryDAO.java
@@ -243,6 +243,19 @@ public interface IImagingReadonlyQueryDAO extends BaseQuery
     // lists all acquired images available for given dataset
     public List<ImgAcquiredImageDTO> listAllAcquiredImagesForDataSet(long datasetId);
 
+    @Select("select ai.ID as ID, ai.IMAGE_TRANSFORMER_FACTORY as IMAGE_TRANSFORMER_FACTORY, ai.IMG_ID as IMG_ID, ai.CHANNEL_STACK_ID as CHANNEL_STACK_ID, ai.CHANNEL_ID as CHANNEL_ID, "
+            + "  s.X as SPOT_X, s.Y as SPOT_Y, i.path as IMAGE_PATH, i.IMAGE_ID as IMAGE_ID, i.color as IMAGE_COLOR, "
+            + "  th.path as THUMBNAIL_PATH, th.IMAGE_ID as THUMBNAIL_IMAGE_ID, th.color as THUMBNAIL_COLOR, "
+            + "  ch.code as CHANNEL_CODE, cs.X as X, cs.Y as Y, cs.Z_in_M as Z_in_M, cs.T_in_SEC as T_in_SEC, cs.SERIES_NUMBER as SERIES_NUMBER "
+            + "from acquired_images ai "
+            + "  join images i on ai.img_id = i.id "
+            + "  left outer join images th on ai.thumbnail_id = th.id "
+            + "  left outer join channels ch on ai.channel_id = ch.id "
+            + "  left outer join channel_stacks cs on ai.channel_stack_id = cs.id "
+            + "  left outer join spots s on cs.spot_id = s.id "
+            + "where ch.ds_id = ?{1} or cs.ds_id = ?{1}")
+    public List<ImgAcquiredImageEnrichedDTO> listAllEnrichedAcquiredImagesForDataSet(long datasetId);
+
     // simple getters
 
     @Select("select * from IMAGE_DATA_SETS where PERM_ID = ?{1}")
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/dataaccess/ImgAcquiredImageEnrichedDTO.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/dataaccess/ImgAcquiredImageEnrichedDTO.java
new file mode 100644
index 00000000000..0d70a8994f9
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/dataaccess/ImgAcquiredImageEnrichedDTO.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright 2012 ETH Zuerich, CISD
+ *
+ * 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.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess;
+
+import net.lemnik.eodsql.ResultColumn;
+
+/**
+ * @author Pawel Glyzewski
+ */
+public class ImgAcquiredImageEnrichedDTO extends ImgAcquiredImageDTO
+{
+    @ResultColumn("SPOT_X")
+    private Integer spotColumn;
+
+    // position in the container, one-based (e.g. well row, 1 is the first row)
+    @ResultColumn("SPOT_Y")
+    private Integer spotRow;
+
+    @ResultColumn("IMAGE_PATH")
+    private String imageFilePath;
+
+    @ResultColumn("IMAGE_ID")
+    private String imageIdOrNull;
+
+    @ResultColumn("IMAGE_COLOR")
+    private String imageColorComponentOrNull;
+
+    @ResultColumn("THUMBNAIL_PATH")
+    private String filePath;
+
+    @ResultColumn("THUMBNAIL_IMAGE_ID")
+    private String thumbnailImageIdOrNull;
+
+    @ResultColumn("THUMBNAIL_COLOR")
+    private String thumbnailColorComponentOrNull;
+
+    @ResultColumn("CHANNEL_CODE")
+    private String channelCode;
+
+    // x and y are kind of a two dimensional sequence number, (e.g. tile column)
+    @ResultColumn("X")
+    private Integer tileColumn;
+
+    // x and y are kind of a two dimensional sequence number, (e.g. tile row, 1 is the first row)
+    // Some use case may only use x and leave y alone.
+    @ResultColumn("Y")
+    private Integer tileRow;
+
+    // can be null
+    @ResultColumn("Z_in_M")
+    private Float z;
+
+    // can be null
+    @ResultColumn("T_in_SEC")
+    private Float t;
+
+    @ResultColumn("SERIES_NUMBER")
+    private Integer seriesNumber;
+
+    public Integer getSpotColumn()
+    {
+        return spotColumn;
+    }
+
+    public void setSpotColumn(Integer spotColumn)
+    {
+        this.spotColumn = spotColumn;
+    }
+
+    public Integer getSpotRow()
+    {
+        return spotRow;
+    }
+
+    public void setSpotRow(Integer spotRow)
+    {
+        this.spotRow = spotRow;
+    }
+
+    public String getImageFilePath()
+    {
+        return imageFilePath;
+    }
+
+    public void setImageFilePath(String imageFilePath)
+    {
+        this.imageFilePath = imageFilePath;
+    }
+
+    public String getImageIdOrNull()
+    {
+        return imageIdOrNull;
+    }
+
+    public void setImageIdOrNull(String imageIdOrNull)
+    {
+        this.imageIdOrNull = imageIdOrNull;
+    }
+
+    public String getImageColorComponentOrNull()
+    {
+        return imageColorComponentOrNull;
+    }
+
+    public void setImageColorComponentOrNull(String imageColorComponentOrNull)
+    {
+        this.imageColorComponentOrNull = imageColorComponentOrNull;
+    }
+
+    public String getFilePath()
+    {
+        return filePath;
+    }
+
+    public void setFilePath(String filePath)
+    {
+        this.filePath = filePath;
+    }
+
+    public String getThumbnailImageIdOrNull()
+    {
+        return thumbnailImageIdOrNull;
+    }
+
+    public void setThumbnailImageIdOrNull(String thumbnailImageIdOrNull)
+    {
+        this.thumbnailImageIdOrNull = thumbnailImageIdOrNull;
+    }
+
+    public String getThumbnailColorComponentOrNull()
+    {
+        return thumbnailColorComponentOrNull;
+    }
+
+    public void setThumbnailColorComponentOrNull(String thumbnailColorComponentOrNull)
+    {
+        this.thumbnailColorComponentOrNull = thumbnailColorComponentOrNull;
+    }
+
+    public String getChannelCode()
+    {
+        return channelCode;
+    }
+
+    public void setChannelCode(String channelCode)
+    {
+        this.channelCode = channelCode;
+    }
+
+    public Integer getTileColumn()
+    {
+        return tileColumn;
+    }
+
+    public void setTileColumn(Integer tileColumn)
+    {
+        this.tileColumn = tileColumn;
+    }
+
+    public Integer getTileRow()
+    {
+        return tileRow;
+    }
+
+    public void setTileRow(Integer tileRow)
+    {
+        this.tileRow = tileRow;
+    }
+
+    public Float getZ()
+    {
+        return z;
+    }
+
+    public void setZ(Float z)
+    {
+        this.z = z;
+    }
+
+    public Float getT()
+    {
+        return t;
+    }
+
+    public void setT(Float t)
+    {
+        this.t = t;
+    }
+
+    public Integer getSeriesNumber()
+    {
+        return seriesNumber;
+    }
+
+    public void setSeriesNumber(Integer seriesNumber)
+    {
+        this.seriesNumber = seriesNumber;
+    }
+}
-- 
GitLab