Repository: python-pillow/Pillow

Issue:
Documentation: Image.point(lut, mode)  not limited to 256-length sequences
Contrary to what the documentation says,  lookup tables larger than 256 values per band can be used for higher-bit images.  256 applies only to 8bit images.

For 16bit images I use 65536-length LUTs all the time with PIL up to 2.2.1 and it works well.

Documentation: Image.point(lut, mode)  not limited to 256-length sequences
Contrary to what the documentation says,  lookup tables larger than 256 values per band can be used for higher-bit images.  256 applies only to 8bit images.

For 16bit images I use 65536-length LUTs all the time with PIL up to 2.2.1 and it works well.



Discussion:

Resolving patch:
diff --git a/PIL/Image.py b/PIL/Image.py
--- a/PIL/Image.py
+++ b/PIL/Image.py
@@ -1134,14 +1134,16 @@ def point(self, lut, mode=None):
         """
         Maps this image through a lookup table or function.
 
-        :param lut: A lookup table, containing 256 values per band in the
-           image. A function can be used instead, it should take a single
-           argument. The function is called once for each possible pixel
-           value, and the resulting table is applied to all bands of the
-           image.
+        :param lut: A lookup table, containing 256 (or 65336 if
+           self.mode=="I" and mode == "L") values per band in the
+           image.  A function can be used instead, it should take a
+           single argument. The function is called once for each
+           possible pixel value, and the resulting table is applied to
+           all bands of the image.
         :param mode: Output mode (default is same as input).  In the
            current version, this can only be used if the source image
-           has mode "L" or "P", and the output has mode "1".
+           has mode "L" or "P", and the output has mode "1" or the
+           source image mode is "I" and the output mode is "L".
         :returns: An :py:class:`~PIL.Image.Image` object.
         """
 
@@ -1150,10 +1152,12 @@ def point(self, lut, mode=None):
         if isinstance(lut, ImagePointHandler):
             return lut.point(self)
 
-        if not isinstance(lut, collections.Sequence):
+        if callable(lut):
             # if it isn't a list, it should be a function
             if self.mode in ("I", "I;16", "F"):
                 # check if the function can be used with point_transform
+                # UNDONE wiredfool -- I think this prevents us from ever doing
+                # a gamma function point transform on > 8bit images. 
                 scale, offset = _getscaleoffset(lut)
                 return self._new(self.im.point_transform(scale, offset))
             # for other modes, convert the function to a table


Test patch:
diff --git a/Tests/test_image_point.py b/Tests/test_image_point.py
--- a/Tests/test_image_point.py
+++ b/Tests/test_image_point.py
@@ -17,3 +17,12 @@ def test_sanity():
     assert_no_exception(lambda: im.point(lambda x: x*1+1))
     assert_exception(TypeError, lambda: im.point(lambda x: x-1))
     assert_exception(TypeError, lambda: im.point(lambda x: x/1))
+
+
+def test_16bit_lut():
+    """ Tests for 16 bit -> 8 bit lut for converting I->L images
+        see https://github.com/python-imaging/Pillow/issues/440
+    """
+
+    im = lena("I")
+    assert_no_exception(lambda: im.point(list(range(256))*256, 'L'))
diff --git a/Tests/test_numpy.py b/Tests/test_numpy.py
--- a/Tests/test_numpy.py
+++ b/Tests/test_numpy.py
@@ -106,3 +106,15 @@ def _to_array(mode, dtype):
     for mode in modes:
         assert_no_exception(lambda: _to_array(*mode))
 
+
+def test_point_lut():
+    # see https://github.com/python-imaging/Pillow/issues/439
+    
+    data = list(range(256))*3
+    lut = numpy.array(data, dtype='uint8')
+
+    im = lena()
+
+    assert_no_exception(lambda: im.point(lut))
+    
+