diff --git a/bob/io/image/cpp/netpbm.cpp b/bob/io/image/cpp/netpbm.cpp
index d1c2fc9520d0796324e57001b1131ea2c8a5a3e6..d74c400393b82d4af7a96a450e5dad2b041c16ca 100644
--- a/bob/io/image/cpp/netpbm.cpp
+++ b/bob/io/image/cpp/netpbm.cpp
@@ -408,7 +408,7 @@ static void im_save_color(const bob::io::base::array::interface& b, struct pam *
       img_data[c+0] = element_r[y*info.shape[2] + x];
       img_data[c+1] = element_g[y*info.shape[2] + x];
       img_data[c+2] = element_b[y*info.shape[2] + x];
-      c = c + 3;
+      c += 3;
     }
   }
   pnm_writepam(out_pam, img_data);
diff --git a/bob/io/image/include/bob.io.image/bmp.h b/bob/io/image/include/bob.io.image/bmp.h
index 84b31a13b97287f5db28d433b269b5eebe1a6a09..803ca2f67e84d0e262e4c9b99374e2745bf7a306 100644
--- a/bob/io/image/include/bob.io.image/bmp.h
+++ b/bob/io/image/include/bob.io.image/bmp.h
@@ -86,14 +86,12 @@ namespace bob { namespace io { namespace image {
 
   };
 
-  template <class T>
-  blitz::Array<T,3> read_bmp(const std::string& filename){
+  inline blitz::Array<uint8_t,3> read_bmp(const std::string& filename){
     BMPFile bmp(filename.c_str(), 'r');
-    return bmp.read<T,3>(0);
+    return bmp.read<uint8_t,3>(0);
   }
 
-  template <class T>
-  void write_bmp(const blitz::Array<T,3>& image, const std::string& filename){
+  inline void write_bmp(const blitz::Array<uint8_t,3>& image, const std::string& filename){
     BMPFile bmp(filename.c_str(), 'w');
     bmp.write(image);
   }
diff --git a/bob/io/image/include/bob.io.image/config.h b/bob/io/image/include/bob.io.image/config.h
index 2a77273f3e40851a4e7ebda2cf2ba5695c9c59b8..9ba23c4712bd599e749eb10ee3a0ee9d6ecd3162 100644
--- a/bob/io/image/include/bob.io.image/config.h
+++ b/bob/io/image/include/bob.io.image/config.h
@@ -89,7 +89,7 @@
    */
 #ifdef HAVE_GIFLIB
   static PyObject* giflib_version() {
-  #ifdef GIF_LIB_VERSION
+  #ifdef GIFLIB_VERSION
    return Py_BuildValue("s", GIF_LIB_VERSION);
   #else
     boost::format f("%s.%s.%s");
diff --git a/bob/io/image/include/bob.io.image/gif.h b/bob/io/image/include/bob.io.image/gif.h
index 3f89f1736d0da83e17f40d4d606689d920b5e56f..f49a0253265b4858c873a7a47856bc4e6b0068c6 100644
--- a/bob/io/image/include/bob.io.image/gif.h
+++ b/bob/io/image/include/bob.io.image/gif.h
@@ -88,14 +88,12 @@ namespace bob { namespace io { namespace image {
 
   };
 
-  template <class T, int N>
-  blitz::Array<T,N> read_gif(const std::string& filename){
+  inline blitz::Array<uint8_t,3> read_gif(const std::string& filename){
     GIFFile gif(filename.c_str(), 'r');
-    return gif.read<T,N>(0);
+    return gif.read<uint8_t,3>(0);
   }
 
-  template <class T, int N>
-  void write_gif(const blitz::Array<T,N>& image, const std::string& filename){
+  inline void write_gif(const blitz::Array<uint8_t,3>& image, const std::string& filename){
     GIFFile gif(filename.c_str(), 'w');
     gif.write(image);
   }
diff --git a/bob/io/image/include/bob.io.image/jpeg.h b/bob/io/image/include/bob.io.image/jpeg.h
index db4fabf32c7ae1b526e5c4ccd1f1a71be88f0274..576ffa548e75ec77253a03abc093857043b5d102 100644
--- a/bob/io/image/include/bob.io.image/jpeg.h
+++ b/bob/io/image/include/bob.io.image/jpeg.h
@@ -88,14 +88,19 @@ namespace bob { namespace io { namespace image {
       static std::string s_codecname;
   };
 
-  template <class T, int N>
-  blitz::Array<T,N> read_jpeg(const std::string& filename){
+  bool is_color_jpeg(const std::string& filename){
     JPEGFile jpeg(filename.c_str(), 'r');
-    return jpeg.read<T,N>(0);
+    return jpeg.type().nd == 3;
   }
 
-  template <class T, int N>
-  void write_jpeg(const blitz::Array<T,N>& image, const std::string& filename){
+  template <int N>
+  blitz::Array<uint8_t,N> read_jpeg(const std::string& filename){
+    JPEGFile jpeg(filename.c_str(), 'r');
+    return jpeg.read<uint8_t,N>(0);
+  }
+
+  template <int N>
+  void write_jpeg(const blitz::Array<uint8_t,N>& image, const std::string& filename){
     JPEGFile jpeg(filename.c_str(), 'w');
     jpeg.write(image);
   }
diff --git a/bob/io/image/include/bob.io.image/netpbm.h b/bob/io/image/include/bob.io.image/netpbm.h
index cad17a6ec06bc5818d55ffd2330db12a651671f4..6d18ed2fbde51dd8ff2eb6fa6e0a1d6f6c5e7218 100644
--- a/bob/io/image/include/bob.io.image/netpbm.h
+++ b/bob/io/image/include/bob.io.image/netpbm.h
@@ -86,6 +86,48 @@ namespace bob { namespace io { namespace image {
 
   };
 
+  template <class T>
+  blitz::Array<T,2> read_pbm(const std::string& filename){
+    NetPBMFile pbm(filename.c_str(), 'r');
+    return pbm.read<T,2>(0);
+  }
+
+  template <class T>
+  void write_pbm(const blitz::Array<T,2>& image, const std::string& filename){
+    NetPBMFile pbm(filename.c_str(), 'w');
+    pbm.write(image);
+  }
+
+  template <class T>
+  blitz::Array<T,2> read_pgm(const std::string& filename){
+    NetPBMFile pgm(filename.c_str(), 'r');
+    return pgm.read<T,2>(0);
+  }
+
+  template <class T>
+  void write_pgm(const blitz::Array<T,2>& image, const std::string& filename){
+    NetPBMFile pgm(filename.c_str(), 'w');
+    pgm.write(image);
+  }
+
+  template <class T>
+  blitz::Array<T,3> read_ppm(const std::string& filename){
+    NetPBMFile ppm(filename.c_str(), 'r');
+    return ppm.read<T,3>(0);
+  }
+
+  template <class T>
+  inline void write_ppm(const blitz::Array<T,3>& image, const std::string& filename){
+    NetPBMFile ppm(filename.c_str(), 'w');
+    ppm.write(image);
+  }
+
+
+  bool is_color_p_m(const std::string& filename){
+    NetPBMFile p_m(filename.c_str(), 'r');
+    return p_m.type().nd == 3;
+  }
+
   template <class T, int N>
   blitz::Array<T,N> read_p_m(const std::string& filename){
     NetPBMFile p_m(filename.c_str(), 'r');
@@ -98,6 +140,7 @@ namespace bob { namespace io { namespace image {
     p_m.write(image);
   }
 
+
 }}}
 
 #endif /* BOB_IO_IMAGE_NETPBM_H */
diff --git a/bob/io/image/include/bob.io.image/png.h b/bob/io/image/include/bob.io.image/png.h
index 3e4e15203fffbef8706511d9f9067ae2ffbfbcb4..0bc0909ec77191d9fcf23ebb0150a9721f89accd 100644
--- a/bob/io/image/include/bob.io.image/png.h
+++ b/bob/io/image/include/bob.io.image/png.h
@@ -88,6 +88,11 @@ namespace bob { namespace io { namespace image {
       static std::string s_codecname;
   };
 
+  bool is_color_png(const std::string& filename){
+    PNGFile png(filename.c_str(), 'r');
+    return png.type().nd == 3;
+  }
+
   template <class T, int N>
   blitz::Array<T,N> read_png(const std::string& filename){
     PNGFile png(filename.c_str(), 'r');
diff --git a/bob/io/image/include/bob.io.image/tiff.h b/bob/io/image/include/bob.io.image/tiff.h
index 839fb3060d71c136fd01cd2df3dfe9d79d29ef16..04254035c4a387f347249098f91f4ed772a8f8d6 100644
--- a/bob/io/image/include/bob.io.image/tiff.h
+++ b/bob/io/image/include/bob.io.image/tiff.h
@@ -88,6 +88,11 @@ namespace bob { namespace io { namespace image {
       static std::string s_codecname;
   };
 
+  bool is_color_tiff(const std::string& filename){
+    TIFFFile tiff(filename.c_str(), 'r');
+    return tiff.type().nd == 3;
+  }
+
   template <class T, int N>
   blitz::Array<T,N> read_tiff(const std::string& filename){
     TIFFFile tiff(filename.c_str(), 'r');
diff --git a/bob/io/image/main.cpp b/bob/io/image/main.cpp
index 893d78a54559807e193c284fc8720f48fcb8c1a5..d7224ec8ff63c19747b4d8cbfe9d17429c7e5efc 100644
--- a/bob/io/image/main.cpp
+++ b/bob/io/image/main.cpp
@@ -64,41 +64,38 @@ BOB_TRY
   // BMP; only color images are supported
   boost::filesystem::path bmp(tempdir); bmp /= std::string("color.bmp");
   bob::io::image::write_bmp(color_image, bmp.string());
-  blitz::Array<uint8_t, 3> color_bmp = bob::io::image::read_bmp<uint8_t>(bmp.string());
 
+  blitz::Array<uint8_t, 3> color_bmp = bob::io::image::read_bmp(bmp.string());
   if (blitz::any(blitz::abs(color_image - color_bmp) > 0))
     throw std::runtime_error("BMP image IO did not succeed, check " + bmp.string());
 
 
-#ifdef HAVE_LIBGIF
-  // GIF
-  boost::filesystem::path gif_gray(tempdir); gif_gray /= std::string("gray.gif");
-  bob::io::image::write_gif(gray_image, gif_gray.string());
-  blitz::Array<uint8_t, 2> gray_gif = bob::io::image::read_gif<uint8_t, 2>(gif_gray.string());
-
-  if (blitz::any(blitz::abs(gray_image - gray_gif) > 0))
-    throw std::runtime_error("GIF gray image IO did not succeed, check " + gif_gray.string());
-
-  boost::filesystem::path gif_color(tempdir); gif_color /= std::string("color.gif");
-  bob::io::image::write_gif(color_image, gif_color.string());
-  blitz::Array<uint8_t, 3> color_gif = bob::io::image::read_gif<uint8_t, 3>(gif_color.string());
+#ifdef HAVE_GIFLIB
+  // GIF; only color images are supported
+  boost::filesystem::path gif(tempdir); gif /= std::string("color.gif");
+  bob::io::image::write_gif(color_image, gif.string());
 
-  if (blitz::any(blitz::abs(color_image - color_gif) > 0))
-    throw std::runtime_error("GIF color image IO did not succeed, check " + gif_color.string());
+  blitz::Array<uint8_t, 3> color_gif = bob::io::image::read_gif(gif.string());
+  if (blitz::any(blitz::abs(color_image - color_gif) > 8)) // TODO: why is GIF not lossless?
+    throw std::runtime_error("GIF image IO did not succeed, check " + gif.string());
 #endif
 
   // NetPBM
   boost::filesystem::path pgm(tempdir); pgm /= std::string("gray.pgm");
-  bob::io::image::write_p_m(gray_image, pgm.string());
-  blitz::Array<uint8_t, 2> gray_pgm = bob::io::image::read_p_m<uint8_t, 2>(pgm.string());
+  bob::io::image::write_pgm(gray_image, pgm.string());
+  if (bob::io::image::is_color_p_m(pgm.string()))
+    throw std::runtime_error("PGM image " + pgm.string() + " is not gray as expected");
 
+  blitz::Array<uint8_t, 2> gray_pgm = bob::io::image::read_pgm<uint8_t>(pgm.string());
   if (blitz::any(blitz::abs(gray_image - gray_pgm) > 0))
     throw std::runtime_error("PGM image IO did not succeed, check " + pgm.string());
 
   boost::filesystem::path ppm(tempdir); ppm /= std::string("color.ppm");
-  bob::io::image::write_p_m(color_image, ppm.string());
-  blitz::Array<uint8_t, 3> color_ppm = bob::io::image::read_p_m<uint8_t, 3>(ppm.string());
+  bob::io::image::write_ppm(color_image, ppm.string());
+  if (!bob::io::image::is_color_p_m(ppm.string()))
+    throw std::runtime_error("PPM image " + ppm.string() + " is not color as expected");
 
+  blitz::Array<uint8_t, 3> color_ppm = bob::io::image::read_ppm<uint8_t>(ppm.string());
   if (blitz::any(blitz::abs(color_image - color_ppm) > 0))
     throw std::runtime_error("PPM image IO did not succeed, check " + ppm.string());
 
@@ -107,15 +104,19 @@ BOB_TRY
   // JPEG
   boost::filesystem::path jpeg_gray(tempdir); jpeg_gray /= std::string("gray.jpg");
   bob::io::image::write_jpeg(gray_image, jpeg_gray.string());
-  blitz::Array<uint8_t, 2> gray_jpeg = bob::io::image::read_jpeg<uint8_t, 2>(jpeg_gray.string());
+  if (bob::io::image::is_color_jpeg(jpeg_gray.string()))
+    throw std::runtime_error("JPEG image " + jpeg_gray.string() + " is not gray as expected");
 
+  blitz::Array<uint8_t, 2> gray_jpeg = bob::io::image::read_jpeg<2>(jpeg_gray.string());
   if (blitz::any(blitz::abs(gray_image - gray_jpeg) > 10))
     throw std::runtime_error("JPEG gray image IO did not succeed, check " + jpeg_gray.string());
 
   boost::filesystem::path jpeg_color(tempdir); jpeg_color /= std::string("color.jpg");
   bob::io::image::write_jpeg(color_image, jpeg_color.string());
-  blitz::Array<uint8_t, 3> color_jpeg = bob::io::image::read_jpeg<uint8_t, 3>(jpeg_color.string());
+  if (!bob::io::image::is_color_jpeg(jpeg_color.string()))
+    throw std::runtime_error("JPEG image " + jpeg_color.string() + " is not color as expected");
 
+  blitz::Array<uint8_t, 3> color_jpeg = bob::io::image::read_jpeg<3>(jpeg_color.string());
   if (blitz::any(blitz::abs(color_image - color_jpeg) > 10))
     throw std::runtime_error("JPEG color image IO did not succeed, check " + jpeg_color.string());
 #endif
@@ -124,34 +125,42 @@ BOB_TRY
   // PNG
   boost::filesystem::path png_gray(tempdir); png_gray /= std::string("gray.png");
   bob::io::image::write_png(gray_image, png_gray.string());
-  blitz::Array<uint8_t, 2> gray_png = bob::io::image::read_png<uint8_t, 2>(png_gray.string());
+  if (bob::io::image::is_color_png(png_gray.string()))
+    throw std::runtime_error("PNG image " + png_gray.string() + " is not gray as expected");
 
+  blitz::Array<uint8_t, 2> gray_png = bob::io::image::read_png<uint8_t, 2>(png_gray.string());
   if (blitz::any(blitz::abs(gray_image - gray_png) > 1))
-    throw std::runtime_error("JPEG gray image IO did not succeed, check " + png_gray.string());
+    throw std::runtime_error("PNG gray image IO did not succeed, check " + png_gray.string());
 
   boost::filesystem::path png_color(tempdir); png_color /= std::string("color.png");
   bob::io::image::write_png(color_image, png_color.string());
-  blitz::Array<uint8_t, 3> color_png = bob::io::image::read_png<uint8_t, 3>(png_color.string());
+  if (!bob::io::image::is_color_png(png_color.string()))
+    throw std::runtime_error("PNG image " + png_color.string() + " is not color as expected");
 
+  blitz::Array<uint8_t, 3> color_png = bob::io::image::read_png<uint8_t, 3>(png_color.string());
   if (blitz::any(blitz::abs(color_image - color_png) > 1))
-    throw std::runtime_error("JPEG color image IO did not succeed, check " + png_color.string());
+    throw std::runtime_error("PNG color image IO did not succeed, check " + png_color.string());
 #endif
 
 #ifdef HAVE_LIBTIFF
   // TIFF
   boost::filesystem::path tiff_gray(tempdir); tiff_gray /= std::string("gray.tiff");
   bob::io::image::write_tiff(gray_image, tiff_gray.string());
-  blitz::Array<uint8_t, 2> gray_tiff = bob::io::image::read_tiff<uint8_t, 2>(tiff_gray.string());
+  if (bob::io::image::is_color_tiff(tiff_gray.string()))
+    throw std::runtime_error("TIFF image " + tiff_gray.string() + " is not gray as expected");
 
+  blitz::Array<uint8_t, 2> gray_tiff = bob::io::image::read_tiff<uint8_t, 2>(tiff_gray.string());
   if (blitz::any(blitz::abs(gray_image - gray_tiff) > 1))
-    throw std::runtime_error("JPEG gray image IO did not succeed, check " + tiff_gray.string());
+    throw std::runtime_error("TIFF gray image IO did not succeed, check " + tiff_gray.string());
 
   boost::filesystem::path tiff_color(tempdir); tiff_color /= std::string("color.tiff");
   bob::io::image::write_tiff(color_image, tiff_color.string());
-  blitz::Array<uint8_t, 3> color_tiff = bob::io::image::read_tiff<uint8_t, 3>(tiff_color.string());
+  if (!bob::io::image::is_color_tiff(tiff_color.string()))
+    throw std::runtime_error("TIFF image " + tiff_color.string() + " is not color as expected");
 
+  blitz::Array<uint8_t, 3> color_tiff = bob::io::image::read_tiff<uint8_t, 3>(tiff_color.string());
   if (blitz::any(blitz::abs(color_image - color_tiff) > 1))
-    throw std::runtime_error("JPEG color image IO did not succeed, check " + tiff_color.string());
+    throw std::runtime_error("TIFF color image IO did not succeed, check " + tiff_color.string());
 #endif
 
 
diff --git a/doc/cpp_api.rst b/doc/cpp_api.rst
new file mode 100644
index 0000000000000000000000000000000000000000..070e87b9c2454fb3fd488179ea01f8c657de0588
--- /dev/null
+++ b/doc/cpp_api.rst
@@ -0,0 +1,188 @@
+.. vim: set fileencoding=utf-8 :
+.. Manuel Gunther <siebenkopf@googlemail.com>
+.. Mon May 23 15:25:41 MDT 2016
+
+=========
+ C++ API
+=========
+
+The C++ API of ``bob.io.image`` allows users to read and write images in different file formats.
+For all image tyres, there exist two functions for reading and writing image, a function to peek the color information (if applicable) and a C++ class that can be used for more detailed information about the image.
+
+BMP
+---
+
+.. code-block: cpp
+
+   #include <bob.io.image/bmp.h>
+
+.. cpp:function:: blitz::Array<uint8_t,3> bob::io::image::read_bmp(const std::string& filename)
+
+   Reads a color BMP image of data type ``uint8_t``.
+
+.. cpp:function:: void bob::io::image::write_bmp(const blitz::Array<uint8_t,3>& image, const std::string& filename)
+
+   Writes the BMP color ``image`` .
+   If the file exists, it will be overwritten.
+   Only ``uint8_t`` data type is supported.
+
+
+GIF
+---
+
+.. code-block: cpp
+
+   #include <bob.io.image/gif.h>
+
+.. cpp:function:: blitz::Array<uint8_t,3> bob::io::image::read_gif(const std::string& filename)
+
+   Reads a color GIF image of data type ``uint8_t``.
+
+.. cpp:function:: void bob::io::image::write_gif(const blitz::Array<uint8_t,3>& image, const std::string& filename)
+
+   Writes the GIF color ``image`` .
+   If the file exists, it will be overwritten.
+   Only ``uint8_t`` data type is supported.
+
+
+JPEG
+----
+
+.. code-block: cpp
+
+   #include <bob.io.image/jpeg.h>
+
+.. cpp:function:: bool bob::io::image::is_color_jpeg(const std::string& filename)
+
+   Returns ``true`` if the JPEG image with the given name is a color image, else ``false``.
+
+.. cpp:function:: template <int N> blitz::Array<uint8_t,N> bob::io::image::read_jpeg(const std::string& filename)
+
+   Reads a JPEG image of the given type (grayscale: ``N=2`` or color: ``N=3``).
+   Only ``uint8_t`` data type is supported.
+   Please assure that you read images of the correct color type, see :cpp:func:`bob::io::image::is_color_jpeg`.
+
+.. cpp:function:: template <int N> void bob::io::image::write_jpeg(const blitz::Array<uint8_t,N>& image, const std::string& filename)
+
+   Writes the JPEG ``image`` of the given type (grayscale: ``N=2`` or color: ``N=3``) to a file with the given ``filename``.
+   If the file exists, it will be overwritten.
+   Only ``uint8_t`` data type is supported.
+
+
+TIFF
+----
+
+.. code-block: cpp
+
+   #include <bob.io.image/tiff.h>
+
+.. cpp:function:: bool bob::io::image::is_color_tiff(const std::string& filename)
+
+   Returns ``true`` if the TIFF image with the given name is a color image, else ``false``.
+
+.. cpp:function:: template <class T, int N> blitz::Array<T,N> bob::io::image::read_tiff(const std::string& filename)
+
+   Reads a TIFF image of the given type (grayscale: ``N=2`` or color: ``N=3``).
+   Only ``uint8_t`` and ``uint16_t`` data types are supported.
+   Please assure that you read images of the correct color type, see :cpp:func:`bob::io::image::is_color_tiff`.
+
+.. cpp:function:: template <class T, int N> void bob::io::image::write_tiff(const blitz::Array<T,N>& image, const std::string& filename)
+
+   Writes the TIFF ``image`` of the given type (grayscale: ``N=2`` or color: ``N=3``) to a file with the given ``filename``.
+   If the file exists, it will be overwritten.
+   Only ``uint8_t`` and ``uint16_t`` data types are supported.
+
+
+PNG
+---
+
+.. code-block: cpp
+
+   #include <bob.io.image/png.h>
+
+.. cpp:function:: bool bob::io::image::is_color_png(const std::string& filename)
+
+   Returns ``true`` if the PNG image with the given name is a color image, else ``false``.
+
+.. cpp:function:: template <class T, int N> blitz::Array<T,N> bob::io::image::read_png(const std::string& filename)
+
+   Reads a PNG image of the given type (grayscale: ``N=2`` or color: ``N=3``).
+   Only ``uint8_t`` and ``uint16_t`` data types are supported.
+   Please assure that you read images of the correct color type, see :cpp:func:`bob::io::image::is_color_png`.
+
+.. cpp:function:: template <class T, int N> void bob::io::image::write_png(const blitz::Array<T,N>& image, const std::string& filename)
+
+   Writes the PNG ``image`` of the given type (grayscale: ``N=2`` or color: ``N=3``) to a file with the given ``filename``.
+   If the file exists, it will be overwritten.
+   Only ``uint8_t`` and ``uint16_t`` data types are supported.
+
+
+NetPBM
+------
+
+.. note::
+   Internally, the image IO is based on the filename extension to decide, which codec to use.
+   Hence, the filename extension needs to match the function and data type that you use.
+   Use ``.pbm`` for binary, ``.pgm`` for gray level images, and any other extension (typically ``.ppm``) for color images.
+
+.. code-block: cpp
+
+   #include <bob.io.image/netpbm.h>
+
+.. cpp:function:: bool bob::io::image::is_color_p_m(const std::string& filename)
+
+   Returns ``true`` if the image with the given name is a color image, else ``false``.
+
+.. cpp:function:: template <class T, int N> blitz::Array<T,N> bob::io::image::read_p_m(const std::string& filename)
+
+   Reads an image of the given type (grayscale: ``N=2`` or color: ``N=3``).
+   Only ``uint8_t`` and ``uint16_t`` data types are supported.
+   Please assure that you read images of the correct color type, see :cpp:func:`bob::io::image::is_color_p_m`.
+
+.. cpp:function:: template <class T, int N> void bob::io::image::write_p_m(const blitz::Array<T,N>& image, const std::string& filename)
+
+   Writes the ``image`` of the given type (grayscale: ``N=2`` or color: ``N=3``) to a file with the given ``filename``.
+   If the file exists, it will be overwritten.
+   Only ``uint8_t`` and ``uint16_t`` data types are supported.
+
+
+.. cpp:function:: template <class T> blitz::Array<T,2> bob::io::image::read_pbm(const std::string& filename)
+
+   Reads an binary image.
+   Only ``uint8_t`` and ``uint16_t`` data types are supported.
+   Filename extension ``.pbm`` is required.
+
+.. cpp:function:: template <class T> void bob::io::image::write_pbm(const blitz::Array<T,2>& image, const std::string& filename)
+
+   Writes the binary ``image`` to a file with the given ``filename``.
+   If the file exists, it will be overwritten.
+   Only ``uint8_t`` and ``uint16_t`` data types are supported.
+   Filename extension ``.pbm`` is required.
+
+
+.. cpp:function:: template <class T> blitz::Array<T,2> bob::io::image::read_pgm(const std::string& filename)
+
+   Reads an grayscale image. Only ``uint8_`` and ``uint16_`` data types are supported.
+   Filename extension ``.pgm`` is required.
+
+.. cpp:function:: template <class T> void bob::io::image::write_pgm(const blitz::Array<T,2>& image, const std::string& filename)
+
+   Writes the grayscale ``image`` to a file with the given ``filename``.
+   If the file exists, it will be overwritten.
+   Only ``uint8_t`` and ``uint16_t`` data types are supported.
+   Filename extension ``.pgm`` is required.
+
+
+.. cpp:function:: template <class T> blitz::Array<T,3> bob::io::image::read_ppm(const std::string& filename)
+
+   Reads an binary color image. Only ``uint8_`` and ``uint16_`` data types are supported.
+   Filename extension cannot be ``.pbm`` or ``.pgm``.
+
+.. cpp:function:: template <class T> void bob::io::image::write_ppm(const blitz::Array<T,3>& image, const std::string& filename)
+
+   Writes the color ``image`` to a file with the given ``filename``.
+   If the file exists, it will be overwritten.
+   Only ``uint8_t`` and ``uint16_t`` data types are supported.
+   Filename extension cannot be ``.pbm`` or ``.pgm``.
+
+.. include:: links.rst
diff --git a/doc/index.rst b/doc/index.rst
index 7fee9c07562e2d408e30515aaca48486c7b5af02..2d4e218d533f4a325c2c90fab931a783f801cdeb 100644
--- a/doc/index.rst
+++ b/doc/index.rst
@@ -18,12 +18,14 @@ to read and write images using its native API (:py:func:`bob.io.base.load` and
 
 At present, this plugin provides support for the following types of images:
 
-* TIFF
-* JPEG
-* GIF
-* PNG
-* BMP
-* Netpbm images (PGM, PPM, PBM)
+* TIFF (gray and color)
+* JPEG (gray and color)
+* GIF (color only)
+* PNG (gray and color)
+* BMP (color only)
+* Netpbm images (binary - PBM, gray - PGM, color - PPM)
+
+Additionally, we provide the pure C++ interface to read and write these kind of images, see :doc:`cpp_api`.
 
 Documentation
 -------------
@@ -33,6 +35,7 @@ Documentation
 
    guide
    py_api
+   cpp_api
 
 Indices and tables
 ------------------