diff --git a/openbis_api/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/ServiceVersionHolder.java b/openbis_api/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/ServiceVersionHolder.java
index 60c37db247db44c4b8a20a80bd9eb3fd94bf7cbc..d14196e7daaba93d70b711684f3a1e3f5a5a10f4 100644
--- a/openbis_api/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/ServiceVersionHolder.java
+++ b/openbis_api/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/ServiceVersionHolder.java
@@ -23,5 +23,5 @@ package ch.systemsx.cisd.openbis.generic.shared.basic.dto;
  */
 public final class ServiceVersionHolder
 {
-    public static final int VERSION = 35; // for S145
+    public static final int VERSION = 36; // for S190
 }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/IImageGenerationAlgorithm.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/IImageGenerationAlgorithm.java
new file mode 100644
index 0000000000000000000000000000000000000000..907e1dda8a62a0cf71cbec9d46afac15441f0b24
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/IImageGenerationAlgorithm.java
@@ -0,0 +1,14 @@
+package ch.systemsx.cisd.openbis.dss.etl.dto.api;
+
+import java.awt.image.BufferedImage;
+import java.util.List;
+
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.ImageDataSetInformation;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.ImageDataSetStructure;
+
+public interface IImageGenerationAlgorithm
+{
+    public List<BufferedImage> generateImages(ImageDataSetInformation information, ImageDataSetStructure structure);
+    public String getDataSetTypeCode();
+    public String getImageFileName(int index);
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/SimpleImageDataConfig.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/SimpleImageDataConfig.java
index acdabb8f08a64458c6afa841099b99d075fb7849..17fd1b64de04e08f4d65e259fb87ce266f1d5407 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/SimpleImageDataConfig.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/SimpleImageDataConfig.java
@@ -47,6 +47,8 @@ abstract public class SimpleImageDataConfig
 {
     // --- one of the following two methods has to be overridden -----------------
 
+    private IImageGenerationAlgorithm imageGenerationAlgorithm;
+
     /**
      * Extracts tile number, channel code and well code for a given relative path to a single image.
      * This method should overridden to deal with files containing single images. It is ignored if
@@ -997,5 +999,12 @@ abstract public class SimpleImageDataConfig
     {
         this.colorDepth = colorDepth;
     }
+    
+    public IImageGenerationAlgorithm getImageGenerationAlgorithm() {
+        return imageGenerationAlgorithm;
+    }
 
+    public void setImageGenerationAlgorithm(IImageGenerationAlgorithm algorithm) {
+        this.imageGenerationAlgorithm = algorithm;
+    }
 }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/EmptyImageCreationAlgorithm.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/EmptyImageCreationAlgorithm.java
new file mode 100644
index 0000000000000000000000000000000000000000..9f036dea2745158698e3a280142f80451676c55d
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/EmptyImageCreationAlgorithm.java
@@ -0,0 +1,33 @@
+package ch.systemsx.cisd.openbis.dss.etl.dto.api.impl;
+
+import java.awt.image.BufferedImage;
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.List;
+
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.IImageGenerationAlgorithm;
+import ch.systemsx.cisd.openbis.generic.shared.IServer;
+
+public class EmptyImageCreationAlgorithm implements IImageGenerationAlgorithm, Serializable
+{
+
+    private static final long serialVersionUID = IServer.VERSION;
+
+    @Override
+    public String getDataSetTypeCode()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public List<BufferedImage> generateImages(ImageDataSetInformation information, ImageDataSetStructure structure)
+    {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public String getImageFileName(int index)
+    {
+        throw new UnsupportedOperationException();
+    }
+}
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 5c893d69d29daea5709c949a1ccae48ddfcfb7ae..88fa3da83bfe12e7fbc42aa8e84f72da4b06af10 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
@@ -24,6 +24,7 @@ import ch.systemsx.cisd.common.shared.basic.string.CommaSeparatedListBuilder;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.BasicDataSetInformation;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.Channel;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.ChannelColorComponent;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.IImageGenerationAlgorithm;
 import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation;
 import ch.systemsx.cisd.openbis.generic.shared.IServer;
 
@@ -60,6 +61,8 @@ public class ImageDataSetInformation extends BasicDataSetInformation
     private Integer colorDepth;
 
     private final List<DataSetInformation> secondaryDataSets = new ArrayList<DataSetInformation>();
+
+    private IImageGenerationAlgorithm imageGenerationAlgorithm;
     
     public File getIncomingDirectory()
     {
@@ -222,4 +225,13 @@ public class ImageDataSetInformation extends BasicDataSetInformation
         }
         return buffer.toString();
     }
+
+    public void setAlgorithm(IImageGenerationAlgorithm imageGenerationAlgorithm)
+    {
+        this.imageGenerationAlgorithm = imageGenerationAlgorithm;
+    }
+    
+    public IImageGenerationAlgorithm getAlgorithm() {
+        return imageGenerationAlgorithm;
+    }
 }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/MaximumIntensityProjectionGenerationAlgorithm.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/MaximumIntensityProjectionGenerationAlgorithm.java
new file mode 100644
index 0000000000000000000000000000000000000000..4358a40ff6c276cab9e02e26ed5105c6f916eac7
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/MaximumIntensityProjectionGenerationAlgorithm.java
@@ -0,0 +1,173 @@
+package ch.systemsx.cisd.openbis.dss.etl.dto.api.impl;
+
+import java.awt.geom.AffineTransform;
+import java.awt.image.AffineTransformOp;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.List;
+
+import ch.systemsx.cisd.openbis.common.io.FileBasedContentNode;
+import ch.systemsx.cisd.openbis.dss.etl.Utils;
+import ch.systemsx.cisd.openbis.dss.etl.dto.ImageLibraryInfo;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.IImageGenerationAlgorithm;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ImageFileInfo;
+import ch.systemsx.cisd.openbis.generic.shared.IServer;
+
+public class MaximumIntensityProjectionGenerationAlgorithm implements IImageGenerationAlgorithm, Serializable
+{
+    private static final long serialVersionUID = IServer.VERSION;
+
+    private transient BufferedImage result = null;
+
+    private String dataSetTypeCode;
+
+    private String filename;
+
+    private int width;
+
+    private int height;
+
+    public MaximumIntensityProjectionGenerationAlgorithm(String dataSetTypeCode) {
+        this(dataSetTypeCode, 0, 0);
+    }
+    public MaximumIntensityProjectionGenerationAlgorithm(String dataSetTypeCode, String filename) {
+        this(dataSetTypeCode, 0, 0, filename);
+    }
+    
+    public MaximumIntensityProjectionGenerationAlgorithm(String dataSetTypeCode, int width, int height) {
+        this(dataSetTypeCode, width, height, "maximum_intensity_projection");
+    }
+
+    public MaximumIntensityProjectionGenerationAlgorithm(String dataSetTypeCode,  int width, int height, String filename) {
+        this.dataSetTypeCode = dataSetTypeCode;
+        this.width = width;
+        this.height = height;
+        this.filename = filename;
+    }
+
+    @Override
+    public String getDataSetTypeCode()
+    {
+        return dataSetTypeCode;
+    }
+
+    @Override
+    public List<BufferedImage> generateImages(ImageDataSetInformation information, ImageDataSetStructure structure)
+    {
+        ImageLibraryInfo library = structure.getImageStorageConfiguraton().tryGetImageLibrary();
+        List<ImageFileInfo> images = structure.getImages();
+        int maxIntensity = 0;
+        for (ImageFileInfo image: images) {
+            String imagePath = image.getImageRelativePath();
+            if (image.tryGetTimepoint() == null || image.tryGetTimepoint() != 0) {
+                continue;
+            }
+            BufferedImage imageData = Utils.loadUnchangedImage(new FileBasedContentNode(new File(
+                    information.getIncomingDirectory(), imagePath)), image.tryGetUniqueStringIdentifier(), library);
+            maxIntensity = addImage(imageData);
+        }
+        
+        if (result == null) {
+            return Collections.emptyList();
+        } else {
+            for (int y=0; y<result.getHeight(); y++) {
+                for (int x=0; x<result.getWidth(); x++) {
+                    result.setRGB(x, y, adjust(result.getRGB(x, y), maxIntensity));
+                }
+            }
+            if (width > 0 && height > 0) {
+                BufferedImage scaled = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
+                AffineTransform at = new AffineTransform();
+                at.scale((double)width / (double)result.getWidth(), (double)height / (double)result.getHeight());
+                AffineTransformOp scaleOp = new AffineTransformOp(at, AffineTransformOp.TYPE_BILINEAR);
+                result = scaleOp.filter(result, scaled);                
+            }
+            
+            return Collections.singletonList(result);
+        }
+
+    }
+
+    private int adjust(int rgb, int maxIntensity)
+    {
+        if (maxIntensity > 255) {
+            maxIntensity = 255;
+        }
+        int r = new Double( ((double)getRed(rgb)) / ((double)maxIntensity) * 255).intValue();
+        int g = new Double( ((double)getGreen(rgb)) / ((double)maxIntensity) * 255).intValue();
+        int b = new Double( ((double)getBlue(rgb)) / ((double)maxIntensity) * 255).intValue();
+        
+        return (r << 16) + (g << 8) + b;
+        
+    }
+
+
+    private int addImage(BufferedImage image)
+    {
+        System.out.println("Adding image "+image.toString());
+        if (result == null) {
+            result = new BufferedImage(image.getWidth(),image.getHeight(), BufferedImage.TYPE_INT_RGB);
+            for (int y=0; y<image.getHeight(); y++) {
+                for (int x=0; x<image.getWidth(); x++) {
+                    image.setRGB(x,y, 0);
+                }
+            }
+        }
+        int maxIntensity = 0;
+        for (int y=0; y<image.getHeight(); y++) {
+            for (int x=0; x<image.getWidth(); x++) {
+                int rgb1 = result.getRGB(x,y);
+                int rgb2 = image.getRGB(x,y);
+                
+                int intensity1 = intensity(rgb1);
+                int intensity2 = intensity(rgb2);
+
+                if (intensity1 > maxIntensity) {
+                    maxIntensity = intensity1;
+                }
+
+                if (intensity2 > maxIntensity) {
+                    maxIntensity = intensity2;
+                }
+                
+                result.setRGB(x,y, intensity1 > intensity2 ? rgb1 : rgb2);
+            }
+        }
+        return maxIntensity;
+    }
+
+    private int intensity(int rgb)
+    {
+        double r = getRed(rgb);
+        double g = getGreen(rgb);
+        double b = getBlue(rgb);
+        return new Double(Math.sqrt(r*r + g*g + b*b)).intValue();
+    }
+
+
+    private int getBlue(int rgb)
+    {
+        return rgb & 0xff;
+    }
+
+
+    private int getGreen(int rgb)
+    {
+        return (rgb >> 8) & 0xff;
+    }
+
+
+    private int getRed(int rgb)
+    {
+        return (rgb >> 16) & 0xff;
+    }
+
+    @Override
+    public String getImageFileName(int index)
+    {
+        return filename;
+    }
+
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v2/ImagingDataSetRegistrationTransaction.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v2/ImagingDataSetRegistrationTransaction.java
index a40189a5dc6afaf0539e2fe7dcfe45fa434b610f..0bf97f8f0c8b66f36f54fa03833a0582f1952e41 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v2/ImagingDataSetRegistrationTransaction.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v2/ImagingDataSetRegistrationTransaction.java
@@ -19,6 +19,7 @@ package ch.systemsx.cisd.openbis.dss.etl.jython.v2;
 import static ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.ScreeningConstants.MICROSCOPY_CONTAINER_TYPE_SUBSTRING;
 import static ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.ScreeningConstants.MICROSCOPY_IMAGE_TYPE_SUBSTRING;
 
+import java.awt.image.BufferedImage;
 import java.io.BufferedWriter;
 import java.io.File;
 import java.io.FileWriter;
@@ -29,6 +30,8 @@ import java.util.LinkedList;
 import java.util.List;
 import java.util.Properties;
 
+import javax.imageio.ImageIO;
+
 import ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnel;
 import ch.systemsx.cisd.common.exceptions.UserFailureException;
 import ch.systemsx.cisd.etlserver.registrator.DataSetRegistrationDetails;
@@ -45,6 +48,7 @@ import ch.systemsx.cisd.openbis.dss.Constants;
 import ch.systemsx.cisd.openbis.dss.etl.Hdf5ThumbnailGenerator;
 import ch.systemsx.cisd.openbis.dss.etl.Utils;
 import ch.systemsx.cisd.openbis.dss.etl.dto.ImageLibraryInfo;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.IImageGenerationAlgorithm;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.ImageFileInfo;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.SimpleImageDataConfig;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.ThumbnailsStorageFormat;
@@ -341,6 +345,29 @@ public class ImagingDataSetRegistrationTransaction extends DataSetRegistrationTr
         }
 
         containedDataSetCodes.add(mainDataset.getDataSetCode());
+        
+        
+        IImageGenerationAlgorithm algorithm = imageDataSetInformation.getAlgorithm();
+        List<BufferedImage> images = algorithm != null ? algorithm.generateImages(imageDataSetInformation, imageDataSetStructure) : new ArrayList<BufferedImage>();
+        if (images.size() > 0) {
+            IDataSet representative = createNewDataSet(algorithm.getDataSetTypeCode());
+            
+            int i=0;
+            for (BufferedImage imageData: images) {
+                String imageFile = createNewFile(representative, algorithm.getImageFileName(i));
+                File f = new File(imageFile);
+                try
+                {
+                   ImageIO.write(imageData, "png", f);
+                } catch (IOException e)
+                {
+                    e.printStackTrace();
+                }
+                i++;
+            }
+            containedDataSetCodes.add(representative.getDataSetCode());
+            thumbnailDatasets.add(representative);
+        }
 
         for (IDataSet thumbnailDataset : thumbnailDatasets)
         {
@@ -353,7 +380,7 @@ public class ImagingDataSetRegistrationTransaction extends DataSetRegistrationTr
         containerDataset.setThumbnailDatasets(thumbnailDatasets);
         String containerDataSetCode = containerDataset.getDataSetCode();
         imageDataSetInformation.setContainerDatasetPermId(containerDataSetCode);
-
+        
         return containerDataset;
     }
 
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v2/SimpleImageDataSetRegistrator.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v2/SimpleImageDataSetRegistrator.java
index 11e1bf0adcf9d099bd08b90b0cbbe2d0b25e739c..d2e8369cdd372405b92a5b4eb5ba2bee9780d7a9 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v2/SimpleImageDataSetRegistrator.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v2/SimpleImageDataSetRegistrator.java
@@ -204,6 +204,7 @@ public class SimpleImageDataSetRegistrator
         imageDataset.setColorDepth(simpleImageConfig.getColorDepth());
 
         setRegistrationDetails(registrationDetails, imageDataset);
+        registrationDetails.getDataSetInformation().setAlgorithm(simpleImageConfig.getImageGenerationAlgorithm());
         return registrationDetails;
     }