Repository: python-pillow/Pillow

Issue:
"cannot identify image file" in 3.0.0 on a TIFF file that worked with 2.9.0
To test, first download the files in this folder: https://github.com/flask-admin/flask-admin/tree/master/flask_admin/tests/data

Then run this code in the same folder as those files:

```
from PIL import Image

file_list = [
    'copyleft.gif',
    'copyleft.jpeg',
    'copyleft.jpg',
    'copyleft.png',
    'copyleft.tiff',
]

for filename in file_list:
    with open(filename, 'rb') as fp:
        image = Image.open(fp)
        print("successfully opened:", filename)
```

It will open all 5 files in 2.9.0, but in 3.0.0 it will fail on the TIFF file. It's failing on OS X Yosemite and Ubuntu 12.04 LTS Server Edition 64 bit with both Python 2 and 3.

The error I'm getting is: `IOError: cannot identify image file <open file 'copyleft.tiff', mode 'rb' at 0x10a15f8a0>`



Discussion:
Well, It's the Tiff IFD change. 

Looks like in the reorg of the format specifications, this one got dropped:

```
...
- compression: packbits
- photometric_interpretation: 2
- planar_configuration: 1
- fill_order: 1
- size: (220, 220)
format key: ('MM', 2, (1, 1, 1), 1, (8, 8, 8), ())
- unsupported format
```

The tiff spec defines `SAMPLEFORMAT` as N shorts, where N is the number of bands in the image. 

For the old code, the sample format was set by `getscalar(SAMPLEFORMAT, (1,))`, where getformat was defined as:

```
    def getscalar(self, tag, default=None):
        try:
            value = self[tag]
            if len(value) != 1:
                if tag == SAMPLEFORMAT:
                    # work around broken (?) matrox library
                    # (from Ted Wright, via Bob Klimek)
                    raise KeyError  # use default
                raise ValueError("not a scalar")
            return value[0]
        except KeyError:
            if default is None:
                raise
            return default
```

Which I think simply means that `SAMPLEFORMAT` isn't a scalar, and would always return the default `(1,)` value unless we happened to have a single band image, in which case, we would actually deal with it correctly. Helpfully enough, we don't actually support anything but unsigned ints in multiband images, so practically we wound up doing the right thing for the wrong reasons. 

The current code just uses the `SAMPLEFORMAT` tag directly, which is fine for single band images but since we don't have any multi-item tuples defined, it's wrong for any color tiff that sets the `SAMPLEFORMAT` tag. 

--edit--
It looks like we've hit this before, since there are OSX grab lines that have the correct SAMPLEFORMAT tuple. 


Resolving patch:
diff --git a/PIL/TiffImagePlugin.py b/PIL/TiffImagePlugin.py
--- a/PIL/TiffImagePlugin.py
+++ b/PIL/TiffImagePlugin.py
@@ -180,8 +180,6 @@
     (MM, 2, (1,), 1, (8, 8, 8, 8), (2,)): ("RGBA", "RGBA"),
     (II, 2, (1,), 1, (8, 8, 8, 8), (999,)): ("RGBA", "RGBA"),  # Corel Draw 10
     (MM, 2, (1,), 1, (8, 8, 8, 8), (999,)): ("RGBA", "RGBA"),  # Corel Draw 10
-    (II, 2, (1, 1, 1, 1), 1, (8, 8, 8, 8), (1,)): ("RGBA", "RGBA"),  # OSX Grab
-    (MM, 2, (1, 1, 1, 1), 1, (8, 8, 8, 8), (1,)): ("RGBA", "RGBA"),  # OSX Grab
     (II, 3, (1,), 1, (1,), ()): ("P", "P;1"),
     (MM, 3, (1,), 1, (1,), ()): ("P", "P;1"),
     (II, 3, (1,), 2, (1,), ()): ("P", "P;1R"),
@@ -967,6 +965,13 @@ def _setup(self):
             print("- size:", self.size)
 
         format = self.tag_v2.get(SAMPLEFORMAT, (1,))
+        if len(format) > 1 and max(format) == min(format) == 1:
+            # SAMPLEFORMAT is properly per band, so an RGB image will
+            # be (1,1,1).  But, we don't support per band pixel types,
+            # and anything more than one band is a uint8. So, just
+            # take the first element. Revisit this if adding support
+            # for more exotic images.
+            format = (1,)
 
         # mode: check photometric interpretation and bits per pixel
         key = (


Test patch:
diff --git a/Tests/images/copyleft.tiff b/Tests/images/copyleft.tiff
new file mode 100644
Binary files /dev/null and b/Tests/images/copyleft.tiff differ
diff --git a/Tests/test_file_tiff.py b/Tests/test_file_tiff.py
--- a/Tests/test_file_tiff.py
+++ b/Tests/test_file_tiff.py
@@ -70,6 +70,11 @@ def test_gimp_tiff(self):
                 ])
         im.load()
 
+    def test_sampleformat(self):
+        # https://github.com/python-pillow/Pillow/issues/1466
+        im = Image.open("Tests/images/copyleft.tiff")
+        self.assertEqual(im.mode, 'RGB')
+
     def test_xyres_tiff(self):
         from PIL.TiffImagePlugin import X_RESOLUTION, Y_RESOLUTION
         filename = "Tests/images/pil168.tif"