diff --git a/screening/resource/test-data/MicroscopyImageDropboxTest/maximum_intensity_projection.png b/screening/resource/test-data/MicroscopyImageDropboxTest/maximum_intensity_projection.png
new file mode 100644
index 0000000000000000000000000000000000000000..1b83f88d594ae05c37b0eecbc9d791f9d61e0c07
Binary files /dev/null and b/screening/resource/test-data/MicroscopyImageDropboxTest/maximum_intensity_projection.png differ
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
index cb88f88cf9b95491f3bb38cb8b395cff2d802200..859c6f77766d22291be50d1a47dcd65047b9b6cf 100644
--- 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
@@ -4,7 +4,6 @@ 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;
 
 /**
  * Algorithm for creating a representative thumbnails.
@@ -14,9 +13,9 @@ import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.ImageDataSetStructure;
 public interface IImageGenerationAlgorithm
 {
     /**
-     * Creates thumbnails for the specified data set info and structure.
+     * Creates thumbnails for the specified data set info.
      */
-    public List<BufferedImage> generateImages(ImageDataSetInformation information, ImageDataSetStructure structure);
+    public List<BufferedImage> generateImages(ImageDataSetInformation information);
     
     /**
      * Returns the code of the data set to be registered containing these representative thumbnails.
@@ -25,7 +24,7 @@ public interface IImageGenerationAlgorithm
     
     /**
      * Returns the thumbnail file name for the specified index. The index specifies the corresponding
-     * image returned by {@link #generateImages(ImageDataSetInformation, ImageDataSetStructure)}.
+     * image returned by {@link #generateImages(ImageDataSetInformation)}.
      * Note, all file names generated by this method have to different.
      */
     public String getImageFileName(int index);
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
index 9f036dea2745158698e3a280142f80451676c55d..5b5c8e530c7299627f15d9ca9d106660a8a3906e 100644
--- 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
@@ -20,7 +20,7 @@ public class EmptyImageCreationAlgorithm implements IImageGenerationAlgorithm, S
     }
 
     @Override
-    public List<BufferedImage> generateImages(ImageDataSetInformation information, ImageDataSetStructure structure)
+    public List<BufferedImage> generateImages(ImageDataSetInformation information)
     {
         return Collections.emptyList();
     }
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
index 263b75669cbb4cae3c8b50a42f1ede89ffac8f17..cb33ecbbf555399a3f54efbc0164e8c656b1fb49 100644
--- 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
@@ -6,17 +6,45 @@ import java.awt.image.BufferedImage;
 import java.io.File;
 import java.io.Serializable;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
+import ch.rinn.restrictions.Private;
 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.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.etl.dto.api.ImageFileInfo;
+import ch.systemsx.cisd.openbis.dss.generic.server.images.ImageChannelsUtils;
 import ch.systemsx.cisd.openbis.generic.shared.IServer;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ColorComponent;
 
+/**
+ * Implementation of {@link IImageGenerationAlgorithm} which generates from a bunch of images
+ * a representative image where at each pixel the brightest pixel from the images are taken. 
+ *
+ * @author Antti Luomi
+ * @author Franz-Josef Elmer
+ */
 public class MaximumIntensityProjectionGenerationAlgorithm implements IImageGenerationAlgorithm, Serializable
 {
+    private static final class ChannelAndColorComponent
+    {
+        private Channel channel;
+        private ColorComponent colorComponent;
+
+        ChannelAndColorComponent(Channel channel, ColorComponent colorComponent)
+        {
+            this.channel = channel;
+            this.colorComponent = colorComponent;
+        }
+    }
+
+    public static final String DEFAULT_FILE_NAME = "maximum_intensity_projection.png";
+
     private static final long serialVersionUID = IServer.VERSION;
 
     private transient BufferedImage result = null;
@@ -29,18 +57,38 @@ public class MaximumIntensityProjectionGenerationAlgorithm implements IImageGene
 
     private int height;
 
-    public MaximumIntensityProjectionGenerationAlgorithm(String dataSetTypeCode) {
+    /**
+     * Creates an instance for the specified data set type. The generated image will have the same size as
+     * the original images. The file name will be <code>maximum_intensity_projection.png</code>.
+     */
+    public MaximumIntensityProjectionGenerationAlgorithm(String dataSetTypeCode)
+    {
         this(dataSetTypeCode, 0, 0);
     }
-    public MaximumIntensityProjectionGenerationAlgorithm(String dataSetTypeCode, String filename) {
+
+    /**
+     * Creates an instance for the specified data set type and file name. 
+     * The generated image will have the same size as the original images.
+     */
+    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");
+
+    /**
+     * Creates an instance for the specified data set type and specified image size.
+     * The file name will be <code>maximum_intensity_projection.png</code>.
+     */
+    public MaximumIntensityProjectionGenerationAlgorithm(String dataSetTypeCode, int width, int height)
+    {
+        this(dataSetTypeCode, width, height, DEFAULT_FILE_NAME);
     }
 
-    public MaximumIntensityProjectionGenerationAlgorithm(String dataSetTypeCode,  int width, int height, String filename) {
+    /**
+     * Creates an instance for the specified data set type, specified image size and specified file name.
+     */
+    public MaximumIntensityProjectionGenerationAlgorithm(String dataSetTypeCode, int width, int height, String filename)
+    {
         this.dataSetTypeCode = dataSetTypeCode;
         this.width = width;
         this.height = height;
@@ -52,86 +100,136 @@ public class MaximumIntensityProjectionGenerationAlgorithm implements IImageGene
     {
         return dataSetTypeCode;
     }
-
+    
     @Override
-    public List<BufferedImage> generateImages(ImageDataSetInformation information, ImageDataSetStructure structure)
+    public List<BufferedImage> generateImages(ImageDataSetInformation information)
     {
+        ImageDataSetStructure structure = information.getImageDataSetStructure();
         ImageLibraryInfo library = structure.getImageStorageConfiguraton().tryGetImageLibrary();
         List<ImageFileInfo> images = structure.getImages();
+        Map<String, ChannelAndColorComponent> channelsByCode = getChannelsByCode(structure);
+        File incomingDirectory = information.getIncomingDirectory();
         int maxIntensity = 0;
-        for (ImageFileInfo image: images) {
-            String imagePath = image.getImageRelativePath();
-            if (image.tryGetTimepoint() == null || image.tryGetTimepoint() != 0) {
+        for (ImageFileInfo imageFileInfo : images)
+        {
+            if (imageToBeIgnored(imageFileInfo))
+            {
                 continue;
             }
-            BufferedImage imageData = Utils.loadUnchangedImage(new FileBasedContentNode(new File(
-                    information.getIncomingDirectory(), imagePath)), image.tryGetUniqueStringIdentifier(), library);
-            maxIntensity = addImage(imageData);
+            String imagePath = imageFileInfo.getImageRelativePath();
+            ChannelAndColorComponent channelAndColorComponent = channelsByCode.get(imageFileInfo.getChannelCode());
+            String identifier = imageFileInfo.tryGetUniqueStringIdentifier();
+            BufferedImage image = loadImage(incomingDirectory, imagePath, identifier, library);
+            image = ImageChannelsUtils.rescaleIfNot8Bit(image, 0f);
+            image = ImageChannelsUtils.extractChannel(image, channelAndColorComponent.colorComponent);
+            image = ImageChannelsUtils.transformGrayToColor(image, channelAndColorComponent.channel.tryGetChannelColor());
+            maxIntensity = addImage(image);
         }
-        
-        if (result == null) {
+
+        if (result == null)
+        {
             return Collections.emptyList();
-        } else {
-            for (int y=0; y<result.getHeight(); y++) {
-                for (int x=0; x<result.getWidth(); x++) {
+        } 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) {
+            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());
+                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);                
+                result = scaleOp.filter(result, scaled);
             }
-            
+
             return Collections.singletonList(result);
         }
+    }
 
+    @Private BufferedImage loadImage(File incomingDirectory, String imagePath, String identifier, ImageLibraryInfo library)
+    {
+        File file = new File(incomingDirectory, imagePath);
+        return Utils.loadUnchangedImage(new FileBasedContentNode(file), identifier, library);
     }
 
-    private int adjust(int rgb, int maxIntensity)
+    /**
+     * Returns <code>true</code> if the specified image should be ignored. Can be overridden.
+     */
+    protected boolean imageToBeIgnored(ImageFileInfo image)
     {
-        if (maxIntensity > 255) {
-            maxIntensity = 255;
+        return image.tryGetTimepoint() == null || image.tryGetTimepoint() != 0;
+    }
+
+    private Map<String, ChannelAndColorComponent> getChannelsByCode(ImageDataSetStructure structure)
+    {
+        Map<String, ChannelAndColorComponent> channelsByCode = new HashMap<String, ChannelAndColorComponent>();
+        List<Channel> channels = structure.getChannels();
+        for (int i = 0; i < channels.size(); i++)
+        {
+            Channel channel = channels.get(i);
+            ColorComponent colorComponent = tryGetColorComponent(structure, i);
+            channelsByCode.put(channel.getCode(), new ChannelAndColorComponent(channel, colorComponent));
+        }
+        return channelsByCode;
+    }
+    
+    private ColorComponent tryGetColorComponent(ImageDataSetStructure structure, int i)
+    {
+        List<ChannelColorComponent> channelColorComponents = structure.getChannelColorComponents();
+        if (channelColorComponents == null || channelColorComponents.isEmpty())
+        {
+            return null;
         }
-        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 ChannelColorComponent.getColorComponent(channelColorComponents.get(i));
+    }
+    
+    private int adjust(int rgb, int maximumIntensity)
+    {
+        int maxIntensity = Math.min(255, maximumIntensity);
+        int r = rescale(getRed(rgb), maxIntensity);
+        int g = rescale(getGreen(rgb), maxIntensity);
+        int b = rescale(getBlue(rgb), maxIntensity);
         return (r << 16) + (g << 8) + b;
-        
     }
-
+    
+    private int rescale(int intensity, int maxIntensity)
+    {
+        return (intensity * 255 + maxIntensity / 2) / maxIntensity;
+    }
 
     private int addImage(BufferedImage image)
     {
-        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 w = image.getWidth();
+        int h = image.getHeight();
+        if (result == null)
+        {
+            result = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
+            for (int y = 0; y < h; y++)
+            {
+                for (int x = 0; x < w; x++)
+                {
+                    result.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);
-                
+        for (int y = 0; y < h; y++)
+        {
+            for (int x = 0; x < w; 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);
+                maxIntensity = Math.max(Math.max(maxIntensity, intensity1), intensity2);
+ 
+                result.setRGB(x, y, intensity1 > intensity2 ? rgb1 : rgb2);
             }
         }
         return maxIntensity;
@@ -142,22 +240,19 @@ public class MaximumIntensityProjectionGenerationAlgorithm implements IImageGene
         double r = getRed(rgb);
         double g = getGreen(rgb);
         double b = getBlue(rgb);
-        return new Double(Math.sqrt(r*r + g*g + b*b)).intValue();
+        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;
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 5a3f323c815056edd0c2660caaee16ed6910328f..2c08e93145687af3afb409799a7deef8201ddf06 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
@@ -347,8 +347,8 @@ public class ImagingDataSetRegistrationTransaction extends DataSetRegistrationTr
 
         containedDataSetCodes.add(mainDataset.getDataSetCode());
         
-        createRepresentativeThumbnailByImageGenerationAlgorithm(imageDataSetInformation, imageDataSetStructure, 
-                containedDataSetCodes, thumbnailDatasets);
+        createRepresentativeThumbnailByImageGenerationAlgorithm(imageDataSetInformation, containedDataSetCodes, 
+                thumbnailDatasets);
 
         for (IDataSet thumbnailDataset : thumbnailDatasets)
         {
@@ -366,14 +366,14 @@ public class ImagingDataSetRegistrationTransaction extends DataSetRegistrationTr
     }
 
     private void createRepresentativeThumbnailByImageGenerationAlgorithm(ImageDataSetInformation imageDataSetInformation,
-            ImageDataSetStructure imageDataSetStructure, List<String> containedDataSetCodes, List<IDataSet> thumbnailDatasets)
+            List<String> containedDataSetCodes, List<IDataSet> thumbnailDatasets)
     {
         IImageGenerationAlgorithm algorithm = imageDataSetInformation.getImageGenerationAlgorithm();
         if (algorithm == null)
         {
             return;
         }
-        List<BufferedImage> images = algorithm.generateImages(imageDataSetInformation, imageDataSetStructure);
+        List<BufferedImage> images = algorithm.generateImages(imageDataSetInformation);
         if (images.size() > 0) {
             IDataSet representative = createNewDataSet(algorithm.getDataSetTypeCode());
             for (int i = 0; i < images.size(); i++)
diff --git a/screening/sourceTest/core-plugins/MicroscopyImageDropboxTest/1/dss/drop-boxes/MicroscopyImageDropboxTest-drop-box/MicroscopySingleDatasetConfig.py b/screening/sourceTest/core-plugins/MicroscopyImageDropboxTest/1/dss/drop-boxes/MicroscopyImageDropboxTest-drop-box/MicroscopySingleDatasetConfig.py
index 149865111cdd22577b48258d1414624cf5097a1c..7dfb4ce3f3dff6bae92f34ecfea045d6006b10d7 100644
--- a/screening/sourceTest/core-plugins/MicroscopyImageDropboxTest/1/dss/drop-boxes/MicroscopyImageDropboxTest-drop-box/MicroscopySingleDatasetConfig.py
+++ b/screening/sourceTest/core-plugins/MicroscopyImageDropboxTest/1/dss/drop-boxes/MicroscopyImageDropboxTest-drop-box/MicroscopySingleDatasetConfig.py
@@ -13,6 +13,13 @@ from ch.systemsx.cisd.openbis.dss.etl.dto.api import ImageMetadata
 from ch.systemsx.cisd.openbis.dss.etl.dto.api import OriginalDataStorageFormat
 from ch.systemsx.cisd.openbis.dss.etl.dto.api import ChannelColorRGB
 from ch.systemsx.cisd.openbis.dss.etl.dto.api import Channel
+from ch.systemsx.cisd.openbis.dss.etl.dto.api.impl import MaximumIntensityProjectionGenerationAlgorithm;
+
+class TestAlgorithm(MaximumIntensityProjectionGenerationAlgorithm):
+    def __init__(self):
+        MaximumIntensityProjectionGenerationAlgorithm.__init__(self, 'MICROSCOPY_REPRESENTATIVE_IMG')
+    def imageToBeIgnored(self, imageFileInfo):
+        return False
 
 class MicroscopySingleDatasetConfig(SimpleImageContainerDataConfig):
     """Image data configuration class for multi datasets image files."""
@@ -60,6 +67,7 @@ class MicroscopySingleDatasetConfig(SimpleImageContainerDataConfig):
 
         # Set the dataset type
         self.setDataSetType("MICROSCOPY_IMG")
+        self.setImageGenerationAlgorithm(TestAlgorithm())
 
     def createChannel(self, channelCode):
         """Create a channel from the channelCode with the name as read from
diff --git a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/MaximumIntensityProjectionGenerationAlgorithmTest.java b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/MaximumIntensityProjectionGenerationAlgorithmTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..c2d5ec5c9ff9897877c632cf76f41243cbdc273e
--- /dev/null
+++ b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/MaximumIntensityProjectionGenerationAlgorithmTest.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright 2014 ETH Zuerich, SIS
+ *
+ * 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.etl.dto.api.impl;
+
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import ch.rinn.restrictions.Friend;
+import ch.systemsx.cisd.base.tests.AbstractFileSystemTestCase;
+import ch.systemsx.cisd.common.image.ImageHistogram;
+import ch.systemsx.cisd.openbis.dss.etl.dto.ImageLibraryInfo;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.Channel;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ChannelColorRGB;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ImageFileInfo;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.ImageStorageConfiguraton;
+
+
+/**
+ * 
+ *
+ * @author Franz-Josef Elmer
+ */
+@Friend(toClasses = MaximumIntensityProjectionGenerationAlgorithm.class)
+public class MaximumIntensityProjectionGenerationAlgorithmTest extends AbstractFileSystemTestCase
+{
+    private static final class ImageBuilder
+    {
+        private BufferedImage image;
+        private Graphics graphics;
+
+        ImageBuilder(int imageType)
+        {
+            image = new BufferedImage(10, 6, BufferedImage.TYPE_INT_RGB);
+            graphics = image.getGraphics();
+        }
+        
+        BufferedImage getImage()
+        {
+            return image;
+        }
+        
+        ImageBuilder rect(int x, int y, int width, int height, Color color)
+        {
+            graphics.setColor(color);
+            graphics.fillRect(x, y, width, height);
+            return this;
+        }
+    }
+    
+    private static final class MaximumIntensityProjectionGenerationAlgorithmWithMockedLoading 
+            extends MaximumIntensityProjectionGenerationAlgorithm
+    {
+        private static final long serialVersionUID = 1L;
+        
+        private final List<String> recorder = new ArrayList<String>();
+
+        private final Map<String, BufferedImage> images;
+        
+        private final Set<String> imagesToIgnore;
+        
+        public MaximumIntensityProjectionGenerationAlgorithmWithMockedLoading(String dataSetTypeCode, 
+                int width, int height, String filename, Map<String, BufferedImage> images, String... imagesToIgnore)
+        {
+            super(dataSetTypeCode, width, height, filename);
+            this.images = images;
+            this.imagesToIgnore = new HashSet<String>(Arrays.asList(imagesToIgnore));
+        }
+
+        @Override
+        BufferedImage loadImage(File incomingDirectory, String imagePath, String identifier, ImageLibraryInfo library)
+        {
+            recorder.add(incomingDirectory.getName() + "/" + imagePath + ": " + identifier + " [" + library + "]");
+            BufferedImage bufferedImage = images.get(identifier);
+            assertNotNull("image " + identifier, bufferedImage);
+            return bufferedImage;
+        }
+
+        @Override
+        protected boolean imageToBeIgnored(ImageFileInfo image)
+        {
+            return imagesToIgnore.contains(image.tryGetUniqueStringIdentifier());
+        }
+    }
+    
+    private Map<String, BufferedImage> images;
+    private ImageDataSetInformation information;
+    private ImageDataSetStructure structure;
+
+    @BeforeMethod
+    public void createImages()
+    {
+        images = new LinkedHashMap<String, BufferedImage>();
+        images.put("i1", new ImageBuilder(BufferedImage.TYPE_INT_RGB)
+            .rect(1, 0, 3, 2, new Color(255, 128, 128))
+            .rect(5, 4, 3, 2, new Color(80, 255, 128)).getImage());
+        images.put("i2", new ImageBuilder(BufferedImage.TYPE_USHORT_GRAY)
+            .rect(2, 1, 5, 4, new Color(100, 100, 100)).getImage());
+        images.put("i3", new ImageBuilder(BufferedImage.TYPE_USHORT_GRAY)
+            .rect(3, 2, 5, 4, new Color(30, 30, 30)).getImage());
+        information = new ImageDataSetInformation();
+        information.setIncomingDirectory(new File(workingDirectory, "incoming"));
+        structure = new ImageDataSetStructure();
+        information.setImageDataSetStructure(structure);
+        ImageStorageConfiguraton imageStorageConfiguraton = new ImageStorageConfiguraton();
+        imageStorageConfiguraton.setImageLibrary(new ImageLibraryInfo("lib", "reader"));
+        structure.setImageStorageConfiguraton(imageStorageConfiguraton);
+        Set<String> keySet = images.keySet();
+        List<ImageFileInfo> imageFileInfos = new ArrayList<ImageFileInfo>();
+        for (String key : keySet)
+        {
+            ImageFileInfo fileInfo = new ImageFileInfo("C" + key.toUpperCase(), 1, 1, "images/" + key + ".png");
+            fileInfo.setUniqueImageIdentifier(key);
+            imageFileInfos.add(fileInfo);
+        }
+        structure.setImages(imageFileInfos);
+    }
+
+    @Test
+    public void test8BitColorImageAnd16BitGrayImage()
+    {
+        
+        MaximumIntensityProjectionGenerationAlgorithmWithMockedLoading generationAlgorithm 
+            = new MaximumIntensityProjectionGenerationAlgorithmWithMockedLoading("ABC", 10, 6, "r.png", images, "i3");
+        assertEquals("ABC", generationAlgorithm.getDataSetTypeCode());
+        assertEquals("r.png", generationAlgorithm.getImageFileName(0));
+        Channel channel1 = new Channel("CI1", "i1", new ChannelColorRGB(200, 100, 80));
+        Channel channel2 = new Channel("CI2", "i2", new ChannelColorRGB(0, 120, 180));
+        structure.setChannels(Arrays.asList(channel1, channel2));
+        
+        List<BufferedImage> generatedImages = generationAlgorithm.generateImages(information);
+        
+        assertEquals("[incoming/images/i1.png: i1 [lib (reader: reader)], "
+                + "incoming/images/i2.png: i2 [lib (reader: reader)]]", generationAlgorithm.recorder.toString());
+        
+        ImageHistogram histogram = ImageHistogram.calculateHistogram(generatedImages.get(0));
+        assertEquals("[0=48, 80=6, 255=6]", renderHistogram(histogram.getRedHistogram()));
+        assertEquals("[0=32, 47=16, 128=6, 255=6]", renderHistogram(histogram.getGreenHistogram()));
+        assertEquals("[0=32, 71=16, 128=12]", renderHistogram(histogram.getBlueHistogram()));
+        assertEquals(1, generatedImages.size());
+    }
+    
+    @Test
+    public void testTwo16BitGrayImages()
+    {
+        
+        MaximumIntensityProjectionGenerationAlgorithmWithMockedLoading generationAlgorithm 
+        = new MaximumIntensityProjectionGenerationAlgorithmWithMockedLoading("ABC", 10, 6, "r.png", images, "i1");
+        Channel channel1 = new Channel("CI2", "i2", new ChannelColorRGB(200, 100, 80));
+        Channel channel2 = new Channel("CI3", "i3", new ChannelColorRGB(0, 120, 180));
+        structure.setChannels(Arrays.asList(channel1, channel2));
+        
+        List<BufferedImage> generatedImages = generationAlgorithm.generateImages(information);
+        
+        assertEquals("[incoming/images/i2.png: i2 [lib (reader: reader)], "
+                + "incoming/images/i3.png: i3 [lib (reader: reader)]]", generationAlgorithm.recorder.toString());
+        
+        ImageHistogram histogram = ImageHistogram.calculateHistogram(generatedImages.get(0));
+        assertEquals("[0=40, 216=20]", renderHistogram(histogram.getRedHistogram()));
+        assertEquals("[0=32, 39=8, 108=20]", renderHistogram(histogram.getGreenHistogram()));
+        assertEquals("[0=32, 58=8, 86=20]", renderHistogram(histogram.getBlueHistogram()));
+        assertEquals(1, generatedImages.size());
+    }
+
+    private String renderHistogram(int[] histogram)
+    {
+        StringBuilder builder = new StringBuilder();
+        for (int i = 0; i < histogram.length; i++)
+        {
+            int value = histogram[i];
+            if (value > 0)
+            {
+                if (builder.length() > 0)
+                {
+                    builder.append(", ");
+                }
+                builder.append(i).append("=").append(value);
+            }
+        }
+        return "[" + builder.toString() + "]";
+    }
+}
diff --git a/screening/sourceTest/java/ch/systemsx/cisd/openbis/screening/systemtests/AbstractScreeningSystemTestCase.java b/screening/sourceTest/java/ch/systemsx/cisd/openbis/screening/systemtests/AbstractScreeningSystemTestCase.java
index 57436c6d52100d5a8f0a47d3813ab339d4c9498a..8270cb500045290516fca04fe521c80663c6f1ce 100644
--- a/screening/sourceTest/java/ch/systemsx/cisd/openbis/screening/systemtests/AbstractScreeningSystemTestCase.java
+++ b/screening/sourceTest/java/ch/systemsx/cisd/openbis/screening/systemtests/AbstractScreeningSystemTestCase.java
@@ -94,12 +94,17 @@ public abstract class AbstractScreeningSystemTestCase extends SystemTestCase
         
     }
     
+    private static interface IImageLoader
+    {
+        public BufferedImage load();
+
+    }
     /**
      * Helper class to load an image from the image download servlet.
      *
      * @author Franz-Josef Elmer
      */
-    protected static final class ImageLoader
+    protected static final class ImageLoader implements IImageLoader
     {
         private final URLMethodWithParameters url;
         private final List<String> channels = new ArrayList<String>();
@@ -120,6 +125,7 @@ public abstract class AbstractScreeningSystemTestCase extends SystemTestCase
             url.addParameter(ImageServletUrlParameters.DATASET_CODE_PARAM, dataSet.getCode());
         }
         
+        @Override
         public BufferedImage load()
         {
             try
@@ -241,7 +247,7 @@ public abstract class AbstractScreeningSystemTestCase extends SystemTestCase
         }
         
         /**
-         * Asserts no failures occurred for all invocations of {@link #check(File, ImageLoader)}.
+         * Asserts no failures occurred for all invocations of {@link #check(File, IImageLoader)}.
          * Otherwise an {@link AssertionError} is thrown.
          */
         public void assertNoFailures()
@@ -253,11 +259,39 @@ public abstract class AbstractScreeningSystemTestCase extends SystemTestCase
             }
         }
         
+        /**
+         * Checks that the specified reference image is equals to the image loaded from the specified file
+         * in the specified data set.
+         */
+        public void check(File referenceImage, final String sessionToken, final AbstractExternalData dataSet, 
+                final String pathInDataSet)
+        {
+            check(referenceImage, new IImageLoader()
+                {
+                    
+                    @Override
+                    public BufferedImage load()
+                    {
+                        URLMethodWithParameters url = new URLMethodWithParameters(dataSet.getDataStore().getHostUrl() 
+                                + "/datastore_server/" + dataSet.getCode() + "/" + pathInDataSet);
+                        url.addParameter(Utils.SESSION_ID_PARAM, sessionToken);
+                        url.addParameter("mode", "simpleHtml");
+                        try
+                        {
+                            return ImageIO.read(new URL(url.toString()));
+                        } catch (Exception ex)
+                        {
+                            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+                        }
+                    }
+                });
+        }
+        
         /**
          * Checks that the specified reference image is equals to the image loaded by the specified image loader.
          * A report is created in case of a failure.
          */
-        public void check(File referenceImage, ImageLoader imageLoader)
+        public void check(File referenceImage, IImageLoader imageLoader)
         {
             FailureReport report = new FailureReport(referenceImage);
             try
diff --git a/screening/sourceTest/java/ch/systemsx/cisd/openbis/screening/systemtests/MicroscopyImageDropboxTest.java b/screening/sourceTest/java/ch/systemsx/cisd/openbis/screening/systemtests/MicroscopyImageDropboxTest.java
index 7c3cbd869e617a5606e1801dd7fbb2b979d6d6dd..a0cdbadaddce386320f76c2e56e82f3cfcc59eee 100644
--- a/screening/sourceTest/java/ch/systemsx/cisd/openbis/screening/systemtests/MicroscopyImageDropboxTest.java
+++ b/screening/sourceTest/java/ch/systemsx/cisd/openbis/screening/systemtests/MicroscopyImageDropboxTest.java
@@ -22,6 +22,7 @@ import java.util.Collections;
 import org.testng.annotations.BeforeTest;
 import org.testng.annotations.Test;
 
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.MaximumIntensityProjectionGenerationAlgorithm;
 import ch.systemsx.cisd.openbis.generic.shared.ICommonServer;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.AbstractExternalData;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetKind;
@@ -67,6 +68,9 @@ public class MicroscopyImageDropboxTest extends AbstractImageDropboxTestCase
         dataSetType = new DataSetType("MICROSCOPY_IMG_OVERVIEW");
         dataSetType.setDataSetKind(DataSetKind.PHYSICAL);
         registerDataSetType(commonServer, dataSetType);
+        dataSetType = new DataSetType("MICROSCOPY_REPRESENTATIVE_IMG");
+        dataSetType.setDataSetKind(DataSetKind.PHYSICAL);
+        registerDataSetType(commonServer, dataSetType);
         dataSetType = new DataSetType("MICROSCOPY_IMG_CONTAINER");
         dataSetType.setDataSetKind(DataSetKind.CONTAINER);
         registerDataSetType(commonServer, dataSetType);
@@ -119,6 +123,8 @@ public class MicroscopyImageDropboxTest extends AbstractImageDropboxTestCase
         imageChecker.check(new File(getTestDataFolder(), "Merged_256x256_C0_0_200_C4_150_300.png"), 
                 new ImageLoader(dataSet, sessionToken).microscopy().rescaling("SERIES-0_CHANNEL-0", 0, 200)
                 .rescaling("SERIES-0_CHANNEL-4", 150, 300).mode("thumbnail256x256"));
+        String pathInDataSet = MaximumIntensityProjectionGenerationAlgorithm.DEFAULT_FILE_NAME;
+        imageChecker.check(new File(getTestDataFolder(), pathInDataSet), sessionToken, dataSet, pathInDataSet);
 
         imageChecker.assertNoFailures();
     }