diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/utils/ImageUtil.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/utils/ImageUtil.java
index 18455e27d6e43148ec32634c5f593f3134e53885..867effcf27ba32ba93ec118ed9feb56c673d1573 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/utils/ImageUtil.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/utils/ImageUtil.java
@@ -21,6 +21,7 @@ import static ch.systemsx.cisd.common.utilities.DataTypeUtil.JPEG_FILE;
 import static ch.systemsx.cisd.common.utilities.DataTypeUtil.PNG_FILE;
 import static ch.systemsx.cisd.common.utilities.DataTypeUtil.TIFF_FILE;
 
+import java.awt.Dimension;
 import java.awt.Graphics2D;
 import java.awt.RenderingHints;
 import java.awt.image.BufferedImage;
@@ -83,6 +84,8 @@ public class ImageUtil
     private static interface ImageLoader
     {
         public BufferedImage load(IRandomAccessFile raf, ImageID imageID);
+
+        public Dimension readDimension(IRandomAccessFile handle, ImageID imageID);
     }
 
     private static final class TiffImageLoader implements ImageLoader
@@ -115,6 +118,33 @@ public class ImageUtil
                 }
             }
         }
+
+        public Dimension readDimension(IRandomAccessFile handle, ImageID imageID)
+        {
+            handle.mark(MAX_READ_AHEAD);
+            try
+            {
+                return loadDimensionWithBioFormats(handle, imageID);
+            } catch (RuntimeException ex1)
+            {
+                try
+                {
+                    return loadDimensionJavaAdvancedImagingTiff(handle, imageID);
+                } catch (RuntimeException ex2)
+                {
+                    if (imageID.equals(ImageID.NULL))
+                    {
+                        handle.reset();
+                        // There are some TIFF files which cannot be opened by JAI, try ImageJ
+                        // instead...
+                        return loadDimensionWithImageJ(handle);
+                    } else
+                    {
+                        throw ex2;
+                    }
+                }
+            }
+        }
     }
 
     private static BufferedImage loadWithImageJ(IRandomAccessFile handle)
@@ -122,12 +152,24 @@ public class ImageUtil
         return loadWithLibrary(handle, ImageID.NULL, ImageReaderConstants.IMAGEJ_LIBRARY, "tiff");
     }
 
+    private static Dimension loadDimensionWithImageJ(IRandomAccessFile handle)
+    {
+        return loadDimensionWithLibrary(handle, ImageID.NULL, ImageReaderConstants.IMAGEJ_LIBRARY,
+                "tiff");
+    }
+
     private static BufferedImage loadWithBioFormats(IRandomAccessFile handle, ImageID imageID)
     {
         return loadWithLibrary(handle, imageID, ImageReaderConstants.BIOFORMATS_LIBRARY,
                 "TiffDelegateReader");
     }
 
+    private static Dimension loadDimensionWithBioFormats(IRandomAccessFile handle, ImageID imageID)
+    {
+        return loadDimensionWithLibrary(handle, imageID, ImageReaderConstants.BIOFORMATS_LIBRARY,
+                "TiffDelegateReader");
+    }
+
     /**
      * For experts only! Loads some kinds of TIFF images handled by JAI library.
      */
@@ -137,6 +179,15 @@ public class ImageUtil
         return loadWithLibrary(handle, imageID, ImageReaderConstants.JAI_LIBRARY, "tiff");
     }
 
+    /**
+     * For experts only! Loads some kinds of TIFF images handled by JAI library.
+     */
+    public static Dimension loadDimensionJavaAdvancedImagingTiff(IRandomAccessFile handle,
+            ImageID imageID) throws EnvironmentFailureException
+    {
+        return loadDimensionWithLibrary(handle, imageID, ImageReaderConstants.JAI_LIBRARY, "tiff");
+    }
+
     private static BufferedImage loadWithLibrary(IRandomAccessFile handle, ImageID imageIDOrNull,
             String libraryName, String readerName)
     {
@@ -156,6 +207,25 @@ public class ImageUtil
         }
     }
 
+    private static Dimension loadDimensionWithLibrary(IRandomAccessFile handle,
+            ImageID imageIDOrNull, String libraryName, String readerName)
+    {
+        operationLog.debug("Load tiff image using " + libraryName);
+        IImageReader imageReader = ImageReaderFactory.tryGetReader(libraryName, readerName);
+        if (imageReader == null)
+        {
+            throw new IllegalStateException(String.format(
+                    "There is no reader '%s' in image library '%s'.", readerName, libraryName));
+        }
+        try
+        {
+            return imageReader.readDimensions(handle, imageIDOrNull);
+        } catch (Exception ex)
+        {
+            throw EnvironmentFailureException.fromTemplate("Cannot decode image.", ex);
+        }
+    }
+
     private static final class JavaImageLoader implements ImageLoader
     {
         private final String fileType;
@@ -184,6 +254,24 @@ public class ImageUtil
             }
         }
 
+        public Dimension readDimension(IRandomAccessFile handle, ImageID imageID)
+        {
+            if (imageID.equals(ImageID.NULL))
+            {
+                IImageReader imageReader =
+                        ImageReaderFactory.tryGetReader(ImageReaderConstants.IMAGEIO_LIBRARY,
+                                fileType);
+                if (imageReader == null)
+                {
+                    throw EnvironmentFailureException.fromTemplate(
+                            "Cannot find ImageIO reader for file type '%s'", fileType);
+                }
+                return imageReader.readDimensions(handle, imageID);
+            } else
+            {
+                throw new UnsupportedOperationException();
+            }
+        }
     }
 
     private static final Map<String, ImageLoader> imageLoaders = new HashMap<String, ImageLoader>();
@@ -247,6 +335,43 @@ public class ImageUtil
         return loadImageGuessingLibrary(contentNode, imageID);
     }
 
+    /**
+     * Loads the image specified by <var>imageIdOrNull</var> from the given </var>inputStream</var>.
+     * Supported images formats are GIF, JPG, PNG, and TIFF. The input stream will be closed after
+     * loading.
+     * <p>
+     * Note that the original color depth will be kept, so e.g. 12 or 16 bit grayscale images will
+     * not be converted to RGB.
+     * 
+     * @throws IllegalArgumentException if the input stream doesn't start with a magic number
+     *             identifying supported image format.
+     */
+    public static Dimension loadUnchangedImageDimension(IHierarchicalContentNode contentNode,
+            String imageIdOrNull, String imageLibraryNameOrNull, String imageLibraryReaderNameOrNull)
+    {
+        assert (imageLibraryReaderNameOrNull == null || imageLibraryNameOrNull != null) : "if image reader "
+                + "is specified then library name should be specified as well";
+        ImageID imageID = parseImageID(imageIdOrNull);
+        if (imageLibraryNameOrNull != null && imageLibraryReaderNameOrNull != null)
+        {
+            IImageReader reader =
+                    ImageReaderFactory.tryGetReader(imageLibraryNameOrNull,
+                            imageLibraryReaderNameOrNull);
+            if (reader != null)
+            {
+                IRandomAccessFile handle = contentNode.getFileContent();
+                try
+                {
+                    return reader.readDimensions(handle, imageID);
+                } finally
+                {
+                    closeQuietly(handle);
+                }
+            }
+        }
+        return loadImageDimensionGuessingLibrary(contentNode, imageID);
+    }
+
     /**
      * Converts the given <var>image</var> to a PNG image. Uses fast parameters for the filter and
      * deflate level (no filter and no deflation).
@@ -412,6 +537,14 @@ public class ImageUtil
         return loadImageGuessingLibrary(handle, fileType, imageID);
     }
 
+    private static Dimension loadImageDimensionGuessingLibrary(
+            IHierarchicalContentNode contentNode, ImageID imageID)
+    {
+        IRandomAccessFile handle = contentNode.getFileContent();
+        String fileType = DataTypeUtil.tryToFigureOutFileTypeOf(handle);
+        return loadImageDimensionGuessingLibrary(handle, fileType, imageID);
+    }
+
     /**
      * Loads the image specified by <var>imageID</var> from the image from the given
      * </var>handle</var>. Supported images formats are GIF, JPG, PNG, and TIFF. The input stream
@@ -443,6 +576,29 @@ public class ImageUtil
         }
     }
 
+    private static Dimension loadImageDimensionGuessingLibrary(IRandomAccessFile handle,
+            String fileType, ImageID imageID)
+    {
+        try
+        {
+            if (fileType == null)
+            {
+                throw new IllegalArgumentException(
+                        "File type of an image input stream couldn't be determined.");
+            }
+            ImageLoader imageLoader = imageLoaders.get(fileType);
+            if (imageLoader == null)
+            {
+                throw new IllegalArgumentException("Unable to load image of file type '" + fileType
+                        + "'.");
+            }
+            return imageLoader.readDimension(handle, imageID);
+        } finally
+        {
+            closeQuietly(handle);
+        }
+    }
+
     /**
      * Only for tests
      */
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 c653eea86c63c9189b96c71d4fae1b619fbb26fc..95d90d19c9804a433f8ba3717bd8b8a1a55740bc 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 java.awt.Dimension;
 import java.awt.image.BufferedImage;
 
 import ch.systemsx.cisd.common.io.hierarchical_content.api.IHierarchicalContentNode;
@@ -119,6 +120,20 @@ public class AbsoluteImageReference extends AbstractImageReference
                 imageLibraryReaderNameOrNull, null);
     }
 
+    static Dimension loadUnchangedImageDimension(IHierarchicalContentNode contentNode,
+            String imageIdOrNull, ImageLibraryInfo imageLibraryOrNull)
+    {
+        String imageLibraryNameOrNull = null;
+        String imageLibraryReaderNameOrNull = null;
+        if (imageLibraryOrNull != null)
+        {
+            imageLibraryNameOrNull = imageLibraryOrNull.getName();
+            imageLibraryReaderNameOrNull = imageLibraryOrNull.getReaderName();
+        }
+        return ImageUtil.loadUnchangedImageDimension(contentNode, imageIdOrNull,
+                imageLibraryNameOrNull, imageLibraryReaderNameOrNull);
+    }
+
     public RequestedImageSize getRequestedSize()
     {
         return imageSize;
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/Hdf5ThumbnailGenerator.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/Hdf5ThumbnailGenerator.java
index b30e716206c37dfbea79c32f4657a714b0ce344d..f3145f15c3af77f014aa659e739b142817c038a7 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/Hdf5ThumbnailGenerator.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/Hdf5ThumbnailGenerator.java
@@ -16,6 +16,7 @@
 
 package ch.systemsx.cisd.openbis.dss.etl;
 
+import java.awt.Dimension;
 import java.awt.image.BufferedImage;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
@@ -43,8 +44,8 @@ import ch.systemsx.cisd.common.logging.LogFactory;
 import ch.systemsx.cisd.common.process.ProcessExecutionHelper;
 import ch.systemsx.cisd.common.process.ProcessIOStrategy;
 import ch.systemsx.cisd.common.process.ProcessResult;
-import ch.systemsx.cisd.openbis.dss.etl.dto.RelativeImageFile;
 import ch.systemsx.cisd.openbis.dss.etl.dto.ImageLibraryInfo;
+import ch.systemsx.cisd.openbis.dss.etl.dto.RelativeImageFile;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.ThumbnailFilePaths;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ImageStorageConfiguraton;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ThumbnailsStorageFormat;
@@ -68,10 +69,10 @@ public class Hdf5ThumbnailGenerator implements IHDF5WriterClient
      */
     public static ThumbnailFilePaths tryGenerateThumbnails(List<RelativeImageFile> images,
             File imagesParentDirectory, String thumbnailFilePath,
-            ImageStorageConfiguraton imageStorageConfiguraton, String thumbnailPhysicalDatasetPermId)
+            ImageStorageConfiguraton imageStorageConfiguraton,
+            String thumbnailPhysicalDatasetPermId,
+            ThumbnailsStorageFormat thumbnailsStorageFormatOrNull)
     {
-        ThumbnailsStorageFormat thumbnailsStorageFormatOrNull =
-                imageStorageConfiguraton.getThumbnailsStorageFormat();
         if (thumbnailsStorageFormatOrNull != null)
         {
             ThumbnailFilePaths thumbnailPaths =
@@ -211,6 +212,19 @@ public class Hdf5ThumbnailGenerator implements IHDF5WriterClient
         String size =
                 thumbnailsStorageFormat.getMaxWidth() + "x"
                         + thumbnailsStorageFormat.getMaxHeight();
+
+        if (thumbnailsStorageFormat.getZoomLevel() != null)
+        {
+            Dimension originalSize = loadUnchangedImageDimension(imageFile, null);
+            long x =
+                    (int) Math.round(thumbnailsStorageFormat.getZoomLevel()
+                            * originalSize.getWidth());
+            long y =
+                    (int) Math.round(thumbnailsStorageFormat.getZoomLevel()
+                            * originalSize.getHeight());
+            size = x + "x" + y;
+        }
+
         String imageFilePath = imageFile.getPath();
         List<String> params = new ArrayList<String>();
         params.addAll(Arrays.asList(convertUtilityOrNull.getPath(), imageFilePath, "-scale", size));
@@ -239,9 +253,17 @@ public class Hdf5ThumbnailGenerator implements IHDF5WriterClient
             ByteArrayOutputStream bufferOutputStream) throws IOException
     {
         BufferedImage image = loadUnchangedImage(imageFile, imageIdOrNull);
+
+        long x = thumbnailsStorageFormat.getMaxWidth();
+        long y = thumbnailsStorageFormat.getMaxHeight();
+        if (thumbnailsStorageFormat.getZoomLevel() != null)
+        {
+            x = Math.round(thumbnailsStorageFormat.getZoomLevel() * image.getWidth());
+            y = Math.round(thumbnailsStorageFormat.getZoomLevel() * image.getHeight());
+        }
+
         BufferedImage thumbnail =
-                ImageUtil.rescale(image, thumbnailsStorageFormat.getMaxWidth(),
-                        thumbnailsStorageFormat.getMaxHeight(), false,
+                ImageUtil.rescale(image, (int) x, (int) y, false,
                         thumbnailsStorageFormat.isHighQuality());
         ImageUtil.writeImageToPng(thumbnail, bufferOutputStream);
         return bufferOutputStream.toByteArray();
@@ -253,6 +275,12 @@ public class Hdf5ThumbnailGenerator implements IHDF5WriterClient
                 imageIdOrNull, imageLibraryOrNull);
     }
 
+    private Dimension loadUnchangedImageDimension(File imageFile, String imageIdOrNull)
+    {
+        return AbsoluteImageReference.loadUnchangedImageDimension(new FileBasedContentNode(
+                imageFile), imageIdOrNull, imageLibraryOrNull);
+    }
+
     private Status createStatus(String thumbnailPath, IOException ex)
     {
         logger.warn("Retriable error when creating thumbnail '" + thumbnailPath + "'", ex);
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/ImageDataSetStructure.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/ImageDataSetStructure.java
index 2c48a25dda81c409043b1f4dfbf7e320910199ba..21b727cda33b1832b3f1bcd48f938338cec59b36 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/ImageDataSetStructure.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/ImageDataSetStructure.java
@@ -79,7 +79,7 @@ public class ImageDataSetStructure
 
     public boolean areThumbnailsGenerated()
     {
-        return getImageStorageConfiguraton().getThumbnailsStorageFormat() != null;
+        return getImageStorageConfiguraton().getThumbnailsStorageFormat().size() > 0;
     }
 
     // ------ setters
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ImageStorageConfiguraton.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ImageStorageConfiguraton.java
index 9625dc3fc1969b74daca684862b6811b826e3aba..2b964329b07a3f2b4746689d463b1ed45e5426d7 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ImageStorageConfiguraton.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ImageStorageConfiguraton.java
@@ -16,6 +16,9 @@
 
 package ch.systemsx.cisd.openbis.dss.etl.dto.api.v1;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import ch.systemsx.cisd.base.image.IImageTransformerFactory;
 import ch.systemsx.cisd.common.utilities.AbstractHashable;
 import ch.systemsx.cisd.openbis.dss.etl.dto.ImageLibraryInfo;
@@ -40,7 +43,8 @@ public class ImageStorageConfiguraton extends AbstractHashable
     // --- State ----------
 
     /** No thumbnails are generated by default. */
-    private ThumbnailsStorageFormat thumbnailsStorageFormatOrNull = null;
+    private List<ThumbnailsStorageFormat> thumbnailsStorageFormatsList =
+            new ArrayList<ThumbnailsStorageFormat>();
 
     private OriginalDataStorageFormat originalDataStorageFormat =
             OriginalDataStorageFormat.UNCHANGED;
@@ -62,15 +66,28 @@ public class ImageStorageConfiguraton extends AbstractHashable
     // --- Getters & Setters ----------
 
     /** @return null if no thumbnails should be generated */
-    public ThumbnailsStorageFormat getThumbnailsStorageFormat()
+    public List<ThumbnailsStorageFormat> getThumbnailsStorageFormat()
     {
-        return thumbnailsStorageFormatOrNull;
+        return thumbnailsStorageFormatsList;
     }
 
-    /** Set to null if no thumbnails should be generated */
+    /** Set to null if no thumbnails should be generated. Overrides previous thumbnails settings. */
     public void setThumbnailsStorageFormat(ThumbnailsStorageFormat thumbnailsStorageFormatOrNull)
     {
-        this.thumbnailsStorageFormatOrNull = thumbnailsStorageFormatOrNull;
+        thumbnailsStorageFormatsList.clear();
+        addThumbnailsStorageFormat(thumbnailsStorageFormatOrNull);
+
+    }
+
+    /**
+     * Adds new thumbnails setting to the list
+     */
+    public void addThumbnailsStorageFormat(ThumbnailsStorageFormat thumbnailsStorageFormatOrNull)
+    {
+        if (thumbnailsStorageFormatOrNull != null)
+        {
+            thumbnailsStorageFormatsList.add(thumbnailsStorageFormatOrNull);
+        }
     }
 
     /**
@@ -79,7 +96,8 @@ public class ImageStorageConfiguraton extends AbstractHashable
      */
     public void switchOnThumbnailsGeneration()
     {
-        this.thumbnailsStorageFormatOrNull = new ThumbnailsStorageFormat();
+        thumbnailsStorageFormatsList.clear();
+        thumbnailsStorageFormatsList.add(new ThumbnailsStorageFormat());
     }
 
     public OriginalDataStorageFormat getOriginalDataStorageFormat()
@@ -143,9 +161,12 @@ public class ImageStorageConfiguraton extends AbstractHashable
             appendNameAndObject(buffer, "original data storage format",
                     originalDataStorageFormat.toString());
         }
-        if (thumbnailsStorageFormatOrNull != null)
+        if (thumbnailsStorageFormatsList.size() > 0)
         {
-            appendNameAndObject(buffer, "thumbnails", thumbnailsStorageFormatOrNull.toString());
+            for (ThumbnailsStorageFormat thumbnailsStorageFormat : thumbnailsStorageFormatsList)
+            {
+                appendNameAndObject(buffer, "thumbnails", thumbnailsStorageFormat.toString());
+            }
         }
         if (storeChannelsOnExperimentLevelOrNull != null)
         {
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/SimpleImageDataConfig.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/SimpleImageDataConfig.java
index e58045e06e8e6ef33498f55cde1279f8a90fc847..5d9b274d0aa2d350fd06c0f0ef541476df2cf245 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/SimpleImageDataConfig.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/SimpleImageDataConfig.java
@@ -16,6 +16,7 @@
 
 package ch.systemsx.cisd.openbis.dss.etl.dto.api.v1;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
@@ -23,6 +24,9 @@ import java.util.List;
 import ch.systemsx.cisd.base.image.IImageTransformerFactory;
 import ch.systemsx.cisd.common.shared.basic.utils.StringUtils;
 import ch.systemsx.cisd.openbis.dss.etl.dto.ImageLibraryInfo;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.thumbnails.DefaultThumbnailsConfiguration;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.thumbnails.IThumbnailsConfiguration;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.thumbnails.ZoomLevelBasedThumbnailsConfiguration;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.transformations.ConvertToolImageTransformerFactory;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.transformations.ImageTransformation;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.transformations.ImageTransformationBuffer;
@@ -200,7 +204,8 @@ abstract public class SimpleImageDataConfig
     private String[] recognizedImageExtensions = new String[]
         { "tiff", "tif", "png", "gif", "jpg", "jpeg" };
 
-    private boolean generateThumbnails = false;
+    private List<IThumbnailsConfiguration> thumbnailsPyramid =
+            new ArrayList<IThumbnailsConfiguration>();
 
     private int maxThumbnailWidthAndHeight = 256;
 
@@ -244,17 +249,10 @@ abstract public class SimpleImageDataConfig
         imageStorageConfiguraton
                 .setStoreChannelsOnExperimentLevel(isStoreChannelsOnExperimentLevel());
         imageStorageConfiguraton.setOriginalDataStorageFormat(getOriginalDataStorageFormat());
-        if (isGenerateThumbnails())
+        for (IThumbnailsConfiguration thumbnailsConfiguration : thumbnailsPyramid)
         {
-            ThumbnailsStorageFormat thumbnailsStorageFormat = new ThumbnailsStorageFormat();
-            thumbnailsStorageFormat
-                    .setAllowedMachineLoadDuringGeneration(getAllowedMachineLoadDuringThumbnailsGeneration());
-            thumbnailsStorageFormat.setMaxWidth(getMaxThumbnailWidthAndHeight());
-            thumbnailsStorageFormat.setMaxHeight(getMaxThumbnailWidthAndHeight());
-            thumbnailsStorageFormat.setGenerateWithImageMagic(generateThumbnailsWithImageMagic);
-            thumbnailsStorageFormat.setImageMagicParams(thumbnailsGenerationImageMagicParams);
-            thumbnailsStorageFormat.setHighQuality(generateThumbnailsIn8BitHighQuality);
-            imageStorageConfiguraton.setThumbnailsStorageFormat(thumbnailsStorageFormat);
+            imageStorageConfiguraton.addThumbnailsStorageFormat(thumbnailsConfiguration
+                    .getThumbnailsStorageFormat(this));
         }
         if (false == StringUtils.isBlank(convertTransformationCliArgumentsOrNull))
         {
@@ -284,7 +282,7 @@ abstract public class SimpleImageDataConfig
 
     public boolean isGenerateThumbnails()
     {
-        return generateThumbnails;
+        return thumbnailsPyramid.size() > 0;
     }
 
     public int getMaxThumbnailWidthAndHeight()
@@ -358,7 +356,22 @@ abstract public class SimpleImageDataConfig
     /** should thumbnails be generated? False by default. */
     public void setGenerateThumbnails(boolean generateThumbnails)
     {
-        this.generateThumbnails = generateThumbnails;
+        thumbnailsPyramid.clear();
+        thumbnailsPyramid.add(new DefaultThumbnailsConfiguration());
+    }
+
+    public void setGenerateThumbnailsPyramid(double[] zoomLevels)
+    {
+        if (zoomLevels == null)
+        {
+            thumbnailsPyramid.clear();
+        } else
+        {
+            for (double zoomLevel : zoomLevels)
+            {
+                thumbnailsPyramid.add(new ZoomLevelBasedThumbnailsConfiguration(zoomLevel));
+            }
+        }
     }
 
     /** the maximal width and height of the generated thumbnails */
@@ -391,6 +404,11 @@ abstract public class SimpleImageDataConfig
         this.generateThumbnailsWithImageMagic = generateWithImageMagic;
     }
 
+    public boolean getGenerateThumbnailsWithImageMagic()
+    {
+        return generateThumbnailsWithImageMagic;
+    }
+
     /**
      * Sets additional parameters which should be passed to ImageMagic 'convert' utility when it is
      * used to generate thumbnails.
@@ -403,6 +421,11 @@ abstract public class SimpleImageDataConfig
         this.thumbnailsGenerationImageMagicParams = Arrays.asList(imageMagicParams);
     }
 
+    public List<String> getThumbnailsGenerationImageMagicParams()
+    {
+        return thumbnailsGenerationImageMagicParams;
+    }
+
     /**
      * If true and thumbnails generation is switched on, thumbnails will be generated with high
      * quality.
@@ -416,6 +439,11 @@ abstract public class SimpleImageDataConfig
         this.generateThumbnailsIn8BitHighQuality = highQualityThumbnails;
     }
 
+    public boolean getGenerateThumbnailsIn8BitHighQuality()
+    {
+        return generateThumbnailsIn8BitHighQuality;
+    }
+
     /**
      * See {@link #setGenerateHighQuality8BitThumbnails}.
      * 
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ThumbnailsStorageFormat.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ThumbnailsStorageFormat.java
index 2b11cceba9f51a07ba1eb971f9dff17428247f46..736b1f09fa668866fbfb2b2b2b3529621a0ca862 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ThumbnailsStorageFormat.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ThumbnailsStorageFormat.java
@@ -20,6 +20,7 @@ import java.util.Collections;
 import java.util.List;
 
 import ch.systemsx.cisd.common.utilities.AbstractHashable;
+import ch.systemsx.cisd.openbis.dss.Constants;
 
 /**
  * Configuration parameters which describe how thumbnails should be generated.
@@ -40,6 +41,8 @@ public class ThumbnailsStorageFormat extends AbstractHashable
 
     private int maxHeight = DEFAULT_THUMBNAIL_MAX_SIZE;
 
+    private Double zoomLevel = null;
+
     private boolean storeCompressed = DEFAULT_COMPRESS_THUMBNAILS;
 
     private double allowedMachineLoadDuringGeneration = 1;
@@ -50,6 +53,8 @@ public class ThumbnailsStorageFormat extends AbstractHashable
 
     private List<String> imageMagicParams = Collections.emptyList();
 
+    private String thumbnailsFileName;
+
     /**
      * Creates empty object which instructs that the thumbnails should be generated with default
      * settings. Use setters to change default behaviour (you will probably not have to).
@@ -153,4 +158,24 @@ public class ThumbnailsStorageFormat extends AbstractHashable
         this.imageMagicParams = imageMagicParams;
     }
 
+    public Double getZoomLevel()
+    {
+        return zoomLevel;
+    }
+
+    public void setZoomLevel(Double zoomLevel)
+    {
+        this.zoomLevel = zoomLevel;
+    }
+
+    public String getThumbnailsFileName()
+    {
+        return thumbnailsFileName == null ? Constants.HDF5_CONTAINER_THUMBNAILS_FILE_NAME
+                : thumbnailsFileName;
+    }
+
+    public void setThumbnailsFileName(String thumbnailsFileName)
+    {
+        this.thumbnailsFileName = thumbnailsFileName;
+    }
 }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/thumbnails/AbstractThumbnailsConfiguration.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/thumbnails/AbstractThumbnailsConfiguration.java
new file mode 100644
index 0000000000000000000000000000000000000000..2f1987fa810375d5e49a857be21087f4d7915020
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/thumbnails/AbstractThumbnailsConfiguration.java
@@ -0,0 +1,25 @@
+/*
+ * 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.thumbnails;
+
+/**
+ * @author Pawel Glyzewski
+ */
+public abstract class AbstractThumbnailsConfiguration implements IThumbnailsConfiguration
+{
+
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/thumbnails/DefaultThumbnailsConfiguration.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/thumbnails/DefaultThumbnailsConfiguration.java
new file mode 100644
index 0000000000000000000000000000000000000000..4088edbaa9978632c3514f8752d493a9f18cd1e8
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/thumbnails/DefaultThumbnailsConfiguration.java
@@ -0,0 +1,41 @@
+/*
+ * 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.thumbnails;
+
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.SimpleImageDataConfig;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ThumbnailsStorageFormat;
+
+/**
+ * @author Pawel Glyzewski
+ */
+public class DefaultThumbnailsConfiguration extends AbstractThumbnailsConfiguration
+{
+    public ThumbnailsStorageFormat getThumbnailsStorageFormat(SimpleImageDataConfig config)
+    {
+        ThumbnailsStorageFormat thumbnailsStorageFormat = new ThumbnailsStorageFormat();
+        thumbnailsStorageFormat.setAllowedMachineLoadDuringGeneration(config
+                .getAllowedMachineLoadDuringThumbnailsGeneration());
+        thumbnailsStorageFormat.setMaxWidth(config.getMaxThumbnailWidthAndHeight());
+        thumbnailsStorageFormat.setMaxHeight(config.getMaxThumbnailWidthAndHeight());
+        thumbnailsStorageFormat.setGenerateWithImageMagic(config
+                .getGenerateThumbnailsWithImageMagic());
+        thumbnailsStorageFormat.setImageMagicParams(config
+                .getThumbnailsGenerationImageMagicParams());
+        thumbnailsStorageFormat.setHighQuality(config.getGenerateThumbnailsIn8BitHighQuality());
+        return thumbnailsStorageFormat;
+    }
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/thumbnails/IThumbnailsConfiguration.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/thumbnails/IThumbnailsConfiguration.java
new file mode 100644
index 0000000000000000000000000000000000000000..411cb80eb4f2138f52e1f4dec6d6c6bd468f914a
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/thumbnails/IThumbnailsConfiguration.java
@@ -0,0 +1,28 @@
+/*
+ * 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.thumbnails;
+
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.SimpleImageDataConfig;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ThumbnailsStorageFormat;
+
+/**
+ * @author Pawel Glyzewski
+ */
+public interface IThumbnailsConfiguration
+{
+    public ThumbnailsStorageFormat getThumbnailsStorageFormat(SimpleImageDataConfig config);
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/thumbnails/ZoomLevelBasedThumbnailsConfiguration.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/thumbnails/ZoomLevelBasedThumbnailsConfiguration.java
new file mode 100644
index 0000000000000000000000000000000000000000..64657150acf9accb81515fbbc87835fca7bb62c6
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/thumbnails/ZoomLevelBasedThumbnailsConfiguration.java
@@ -0,0 +1,49 @@
+/*
+ * 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.thumbnails;
+
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.SimpleImageDataConfig;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ThumbnailsStorageFormat;
+
+/**
+ * @author Pawel Glyzewski
+ */
+public class ZoomLevelBasedThumbnailsConfiguration extends AbstractThumbnailsConfiguration
+{
+    private double zoomLevel;
+
+    public ZoomLevelBasedThumbnailsConfiguration(double zoomLevel)
+    {
+        this.zoomLevel = zoomLevel;
+    }
+
+    public ThumbnailsStorageFormat getThumbnailsStorageFormat(SimpleImageDataConfig config)
+    {
+        ThumbnailsStorageFormat thumbnailsStorageFormat = new ThumbnailsStorageFormat();
+        thumbnailsStorageFormat.setAllowedMachineLoadDuringGeneration(config
+                .getAllowedMachineLoadDuringThumbnailsGeneration());
+        thumbnailsStorageFormat.setZoomLevel(zoomLevel);
+        thumbnailsStorageFormat.setThumbnailsFileName(String.format("thumbnails_%.0f%%.h5",
+                zoomLevel * 100.0));
+        thumbnailsStorageFormat.setGenerateWithImageMagic(config
+                .getGenerateThumbnailsWithImageMagic());
+        thumbnailsStorageFormat.setImageMagicParams(config
+                .getThumbnailsGenerationImageMagicParams());
+        thumbnailsStorageFormat.setHighQuality(config.getGenerateThumbnailsIn8BitHighQuality());
+        return thumbnailsStorageFormat;
+    }
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/JythonPlateDataSetHandler.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/JythonPlateDataSetHandler.java
index db29ded27713fd02364cd66084fbfaba935d3bd3..1054c30c7d3a6477ba585444499b89a7763a2f88 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/JythonPlateDataSetHandler.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/JythonPlateDataSetHandler.java
@@ -44,6 +44,7 @@ import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.IImagingDataSetRegistrationTr
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.IImagingDatasetFactory;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ImageFileInfo;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.SimpleImageDataConfig;
+import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ThumbnailsStorageFormat;
 import ch.systemsx.cisd.openbis.dss.etl.featurevector.CsvFeatureVectorParser;
 import ch.systemsx.cisd.openbis.dss.generic.shared.IEncapsulatedOpenBISService;
 import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation;
@@ -419,17 +420,25 @@ public class JythonPlateDataSetHandler extends JythonTopLevelDataSetHandler<Data
             List<String> containedDataSetCodes = new ArrayList<String>();
 
             // create thumbnails dataset if needed
-            IDataSet thumbnailDatasetOrNull = null;
+            List<IDataSet> thumbnailDatasets = new ArrayList<IDataSet>();
             boolean generateThumbnails = imageDataSetStructure.areThumbnailsGenerated();
             if (generateThumbnails)
             {
-                thumbnailDatasetOrNull = createThumbnailDataset();
+                List<ThumbnailsStorageFormat> thumbnailsStorageFormatList =
+                        imageDataSetStructure.getImageStorageConfiguraton()
+                                .getThumbnailsStorageFormat();
 
-                ThumbnailFilePaths thumbnailPaths =
-                        generateThumbnails(imageDataSetStructure, incomingDirectory,
-                                thumbnailDatasetOrNull);
-                imageDataSetInformation.setThumbnailFilePaths(thumbnailPaths);
-                containedDataSetCodes.add(thumbnailDatasetOrNull.getDataSetCode());
+                for (ThumbnailsStorageFormat thumbnailsStorageFormat : thumbnailsStorageFormatList)
+                {
+                    IDataSet thumbnailDataset = createThumbnailDataset();
+                    thumbnailDatasets.add(thumbnailDataset);
+
+                    ThumbnailFilePaths thumbnailPaths =
+                            generateThumbnails(imageDataSetStructure, incomingDirectory,
+                                    thumbnailDataset, thumbnailsStorageFormat);
+                    imageDataSetInformation.setThumbnailFilePaths(thumbnailPaths);
+                    containedDataSetCodes.add(thumbnailDataset.getDataSetCode());
+                }
             }
             // create main dataset (with original images)
             @SuppressWarnings("unchecked")
@@ -438,18 +447,17 @@ public class JythonPlateDataSetHandler extends JythonTopLevelDataSetHandler<Data
                             .createNewDataSet(imageRegistrationDetails);
             containedDataSetCodes.add(mainDataset.getDataSetCode());
 
-            if (thumbnailDatasetOrNull != null)
+            for (IDataSet thumbnailDataset : thumbnailDatasets)
             {
-                setSameDatasetOwner(mainDataset, thumbnailDatasetOrNull);
+                setSameDatasetOwner(mainDataset, thumbnailDataset);
             }
-
             ImageContainerDataSet containerDataset =
                     createImageContainerDataset(mainDataset, imageDataSetInformation,
                             containedDataSetCodes);
             containerDataset.setOriginalDataset(mainDataset);
-            if (thumbnailDatasetOrNull != null)
+            for (IDataSet thumbnailDataset : thumbnailDatasets)
             {
-                containerDataset.setThumbnailDatasets(Arrays.asList(thumbnailDatasetOrNull));
+                containerDataset.setThumbnailDatasets(Arrays.asList(thumbnailDataset));
             }
             imageDataSetInformation.setContainerDatasetPermId(containerDataset.getDataSetCode());
 
@@ -462,16 +470,27 @@ public class JythonPlateDataSetHandler extends JythonTopLevelDataSetHandler<Data
         }
 
         private ThumbnailFilePaths generateThumbnails(ImageDataSetStructure imageDataSetStructure,
-                File incomingDirectory, IDataSet thumbnailDataset)
+                File incomingDirectory, IDataSet thumbnailDataset,
+                ThumbnailsStorageFormat thumbnailsStorageFormatOrNull)
         {
-            String thumbnailFile =
-                    createNewFile(thumbnailDataset, Constants.HDF5_CONTAINER_THUMBNAILS_FILE_NAME);
+            String thumbnailFile;
+            if (thumbnailsStorageFormatOrNull == null)
+            {
+                thumbnailFile =
+                        createNewFile(thumbnailDataset,
+                                Constants.HDF5_CONTAINER_THUMBNAILS_FILE_NAME);
+            } else
+            {
+                thumbnailFile =
+                        createNewFile(thumbnailDataset,
+                                thumbnailsStorageFormatOrNull.getThumbnailsFileName());
+            }
 
             List<RelativeImageFile> images = asRelativeImageFile(imageDataSetStructure.getImages());
             ThumbnailFilePaths thumbnailPaths =
                     Hdf5ThumbnailGenerator.tryGenerateThumbnails(images, incomingDirectory,
                             thumbnailFile, imageDataSetStructure.getImageStorageConfiguraton(),
-                            thumbnailDataset.getDataSetCode());
+                            thumbnailDataset.getDataSetCode(), thumbnailsStorageFormatOrNull);
             return thumbnailPaths;
         }