Repository: python-pillow/Pillow

Issue:
.ico files are saved as 255x255
### What did you do?

Loading an .ico of the size 256x256 and then saving it results in an .ico file of the size 255x255. I tested it on an example .ico file: http://www.axialis.com/tutorials/iw/down.ico

### What did you expect to happen?

The icon file should stay the same after saving. No other adjustments have been made. See the code below.

### What actually happened?

The saved .ico file ended up as 255x255 file. Because Windows doesn't support 255x255 size for .ico files, it is downscaled to 128x128 when used as desktop icons. [Example](http://i.imgur.com/fm7FTfw.png). The Chromium and Chrome icons are default ones, the Chrome Canary one was saved with Pillow.

### What versions of Pillow and Python are you using?
Pillow 3.4.2, Python 3.5.2

```python
from PIL import Image
im = Image.open('down.ico')
im.save('saved.ico')
im_saved = Image.open('saved.ico')

In [2]: im.size
Out[2]: (256, 256)

In [3]: im_saved.size
Out[3]: (255, 255)
```

`(255, 255)` appears on the list of sizes at https://github.com/python-pillow/Pillow/blob/master/PIL/IcoImagePlugin.py#L45 .


Discussion:

Resolving patch:
diff --git a/PIL/IcoImagePlugin.py b/PIL/IcoImagePlugin.py
--- a/PIL/IcoImagePlugin.py
+++ b/PIL/IcoImagePlugin.py
@@ -44,16 +44,17 @@ def _save(im, fp, filename):
     fp.write(_MAGIC)  # (2+2)
     sizes = im.encoderinfo.get("sizes",
                                [(16, 16), (24, 24), (32, 32), (48, 48),
-                                (64, 64), (128, 128), (255, 255)])
+                                (64, 64), (128, 128), (256, 256)])
     width, height = im.size
     filter(lambda x: False if (x[0] > width or x[1] > height or
-                               x[0] > 255 or x[1] > 255) else True, sizes)
+                               x[0] > 256 or x[1] > 256) else True, sizes)
     fp.write(struct.pack("<H", len(sizes)))  # idCount(2)
     offset = fp.tell() + len(sizes)*16
     for size in sizes:
         width, height = size
-        fp.write(struct.pack("B", width))  # bWidth(1)
-        fp.write(struct.pack("B", height))  # bHeight(1)
+        # 0 means 256
+        fp.write(struct.pack("B", width if width < 256 else 0))  # bWidth(1)
+        fp.write(struct.pack("B", height if height < 256 else 0))  # bHeight(1)
         fp.write(b"\0")  # bColorCount(1)
         fp.write(b"\0")  # bReserved(1)
         fp.write(b"\0\0")  # wPlanes(2)
@@ -215,13 +216,13 @@ def frame(self, idx):
                 total_bytes = int((w * im.size[1]) / 8)
 
                 self.buf.seek(and_mask_offset)
-                maskData = self.buf.read(total_bytes)
+                mask_data = self.buf.read(total_bytes)
 
                 # convert raw data to image
                 mask = Image.frombuffer(
                     '1',            # 1 bpp
                     im.size,        # (w, h)
-                    maskData,       # source chars
+                    mask_data,      # source chars
                     'raw',          # raw decoder
                     ('1;I', int(w/8), -1)  # 1bpp inverted, padded, reversed
                 )
@@ -278,6 +279,7 @@ def load_seek(self):
 #
 # --------------------------------------------------------------------
 
+
 Image.register_open(IcoImageFile.format, IcoImageFile, _accept)
 Image.register_save(IcoImageFile.format, _save)
 Image.register_extension(IcoImageFile.format, ".ico")


Test patch:
diff --git a/Tests/images/hopper_256x256.ico b/Tests/images/hopper_256x256.ico
new file mode 100644
Binary files /dev/null and b/Tests/images/hopper_256x256.ico differ
diff --git a/Tests/test_file_ico.py b/Tests/test_file_ico.py
--- a/Tests/test_file_ico.py
+++ b/Tests/test_file_ico.py
@@ -48,6 +48,19 @@ def test_save_to_bytes(self):
         self.assert_image_equal(reloaded,
                                 hopper().resize((32, 32), Image.LANCZOS))
 
+    def test_save_256x256(self):
+        """Issue #2264 https://github.com/python-pillow/Pillow/issues/2264"""
+        # Arrange
+        im = Image.open("Tests/images/hopper_256x256.ico")
+        outfile = self.tempfile("temp_saved_hopper_256x256.ico")
+
+        # Act
+        im.save(outfile)
+        im_saved = Image.open(outfile)
+
+        # Assert
+        self.assertEqual(im_saved.size, (256, 256))
+
 
 if __name__ == '__main__':
     unittest.main()