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 e13c2039879287d04336b9638dc5d4be9b42e47c..0346aa55ac4bcc40d9f5702b7e4e7adcf1e5cf64 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
@@ -20,6 +20,8 @@ import java.awt.Dimension;
 import java.awt.Graphics2D;
 import java.awt.RenderingHints;
 import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.WritableRaster;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.IOException;
@@ -41,7 +43,6 @@ import ar.com.hjg.pngj.ImageLine;
 import ar.com.hjg.pngj.ImageLineHelper;
 import ar.com.hjg.pngj.PngFilterType;
 import ar.com.hjg.pngj.PngWriter;
-
 import ch.rinn.restrictions.Private;
 import ch.systemsx.cisd.base.exceptions.IOExceptionUnchecked;
 import ch.systemsx.cisd.base.io.IRandomAccessFile;
@@ -699,25 +700,16 @@ public class ImageUtil
     public static void writeImageToPng(BufferedImage image, OutputStream out,
             PngFilterType filterType, int compressionLevel)
     {
-        final int cols = image.getWidth();
-        final int rows = image.getHeight();
-        int bitDepth = image.getColorModel().getComponentSize(0);
-        boolean hasAlpha = false; // NOTE: it would be nice to support alpha channel
-        boolean isGrayscale = isGrayscale(image);
-        ImageInfo imgInfo = new ImageInfo(cols, rows, bitDepth, hasAlpha, isGrayscale, false);
+        PngWritingHelper helper = PngWritingHelper.createHelper(image);
+        ImageInfo imgInfo = helper.getImageInfo();
+        int rows = imgInfo.rows;
         PngWriter png = new PngWriter(out, imgInfo);
         png.setFilterType(filterType == null ? PngFilterType.FILTER_DEFAULT : filterType);
         png.setCompLevel(compressionLevel == -1 ? 6 : compressionLevel);
         ImageLine imageLine = new ImageLine(imgInfo);
         for (int row = 0; row < rows; ++row)
         {
-            if (isGrayscale)
-            {
-                fillGrayscaleLine(image, cols, isGrayscale, imageLine, row);
-            } else
-            {
-                fillRGBLine(image, cols, isGrayscale, imageLine, row);
-            }
+            helper.fillLine(imageLine, row);
             imageLine.setRown(row);
             png.writeRow(imageLine);
         }
@@ -736,25 +728,6 @@ public class ImageUtil
         }
     }
 
-    private static void fillGrayscaleLine(BufferedImage image, final int cols, boolean isGrayscale,
-            ImageLine imageLine, int row)
-    {
-        for (int col = 0; col < cols; ++col)
-        {
-            imageLine.scanline[col] = image.getRaster().getSample(col, row, 0);
-        }
-    }
-
-    private static void fillRGBLine(BufferedImage image, final int cols, boolean isGrayscale,
-            ImageLine imageLine, int row)
-    {
-        for (int col = 0; col < cols; ++col)
-        {
-            int pixel = image.getRGB(col, row);
-            ImageLineHelper.setPixelRGB8(imageLine, col, pixel);
-        }
-    }
-
     /**
      * Parses specified string representation of an {@link ImageID}. If the argument is
      * <code>null</code> {@link ImageID#NULL} will be returned.
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/utils/PngWritingHelper.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/utils/PngWritingHelper.java
new file mode 100644
index 0000000000000000000000000000000000000000..42cb1100ad76122b426a9bfd03ea112faf43bdf7
--- /dev/null
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/utils/PngWritingHelper.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2013 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.generic.shared.utils;
+
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.WritableRaster;
+
+import ar.com.hjg.pngj.ImageInfo;
+import ar.com.hjg.pngj.ImageLine;
+import ar.com.hjg.pngj.ImageLineHelper;
+
+/**
+ * An object that encapsulates some knowledge about how PNG files should be created.
+ * 
+ * @author cramakri
+ */
+public class PngWritingHelper
+{
+    public static PngWritingHelper createHelper(BufferedImage image)
+    {
+        ColorModel colorModel = image.getColorModel();
+        int[] componentSize = colorModel.getComponentSize();
+        if (componentSize != null)
+        {
+            return new NormalPngWritingHelper(image, componentSize[0]);
+        }
+        if ("loci.formats.gui.Index16ColorModel".equals(colorModel.getClass().getName()))
+        {
+            return new Index16PngWritingHelper(image);
+        } else
+        {
+            throw new IllegalArgumentException(
+                    "The image color model does not specify a bit depth for the color channels and is not one of the known special cases.");
+        }
+    }
+
+    /**
+     * The png writing helper that handles most cases.
+     * 
+     * @author cramakri
+     */
+    private static class NormalPngWritingHelper extends PngWritingHelper
+    {
+        private NormalPngWritingHelper(BufferedImage image, int bitDepth)
+        {
+            super(image, bitDepth);
+        }
+    }
+
+    /**
+     * The png writing helper that handles images that use the loci.formats.gui.Index16ColorModel
+     * color model from BioFormats and have no component information. Images that use this color
+     * model and have component information are treated normally.
+     * 
+     * @author cramakri
+     */
+    private static class Index16PngWritingHelper extends PngWritingHelper
+    {
+        private Index16PngWritingHelper(BufferedImage image)
+        {
+            super(image, 8);
+        }
+
+        @Override
+        protected void fillRGBLine(ImageLine imageLine, int row)
+        {
+            for (int col = 0; col < cols; ++col)
+            {
+                WritableRaster raster = image.getRaster();
+                short[] value = (short[]) raster.getDataElements(row, col, null);
+                // TODO The values converted by the color model seem to be byte swapped. We
+                // currently just put the value in the green channel until we figure out how to
+                // handle these images.
+                // Alpha is ignored by setPixelRGB8
+                int pixel = (0 << 24) | (0 << 16) | ((value[0]) << 8) | (0 << 0);
+                ImageLineHelper.setPixelRGB8(imageLine, col, pixel);
+
+                // Potentially useful code if we improve the implementation of this method.
+                // ColorModel colorModel = image.getColorModel();
+                // int a = colorModel.getAlpha(value);
+                // int g = colorModel.getGreen(value);
+            }
+        }
+
+    }
+
+    private static boolean isGrayscale(BufferedImage image)
+    {
+        return image.getColorModel().getColorSpace().getNumComponents() == 1;
+    }
+
+    protected final BufferedImage image;
+
+    protected final int cols;
+
+    protected final int rows;
+
+    protected final boolean hasAlpha;
+
+    protected final boolean isGrayscale;
+
+    protected final int bitDepth;
+
+    private PngWritingHelper(BufferedImage image, int bitDepth)
+    {
+        this.image = image;
+        cols = image.getWidth();
+        rows = image.getHeight();
+        this.bitDepth = bitDepth;
+        hasAlpha = false; // NOTE: it would be nice to support alpha channel
+        isGrayscale = isGrayscale(image);
+    }
+
+    public int getRows()
+    {
+        return rows;
+    }
+
+    public int getCols()
+    {
+        return cols;
+    }
+
+    public ImageInfo getImageInfo()
+    {
+        ImageInfo imgInfo = new ImageInfo(cols, rows, bitDepth, hasAlpha, isGrayscale, false);
+        return imgInfo;
+    }
+
+    public void fillLine(ImageLine imageLine, int row)
+    {
+        if (isGrayscale)
+        {
+            fillGrayscaleLine(imageLine, row);
+        } else
+        {
+            fillRGBLine(imageLine, row);
+        }
+    }
+
+    protected void fillGrayscaleLine(ImageLine imageLine, int row)
+    {
+        for (int col = 0; col < cols; ++col)
+        {
+            imageLine.scanline[col] = image.getRaster().getSample(col, row, 0);
+        }
+    }
+
+    protected void fillRGBLine(ImageLine imageLine, int row)
+    {
+        for (int col = 0; col < cols; ++col)
+        {
+            int pixel = image.getRGB(col, row);
+            ImageLineHelper.setPixelRGB8(imageLine, col, pixel);
+        }
+    }
+}