Repository: python-pillow/Pillow

Issue:
ImageTk is broken on pypy
Pypy 5.6 is segfaulting in _imagingtk.c:_tkinit:

```
    /* This will bomb if interp is invalid... */
    TkImaging_Init(interp);
```

It's consistent back to 2.5.0, which is well before the Tk reorg where we're dynamically getting the interpreter address.

### What did you do?

It's trivially reproducable:

pypy viewer.py [path to image]

We're not actually testing this anywhere in our test scripts, and we're not even getting Tk recognized on pypy3 on travis. 

I haven't dug back in the archives yet to determine if this is a pypy5.6 thing, or if it's more general. 


Discussion:

Resolving patch:
diff --git a/PIL/ImageTk.py b/PIL/ImageTk.py
--- a/PIL/ImageTk.py
+++ b/PIL/ImageTk.py
@@ -32,6 +32,13 @@
     tkinter = Tkinter
     del Tkinter
 
+# required for pypy, which always has cffi installed
+try:
+    from cffi import FFI
+    ffi = FFI()
+except ImportError:
+    pass
+
 from . import Image
 from io import BytesIO
 
@@ -184,7 +191,13 @@ def paste(self, im, box=None):
             try:
                 from . import _imagingtk
                 try:
-                    _imagingtk.tkinit(tk.interpaddr(), 1)
+                    if hasattr(tk, 'interp'):
+                        # Pypy is using a ffi cdata element
+                        # (Pdb) self.tk.interp
+                        #  <cdata 'Tcl_Interp *' 0x3061b50>
+                        _imagingtk.tkinit(int(ffi.cast("uintptr_t", tk.interp)), 1)
+                    else:
+                        _imagingtk.tkinit(tk.interpaddr(), 1)
                 except AttributeError:
                     _imagingtk.tkinit(id(tk), 0)
                 tk.call("PyImagingPhoto", self.__photo, block.id)
@@ -264,6 +277,8 @@ def __str__(self):
 
 
 def getimage(photo):
+    """ This function is unimplemented """
+    
     """Copies the contents of a PhotoImage to a PIL image memory."""
     photo.tk.call("PyImagingPhotoGet", photo)
 


Test patch:
diff --git a/Tests/test_imagetk.py b/Tests/test_imagetk.py
--- a/Tests/test_imagetk.py
+++ b/Tests/test_imagetk.py
@@ -1,22 +1,29 @@
-from helper import unittest, PillowTestCase
+from helper import unittest, PillowTestCase, hopper
 from PIL import Image
 
+
 try:
     from PIL import ImageTk
+    import Tkinter as tk
     dir(ImageTk)
+    HAS_TK = True
 except (OSError, ImportError) as v:
     # Skipped via setUp()
-    pass
-
+    HAS_TK = False
+    
+TK_MODES = ('1', 'L', 'P', 'RGB', 'RGBA')
 
 class TestImageTk(PillowTestCase):
 
     def setUp(self):
+        if not HAS_TK:
+            self.skipTest("Tk not installed")
         try:
-            from PIL import ImageTk
-            dir(ImageTk)
-        except (OSError, ImportError) as v:
-            self.skipTest(v)
+            # setup tk
+            app = tk.Frame()
+            #root = tk.Tk()
+        except (tk.TclError) as v:
+            self.skipTest("TCL Error: %s" % v)
 
     def test_kw(self):
         TEST_JPG = "Tests/images/hopper.jpg"
@@ -40,5 +47,47 @@ def test_kw(self):
         self.assertEqual(im, None)
 
 
+    def test_photoimage(self):
+        for mode in TK_MODES:
+            # test as image:
+            im = hopper(mode)
+            
+            # this should not crash
+            im_tk = ImageTk.PhotoImage(im)
+
+            self.assertEqual(im_tk.width(), im.width)
+            self.assertEqual(im_tk.height(), im.height)
+
+            # _tkinter.TclError: this function is not yet supported
+            #reloaded = ImageTk.getimage(im_tk)
+            #self.assert_image_equal(reloaded, im)
+
+            
+
+    def test_photoimage_blank(self):
+        # test a image using mode/size:
+        for mode in TK_MODES:
+            im_tk = ImageTk.PhotoImage(mode, (100,100))
+            
+            self.assertEqual(im_tk.width(), 100)
+            self.assertEqual(im_tk.height(), 100)
+            
+            #reloaded = ImageTk.getimage(im_tk)
+            #self.assert_image_equal(reloaded, im)
+
+    def test_bitmapimage(self):
+        im = hopper('1')
+
+        # this should not crash
+        im_tk = ImageTk.BitmapImage(im)
+        
+        self.assertEqual(im_tk.width(), im.width)
+        self.assertEqual(im_tk.height(), im.height)
+        
+        #reloaded = ImageTk.getimage(im_tk)
+        #self.assert_image_equal(reloaded, im)
+    
+
+            
 if __name__ == '__main__':
     unittest.main()