-
-
Notifications
You must be signed in to change notification settings - Fork 31.6k
tkinter askcolor returning floats for r, g, b values instead of ints #77470
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
Comments
Even though the underlying tcl/tk interpreter is returning ints, askcolor is converting the values to floats. My guess is this is an oversight related to the change in functionality of the / operator in python3. this:
should probably be this:
|
For future reference, 3.4 and 3.5 only get security fixes. The quoted line of code is from the main part of tkinter.colorchooser,Chooser._fixresult: where tkinter.Misc defines The code in tkColorChooser and Tkinter in 2.x is the same. The docstring for winfo_rgb is wrong as it returns a tuple of ints in range(2**16256). For red, the results are
>>> Tk().winfo_rgb('red')
(65535, 0, 0) # 2.x and 3.x
>>> cc.askcolor('red')
((255, 0, 0), '#ff0000') # 2.7
>>> cc.askcolor('red')
((255.99609375, 0.0, 0.0), '#ff0000') # 3.8 In addition to fixing the winfo_rgb docstring (in all versions), and adding doc strings to colorchooser, it seems that '/' should be '//' in 3.x. I don't know if I would fix this in 3.6. |
Good catch! A color tuple will likely be used in '#%02x%02x%02x' % color, and this will fail because %x works only with integers (in general sense). Therefore returning a tuple of floats is a bug. The downside is that we loss some information. Tk supports up to 16 bit per color component, and askcolor() keeps only higher 8 of them. This can't be changed for backward compatibility, but it may be worth to add an option for control the representation of the result. winfo_rgb() returns 16-bit color components. This is a separate issue. |
Adding to what Serhiy said about the askcolor() return value is an issue that also affects input: >>> cc.askcolor('red')
((255, 0, 0), '#ff0000')
>>> cc.askcolor((255, 0, 0))
((255, 0, 0), '#ff0000')
>>> cc.askcolor((65535, 0, 0))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/cheryl/cpython/Lib/tkinter/colorchooser.py", line 75, in askcolor
return Chooser(**options).show()
File "/home/cheryl/cpython/Lib/tkinter/commondialog.py", line 43, in show
s = w.tk.call(self.command, *w._options(self.options))
_tkinter.TclError: invalid color name "#ffff0000" Changing _fixoptions to format initialcolor using "#%04x%04x%04x" % color. allows for 16-bit hex values, but it's not the same as 8-bit. >>> cc.askcolor('red')
((255, 0, 0), '#ff0000')
>>> cc.askcolor((255, 0, 0))
((0, 0, 0), '#000000')
>>> cc.askcolor((65535, 0, 0))
((255, 0, 0), '#ff0000') (255, 0, 0) in the second call is black and not red. |
Is this issue a regression of Python 3? red/256 gave an integer on Python 2? |
It appears so. |
yes, this is a well known backwards incompatibility. In python 2, the https://www.python.org/dev/peps/pep-0238/ On Thu, Jul 12, 2018 at 8:48 AM STINNER Victor <report@bugs.python.org>
|
https://www.tcl.tk/man/tcl8.6/TkCmd/winfo.htm says Since tk represents data as strings, 'decimal value in [0, 65535)' means 'integer value represented by decimal digits'. 'correspond to color in the window' implies that the mapping from color to decimal value could depend on the window. The mapping *does* differ between systems (see below). https://www.tcl.tk/man/tcl8.6/TkLib/GetColor.htm This omits to say what happens when there are 2 or 3 hex digits. Windows ignores 3rd and 4th hex digits. On Windows, dividing by 257 instead of 256 would be correct. However, 256 works because the 'error', represented by the remainder, is always in [0, 256). MacOS does not ignore digits. https://www.tcl.tk/man/tcl8.6/TkCmd/colors.htm The PR is blocked because the new colorchooser tests pass on Windows and macOS but fail on Ubuntu. Cheryl speculated that the color names values vary across systems. I think that it might instead be a coding issue, but I want to understand coding on Windows and Mac better before looking into Linux. |
65535 = 35536 - 1 = 256 * 256 - 1 == 255 * 257 On Windows, each r, g, b value is n * 257 for n in range(256) (see attached file). The precision loss happens when colors are stored, before the division in winfo_rgb. Perhaps 8 bits/channel (including alpha) is baked in. Since divmod(n * 257, 257) = (n, 0) and divmod(n * 257, 256) = (n, n), macOS appears (from limited experiments) to handle 1 and 2 digits the same as Windows (repeat 4 or 2 times): val('#a00') = val('#aaaa00000000') = 0xaaaa, val('#ab0000') = val('#abab00000000') = 0xabab. 4 digits are left alone while 3 digits use the 1st as the 4th val('#abc000000') = val('#abca00000000') = 0xabca. |
I do not understand why #abc000000 and #abcd00000000 give 0xabab on my computer (Linux) and even weirder result on Ubuntu on CI. Reading the code I expected the same behavior as on macOS. |
Your Linux result is the same as on Windows. Given strings 'abc' or 'abcd', ignore 'c' or 'cd' and expand 'ab' to 'abab', making value 0xabab. Is your computer Ubuntu (implying that personal Ubuntu != CI Ubuntu) or a different Linux? Are there tk/tcl compilation flags or X window options that could affect stored color values? |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: