Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ImageTk.PhotoImage from PIL leads to segfault #2471

Closed
MarkusLohmayer opened this issue May 12, 2016 · 18 comments
Closed

ImageTk.PhotoImage from PIL leads to segfault #2471

MarkusLohmayer opened this issue May 12, 2016 · 18 comments
Labels
locked [bot] locked due to inactivity

Comments

@MarkusLohmayer
Copy link

I would like to show a webcam image in a TKinter window.
I did conda install opencv pil into a python 2.7 env.

import numpy
import Tkinter as tk
import cv2
from PIL import Image, ImageTk

to get the image I do:
cam = cv2.VideoCapture(0)
ret_val, frame = cam.read()
cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
img = Image.fromarray(cv2image)
imgtk = ImageTk.PhotoImage(image=img)

the last command kills the interpreter:
Segmentation fault: 11

I am on OS X 10.11 btw.
Thanks!

@cjrh
Copy link

cjrh commented May 14, 2016

Conda? ✓
OS X? ✓
ImageTk.PhotoImage? ✓
Segfault 11? ✓

I strongly suspect this issue may be due to the "double framework" problem, i.e. Python's tkinter binary module is linked to the Tcl inside the conda distribution, while Pillow's _imagingtk.so binary has been linked to the system framework Tcl. I wrote up quite a detailed StackOverflow answer for this problem here:

http://stackoverflow.com/a/37222391/170656

Does the _imagingtk.so binary get built by the Conda team, or by the Pillow folks?

@MarkusLohmayer
Copy link
Author

Thanks, also assume this is the right direction ...
I tired what you suggest using otool and install_name_tool.
For the untouched object file I get:

otool -L _imagingtk.so.bak
/System/Library/Frameworks/Tcl.framework/Versions/8.4/Tcl (compatibility version 8.4.0, current version 8.4.0)
/usr/lib/libgcc_s.1.dylib (compatibility version 1.0.0, current version 1.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 111.0.0)

So I did:
install_name_tool -change "/System/Library/Frameworks/Tcl.framework/Versions/8.4/Tcl" "@rpath/libtcl8.5.dylib" _imagingtk.so
otool now tells me the line:
@rpath/libtcl8.5.dylib (compatibility version 8.4.0, current version 8.4.0)
I am not by any means knowledgable about those things but I notice that I pointed the code somehow to another version and the inspector tool does not recognise this.
I still end up with Segmentation fault: 11.
I did not put the right path the for the dylib the first time because in the env it is version 8.5 instead of the frameworks 8.4. When I ran the code python told me that it can not find the library (instead of causing a segfault). So yes, the problem might most likely be related to "libtcl".
Thanks so far!

@cjrh
Copy link

cjrh commented May 14, 2016

@MarquitoForrest Your original is Tcl 8.4, so your replacement must also be 8.4. What I mean, is that you need to do:

install_name_tool -change "/System/Library/Frameworks/Tcl.framework/Versions/8.4/Tcl" "@rpath/libtcl8.4.dylib" _imagingtk.so

And remember, you have to do one of those for tk as well.

I'd suggest just copy whatever you see in the _tkinter binary that is part of the Python distro itself. See the addendum in the SO post. (TBH I should change the post, so that the only solution is to match what appears in the _tkinter binary, i.e., @loader_path/../ etc)

@cjrh
Copy link

cjrh commented May 15, 2016

This is a known issue, here: ContinuumIO/anaconda-issues#188

@greglandrum
Copy link

Since #188 has been closed and there's been no response to recent comments, I added #786 in an attempt to revive things.

@MarkusLohmayer
Copy link
Author

Thanks for pointing me in the right direction, but I am not knowledgeable enough to follow.

What I know:

  • I want to use functionality of TCL/Tk and PIL/pillow inside a conda environment

What I think I understand so far is:

  • I have a proper install of TCL/Tk inside my env (conda install tk)
  • The PIL that I installed (conda install pil) is flawed in the sense, that it is linked to the TCL/Tk that came with OS X.

Then again I do know:

  • by looking at conda-meta/tk-8.5.18-0.json, that the tk package I have contains libtcl8.5so
  • by running conda info pil, that pil has no dependence on tk

Not being an expert, I assume it can generally be considered a mistake to compile the pil package in that way. Maybe the thought was, that compiling against the "framework tcl" would avoid that everyone who wants to use pil, has to install the tk package. But this seems the wrong compromise considering the bandwidth and storage we have these days.

So I figure, that the pil package needs to be changed so it is compiled against libtcl8.5, because this is the version that gets installed in a python2.7 environment at the moment.

I could attempt a workaround by trying to compile tcl myself in order to get the libtcl8.4.so file on my system but I would not know what I have to take care of that it turns out right. In some way it must differ obviously from the "framework libtcl".
But actually I would rather be able to fix the pil package so other people can enjoy a fully working setup right away.

THANKS everyOne

@cjrh
Copy link

cjrh commented May 15, 2016

@MarquitoForrest Your understanding is exactly right. What I said in that StackOverflow post is a temporary workaround. The correct solution will be for Pillow to be linked to Tcl and Tk in exactly the same way as Python's own _tkinter binary is linked; then ImageTk.PhotoImage() will "Just Work". It is very frustrating for everyone, but that's just how it goes sometimes, and we try our best to help in little bits where possible.

I saw now that I made an error in the StackOverflow answer I made. I have now fixed that mistake, perhaps try reading through it again to see if it makes more sense?

I'll try to explain a bit more, to perhaps help you get a bit further. The otool -L command tells you how a binary file has been linked on the system. There are several ways that so-called dynamic linking can be set up. In the Pillow (PIL) distribution, there is one particular binary file causing us all these problems (in my conda env named "py35"; yours will differ):

~/anaconda/envs/py35/lib/python3.5/site-packages/PIL/_imagingtk.so

This is where the support for Tkinter in Pillow comes from. Unfortunately for us, when this was compiled it was linked to a framework version of Tcl and Tk. On OS X, the linking path is often saved in the final binary. To see what these paths are, you can use otool:

$ otool -L _imagingtk.so

(Assuming you're in that folder). So what you see will be framework paths. This doesn't work because in the conda env, Tkinter itself was not linked to a framework, but rather, the Tcl and Tk binaries inside the conda env itself. You can see that also with otool, but run it on the _tkinter.so binary:

otool -L ~/anaconda/envs/py35/lib/python3.5/lib-dynload/_tkinter.so

With Python 3, the name of the binary includes the Python version, so it may look something like _tkinter.cpython-35m-darwin.so.

So, one way to fix the issue, is to simply change the linking path directly inside the Pillow binary. For this, you can use a tool called install_name_tool. What I recommend for you, is to change the two framework paths for Tcl and Tk, to be exactly the same as they appear in the _tkinter.so binary. This should work. In my case, I just used @rpath/libtcl8.5.dylib and @rpath/libtk8.5.dylib, but remember, my venv uses a Tcl 8.5 version, whereas it seems yours is using 8.4. You have to match what is in your conda environment.

@MarkusLohmayer
Copy link
Author

@cjrh
Yes thanks a lot. I understood how to use otool and install_name_tool.
In my python2.7 env Tkinter is linked to tcl8.5, which is actually provided by the tk package.
On the other hand pil is linked as we know to tcl8.4 of the framework.
Because of these two obviously incompatible versions it seems like mission impossible to me.

For now I switched "back" to python 3.5 which I abandoned for this short period because first I thought openCV was not available for 3.5 yet but now I found it on another channel.
I used install_name_tool which in this case (both tkinter and PIL being compiled against some 8.5 version of tcl) worked as explained in the StackOverflow post.

@cjrh
Copy link

cjrh commented May 15, 2016

On the other hand pil is linked as we know to tcl8.4 of the framework.

Aha, now I understand your dilemma.

@gdavtor
Copy link

gdavtor commented Jun 14, 2016

@cjrh Can I revive this? I'm having the same issue, but I'm still getting errors after following this thread.

When I do otool -L _imagingtk.so I get:

➤  otool -L _imagingtk.so
_imagingtk.so:
    @rpath/libtcl8.4.dylib (compatibility version 8.4.0, current version 8.4.0)
    /usr/lib/libgcc_s.1.dylib (compatibility version 1.0.0, current version 1.0.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 111.0.0)

Which looks correct. However, when run my Python code again, I get the following error:

Traceback (most recent call last):
  File "flagquiz.py", line 28, in <module>
    img=ImageTk.PhotoImage(Image.open(testim));
  File "/Users/David/anaconda/lib/python2.7/site-packages/PIL/ImageTk.py", line 116, in __init__
    self.paste(image)
  File "/Users/David/anaconda/lib/python2.7/site-packages/PIL/ImageTk.py", line 181, in paste
    import _imagingtk
ImportError: dlopen(/Users/David/anaconda/lib/python2.7/site-packages/PIL/_imagingtk.so, 2): Library not loaded: @rpath/libtcl8.4.dylib
  Referenced from: /Users/David/anaconda/lib/python2.7/site-packages/PIL/_imagingtk.so
  Reason: image not found

@cjrh
Copy link

cjrh commented Jun 14, 2016

@gdavtor What do you see for otool -L _tkinter.so? (or whatever the name is in your python version)

@gdavtor
Copy link

gdavtor commented Jun 14, 2016

I have:

_tkinter.so:
    @loader_path/../../libtcl8.5.dylib (compatibility version 8.5.0, current version 8.5.18)
    @loader_path/../../libtk8.5.dylib (compatibility version 8.5.0, current version 8.5.18)
    /usr/lib/libgcc_s.1.dylib (compatibility version 1.0.0, current version 1.0.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 111.0.0)

@cjrh
Copy link

cjrh commented Jun 14, 2016

@gdavtor Your Pillow is linked to libtcl8.4.dylib, but your tkinter is linked to libtcl8.5.dylib. That's not going to work. This is the same issue as @MarquitoForrest found.

@cjrh
Copy link

cjrh commented Jun 14, 2016

The Pillow team is aware of these problems, see:

python-pillow/Pillow#1883
python-pillow/Pillow#1932
python-pillow/Pillow#1768

@gdavtor
Copy link

gdavtor commented Jun 14, 2016

Thanks! I'm not sure I understand what the fix is. Are these recommending that I run setup.py with a --disable-osx-tcltk-framework option?

@cjrh
Copy link

cjrh commented Jun 14, 2016

@gdavtor I'm also not sure! I haven't had time to look into this more. I just wanted to say that they are working on it. Hopefully when the next release comes out everything will "just work". In the meantime you can probably get things working by using a stock Python and not Anaconda. Or, you can build Pillow yourself and link to the correct Tcl libs manually.

@kalefranz
Copy link
Contributor

Not really a conda issue. Going to close. Feel free to keep discussing.

@github-actions
Copy link

Hi there, thank you for your contribution to Conda!

This issue has been automatically locked since it has not had recent activity after it was closed.

Please open a new issue if needed.

@github-actions github-actions bot added the locked [bot] locked due to inactivity label Oct 23, 2021
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Oct 23, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
locked [bot] locked due to inactivity
Projects
None yet
Development

No branches or pull requests

5 participants