Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 37 additions & 5 deletions Doc/library/tkinter.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6151,7 +6151,7 @@ Image classes


.. method:: data(format=None, *, from_coords=None, background=None, \
grayscale=False)
grayscale=False, metadata=None)

Return the image data.

Expand All @@ -6175,16 +6175,27 @@ Image classes
If *grayscale* is true, the data does not contain color information; all
pixel data is transformed into grayscale.

*metadata* is a dictionary passed to the image format driver.
It requires Tcl/Tk 9.0 or newer.

.. versionadded:: 3.13

.. versionchanged:: next
Added the *metadata* parameter.


.. method:: get(x, y)
.. method:: get(x, y, *, withalpha=False)

Return the color of the pixel at coordinates (*x*, *y*) as an
``(r, g, b)`` tuple of three integers between 0 and 255, representing the
red, green and blue components respectively.
If *withalpha* is true, the returned tuple has a fourth element giving
the alpha (opacity) value of the pixel.

.. versionchanged:: next
Added the *withalpha* parameter, which requires Tcl/Tk 9.0 or newer.

.. method:: put(data, to=None)
.. method:: put(data, to=None, *, format=None, metadata=None)

Set pixels of the image to the colors given in *data*, which must be a
string or a nested sequence of horizontal rows of pixel colors (for
Expand All @@ -6197,13 +6208,25 @@ Image classes
bottom-right corner, of the region.
The default position is ``(0, 0)``.

*format* specifies the format of the image *data*, so that only image
file format handlers whose names begin with it are tried.

*metadata* is a dictionary passed to the image format driver.
It requires Tcl/Tk 9.0 or newer.

.. versionchanged:: next
Added the *format* and *metadata* parameters.

.. method:: read(filename, format=None, *, from_coords=None, to=None, \
shrink=False)
shrink=False, metadata=None)

Read image data from the file named *filename* into the image.

*format* specifies the format of the image data in the file.

*metadata* is a dictionary passed to the image format driver.
It requires Tcl/Tk 9.0 or newer.

*from_coords* specifies a rectangular sub-region of the image file data
to be copied to the destination image.
It must be a tuple or a list of 1 to 4 integers ``(x1, y1, x2, y2)``.
Expand All @@ -6224,6 +6247,9 @@ Image classes

.. versionadded:: 3.13

.. versionchanged:: next
Added the *metadata* parameter.


.. method:: subsample(x, y='', *, from_coords=None)

Expand Down Expand Up @@ -6256,7 +6282,7 @@ Image classes


.. method:: write(filename, format=None, from_coords=None, *, \
background=None, grayscale=False)
background=None, grayscale=False, metadata=None)

Write image data from the image to the file named *filename*.

Expand All @@ -6278,9 +6304,15 @@ Image classes
If *grayscale* is true, the data does not contain color information; all
pixel data is transformed into grayscale.

*metadata* is a dictionary passed to the image format driver.
It requires Tcl/Tk 9.0 or newer.

.. versionchanged:: 3.13
Added the *background* and *grayscale* parameters.

.. versionchanged:: next
Added the *metadata* parameter.


.. method:: zoom(x, y='', *, from_coords=None)

Expand Down
7 changes: 7 additions & 0 deletions Doc/whatsnew/3.16.rst
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,13 @@ tkinter
badge) and :meth:`~tkinter.Wm.wm_stackorder` (toplevel stacking order).
(Contributed by Serhiy Storchaka in :gh:`151874`.)

* Added support for more options in :class:`!tkinter.PhotoImage` methods: the
*format* parameter of :meth:`~tkinter.PhotoImage.put`, the *metadata*
parameter of :meth:`~tkinter.PhotoImage.put`, :meth:`~tkinter.PhotoImage.read`,
:meth:`~tkinter.PhotoImage.write` and :meth:`~tkinter.PhotoImage.data`, and
the *withalpha* parameter of :meth:`~tkinter.PhotoImage.get`.
(Contributed by Serhiy Storchaka in :gh:`151890`.)

* Added the :meth:`~tkinter.PhotoImage.redither` method which recalculates the
dithered image when its data was supplied in pieces.
(Contributed by Serhiy Storchaka in :gh:`151888`.)
Expand Down
33 changes: 33 additions & 0 deletions Lib/test/test_tkinter/test_images.py
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,16 @@ def test_put(self):
self.assertEqual(image.get(0, 1), self.colorlist(0, 0, 255))
self.assertEqual(image.get(1, 1), self.colorlist(255, 255, 0))

def test_put_format(self):
image = self.create()
with open(self.testfile, 'rb') as f:
data = f.read()
image2 = tkinter.PhotoImage(master=self.root)
image2.put(data, format='gif')
self.assertEqual(image2.width(), 16)
self.assertEqual(image2.height(), 16)
self.assertEqual(image2.get(4, 6), image.get(4, 6))

def test_get(self):
image = self.create()
self.assertEqual(image.get(4, 6), self.colorlist(62, 116, 162))
Expand All @@ -525,6 +535,29 @@ def test_get(self):
self.assertRaises(tkinter.TclError, image.get, 16, 15)
self.assertRaises(tkinter.TclError, image.get, 15, 16)

@requires_tk(9, 0)
def test_get_withalpha(self):
image = self.create()
rgb = image.get(4, 6)
rgba = image.get(4, 6, withalpha=True)
if self.wantobjects:
self.assertEqual(rgba[:3], rgb)
self.assertEqual(len(rgba), 4)
self.assertIn(rgba[3], (0, 255)) # GIF alpha is fully on or off
else:
self.assertTrue(rgba.startswith(rgb + ' '))

@requires_tk(9, 0)
def test_metadata(self):
image = self.create()
# The -metadata configuration option holds the image's metadata.
image.configure(metadata=('Comment', 'spam'))
self.assertIn('Comment', str(image.cget('metadata')))
# put() and data() accept a metadata dictionary, passed to the image
# format driver. put() does not change the image's own metadata.
image.put('{red green} {blue yellow}', metadata={'Comment': 'spam'})
self.assertTrue(image.data(metadata={'Comment': 'spam'}))

def test_read(self):
# Due to the Tk bug https://core.tcl-lang.org/tk/tktview/1576528
# the -from option does not work correctly for GIF and PNG files.
Expand Down
63 changes: 54 additions & 9 deletions Lib/tkinter/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4692,26 +4692,59 @@ def copy_replace(self, sourceImage, *, from_coords=None, to=None, shrink=False,
options.extend(('-compositingrule', compositingrule))
self.tk.call(self.name, 'copy', sourceImage, *options)

def get(self, x, y):
"""Return the color (red, green, blue) of the pixel at X,Y."""
return self.tk.call(self.name, 'get', x, y)
@staticmethod
def _metadata(metadata):
# A Tcl dict is a flat list of alternating keys and values. A Python
# dict passed directly would expand to its keys only, so flatten it.
flat = ()
for key, value in metadata.items():
flat += (key, value)
return flat

def get(self, x, y, *, withalpha=False):
"""Return the color of the pixel at X,Y as a tuple of its red, green
and blue components.

If WITHALPHA is true, the returned tuple has a fourth element giving
the alpha (opacity) value of the pixel. This requires Tcl/Tk 9.0 or
newer.
"""
args = (self.name, 'get', x, y)
if withalpha:
args += ('-withalpha',)
return self.tk.call(args)

def put(self, data, to=None):
def put(self, data, to=None, *, format=None, metadata=None):
"""Put row formatted colors to image starting from
position TO, e.g. image.put("{red green} {blue yellow}", to=(4,6))"""
position TO, e.g. image.put("{red green} {blue yellow}", to=(4,6))

The FORMAT option specifies the format of the image DATA, so that only
image file format handlers whose names begin with it are tried.

The METADATA option, a dictionary passed to the image format driver,
requires Tcl/Tk 9.0 or newer.
"""
args = (self.name, 'put', data)
if format is not None:
args += ('-format', format)
if metadata is not None:
args += ('-metadata', self._metadata(metadata))
if to:
if to[0] == '-to':
to = to[1:]
args = args + ('-to',) + tuple(to)
args += ('-to',) + tuple(to)
self.tk.call(args)

def read(self, filename, format=None, *, from_coords=None, to=None, shrink=False):
def read(self, filename, format=None, *, from_coords=None, to=None,
shrink=False, metadata=None):
"""Reads image data from the file named FILENAME into the image.

The FORMAT option specifies the format of the image data in the
file.

The METADATA option, a dictionary passed to the image format driver,
requires Tcl/Tk 9.0 or newer.

The FROM_COORDS option specifies a rectangular sub-region of the image
file data to be copied to the destination image. It must be a tuple
or a list of 1 to 4 integers (x1, y1, x2, y2). (x1, y1) and
Expand All @@ -4731,6 +4764,8 @@ def read(self, filename, format=None, *, from_coords=None, to=None, shrink=False
options = ()
if format is not None:
options += ('-format', format)
if metadata is not None:
options += ('-metadata', self._metadata(metadata))
if from_coords is not None:
options += ('-from', *from_coords)
if shrink:
Expand All @@ -4740,13 +4775,16 @@ def read(self, filename, format=None, *, from_coords=None, to=None, shrink=False
self.tk.call(self.name, 'read', filename, *options)

def write(self, filename, format=None, from_coords=None, *,
background=None, grayscale=False):
background=None, grayscale=False, metadata=None):
"""Writes image data from the image to a file named FILENAME.

The FORMAT option specifies the name of the image file format
handler to be used to write the data to the file. If this option
is not given, the format is guessed from the file extension.

The METADATA option, a dictionary passed to the image format driver,
requires Tcl/Tk 9.0 or newer.

The FROM_COORDS option specifies a rectangular region of the image
to be written to the image file. It must be a tuple or a list of 1
to 4 integers (x1, y1, x2, y2). If only x1 and y1 are specified,
Expand All @@ -4765,6 +4803,8 @@ def write(self, filename, format=None, from_coords=None, *,
options = ()
if format is not None:
options += ('-format', format)
if metadata is not None:
options += ('-metadata', self._metadata(metadata))
if from_coords is not None:
options += ('-from', *from_coords)
if grayscale:
Expand All @@ -4774,9 +4814,12 @@ def write(self, filename, format=None, from_coords=None, *,
self.tk.call(self.name, 'write', filename, *options)

def data(self, format=None, *, from_coords=None,
background=None, grayscale=False):
background=None, grayscale=False, metadata=None):
"""Returns image data.

The METADATA option, a dictionary passed to the image format driver,
requires Tcl/Tk 9.0 or newer.

The FORMAT option specifies the name of the image file format
handler to be used. If this option is not given, this method uses
a format that consists of a tuple (one element per row) of strings
Expand All @@ -4803,6 +4846,8 @@ def data(self, format=None, *, from_coords=None,
options = ()
if format is not None:
options += ('-format', format)
if metadata is not None:
options += ('-metadata', self._metadata(metadata))
if from_coords is not None:
options += ('-from', *from_coords)
if grayscale:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Add the *format* parameter to the :meth:`tkinter.PhotoImage.put` method, the
*metadata* parameter to the :meth:`~tkinter.PhotoImage.put`,
:meth:`~tkinter.PhotoImage.read`, :meth:`~tkinter.PhotoImage.write` and
:meth:`~tkinter.PhotoImage.data` methods, and the *withalpha* parameter to the
:meth:`~tkinter.PhotoImage.get` method. The *metadata* and *withalpha*
parameters require Tcl/Tk 9.0 or newer.
Loading