"""A bare bones Image class based on tkinter. Requires Python 3. """ import tkinter _root = tkinter.Tk() _root.withdraw() # hide root window so no one can quit program until all windows have been closed _numWindows = 0 def mainloop(): _root.mainloop() class Image: """A bare bones Image class based on tkinter.""" def __init__(self, width = 300, height = 200, file = None, title = None): """Constructs a new Image object from a GIF file or a new empty image with the given width and height.""" self._checkArgsConstructor(file, width, height, title) if file is not None: self._file = file self._image = tkinter.PhotoImage(file = self._file) self._width = self._image.width() self._height = self._image.height() else: self._file = None self._width = width self._height = height self._image = tkinter.PhotoImage(width = self._width, height = self._height) if title is not None: self._title = title else: self._title = 'Image' def width(self): """Returns the width of the image.""" return self._width def height(self): """Returns the height of the image.""" return self._height def get(self, x, y): """Returns the color (as a 3-tuple) at coordinates (x,y).""" self._checkCoordinates(x, y) color = self._image.get(x, y) if isinstance(color, str): color = color.split() return (int(color[0]), int(color[1]), int(color[2])) def set(self, x, y, color): """Sets the color (a 3-tuple or Tk color string) at coordinates (x,y).""" self._checkCoordinates(x, y) if not isinstance(color, str): color = self._tuple2hex(color) self._image.put(color, (x, y)) def show(self): """Displays the image in a window and waits for it to be closed.""" global _numWindows self._window = tkinter.Toplevel() _numWindows = _numWindows + 1 self._window.title(self._title) self._window.protocol('WM_DELETE_WINDOW', self._quitWhenAllDone) label = tkinter.Label(self._window, image = self._image) label.grid() self._window.update() def _quitWhenAllDone(self): global _numWindows _numWindows = _numWindows - 1 self._window.destroy() if _numWindows == 0: _root.quit() def _checkArgsConstructor(self, file, width, height, title): if file is not None and not isinstance(file, str): raise TypeError('file name must be a string') if not isinstance(width, int): raise TypeError('width must be an integer') if not isinstance(height, int): raise TypeError('height must be an integer') if title is not None and not isinstance(title, str): raise TypeError('title must be a string') def _checkCoordinates(self, x, y): if not isinstance(x, int) or not isinstance(y, int): raise TypeError('x and y must be integers') if (x < 0 or x >= self._width) or (y < 0 or y >= self._height): raise IndexError('coordinates are out of bounds (image is ' + str(self._width) + ' X ' + str(self._height) + ')') def _tuple2hex(self, color): if not isinstance(color, tuple) or len(color) > 3: raise TypeError('color must be a 3-element (red, green, blue) tuple') for i in range(3): if not isinstance(color[i], int) or color[i] < 0 or color[i] > 255: raise TypeError('color channel values must be integers between 0 and 255') return '#{0:02x}{1:02x}{2:02x}'.format(color[0], color[1], color[2])