diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/AbsoluteImageReference.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/AbsoluteImageReference.java
index f648d1fdb730cb96d689525fd53b910bcdf7056a..7e2d3012d9b6c86f1d83028777c9b9420e03250d 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/AbsoluteImageReference.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/AbsoluteImageReference.java
@@ -16,6 +16,7 @@
 
 package ch.systemsx.cisd.openbis.dss.etl;
 
+import ch.systemsx.cisd.base.image.IImageTransformerFactory;
 import ch.systemsx.cisd.common.io.IContent;
 import ch.systemsx.cisd.openbis.dss.generic.server.AbstractDatasetDownloadServlet.Size;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ColorComponent;
@@ -33,6 +34,10 @@ public class AbsoluteImageReference extends AbstractImageReference
 
     private final Size thumbnailSizeOrNull;
 
+    private IImageTransformerFactory transformerFactory;
+    
+    private IImageTransformerFactory transformerFactoryForMergedChannels;
+
     /**
      * @param content the content before choosing the color component and the page
      */
@@ -64,11 +69,36 @@ public class AbsoluteImageReference extends AbstractImageReference
         return thumbnailSizeOrNull;
     }
 
+    public final IImageTransformerFactory getTransformerFactory()
+    {
+        return transformerFactory;
+    }
+
+    public final IImageTransformerFactory getTransformerFactoryForMergedChannels()
+    {
+        return transformerFactoryForMergedChannels;
+    }
+
+    public final void setTransformerFactoryForMergedChannels(
+            IImageTransformerFactory transformerFactoryForMergedChannels)
+    {
+        this.transformerFactoryForMergedChannels = transformerFactoryForMergedChannels;
+    }
+
+    public final void setTransformerFactory(IImageTransformerFactory transformerFactory)
+    {
+        this.transformerFactory = transformerFactory;
+    }
+
     public AbsoluteImageReference createWithoutColorComponent()
     {
         ColorComponent colorComponent = null;
-        return new AbsoluteImageReference(content, uniqueId, tryGetPage(), colorComponent,
-                thumbnailSizeOrNull);
+        AbsoluteImageReference ref =
+                new AbsoluteImageReference(content, uniqueId, tryGetPage(), colorComponent,
+                        thumbnailSizeOrNull);
+        ref.setTransformerFactory(transformerFactory);
+        ref.setTransformerFactoryForMergedChannels(transformerFactoryForMergedChannels);
+        return ref;
 
     }
 }
\ No newline at end of file
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/ImagingDatabaseVersionHolder.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/ImagingDatabaseVersionHolder.java
index 1ee677222bd41d03ff5d06376d80ea51b1509d57..290ac0f99fe54ae9a7c259f8994a6612d83a1ca4 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/ImagingDatabaseVersionHolder.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/ImagingDatabaseVersionHolder.java
@@ -28,7 +28,7 @@ public class ImagingDatabaseVersionHolder implements IDatabaseVersionHolder
 
     public String getDatabaseVersion()
     {
-        return "006"; // changed in S88
+        return "007"; // changed in S94
     }
 
 }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/ScreeningContainerDatasetInfoHelper.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/ScreeningContainerDatasetInfoHelper.java
index d6e4edb7dbaeaf6b5853e446953d99add4658e67..fb279e1cbef6b2293a97bae2786b17fc1cde0c40 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/ScreeningContainerDatasetInfoHelper.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/ScreeningContainerDatasetInfoHelper.java
@@ -26,6 +26,7 @@ import ch.systemsx.cisd.openbis.dss.etl.dataaccess.IImagingQueryDAO;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ImgChannelDTO;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ImgContainerDTO;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ImgDatasetDTO;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ImgExperimentDTO;
 
 /**
  * Helper class for retrieving and/or creating entities associated with the screening container data
@@ -141,13 +142,13 @@ public class ScreeningContainerDatasetInfoHelper
             ScreeningContainerDatasetInfo info)
     {
         String experimentPermId = info.getExperimentPermId();
-        Long expId = dao.tryGetExperimentIdByPermId(experimentPermId);
-        if (expId != null)
+        ImgExperimentDTO experiment = dao.tryGetExperimentByPermId(experimentPermId);
+        if (experiment != null)
         {
-            return new CreatedOrFetchedEntity(true, expId);
+            return new CreatedOrFetchedEntity(true, experiment.getId());
         } else
         {
-            expId = dao.addExperiment(experimentPermId);
+            Long expId = dao.addExperiment(experimentPermId);
             return new CreatedOrFetchedEntity(false, expId);
         }
     }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dataaccess/HCSImageDatasetLoader.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dataaccess/HCSImageDatasetLoader.java
index c6ce95b5e940ce1ec2288eae8d107cdf3f866f91..c65d486fc23f74ff63925ab332c9b694723df967 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dataaccess/HCSImageDatasetLoader.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dataaccess/HCSImageDatasetLoader.java
@@ -26,7 +26,10 @@ import ch.systemsx.cisd.openbis.dss.generic.server.AbstractDatasetDownloadServle
 import ch.systemsx.cisd.openbis.dss.generic.server.images.ImageChannelStackReference;
 import ch.systemsx.cisd.openbis.dss.generic.server.images.ImageChannelStackReference.LocationImageChannelStackReference;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.HCSDatasetLoader;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ColorComponent;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.IImagingReadonlyQueryDAO;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ImgChannelDTO;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ImgExperimentDTO;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ImgImageDTO;
 
 /**
@@ -65,10 +68,10 @@ public class HCSImageDatasetLoader extends HCSDatasetLoader implements IHCSImage
             assert stackLocations.getWellLocation().getY() <= getContainer().getNumberOfRows();
         }
 
-        Long chosenChannelId =
-                query.tryGetChannelIdByChannelCodeDatasetIdOrExperimentId(getDataset().getId(),
+        ImgChannelDTO channel =
+                query.tryGetChannelByChannelCodeDatasetIdOrExperimentId(getDataset().getId(),
                         getContainer().getExperimentId(), chosenChannelCode);
-        if (chosenChannelId == null)
+        if (channel == null)
         {
             return null;
         }
@@ -76,15 +79,21 @@ public class HCSImageDatasetLoader extends HCSDatasetLoader implements IHCSImage
         long datasetId = getDataset().getId();
         boolean thumbnailPrefered = thumbnailSizeOrNull != null;
         ImgImageDTO imageDTO =
-                tryGetImageDTO(channelStackReference, thumbnailPrefered, chosenChannelId, datasetId);
+                tryGetImageDTO(channelStackReference, thumbnailPrefered, channel.getId(), datasetId);
         if (imageDTO == null)
         {
             return null;
         }
         String path = imageDTO.getFilePath();
         IContent content = contentRepository.getContent(path);
-        return new AbsoluteImageReference(content, path, imageDTO.getPage(), imageDTO
-                .getColorComponent(), thumbnailSizeOrNull);
+        ColorComponent colorComponent = imageDTO.getColorComponent();
+        AbsoluteImageReference imgRef =
+                new AbsoluteImageReference(content, path, imageDTO.getPage(), colorComponent,
+                        thumbnailSizeOrNull);
+        imgRef.setTransformerFactory(channel.getImageTransformerFactory());
+        ImgExperimentDTO experiment = query.tryGetExperimentById(getContainer().getExperimentId());
+        imgRef.setTransformerFactoryForMergedChannels(experiment.getImageTransformerFactory());
+        return imgRef;
     }
 
     private ImgImageDTO tryGetImageDTO(ImageChannelStackReference channelStackReference,
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/MergingImagesDownloadServlet.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/MergingImagesDownloadServlet.java
index d4605658f29074eb883fdf2ac53f3baa2b7fa9b6..c6bde9a3522cce4155067aa719776db77d56a2d1 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/MergingImagesDownloadServlet.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/MergingImagesDownloadServlet.java
@@ -21,6 +21,8 @@ import java.io.IOException;
 
 import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException;
 import ch.systemsx.cisd.common.io.IContent;
+import ch.systemsx.cisd.openbis.dss.etl.HCSImageDatasetLoaderFactory;
+import ch.systemsx.cisd.openbis.dss.etl.IHCSImageDatasetLoader;
 import ch.systemsx.cisd.openbis.dss.generic.server.images.ImageChannelsUtils;
 import ch.systemsx.cisd.openbis.dss.generic.server.images.TileImageReference;
 
@@ -43,7 +45,9 @@ public class MergingImagesDownloadServlet extends AbstractImagesDownloadServlet
     protected final ResponseContentStream createImageResponse(TileImageReference params,
             File datasetRoot, String datasetCode) throws IOException, EnvironmentFailureException
     {
-        IContent image = ImageChannelsUtils.getImage(datasetRoot, datasetCode, params);
+        IHCSImageDatasetLoader imageAccessor =
+                HCSImageDatasetLoaderFactory.create(datasetRoot, datasetCode);
+        IContent image = ImageChannelsUtils.getImage(imageAccessor, params);
         return createResponseContentStream(image.getInputStream(), image.getSize(),
                 ImageChannelsUtils.IMAGES_CONTENT_TYPE, image.tryGetName());
     }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/images/ImageChannelsUtils.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/images/ImageChannelsUtils.java
index 1360dd4c4e342c313e3ee29c789600d9f324b0db..67870306f2e194f2694ccb019d2c849f8a19907b 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/images/ImageChannelsUtils.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/images/ImageChannelsUtils.java
@@ -20,7 +20,6 @@ import java.awt.Color;
 import java.awt.image.BufferedImage;
 import java.awt.image.RenderedImage;
 import java.io.ByteArrayOutputStream;
-import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
@@ -30,13 +29,13 @@ import javax.imageio.ImageIO;
 
 import org.apache.log4j.Logger;
 
+import ch.systemsx.cisd.base.image.IImageTransformerFactory;
 import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException;
 import ch.systemsx.cisd.common.io.ByteArrayBasedContent;
 import ch.systemsx.cisd.common.io.IContent;
 import ch.systemsx.cisd.common.logging.LogCategory;
 import ch.systemsx.cisd.common.logging.LogFactory;
 import ch.systemsx.cisd.openbis.dss.etl.AbsoluteImageReference;
-import ch.systemsx.cisd.openbis.dss.etl.HCSImageDatasetLoaderFactory;
 import ch.systemsx.cisd.openbis.dss.etl.IHCSImageDatasetLoader;
 import ch.systemsx.cisd.openbis.dss.generic.server.AbstractDatasetDownloadServlet.Size;
 import ch.systemsx.cisd.openbis.dss.generic.shared.utils.ImageUtil;
@@ -53,17 +52,25 @@ public class ImageChannelsUtils
     static protected final Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION,
             ImageChannelsUtils.class);
 
-    // MIME type of the images which are produced by thsi class
+    // MIME type of the images which are produced by this class
     public static final String IMAGES_CONTENT_TYPE = "image/png";
 
     /**
-     * @return an image for the specified tile in the specified size and for the requested channel
-     *         or with all channels merged.
+     * Returns content of image for the specified tile in the specified size and for the requested
+     * channel or with all channels merged.
      */
-    public static IContent getImage(File datasetRoot, String datasetCode, TileImageReference params)
+    public static IContent getImage(IHCSImageDatasetLoader imageAccessor, TileImageReference params)
     {
-        List<AbsoluteImageReference> images = getImageReferences(datasetRoot, datasetCode, params);
-        return calculateImage(images);
+        List<AbsoluteImageReference> images = getImageReferences(imageAccessor, params);
+        if (images.size() > 1)
+        {
+            return mergeAllChannels(images);
+        } else
+        {
+            AbsoluteImageReference imageReference = images.get(0);
+            return calculateSingleImageContent(imageReference,
+                    imageReference.getTransformerFactory(), true);
+        }
     }
 
     /**
@@ -76,19 +83,12 @@ public class ImageChannelsUtils
         AbsoluteImageReference imageReference =
                 getImageReference(imageAccessor, channelStackReference, chosenChannelCode,
                         thumbnailSizeOrNull);
-        return calculateSingleImageContent(imageReference, convertToPng);
+        return calculateSingleImageContent(imageReference, null, convertToPng);
     }
 
-    /**
-     * @return file with the image for the chosen channel or images for all channels if they should
-     *         be merged.
-     * @throw {@link EnvironmentFailureException} when image does not exist
-     */
-    private static List<AbsoluteImageReference> getImageReferences(File datasetRoot,
-            String datasetCode, TileImageReference params)
+    private static List<AbsoluteImageReference> getImageReferences(
+            IHCSImageDatasetLoader imageAccessor, TileImageReference params)
     {
-        IHCSImageDatasetLoader imageAccessor =
-                HCSImageDatasetLoaderFactory.create(datasetRoot, datasetCode);
         List<AbsoluteImageReference> images = new ArrayList<AbsoluteImageReference>();
 
         Size thumbnailSizeOrNull = params.tryGetThumbnailSize();
@@ -111,24 +111,13 @@ public class ImageChannelsUtils
         return images;
     }
 
-    private static IContent calculateImage(List<AbsoluteImageReference> images)
-    {
-        if (images.size() > 1)
-        {
-            return mergeAllChannels(images);
-        } else
-        {
-            return calculateSingleImageContent(images.get(0), true);
-        }
-    }
-
     private static IContent calculateSingleImageContent(AbsoluteImageReference imageReference,
-            boolean convertToPng)
+            IImageTransformerFactory transformerFactoryOrNull, boolean convertToPng)
     {
         final IContent content;
         if (convertToPng || imageReference.tryGetColorComponent() != null)
         {
-            final BufferedImage image = calculateSingleImage(imageReference);
+            final BufferedImage image = transform(calculateSingleImage(imageReference), transformerFactoryOrNull);
 
             long start = operationLog.isDebugEnabled() ? System.currentTimeMillis() : 0;
             content = createPngContent(image, imageReference.getContent().tryGetName());
@@ -138,7 +127,14 @@ public class ImageChannelsUtils
             }
         } else
         {
-            content = imageReference.getContent();
+            if (transformerFactoryOrNull != null)
+            {
+                BufferedImage img = transform(loadImage(imageReference), transformerFactoryOrNull);
+                content = createPngContent(img, imageReference.getContent().tryGetName());
+            } else
+            {
+                content = imageReference.getContent();
+            }
         }
 
         return content;
@@ -146,15 +142,9 @@ public class ImageChannelsUtils
 
     private static BufferedImage calculateSingleImage(AbsoluteImageReference imageReference)
     {
-        IContent content = imageReference.getContent();
-
-        InputStream inputStream = content.getInputStream();
-
-        // extracts the correct page if necessary
-        int page = (imageReference.tryGetPage() != null) ? imageReference.tryGetPage() : 0;
 
         long start = operationLog.isDebugEnabled() ? System.currentTimeMillis() : 0;
-        BufferedImage image = ImageUtil.loadImage(inputStream, page);
+        BufferedImage image = loadImage(imageReference);
         if (operationLog.isDebugEnabled())
         {
             operationLog.debug("Load original image: " + (System.currentTimeMillis() - start));
@@ -186,6 +176,18 @@ public class ImageChannelsUtils
         return image;
     }
 
+    private static BufferedImage loadImage(AbsoluteImageReference imageReference)
+    {
+        IContent content = imageReference.getContent();
+        InputStream inputStream = content.getInputStream();
+
+        // extracts the correct page if necessary
+        int page = (imageReference.tryGetPage() != null) ? imageReference.tryGetPage() : 0;
+
+        BufferedImage image = ImageUtil.loadImage(inputStream, page);
+        return image;
+    }
+
     private static IContent mergeAllChannels(List<AbsoluteImageReference> imageReferences)
     {
         AbsoluteImageReference allChannelsImageReference =
@@ -193,13 +195,25 @@ public class ImageChannelsUtils
         if (allChannelsImageReference != null)
         {
             // all channels are on an image in one file, no pixel-level operations needed
-            return calculateSingleImageContent(allChannelsImageReference, true);
+            return calculateSingleImageContent(allChannelsImageReference,
+                    allChannelsImageReference.getTransformerFactoryForMergedChannels(), true);
         } else
         {
             List<BufferedImage> images = calculateSingleImages(imageReferences);
             BufferedImage mergedImage = mergeChannels(images);
-            return createPngContent(mergedImage, null);
+            IImageTransformerFactory transformerFactory =
+                    imageReferences.get(0).getTransformerFactoryForMergedChannels();
+            return createPngContent(transform(mergedImage, transformerFactory), null);
+        }
+    }
+    
+    private static BufferedImage transform(BufferedImage input, IImageTransformerFactory factoryOrNull)
+    {
+        if (factoryOrNull == null)
+        {
+            return input;
         }
+        return factoryOrNull.createTransformer().transform(input);
     }
 
     private static List<BufferedImage> calculateSingleImages(
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/server/DssServiceRpcScreening.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/server/DssServiceRpcScreening.java
index 9d6194321e71be37f3cc8beda6f8745ab5e7f226..c6540ff4516922bfc2e80169d55795fa91a63daf 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/server/DssServiceRpcScreening.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/server/DssServiceRpcScreening.java
@@ -26,8 +26,11 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import net.lemnik.eodsql.QueryTool;
+
 import org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter;
 
+import ch.systemsx.cisd.base.image.IImageTransformerFactory;
 import ch.systemsx.cisd.bds.hcs.Location;
 import ch.systemsx.cisd.common.api.RpcServiceInterfaceVersionDTO;
 import ch.systemsx.cisd.common.api.server.RpcServiceNameServer;
@@ -69,8 +72,10 @@ import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.FeatureVectorLoa
 import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.FeatureVectorLoader.IMetadataProvider;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.FeatureVectorLoader.WellFeatureCollection;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.IImagingReadonlyQueryDAO;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.IImagingTransformerDAO;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ImgDatasetDTO;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ImgFeatureDefDTO;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.TransformerFactoryMapper;
 
 /**
  * Implementation of the screening API interface using RPC. The instance will be created in spring
@@ -86,20 +91,30 @@ public class DssServiceRpcScreening extends AbstractDssServiceRpc implements
      * The minor version of this service.
      */
     public static final int MINOR_VERSION = 3;
+    
+    static
+    {
+        QueryTool.getTypeMap().put(IImageTransformerFactory.class, new TransformerFactoryMapper());
+    }
 
     // this dao will hold one connection to the database
     private IImagingReadonlyQueryDAO dao;
 
+    private final IImagingTransformerDAO transformerDAO;
+    
     public DssServiceRpcScreening(String storeRootDir)
     {
-        this(storeRootDir, null, ServiceProvider.getOpenBISService(), true);
+        this(storeRootDir, null, QueryTool.getQuery(ServiceProvider.getDataSourceProvider()
+                .getDataSource(ScreeningConstants.IMAGING_DATA_SOURCE),
+                IImagingTransformerDAO.class), ServiceProvider.getOpenBISService(), true);
     }
 
-    DssServiceRpcScreening(String storeRootDir, IImagingReadonlyQueryDAO dao,
+    DssServiceRpcScreening(String storeRootDir, IImagingReadonlyQueryDAO dao, IImagingTransformerDAO transformerDAO,
             IEncapsulatedOpenBISService service, boolean registerAtNameService)
     {
         super(service);
         this.dao = dao;
+        this.transformerDAO = transformerDAO;
         setStoreDirectory(new File(storeRootDir));
         if (registerAtNameService)
         {
@@ -354,6 +369,78 @@ public class DssServiceRpcScreening extends AbstractDssServiceRpc implements
         }
         return new ConcatenatedContentInputStream(true, imageContents);
     }
+    
+    
+
+    public void saveImageTransformerFactory(String sessionToken, List<IDatasetIdentifier> dataSetIdentifiers,
+            String channel, IImageTransformerFactory transformerFactory)
+    {
+        List<String> experimentPermIDs = getExperimentPermIDs(sessionToken, dataSetIdentifiers);
+        for (String experimentPermID : experimentPermIDs)
+        {
+            if (ScreeningConstants.MERGED_CHANNELS.equals(channel))
+            {
+                if (operationLog.isInfoEnabled())
+                {
+                    operationLog.info("save image transformer factory " + transformerFactory
+                            + " for experiment " + experimentPermID);
+                }
+                transformerDAO
+                .saveTransformerFactoryForExperiment(experimentPermID, transformerFactory);
+            } else
+            {
+                if (operationLog.isInfoEnabled())
+                {
+                    operationLog
+                    .info("save image transformer factory " + transformerFactory
+                            + " for experiment " + experimentPermID + " and channel '"
+                            + channel + "'.");
+                }
+                transformerDAO.saveTransformerFactoryForChannel(experimentPermID, channel,
+                        transformerFactory);
+            }
+        }
+        transformerDAO.commit();
+    }
+    
+    public IImageTransformerFactory getImageTransformerFactory(String sessionToken,
+            List<IDatasetIdentifier> dataSetIdentifiers, String channel)
+    {
+        List<String> experimentPermIDs = getExperimentPermIDs(sessionToken, dataSetIdentifiers);
+        if (experimentPermIDs.isEmpty())
+        {
+            throw new UserFailureException("No data set identifers specified.");
+        }
+        if (experimentPermIDs.size() > 1)
+        {
+            throw new UserFailureException("All data sets have to belong to the same experiment: "
+                    + dataSetIdentifiers);
+        }
+        String experimentPermID = experimentPermIDs.get(0);
+        if (ScreeningConstants.MERGED_CHANNELS.equals(channel))
+        {
+            return getDAO().tryGetExperimentByPermId(experimentPermID).getImageTransformerFactory();
+        }
+        return getDAO().tryGetChannelByChannelCodeAndExperimentPermId(experimentPermID, channel)
+                .getImageTransformerFactory();
+    }
+
+    private List<String> getExperimentPermIDs(String sessionToken,
+            List<IDatasetIdentifier> dataSetIdentifiers)
+    {
+        List<String> experimentPermIDs = new ArrayList<String>();
+        for (IDatasetIdentifier dataSetIdentifier : dataSetIdentifiers)
+        {
+            ExternalData dataSet =
+                getOpenBISService().tryGetDataSet(sessionToken, dataSetIdentifier.getDatasetCode());
+            if (dataSet == null)
+            {
+                throw new UserFailureException("Unkown data set " + dataSetIdentifier);
+            }
+            experimentPermIDs.add(dataSet.getExperiment().getPermId());
+        }
+        return experimentPermIDs;
+    }
 
     private List<PlateImageReference> createPlateImageReferences(
             IHCSImageDatasetLoader imageAccessor, IDatasetIdentifier dataSetIdentifier,
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/shared/api/v1/IDssServiceRpcScreening.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/shared/api/v1/IDssServiceRpcScreening.java
index bb1395d28636340ee0eb52f66896e8f74ed489ad..b9bd891562c70428bfd43823e647265d3d692a32 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/shared/api/v1/IDssServiceRpcScreening.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/shared/api/v1/IDssServiceRpcScreening.java
@@ -19,6 +19,7 @@ package ch.systemsx.cisd.openbis.dss.screening.shared.api.v1;
 import java.io.InputStream;
 import java.util.List;
 
+import ch.systemsx.cisd.base.image.IImageTransformerFactory;
 import ch.systemsx.cisd.common.api.IRpcService;
 import ch.systemsx.cisd.common.api.MinimalMinorVersion;
 import ch.systemsx.cisd.openbis.dss.generic.shared.api.authorization.AuthorizationGuard;
@@ -166,7 +167,21 @@ public interface IDssServiceRpcScreening extends IRpcService
             String sessionToken,
             @AuthorizationGuard(guardClass = SingleDataSetIdentifierPredicate.class) IDatasetIdentifier dataSetIdentifier,
             List<WellPosition> wellPositions, String channel, ImageSize thumbnailSizeOrNull);
+    
+    @MinimalMinorVersion(4)
+    @DataSetAccessGuard
+    public void saveImageTransformerFactory(
+            String sessionToken,
+            @AuthorizationGuard(guardClass = DatasetIdentifierPredicate.class) List<IDatasetIdentifier> dataSetIdentifiers,
+            String channel, IImageTransformerFactory transformerFactory);
 
+    @MinimalMinorVersion(4)
+    @DataSetAccessGuard
+    public IImageTransformerFactory getImageTransformerFactory(
+            String sessionToken,
+            @AuthorizationGuard(guardClass = DatasetIdentifierPredicate.class) List<IDatasetIdentifier> dataSetIdentifiers,
+            String channel);
+    
     /**
      * For a given set of image data sets, provide all image channels that have been acquired and
      * the available (natural) image size(s).
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/shared/DssScreeningUtils.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/shared/DssScreeningUtils.java
index 325a99a7c663e1244e8224e9c6379df398fa00d5..3eae016990a9e80953b8adb21da3edf07b5d9081 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/shared/DssScreeningUtils.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/shared/DssScreeningUtils.java
@@ -32,7 +32,7 @@ import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.IImag
 public class DssScreeningUtils
 {
     private static final IImagingReadonlyQueryDAO query = createQuery();
-
+    
     public static IImagingReadonlyQueryDAO getQuery()
     {
         return query;
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/api/v1/ExampleImageTransformerFactory.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/api/v1/ExampleImageTransformerFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..bbe6c0d9dc58b1ba2fcbdd1b63cbdf09ff0896c2
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/api/v1/ExampleImageTransformerFactory.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2010 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.client.api.v1;
+
+import java.awt.image.BufferedImage;
+
+import ch.systemsx.cisd.base.image.IImageTransformer;
+import ch.systemsx.cisd.base.image.IImageTransformerFactory;
+
+/**
+ * 
+ *
+ * @author Franz-Josef Elmer
+ */
+public class ExampleImageTransformerFactory implements IImageTransformerFactory
+{
+    private static final long serialVersionUID = 1L;
+    
+    private final int indexOfRed;
+    private final int indexOfGreen;
+    private final int indexOfBlue;
+    
+    public ExampleImageTransformerFactory(String colorPattern)
+    {
+        indexOfRed = colorPattern.indexOf('r');
+        indexOfGreen = colorPattern.indexOf('g');
+        indexOfBlue = colorPattern.indexOf('b');
+    }
+    
+    public IImageTransformer createTransformer()
+    {
+        return new IImageTransformer()
+            {
+                public BufferedImage transform(BufferedImage input)
+                {
+                    int width = input.getWidth();
+                    int height = input.getHeight();
+                    BufferedImage output = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
+                    for (int x = 0; x < width; x++)
+                    {
+                        for (int y = 0; y < height; y++)
+                        {
+                            int rgb = input.getRGB(x, y);
+                            int blue = (rgb >> 16) & 0xff;
+                            int green = (rgb >> 8) & 0xff;
+                            int red = rgb & 0xff;
+                            output.setRGB(x, y, shift(red, indexOfRed) + shift(green, indexOfGreen)
+                                    + shift(blue, indexOfBlue));
+                        }
+                    }
+                    return output;
+                }
+            };
+    }
+    
+    private int shift(int color, int position)
+    {
+        return color << (8 * (2 - position));
+    }
+
+    @Override
+    public String toString()
+    {
+        return getClass().getSimpleName() + "[" + indexOfRed + "." + indexOfGreen + "." + indexOfBlue + "]";
+    }
+
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/api/v1/IScreeningOpenbisServiceFacade.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/api/v1/IScreeningOpenbisServiceFacade.java
index 2cb44013e12003fa2d9e1b44d547ad3a7710b0ff..8731c64f3fe508c656acf95b48a8e2452592ac32 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/api/v1/IScreeningOpenbisServiceFacade.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/api/v1/IScreeningOpenbisServiceFacade.java
@@ -19,6 +19,7 @@ package ch.systemsx.cisd.openbis.plugin.screening.client.api.v1;
 import java.io.IOException;
 import java.util.List;
 
+import ch.systemsx.cisd.base.image.IImageTransformerFactory;
 import ch.systemsx.cisd.openbis.plugin.screening.client.api.v1.ScreeningOpenbisServiceFacade.IImageOutputStreamProvider;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.ExperimentIdentifier;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.FeatureVectorDataset;
@@ -263,6 +264,22 @@ public interface IScreeningOpenbisServiceFacade
     public List<byte[]> loadImages(IDatasetIdentifier dataSetIdentifier,
             List<WellPosition> wellPositions, String channel, ImageSize thumbnailSizeOrNull)
             throws IOException;
+    
+    /**
+     * Saves the specified transformer factory for the specified channel and the experiment to
+     * which the specified data sets belong.
+     */
+    public void saveImageTransformerFactory(List<IDatasetIdentifier> dataSetIdentifiers, String channel,
+            IImageTransformerFactory transformerFactory);
+
+    /**
+     * Returns the transformer factory for the specified channel and the experiment to which
+     * the specified data sets belong.
+     * 
+     * @return <code>null</code> if such a factory has been defined yet.
+     */
+    public IImageTransformerFactory getImageTransformerFactoryOrNull(
+            List<IDatasetIdentifier> dataSetIdentifiers, String channel);
 
     /**
      * For a given set of image data sets, provide all image channels that have been acquired and
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/api/v1/ImageViewer.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/api/v1/ImageViewer.java
index a9ecceeef0ab053c18575f17c432c9be156d4c75..526ed5b8b9f3443edd31fd0c67e585f1cde02600 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/api/v1/ImageViewer.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/api/v1/ImageViewer.java
@@ -18,7 +18,6 @@ package ch.systemsx.cisd.openbis.plugin.screening.client.api.v1;
 
 import java.awt.Container;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -29,8 +28,7 @@ import javax.swing.JFrame;
 import javax.swing.JLabel;
 import javax.swing.JPanel;
 
-import org.apache.commons.lang.StringUtils;
-
+import ch.systemsx.cisd.base.image.IImageTransformerFactory;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.DataSetCodeAndWellPositions;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.IDatasetIdentifier;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.ImageSize;
@@ -44,15 +42,14 @@ import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.WellPosition;
  */
 public class ImageViewer
 {
-    public static void main(String[] args)
+    public static void main(String[] args) throws Exception
     {
         String serviceURL = args[0];
         String sessionToken = args[1];
-        long experimentID = Long.parseLong(args[2]);
-        String channel = args[3];
+        String channel = args[2];
         Map<String, DataSetCodeAndWellPositions> dataSets =
                 new HashMap<String, DataSetCodeAndWellPositions>();
-        for (int i = 4; i < args.length; i++)
+        for (int i = 3; i < args.length; i++)
         {
             DataSetCodeAndWellPositions dw = new DataSetCodeAndWellPositions(args[i]);
             dataSets.put(dw.getDataSetCode(), dw);
@@ -69,9 +66,9 @@ public class ImageViewer
         {
             IScreeningOpenbisServiceFacade facade =
                     ScreeningOpenbisServiceFacadeFactory.tryCreate(sessionToken, serviceURL);
-            List<IDatasetIdentifier> dsIdentifier =
+            List<IDatasetIdentifier> dsIdentifiers =
                     facade.getDatasetIdentifiers(new ArrayList<String>(dataSets.keySet()));
-            for (IDatasetIdentifier identifier : dsIdentifier)
+            for (IDatasetIdentifier identifier : dsIdentifiers)
             {
                 content.add(new JLabel("Images for data set " + identifier.getDatasetCode()));
                 JPanel imagePanel = new JPanel();
@@ -86,9 +83,14 @@ public class ImageViewer
                     imagePanel.add(new JLabel(new ImageIcon(bytes)));
                 }
             }
+            String pattern = channel.equals("Merged Channels") ? "brg" : "gbr";
+            facade.saveImageTransformerFactory(dsIdentifiers, channel, new ExampleImageTransformerFactory(pattern));
+            IImageTransformerFactory factory = facade.getImageTransformerFactoryOrNull(dsIdentifiers, channel);
+            System.out.println("Image Transformer Factory: " + factory);
         } catch (Exception ex)
         {
             content.add(new JLabel(ex.toString()));
+            throw ex;
         }
         
         frame.pack();
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/api/v1/ScreeningOpenbisServiceFacade.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/api/v1/ScreeningOpenbisServiceFacade.java
index 47ccad7a181a161f110f71ed7b9ee2d1a6000adc..cc19b2ba29628c7a2e04cda2c143ba7f513e52aa 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/api/v1/ScreeningOpenbisServiceFacade.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/api/v1/ScreeningOpenbisServiceFacade.java
@@ -14,6 +14,7 @@ import java.util.Map;
 import java.util.Set;
 import java.util.Map.Entry;
 
+import ch.systemsx.cisd.base.image.IImageTransformerFactory;
 import ch.systemsx.cisd.common.api.MinimalMinorVersion;
 import ch.systemsx.cisd.common.api.client.ServiceFinder;
 import ch.systemsx.cisd.common.io.ConcatenatedFileOutputStreamWriter;
@@ -565,6 +566,26 @@ public class ScreeningOpenbisServiceFacade implements IScreeningOpenbisServiceFa
         return result;
     }
 
+    public void saveImageTransformerFactory(List<IDatasetIdentifier> dataSetIdentifiers, String channel,
+            IImageTransformerFactory transformerFactory)
+    {
+        Map<String, List<IDatasetIdentifier>> map = getReferencesPerDss(dataSetIdentifiers);
+        Set<Entry<String, List<IDatasetIdentifier>>> entrySet = map.entrySet();
+        for (Entry<String, List<IDatasetIdentifier>> entry : entrySet)
+        {
+            String serverUrl = entry.getKey();
+            IDssServiceRpcScreening service = dssServiceCache.createDssService(serverUrl).getService();
+            service.saveImageTransformerFactory(sessionToken, entry.getValue(), channel, transformerFactory);
+        }
+    }
+
+    public IImageTransformerFactory getImageTransformerFactoryOrNull(
+            List<IDatasetIdentifier> dataSetIdentifiers, String channel)
+    {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
     /**
      * For a given set of image data sets, provide all image channels that have been acquired and
      * the available (natural) image size(s).
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/WellContentDialog.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/WellContentDialog.java
index 79c2c12c819b723208b12e9e5e06c2ab733678c7..8e042e4cc8f936977edd0a7cba6b5ca21557a944 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/WellContentDialog.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/WellContentDialog.java
@@ -412,8 +412,6 @@ public class WellContentDialog extends Dialog
                                                 viewContext.getModel().getSessionContext()
                                                         .getSessionID();
                                         urlParams.addParameter("session", sessionToken);
-                                        urlParams.addParameter(ParameterNames.EXPERIMENT_ID,
-                                                experimentCriteria.getExperimentId());
                                         if (selectionProvider != null)
                                         {
                                             urlParams.addParameter(ParameterNames.CHANNEL, selectionProvider
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/server/ImageViewerLaunchServlet.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/server/ImageViewerLaunchServlet.java
index 03ae3ba93779d5fb99947b717819a050719c1c9f..4b0890f015337e8ee0c8a45195f751cee7d01865 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/server/ImageViewerLaunchServlet.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/server/ImageViewerLaunchServlet.java
@@ -86,7 +86,6 @@ public class ImageViewerLaunchServlet extends AbstractServlet
                         + "  <application-desc main-class='${main-class}'>\n"
                         + "    <argument>${service-URL}</argument>\n"
                         + "    <argument>${session-id}</argument>\n"
-                        + "    <argument>${experiment-id}</argument>\n"
                         + "    <argument>${channel}</argument>\n"
                         + "${data-set-and-wells-arguments}\n"
                         + "  </application-desc>\n" + "</jnlp>\n");
@@ -114,7 +113,6 @@ public class ImageViewerLaunchServlet extends AbstractServlet
             template.bind("main-class", getMainClass());
             template.bind("service-URL", basicURL);
             template.bind("session-id", getSessionToken(request));
-            template.bind("experiment-id", getParam(request, ParameterNames.EXPERIMENT_ID));
             template.bind("channel", getParam(request, ParameterNames.CHANNEL));
             StringBuilder builder = new StringBuilder();
             for (String dataSetAndWells : getParams(request, ParameterNames.DATA_SET_AND_WELLS))
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/dataaccess/AbstractImageTransformerFactoryHolder.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/dataaccess/AbstractImageTransformerFactoryHolder.java
new file mode 100644
index 0000000000000000000000000000000000000000..c93bc26675043cc8bcc717b98b24cc401838164b
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/dataaccess/AbstractImageTransformerFactoryHolder.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2010 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 org.apache.commons.lang.SerializationUtils;
+
+import net.lemnik.eodsql.ResultColumn;
+
+import ch.systemsx.cisd.base.image.IImageTransformerFactory;
+import ch.systemsx.cisd.common.utilities.AbstractHashable;
+
+/**
+ * 
+ *
+ * @author Franz-Josef Elmer
+ */
+abstract class AbstractImageTransformerFactoryHolder extends AbstractHashable
+{
+    @ResultColumn("IMAGE_TRANSFORMER_FACTORY")
+    private byte[] serializedImageTransformerFactory;
+
+    public final byte[] getSerializedImageTransformerFactory()
+    {
+        return serializedImageTransformerFactory;
+    }
+
+    public final void setSerializedImageTransformerFactory(byte[] serializedImageTransformerFactory)
+    {
+        this.serializedImageTransformerFactory = serializedImageTransformerFactory;
+    }
+    
+    public IImageTransformerFactory getImageTransformerFactory()
+    {
+        if (serializedImageTransformerFactory == null)
+        {
+            return null;
+        }
+        return (IImageTransformerFactory) SerializationUtils.deserialize(serializedImageTransformerFactory);
+    }
+
+}
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 2e7b6ba7b7b0151f62a492c63fb4928b81322fb2..7e59b00c86bbcb049975715dc627776fec55ec45 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
@@ -89,9 +89,12 @@ public interface IImagingReadonlyQueryDAO extends BaseQuery
 
     // simple getters
 
-    @Select("select ID from EXPERIMENTS where PERM_ID = ?{1}")
-    public Long tryGetExperimentIdByPermId(String experimentPermId);
+    @Select("select * from EXPERIMENTS where PERM_ID = ?{1}")
+    public ImgExperimentDTO tryGetExperimentByPermId(String experimentPermId);
 
+    @Select("select * from EXPERIMENTS where ID = ?{1}")
+    public ImgExperimentDTO tryGetExperimentById(long experimentId);
+    
     @Select("select ID from CONTAINERS where PERM_ID = ?{1}")
     public Long tryGetContainerIdPermId(String containerPermId);
 
@@ -127,8 +130,13 @@ public interface IImagingReadonlyQueryDAO extends BaseQuery
     @Select(sql = "select * from FEATURE_VALUES where FD_ID = ?{1.id} order by T_in_SEC, Z_in_M", resultSetBinding = FeatureVectorDataObjectBinding.class)
     public List<ImgFeatureValuesDTO> getFeatureValues(ImgFeatureDefDTO featureDef);
 
-    @Select("select ID from CHANNELS where (DS_ID = ?{1} or EXP_ID = ?{2}) and CODE = upper(?{3})")
-    public Long tryGetChannelIdByChannelCodeDatasetIdOrExperimentId(long id, long experimentId,
+    @Select("select * from CHANNELS where (DS_ID = ?{1} or EXP_ID = ?{2}) and CODE = upper(?{3})")
+    public ImgChannelDTO tryGetChannelByChannelCodeDatasetIdOrExperimentId(long id, long experimentId,
             String chosenChannelCode);
-
+    
+    @Select("select * from channels where code = ?{2} and "
+            + "exp_id in (select id from experiments where perm_id = ?{1})")
+    public ImgChannelDTO tryGetChannelByChannelCodeAndExperimentPermId(String experimentPermId,
+            String chosenChannelCode);
+    
 }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/dataaccess/IImagingTransformerDAO.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/dataaccess/IImagingTransformerDAO.java
new file mode 100644
index 0000000000000000000000000000000000000000..fdb0e86cbe15c9ce953463da47565fef1d848886
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/dataaccess/IImagingTransformerDAO.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2010 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.TransactionQuery;
+import net.lemnik.eodsql.TypeMapper;
+import net.lemnik.eodsql.Update;
+
+import ch.systemsx.cisd.base.image.IImageTransformerFactory;
+
+/**
+ * 
+ *
+ * @author Franz-Josef Elmer
+ */
+public interface IImagingTransformerDAO extends TransactionQuery
+{
+    @Update(sql = "update experiments set image_transformer_factory = ?{2} where perm_id = ?{1}", parameterBindings =
+        { TransformerFactoryMapper.class, TypeMapper.class/* default */  })
+    public void saveTransformerFactoryForExperiment(String experimentPermID,
+            IImageTransformerFactory factory);
+    
+    @Update(sql = "update channels set image_transformer_factory = ?{3} "
+            + "where code = ?{2} and exp_id in (select id from experiments where perm_id = ?{1})", parameterBindings =
+        { TransformerFactoryMapper.class, TypeMapper.class/* default */, TypeMapper.class /* default */ })
+    public void saveTransformerFactoryForChannel(String experimentPermID, String channel,
+            IImageTransformerFactory factory);
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/dataaccess/ImgChannelDTO.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/dataaccess/ImgChannelDTO.java
index 0072348e2b147f3cf0b72817ed59e82666d48a83..dc9a6216900861ae79c6dc88bf1a724f98f6224f 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/dataaccess/ImgChannelDTO.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/dataaccess/ImgChannelDTO.java
@@ -19,12 +19,10 @@ package ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess;
 import net.lemnik.eodsql.AutoGeneratedKeys;
 import net.lemnik.eodsql.ResultColumn;
 
-import ch.systemsx.cisd.common.utilities.AbstractHashable;
-
 /**
  * @author Tomasz Pylak
  */
-public class ImgChannelDTO extends AbstractHashable
+public class ImgChannelDTO extends AbstractImageTransformerFactoryHolder
 {
     @AutoGeneratedKeys
     private long id;
@@ -48,7 +46,7 @@ public class ImgChannelDTO extends AbstractHashable
     // can be null if datasetId is not null
     @ResultColumn("EXP_ID")
     private Long experimentIdOrNull;
-
+    
     public static ImgChannelDTO createDatasetChannel(String code, String descriptionOrNull,
             Integer wavelengthOrNull, long datasetId, String label)
     {
@@ -151,4 +149,5 @@ public class ImgChannelDTO extends AbstractHashable
         this.experimentIdOrNull = experimentId;
     }
 
+
 }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/dataaccess/ImgExperimentDTO.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/dataaccess/ImgExperimentDTO.java
new file mode 100644
index 0000000000000000000000000000000000000000..c7c24ff4d96f91731ebc08d7a8819000eff65782
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/dataaccess/ImgExperimentDTO.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2010 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.AutoGeneratedKeys;
+import net.lemnik.eodsql.ResultColumn;
+
+/**
+ * 
+ *
+ * @author Franz-Josef Elmer
+ */
+public class ImgExperimentDTO extends AbstractImageTransformerFactoryHolder
+{
+    @AutoGeneratedKeys
+    private long id;
+
+    @ResultColumn("PERM_ID")
+    private String permId;
+
+    public long getId()
+    {
+        return id;
+    }
+
+    public void setId(long id)
+    {
+        this.id = id;
+    }
+
+    public String getPermId()
+    {
+        return permId;
+    }
+
+    public void setPermId(String permId)
+    {
+        this.permId = permId;
+    }
+
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/dataaccess/TransformerFactoryMapper.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/dataaccess/TransformerFactoryMapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..88dbf938cb41bac1c2b86a42b6eafef0dc3c9709
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/dataaccess/TransformerFactoryMapper.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2010 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 java.io.Serializable;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import ch.systemsx.cisd.base.image.IImageTransformerFactory;
+import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.SerializableObjectMapper;
+
+import net.lemnik.eodsql.TypeMapper;
+
+/**
+ * 
+ *
+ * @author Franz-Josef Elmer
+ */
+public class TransformerFactoryMapper implements TypeMapper<IImageTransformerFactory>
+{
+    private final TypeMapper<Serializable> serializableObjectMapper = new SerializableObjectMapper();
+
+    public IImageTransformerFactory get(ResultSet results, int column) throws SQLException
+    {
+        return (IImageTransformerFactory) serializableObjectMapper.get(results, column);
+    }
+
+    public void set(ResultSet results, int column, IImageTransformerFactory obj)
+            throws SQLException
+    {
+        serializableObjectMapper.set(results, column, obj);
+    }
+
+    public void set(PreparedStatement statement, int column, IImageTransformerFactory obj)
+            throws SQLException
+    {
+        serializableObjectMapper.set(statement, column, obj);
+    }
+
+}
diff --git a/screening/source/sql/postgresql/007/schema-007.sql b/screening/source/sql/postgresql/007/schema-007.sql
index 84614f313a73e15e7bdb082b0dcf4a39d709b5e1..2c2af9c2a051c8f17ff33229f64184a67653fd61 100644
--- a/screening/source/sql/postgresql/007/schema-007.sql
+++ b/screening/source/sql/postgresql/007/schema-007.sql
@@ -24,7 +24,7 @@ CREATE DOMAIN BOOLEAN_CHAR AS BOOLEAN DEFAULT FALSE;
 CREATE TABLE EXPERIMENTS (
   ID BIGSERIAL NOT NULL,
   PERM_ID CODE NOT NULL,
-  IMAGE_TRANSFORMATION_FACTORY BYTEA,
+  IMAGE_TRANSFORMER_FACTORY BYTEA,
 
   PRIMARY KEY (ID),
   UNIQUE (PERM_ID)
@@ -87,7 +87,7 @@ CREATE TABLE CHANNELS (
     LABEL NAME NOT NULL,
     DESCRIPTION DESCRIPTION,
     WAVELENGTH INTEGER,
-    IMAGE_TRANSFORMATION_FACTORY BYTEA,
+    IMAGE_TRANSFORMER_FACTORY BYTEA,
 
     DS_ID TECH_ID,
     EXP_ID TECH_ID,
diff --git a/screening/source/sql/postgresql/migration/migration-006-007.sql b/screening/source/sql/postgresql/migration/migration-006-007.sql
index 4ea38cfa3d65dfa3db65d51e8f1c15b42bdda7ab..d555348bc3ef43089a6251f9243d9c029bd02e7b 100644
--- a/screening/source/sql/postgresql/migration/migration-006-007.sql
+++ b/screening/source/sql/postgresql/migration/migration-006-007.sql
@@ -1,4 +1,4 @@
 -- Migration from 006 to 007
 
-ALTER TABLE CHANNELS ADD COLUMN IMAGE_TRANSFORMATION_FACTORY BYTEA;
-ALTER TABLE EXPERIMENTS ADD COLUMN IMAGE_TRANSFORMATION_FACTORY BYTEA,
+ALTER TABLE CHANNELS ADD COLUMN IMAGE_TRANSFORMER_FACTORY BYTEA;
+ALTER TABLE EXPERIMENTS ADD COLUMN IMAGE_TRANSFORMER_FACTORY BYTEA;
diff --git a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/dataaccess/ImagingQueryDAOTest.java b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/dataaccess/ImagingQueryDAOTest.java
index 3f4539f4e48242955d5aca9863469b69af354eca..a01629d43d027a6466ad8d225df3d41a476864be 100644
--- a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/dataaccess/ImagingQueryDAOTest.java
+++ b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/dataaccess/ImagingQueryDAOTest.java
@@ -191,8 +191,8 @@ public class ImagingQueryDAOTest extends AbstractDBTest
         // test get id of first channel
         assertEquals(
                 channels.get(0).getId(),
-                dao.tryGetChannelIdByChannelCodeDatasetIdOrExperimentId(datasetId, experimentId,
-                        "dsChannel").intValue());
+                dao.tryGetChannelByChannelCodeDatasetIdOrExperimentId(datasetId, experimentId,
+                        "dsChannel").getId());
 
         List<ImgChannelDTO> experimentChannels = dao.getChannelsByExperimentId(experimentId);
         assertEquals(1, experimentChannels.size());
@@ -217,7 +217,7 @@ public class ImagingQueryDAOTest extends AbstractDBTest
         final String permId = EXP_PERM_ID;
         final long experimentId = dao.addExperiment(permId);
 
-        assertEquals(Long.valueOf(experimentId), dao.tryGetExperimentIdByPermId(permId));
+        assertEquals(experimentId, dao.tryGetExperimentByPermId(permId).getId());
 
         return experimentId;
     }
diff --git a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/genedata/FeatureStorageProcessorTest.java b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/genedata/FeatureStorageProcessorTest.java
index dfddca565e7280a29d7dd1cbdba540c602c284a7..9a6297cb4890f2d689a47379a33fca6c4729cfdd 100644
--- a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/genedata/FeatureStorageProcessorTest.java
+++ b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/genedata/FeatureStorageProcessorTest.java
@@ -43,6 +43,7 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.PropertyType;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.dto.PlateDimensionParser;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ImgDatasetDTO;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ImgExperimentDTO;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ImgFeatureDefDTO;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ImgFeatureValuesDTO;
 
@@ -84,8 +85,10 @@ public class FeatureStorageProcessorTest extends AbstractFileSystemTestCase
         context.checking(new Expectations()
             {
                 {
-                    one(dao).tryGetExperimentIdByPermId(EXPERIMENT_PERM_ID);
-                    will(returnValue((long) 1));
+                    one(dao).tryGetExperimentByPermId(EXPERIMENT_PERM_ID);
+                    ImgExperimentDTO exp = new ImgExperimentDTO();
+                    exp.setId(1);
+                    will(returnValue(exp));
 
                     one(dao).tryGetContainerIdPermId(CONTAINER_PERM_ID);
                     will(returnValue((long) 1));
diff --git a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/screening/server/DssServiceRpcScreeningTest.java b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/screening/server/DssServiceRpcScreeningTest.java
index 1dcd92e90d7b98279e9f2ec5f3ad0311ba5963b6..1fc67af76c5ba43ecf1d9134bb081f877c0e1dc3 100644
--- a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/screening/server/DssServiceRpcScreeningTest.java
+++ b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/screening/server/DssServiceRpcScreeningTest.java
@@ -44,6 +44,7 @@ import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.FeatureVector
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.IFeatureVectorDatasetIdentifier;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.dto.PlateFeatureValues;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.IImagingReadonlyQueryDAO;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.IImagingTransformerDAO;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ImgContainerDTO;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ImgDatasetDTO;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ImgFeatureDefDTO;
@@ -70,16 +71,19 @@ public class DssServiceRpcScreeningTest extends AssertJUnit
 
     private DssServiceRpcScreening screeningService;
 
+    private IImagingTransformerDAO transformerDAO;
+
     @BeforeMethod
     public void beforeMethod()
     {
         context = new Mockery();
         service = context.mock(IEncapsulatedOpenBISService.class);
         dao = context.mock(IImagingReadonlyQueryDAO.class);
+        transformerDAO = context.mock(IImagingTransformerDAO.class);
         featureVectorDatasetIdentifier1 = create("ds1");
         featureVectorDatasetIdentifier2 = create("ds2");
 
-        screeningService = new DssServiceRpcScreening("targets", dao, service, false);
+        screeningService = new DssServiceRpcScreening("targets", dao, transformerDAO, service, false);
     }
 
     private IFeatureVectorDatasetIdentifier create(final String dataSetCode)