diff --git a/lib/matplotlib/cm.py b/lib/matplotlib/cm.py
index f3a80f470d7..dcc0a1db6bd 100644
--- a/lib/matplotlib/cm.py
+++ b/lib/matplotlib/cm.py
@@ -269,10 +269,6 @@ def to_rgba(self, x, alpha=None, bytes=False, norm=True):
if norm:
x = self.norm(x)
rgba = self.cmap(x, alpha=alpha, bytes=bytes)
- # For floating-point greyscale images, we treat negative as
- # transparent so we copy that over to the alpha channel
- if x.ndim == 2 and x.dtype.kind == 'f':
- rgba[:, :, 3][x < 0.0] = 0
return rgba
def set_array(self, A):
diff --git a/lib/matplotlib/image.py b/lib/matplotlib/image.py
index ade8bd8a28f..a29e62cc78a 100644
--- a/lib/matplotlib/image.py
+++ b/lib/matplotlib/image.py
@@ -354,20 +354,22 @@ def _make_image(self, A, in_bbox, out_bbox, clip_bbox, magnification=1.0,
out_height = int(out_height_base)
if not unsampled:
+ created_rgba_mask = False
+
if A.ndim == 2:
A = self.norm(A)
+ # If the image is greyscale, convert to RGBA with the
+ # correct alpha channel for resizing
+ rgba = np.empty((A.shape[0], A.shape[1], 4), dtype=A.dtype)
+ rgba[..., 0:3] = np.expand_dims(A, 2)
if A.dtype.kind == 'f':
- # For floating-point greyscale images, we treat negative
- # numbers as transparent.
-
- # TODO: Use np.full when we support Numpy 1.9 as a
- # minimum
- output = np.empty((out_height, out_width), dtype=A.dtype)
- output[...] = -100.0
+ rgba[..., 3] = ~A.mask
else:
- output = np.zeros((out_height, out_width), dtype=A.dtype)
-
+ rgba[..., 3] = np.where(A.mask, 0, np.iinfo(A.dtype).max)
+ A = rgba
+ output = np.zeros((out_height, out_width, 4), dtype=A.dtype)
alpha = 1.0
+ created_rgba_mask = True
elif A.ndim == 3:
# Always convert to RGBA, even if only RGB input
if A.shape[2] == 3:
@@ -388,10 +390,16 @@ def _make_image(self, A, in_bbox, out_bbox, clip_bbox, magnification=1.0,
self.get_resample(), alpha,
self.get_filternorm() or 0.0, self.get_filterrad() or 0.0)
+ if created_rgba_mask:
+ # Convert back to a masked greyscale array so
+ # colormapping works correctly
+ output = np.ma.masked_array(
+ output[..., 0], output[..., 3] < 0.5)
+
output = self.to_rgba(output, bytes=True, norm=False)
- # Apply alpha *after* if the input was greyscale
- if A.ndim == 2:
+ # Apply alpha *after* if the input was greyscale without a mask
+ if A.ndim == 2 or created_rgba_mask:
alpha = self.get_alpha()
if alpha is not None and alpha != 1.0:
alpha_channel = output[:, :, 3]
diff --git a/lib/matplotlib/tests/baseline_images/test_image/mask_image.pdf b/lib/matplotlib/tests/baseline_images/test_image/mask_image.pdf
new file mode 100644
index 00000000000..695b149f03d
Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_image/mask_image.pdf differ
diff --git a/lib/matplotlib/tests/baseline_images/test_image/mask_image.png b/lib/matplotlib/tests/baseline_images/test_image/mask_image.png
new file mode 100644
index 00000000000..1e4f2873e39
Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_image/mask_image.png differ
diff --git a/lib/matplotlib/tests/baseline_images/test_image/mask_image.svg b/lib/matplotlib/tests/baseline_images/test_image/mask_image.svg
new file mode 100644
index 00000000000..174c5942c2c
--- /dev/null
+++ b/lib/matplotlib/tests/baseline_images/test_image/mask_image.svg
@@ -0,0 +1,365 @@
+
+
+
+
diff --git a/lib/matplotlib/tests/baseline_images/test_image/rotate_image.png b/lib/matplotlib/tests/baseline_images/test_image/rotate_image.png
index fd72f2a9bff..cb1853ed179 100644
Binary files a/lib/matplotlib/tests/baseline_images/test_image/rotate_image.png and b/lib/matplotlib/tests/baseline_images/test_image/rotate_image.png differ
diff --git a/lib/matplotlib/tests/test_image.py b/lib/matplotlib/tests/test_image.py
index 252c5248a68..6af9a5ef5f1 100644
--- a/lib/matplotlib/tests/test_image.py
+++ b/lib/matplotlib/tests/test_image.py
@@ -610,6 +610,25 @@ def test_image_preserve_size2():
np.identity(n, bool)[::-1])
+@image_comparison(baseline_images=['mask_image'],
+ remove_text=True)
+def test_mask_image():
+ # Test mask image two ways: Using nans and using a masked array.
+
+ fig, (ax1, ax2) = plt.subplots(1, 2)
+
+ A = np.ones((5, 5))
+ A[1:2, 1:2] = np.nan
+
+ ax1.imshow(A, interpolation='nearest')
+
+ A = np.zeros((5, 5), dtype=np.bool)
+ A[1:2, 1:2] = True
+ A = np.ma.masked_array(np.ones((5, 5), dtype=np.uint16), A)
+
+ ax2.imshow(A, interpolation='nearest')
+
+
if __name__=='__main__':
import nose
nose.runmodule(argv=['-s','--with-doctest'], exit=False)
diff --git a/src/_image_resample.h b/src/_image_resample.h
index 3bf7aa182fb..cee102244f2 100644
--- a/src/_image_resample.h
+++ b/src/_image_resample.h
@@ -533,6 +533,35 @@ template <> class type_mapping
};
+template <> class type_mapping
+{
+ public:
+ typedef agg::rgba16 color_type;
+ typedef fixed_blender_rgba_plain blender_type;
+ typedef fixed_blender_rgba_pre pre_blender_type;
+ typedef agg::pixfmt_alpha_blend_rgba pixfmt_type;
+ typedef agg::pixfmt_alpha_blend_rgba pixfmt_pre_type;
+
+ template
+ struct span_gen_affine_type
+ {
+ typedef agg::span_image_resample_rgba_affine type;
+ };
+
+ template
+ struct span_gen_filter_type
+ {
+ typedef agg::span_image_filter_rgba type;
+ };
+
+ template
+ struct span_gen_nn_type
+ {
+ typedef agg::span_image_filter_rgba_nn type;
+ };
+};
+
+
template <> class type_mapping
{
public:
diff --git a/src/_image_wrapper.cpp b/src/_image_wrapper.cpp
index dac7c44e2ad..aac86bf9367 100644
--- a/src/_image_wrapper.cpp
+++ b/src/_image_wrapper.cpp
@@ -226,6 +226,19 @@ image_resample(PyObject *self, PyObject* args, PyObject *kwargs)
params);
Py_END_ALLOW_THREADS
break;
+ case NPY_UINT16:
+ case NPY_INT16:
+ Py_BEGIN_ALLOW_THREADS
+ resample(
+ (agg::rgba16 *)PyArray_DATA(input_array),
+ PyArray_DIM(input_array, 1),
+ PyArray_DIM(input_array, 0),
+ (agg::rgba16 *)PyArray_DATA(output_array),
+ PyArray_DIM(output_array, 1),
+ PyArray_DIM(output_array, 0),
+ params);
+ Py_END_ALLOW_THREADS
+ break;
case NPY_FLOAT32:
Py_BEGIN_ALLOW_THREADS
resample(
@@ -254,13 +267,13 @@ image_resample(PyObject *self, PyObject* args, PyObject *kwargs)
PyErr_SetString(
PyExc_ValueError,
"3-dimensional arrays must be of dtype unsigned byte, "
- "float32 or float64");
+ "unsigned short, float32 or float64");
goto error;
}
} else {
PyErr_Format(
PyExc_ValueError,
- "If 3-dimensional, array must be RGBA. Got %d.",
+ "If 3-dimensional, array must be RGBA. Got %d planes.",
PyArray_DIM(input_array, 2));
goto error;
}