diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/transformations/AutoRescaleIntensityImageTransformerFactory.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/transformations/AutoRescaleIntensityImageTransformerFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..06e0c6acbcd8962aa4aac6173b78c5d7f25323b1
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/transformations/AutoRescaleIntensityImageTransformerFactory.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2011 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.transformations;
+
+import java.awt.image.BufferedImage;
+
+import ch.systemsx.cisd.base.image.IImageTransformer;
+import ch.systemsx.cisd.base.image.IImageTransformerFactory;
+import ch.systemsx.cisd.common.image.IntensityRescaling;
+import ch.systemsx.cisd.common.image.IntensityRescaling.Levels;
+
+/**
+ * Transformation performed by
+ * {@link IntensityRescaling#rescaleIntensityLevelTo8Bits(BufferedImage, Levels)} where levels are
+ * computed automatically by {@link IntensityRescaling#computeLevels(BufferedImage, float)}.
+ * <p>
+ * Warning: The serialized version of this class can be stored in the database for each image.
+ * Moving this class to a different package or changing it in a backward incompatible way would make
+ * all the saved transformations invalid.
+ * 
+ * @author Tomasz Pylak
+ */
+public class AutoRescaleIntensityImageTransformerFactory implements IImageTransformerFactory
+{
+    private static final long serialVersionUID = 1L;
+
+    private final float threshold;
+
+    public AutoRescaleIntensityImageTransformerFactory(float threshold)
+    {
+        this.threshold = threshold;
+    }
+
+    public IImageTransformer createTransformer()
+    {
+        return new IImageTransformer()
+            {
+                public BufferedImage transform(BufferedImage image)
+                {
+                    Levels levels = IntensityRescaling.computeLevels(image, threshold);
+                    return IntensityRescaling.rescaleIntensityLevelTo8Bits(image, levels);
+                }
+            };
+    }
+
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/transformations/BitShiftingImageTransformerFactory.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/transformations/BitShiftingImageTransformerFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..b036a1046c514669f92d78da0a47b594bb40781d
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/transformations/BitShiftingImageTransformerFactory.java
@@ -0,0 +1,40 @@
+package ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.transformations;
+
+import java.awt.image.BufferedImage;
+
+import ch.systemsx.cisd.base.image.IImageTransformer;
+import ch.systemsx.cisd.base.image.IImageTransformerFactory;
+import ch.systemsx.cisd.common.image.IntensityRescaling;
+
+/**
+ * Transformation performed by
+ * {@link IntensityRescaling#rescaleIntensityBitShiftTo8Bits(java.awt.image.BufferedImage, int)}
+ * <p>
+ * Warning: The serialized version of this class can be stored in the database for each image.
+ * Moving this class to a different package or changing it in a backward incompatible way would make
+ * all the saved transformations invalid.
+ * 
+ * @author Tomasz Pylak
+ */
+final class BitShiftingImageTransformerFactory implements IImageTransformerFactory
+{
+    private static final long serialVersionUID = 1L;
+
+    private final int shiftBits;
+
+    public BitShiftingImageTransformerFactory(int shiftBits)
+    {
+        this.shiftBits = shiftBits;
+    }
+
+    public IImageTransformer createTransformer()
+    {
+        return new IImageTransformer()
+            {
+                public BufferedImage transform(BufferedImage image)
+                {
+                    return IntensityRescaling.rescaleIntensityBitShiftTo8Bits(image, shiftBits);
+                }
+            };
+    }
+}
\ No newline at end of file
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/transformations/ImageTransformationBuffer.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/transformations/ImageTransformationBuffer.java
new file mode 100644
index 0000000000000000000000000000000000000000..75edc13c1b6cf2bb88162f79d0b84f7b8989b84e
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/transformations/ImageTransformationBuffer.java
@@ -0,0 +1,395 @@
+/*
+ * Copyright 2011 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.transformations;
+
+import java.text.DecimalFormat;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import ch.systemsx.cisd.base.image.IImageTransformerFactory;
+import ch.systemsx.cisd.common.shared.basic.utils.StringUtils;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ImageTransformation;
+
+/**
+ * Utility class to construct various kinds of image transformations.
+ * 
+ * @author Tomasz Pylak
+ */
+public class ImageTransformationBuffer
+{
+    private static final String PREDEFINED_TRANSFORMATIONS_CODE_PREFIX = "PREDEFINED_";
+
+    private final List<ImageTransformation> imageTransformations;
+
+    private final Set<String> usedTransformationCodes;
+
+    public ImageTransformationBuffer()
+    {
+        this.imageTransformations = new ArrayList<ImageTransformation>();
+        this.usedTransformationCodes = new HashSet<String>();
+    }
+
+    /**
+     * Appends any specified transformation. Note that code of each added transformation should be
+     * unique.
+     */
+    public void append(ImageTransformation transformation)
+    {
+        String newCode = transformation.getCode();
+        if (usedTransformationCodes.contains(newCode))
+        {
+            throw new IllegalArgumentException("Two transformations have the same code: " + newCode);
+        }
+        usedTransformationCodes.add(newCode);
+        imageTransformations.add(transformation);
+    }
+
+    /** @returns all appended transformations */
+    public ImageTransformation[] getTransformations()
+    {
+        return imageTransformations.toArray(new ImageTransformation[imageTransformations.size()]);
+    }
+
+    // -------------- bit shifting transformations ---------------------
+
+    /**
+     * Appends transformations which extracts a range of grayscale image colors by choosing 8
+     * consecutive bits. All shifts which make sense for 12 bit images will be appended (from 0 to
+     * 4).
+     */
+    public void appendAllBitShiftsFor12Bit()
+    {
+        appendAllAvailableBitShifts(12);
+    }
+
+    /**
+     * Appends transformations which extracts a range of grayscale image colors by choosing 8
+     * consecutive bits. All shifts which make sense for 16 bit images will be appended (from 0 to
+     * 8).
+     */
+    public void appendAllBitShiftsFor16Bit()
+    {
+        appendAllAvailableBitShifts(16);
+    }
+
+    private void appendAllAvailableBitShifts(int totalNumberOfBits)
+    {
+        for (int i = 0; i <= (totalNumberOfBits - 8); i++)
+        {
+            appendBitShiftingTransformation(i);
+        }
+    }
+
+    /**
+     * Appends transformation which extracts a range of grayscale image colors by choosing 8
+     * consecutive bits starting from the specified one.
+     */
+    public void appendBitShiftingTransformation(int shiftBits)
+    {
+        append(createBitShifting(shiftBits));
+    }
+
+    /**
+     * Creates a transformation which extracts a range of grayscale image colors by choosing 8
+     * consecutive bits, staring from the specified one.
+     * <p>
+     * This method is useful when one wants to modify the default code, label or description
+     * afterwards.
+     */
+    public static ImageTransformation createBitShifting(int shiftBits)
+    {
+        if (shiftBits < 0)
+        {
+            throw new IllegalArgumentException(
+                    "Cannot create an image transformation which shifts by a negative number of bits");
+        }
+        String label = createBitShiftingTransformationLabel(shiftBits);
+        String code = createBitShiftingTransformationCode(shiftBits);
+        String description = createBitShiftingTransformationDescription(shiftBits);
+
+        IImageTransformerFactory factory = new BitShiftingImageTransformerFactory(shiftBits);
+        return new ImageTransformation(code, label, description, factory);
+    }
+
+    private static String createBitShiftingTransformationCode(int shiftBits)
+    {
+        return PREDEFINED_TRANSFORMATIONS_CODE_PREFIX + "BIT_SHIFTING_" + shiftBits;
+    }
+
+    private static String createBitShiftingTransformationDescription(int shiftBits)
+    {
+        return String.format(
+                "Shows a range of grayscale image colors by visualising only 8 consecutive bits from %d to %d. "
+                        + "Useful for extracting information from 12 and 16 bit images.",
+                shiftBits, shiftBits + 7);
+    }
+
+    private static String createBitShiftingTransformationLabel(int shiftBits)
+    {
+        return String.format("Show bits %d-%d", shiftBits, shiftBits + 7);
+    }
+
+    // -----------------------------
+
+    /**
+     * Appends transformation which converts grayscale image pixel intensities from the range
+     * [blackPointIntensity, whitePointIntensity] to 8 bit color depth. Useful to compare images of
+     * higher color depth with each other when they do not use the whole range of available
+     * intensities.
+     */
+    public void appendRescaleIntensityRangeTo8Bits(int blackPointIntensity, int whitePointIntensity)
+    {
+        appendRescaleIntensityRangeTo8Bits(blackPointIntensity, whitePointIntensity, null);
+    }
+
+    /**
+     * See {@link #appendRescaleIntensityRangeTo8Bits(int, int)}.
+     * <p>
+     * Additionally sets the label of the transformation.
+     */
+    public void appendRescaleIntensityRangeTo8Bits(int blackPointIntensity,
+            int whitePointIntensity, String userFriendlyLabelOrNull)
+    {
+        append(createRescaleIntensityRangeTo8Bits(blackPointIntensity, whitePointIntensity,
+                userFriendlyLabelOrNull));
+    }
+
+    /**
+     * Creates a transformation which converts grayscale image pixel intensities from the range
+     * [blackPointIntensity, whitePointIntensity] to 8 bit color depth.
+     * <p>
+     * This method is useful when one wants to modify the default code, label or description
+     * afterwards.
+     * 
+     * @param userFriendlyLabelOrNull label of the transformation. If null a default label is
+     *            assigned.
+     */
+    public static ImageTransformation createRescaleIntensityRangeTo8Bits(int blackPointIntensity,
+            int whitePointIntensity, String userFriendlyLabelOrNull)
+    {
+        if (blackPointIntensity > whitePointIntensity || blackPointIntensity < 0
+                || whitePointIntensity < 0)
+        {
+            throw new IllegalArgumentException(String.format(
+                    "Cannot create an image transformation because the range "
+                            + "of intensities is invalid: [%d, %d]", blackPointIntensity,
+                    whitePointIntensity));
+        }
+        String label = createIntensityRangeTransformationLabel(userFriendlyLabelOrNull);
+        String code =
+                createIntensityRangeTransformationCode(blackPointIntensity, whitePointIntensity);
+        String description =
+                createIntensityRangeTransformationDescription(blackPointIntensity,
+                        whitePointIntensity);
+
+        IImageTransformerFactory factory =
+                new IntensityRangeImageTransformerFactory(blackPointIntensity, whitePointIntensity);
+        return new ImageTransformation(code, label, description, factory);
+    }
+
+    private static String createIntensityRangeTransformationCode(int blackPointIntensity,
+            int whitePointIntensity)
+    {
+        return PREDEFINED_TRANSFORMATIONS_CODE_PREFIX + "INTENSITY_LEVEL_" + blackPointIntensity
+                + "_" + whitePointIntensity;
+    }
+
+    private static String createIntensityRangeTransformationDescription(int blackPointIntensity,
+            int whitePointIntensity)
+    {
+        return String
+                .format("Transforms grayscale image by converting intensities of its pixels "
+                        + "which are in the range [%d, %d] to 8 bit color depth. "
+                        + "The range of intensities is usually calculated by processing a series of 12 or 16 bit images, "
+                        + "then the transformation becomes useful to compare these images with each other in 8 bit color depth, "
+                        + "especially when they use only a small part of available intensities range.",
+                        blackPointIntensity, whitePointIntensity);
+    }
+
+    private static String createIntensityRangeTransformationLabel(String labelOrNull)
+    {
+        return labelOrNull != null ? labelOrNull : "Comparable Autorescaling";
+    }
+
+    // --------------------------
+
+    /**
+     * Appends transformation which converts each single grayscale image to 8 bit color depth and
+     * rescales pixels intensities so that the darkest pixel will become black and the brightest
+     * will become white.
+     */
+    public void appendAutoRescaleIntensityTo8Bits()
+    {
+        appendAutoRescaleIntensityTo8Bits(0, null);
+    }
+
+    /**
+     * See {@link #appendAutoRescaleIntensityTo8Bits()}.
+     * 
+     * @param threshold value form 0 to 1, it specifies the percentage of darkest and brightest
+     *            pixels which will be ignored (they will all become black or white).
+     */
+    public void appendAutoRescaleIntensityTo8Bits(float threshold)
+    {
+        appendAutoRescaleIntensityTo8Bits(threshold, null);
+    }
+
+    /**
+     * See {@link #appendAutoRescaleIntensityTo8Bits(float)}.
+     * <p>
+     * Additionally sets the label of the transformation.
+     */
+    public void appendAutoRescaleIntensityTo8Bits(float threshold, String userFriendlyLabelOrNull)
+    {
+        append(createAutoRescaleIntensityTo8Bits(threshold, userFriendlyLabelOrNull));
+    }
+
+    /**
+     * Creates a transformation which converts each single grayscale image to 8 bit color depth and
+     * rescales pixels intensities so that the darkest pixel will become black and the brightest
+     * will become white (with some threshold margin).
+     * <p>
+     * This method is useful when one wants to modify the default code, label or description
+     * afterwards.
+     * 
+     * @param threshold value form 0 to 1, it specifies the percentage of darkest and brightest
+     *            pixels which will be ignored (they will all become black or white).
+     * @param userFriendlyLabelOrNull label of the transformation. If null a default label is
+     *            assigned.
+     */
+    public static ImageTransformation createAutoRescaleIntensityTo8Bits(float threshold,
+            String userFriendlyLabelOrNull)
+    {
+        if (threshold < 0 || threshold > 1)
+        {
+            throw new IllegalArgumentException(
+                    "Invalid value of the threshold, should be between 0 and 1, but is: "
+                            + threshold);
+        }
+        String label = createAutoRescaleIntensityTransformationLabel(userFriendlyLabelOrNull);
+        String code = createAutoRescaleIntensityTransformationCode(threshold);
+        String description = createAutoRescaleIntensityTransformationDescription(threshold);
+
+        IImageTransformerFactory factory =
+                new AutoRescaleIntensityImageTransformerFactory(threshold);
+        return new ImageTransformation(code, label, description, factory);
+    }
+
+    private static String createAutoRescaleIntensityTransformationCode(float threshold)
+    {
+        return PREDEFINED_TRANSFORMATIONS_CODE_PREFIX + "AUTO_INTENSITY_LEVEL_" + threshold;
+    }
+
+    private static String createAutoRescaleIntensityTransformationDescription(float threshold)
+    {
+        return String
+                .format("Creates a transformation which converts each single grayscale image to 8 bit color depth and "
+                        + "rescales pixels intensities so that the darkest pixel will become black and the brightest "
+                        + "will become white (threshold margin: %s).",
+                        new DecimalFormat("#.###").format(threshold));
+    }
+
+    private static String createAutoRescaleIntensityTransformationLabel(String labelOrNull)
+    {
+        return labelOrNull != null ? labelOrNull : "Autorescaling";
+    }
+
+    // --------------------------
+
+    /**
+     * Allows to transform the images with ImageMagic convert tool (which has to be installed and
+     * accessible). Convert will be called with the specified parameters.
+     */
+    public void appendImageMagicConvertTransformation(String convertCliArguments)
+    {
+        appendImageMagicConvertTransformation(convertCliArguments, null);
+    }
+
+    /**
+     * See {@link #appendImageMagicConvertTransformation(String)}.
+     * <p>
+     * Additionally sets the label of the transformation.
+     */
+    public void appendImageMagicConvertTransformation(String convertCliArguments,
+            String userFriendlyLabelOrNull)
+    {
+        append(createImageMagicConvert(convertCliArguments,
+                generateUniqueConvertTransformationCode(), userFriendlyLabelOrNull));
+    }
+
+    /**
+     * Creates a transformation which converts the images with ImageMagic convert tool.
+     * <p>
+     * This method is useful when one wants to modify the default code, label or description
+     * afterwards.
+     * 
+     * @param userFriendlyLabelOrNull label of the transformation. If null a default label is
+     *            assigned.
+     */
+    public static ImageTransformation createImageMagicConvert(String convertCliArguments,
+            String transformationCode, String userFriendlyLabelOrNull)
+    {
+        if (StringUtils.isBlank(convertCliArguments))
+        {
+            throw new IllegalArgumentException(
+                    "No argument has been specified for the 'convert' command");
+        }
+        if (StringUtils.isBlank(transformationCode))
+        {
+            throw new IllegalArgumentException("Transformation has not been specified");
+        }
+        String label =
+                createImageMagicConvertTransformationLabel(convertCliArguments,
+                        userFriendlyLabelOrNull);
+        String description = createImageMagicConvertTransformationDescription(convertCliArguments);
+
+        IImageTransformerFactory factory =
+                new ConvertToolImageTransformerFactory(convertCliArguments);
+        return new ImageTransformation(transformationCode, label, description, factory);
+    }
+
+    private static String createImageMagicConvertTransformationDescription(
+            String convertCliArguments)
+    {
+        return "Transforms images with ImageMagic 'convert' tool with parameters: "
+                + convertCliArguments;
+    }
+
+    private static String createImageMagicConvertTransformationLabel(String convertCliArguments,
+            String labelOrNull)
+    {
+        return labelOrNull != null ? labelOrNull : String.format("Convert (%s)",
+                convertCliArguments);
+    }
+
+    private String generateUniqueConvertTransformationCode()
+    {
+        int i = 1;
+        while (usedTransformationCodes.contains(getConvertTransformationCode(i)))
+        {
+            i++;
+        }
+        return getConvertTransformationCode(i);
+    }
+
+    private static String getConvertTransformationCode(int seqNumber)
+    {
+        return PREDEFINED_TRANSFORMATIONS_CODE_PREFIX + "CONVERT_" + seqNumber;
+    }
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/transformations/IntensityRangeImageTransformerFactory.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/transformations/IntensityRangeImageTransformerFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..5c3207ddec4f8845856cec621d0cd695ff6226fe
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/transformations/IntensityRangeImageTransformerFactory.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2011 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.transformations;
+
+import java.awt.image.BufferedImage;
+
+import ch.systemsx.cisd.base.image.IImageTransformer;
+import ch.systemsx.cisd.base.image.IImageTransformerFactory;
+import ch.systemsx.cisd.common.image.IntensityRescaling;
+import ch.systemsx.cisd.common.image.IntensityRescaling.Levels;
+
+/**
+ * Transformation performed by
+ * {@link IntensityRescaling#rescaleIntensityLevelTo8Bits(BufferedImage, Levels)}.
+ * <p>
+ * Warning: The serialized version of this class can be stored in the database for each image.
+ * Moving this class to a different package or changing it in a backward incompatible way would make
+ * all the saved transformations invalid.
+ * 
+ * @author Tomasz Pylak
+ */
+public class IntensityRangeImageTransformerFactory implements IImageTransformerFactory
+{
+    private static final long serialVersionUID = 1L;
+
+    private final int blackPointIntensity;
+
+    private final int whitePointIntensity;
+
+    public IntensityRangeImageTransformerFactory(int blackPointIntensity, int whitePointIntensity)
+    {
+        this.blackPointIntensity = blackPointIntensity;
+        this.whitePointIntensity = whitePointIntensity;
+    }
+
+    public IImageTransformer createTransformer()
+    {
+        return new IImageTransformer()
+            {
+                public BufferedImage transform(BufferedImage image)
+                {
+                    Levels levels = new Levels(blackPointIntensity, whitePointIntensity);
+                    return IntensityRescaling.rescaleIntensityLevelTo8Bits(image, levels);
+                }
+            };
+    }
+
+}