Repository: scikit-image/scikit-image

Issue:
Feature request: skimage.io.imdecode
## Description
We have to write the image to disk for skimage to read from it.
Why not let skimage.io to decode form a bytes  string directly inside memory.



Discussion:
@dwSun this would be a useful feature, I agree. One of the usecases is to decode a received via REST, gRPC bytesting.
Even if we decide not to incorporate such function, you can always use `imread` with `imageio` plugin which supports reading from `bytes` (see http://imageio.readthedocs.io/en/latest/userapi.html#imageio.imread):
```
import os
import skimage
from skimage import io

p = skimage.data_dir
with open(os.path.join(p, 'coins.png'), 'rb') as f:
    b = f.read()

img = imread(b, plugin='imageio')

img

Image([[ 47, 123, 133, ...,  14,   3,  12],
       [ 93, 144, 145, ...,  12,   7,   7],
       [126, 147, 143, ...,   2,  13,   3],
       ..., 
       [ 81,  79,  74, ...,   6,   4,   7],
       [ 88,  82,  74, ...,   5,   7,   8],
       [ 91,  79,  68, ...,   4,  10,   7]], dtype=uint8)
```

@soupault thanks for your reply and your solution. I will use imageio plugin to decode my image bytestring.
The solution by @soupault looks simple and straightforward. Do we need a specific function for that? Or should the example appear in the doc? It's my usual reaction to try to keep the API as short as possible :-).
@emmanuelle mentioning this case in the docstring will do it for me. :)
Also, `imread` can detect when the object is a bytestream and automatically attempt to use `imageio`?  Also, we should just switch to `imageio` by default.
I've changed the milestone, because I don't think this should hold up 0.14

Resolving patch:
diff --git a/skimage/io/_io.py b/skimage/io/_io.py
--- a/skimage/io/_io.py
+++ b/skimage/io/_io.py
@@ -24,7 +24,7 @@ def imread(fname, as_gray=False, plugin=None, flatten=None,
         Images that are already in gray-scale format are not converted.
     plugin : str, optional
         Name of plugin to use.  By default, the different plugins are
-        tried (starting with the Python Imaging Library) until a suitable
+        tried (starting with imageio) until a suitable
         candidate is found.  If not given and fname is a tiff file, the
         tifffile plugin will be used.
 
@@ -115,7 +115,7 @@ def imsave(fname, arr, plugin=None, **plugin_args):
         Image data.
     plugin : str
         Name of plugin to use.  By default, the different plugins are
-        tried (starting with the Python Imaging Library) until a suitable
+        tried (starting with imageio) until a suitable
         candidate is found.  If not given and fname is a tiff file, the
         tifffile plugin will be used.
 
@@ -151,7 +151,7 @@ def imshow(arr, plugin=None, **plugin_args):
         Image data or name of image file.
     plugin : str
         Name of plugin to use.  By default, the different plugins are
-        tried (starting with the Python Imaging Library) until a suitable
+        tried (starting with imageio) until a suitable
         candidate is found.
 
     Other parameters
diff --git a/skimage/io/manage_plugins.py b/skimage/io/manage_plugins.py
--- a/skimage/io/manage_plugins.py
+++ b/skimage/io/manage_plugins.py
@@ -45,7 +45,7 @@
 # the following preferences.
 preferred_plugins = {
     # Default plugins for all types (overridden by specific types below).
-    'all': ['pil', 'matplotlib', 'qt'],
+    'all': ['imageio', 'pil', 'matplotlib', 'qt'],
     'imshow': ['matplotlib'],
     'imshow_collection': ['matplotlib']
 }


Test patch:
diff --git a/skimage/io/tests/test_collection.py b/skimage/io/tests/test_collection.py
--- a/skimage/io/tests/test_collection.py
+++ b/skimage/io/tests/test_collection.py
@@ -46,7 +46,7 @@ def test_len(self):
     def test_getitem(self):
         num = len(self.images)
         for i in range(-num, num):
-            assert type(self.images[i]) is np.ndarray
+            assert isinstance(self.images[i], np.ndarray)
         assert_allclose(self.images[0],
                         self.images[-num])