associação pythonbrasil[11] django zope/plone planet Início Logado como (Entrar)

ImagemRasterTkinter

ImagemRasterTkinter (por JoaoBueno)

Python é famoso, entre outras coisas, por ser simples para fazer coisas rápidas. Tkinter é um toolkit que acompanha essa "fama", especialmente por não exigir a instalação de nenhum módulo adicional ao Python.

No entanto, se alguém quer desenhar - quer com elementos vetoriais, quer usando imagens raster (compostas por pixels), anos de história do desenvolvimento da Python Imaging Libray de um lado, e do toolkit Tk de outro entram no caminho da simplicidade.

Um objeto Canvas do Tkinter é praticamente um programa de edição vetorial auto-contido, em que elementos como linhas, retângulos, imagens e mesmo outros widgets de Tkinter podem ser dispostos, eventos de entrada tratados, e até é possível gerar um arquivo postscript com uma versão vetorial do conteúdo do Canvas.

No entanto, a documentação para criação desses elementos é escassa - e a documentação oficial do TKinter bastante rasa, chata de entender e com quase nenhum exemplo.

Esta receita contém uma classe para de se criar desenhos raster em tkinter, que faz toda a burocracia necessária - você cria uma instância da classe ScreenImage (uma subclasse de uma imagem da PIL), e tem disponíveis, entre outros, os métodos imagem.putpixel((x,y), (r,g,b))) para plotar um pixel, os métodos de desenho como rectangle, polygon, text - disponíveis numa instâncias de ImageDraw em imagem.draw, e sobretudo, deve chamar o método imagem.update() para sincronizar o buffer em memória com a imagem exibida na tela pelo TKinter.

Esta receita é necessária por que para se exibir uma imagem raster em TKinter é preciso ter um Tkinter.Canvas que contém uma instância de ImagemTk.PhotoImage, adicionada com o parcamente documentado Canvas.create_image. A PhotoImage, por sua vez, não pode ser objeto dos métodos de desenho disponibilizados em ImageDraw, nem tem "putpixel" - então é necessária uma imagem do módulo Image que é copiada para a PhotoImage através do update()

Código

   1 #! /usr/bin/env python
   2 
   3 import Tkinter
   4 import Image, ImageTk, ImageDraw
   5 
   6 class ScreenImage(Image.Image):
   7     """
   8     Helper Class to get a drawable raster surface in a tkinter app.
   9     Tries to bypass most bureacracy.
  10     """
  11     def __init__(self, widget=None, size=(640,480), color=(255,255,255)):
  12         """
  13         Widget should be the container Tkinter widget for the canvas contaning this
  14         image
  15         """
  16         width, height = size
  17         #Inheriting from PIL's image class is not very clean.
  18         #we have to re-issue the statements found in its "_new"  constructor:
  19         Image.Image.__init__(self)
  20         self.im = Image.core.fill("RGB", size, color)
  21         self.mode = "RGB"
  22         self.size = size
  23         self.draw = ImageDraw.Draw(self)
  24         self.photoimage = ImageTk.PhotoImage("RGB", (width, height))
  25         self.canvas = Tkinter.Canvas(widget, width=width, height=height)
  26         self.canvas.create_image(width // 2, height // 2, image=self.photoimage)
  27         self.canvas.pack()
  28         self.update()
  29         
  30     def update(self):
  31         """Updates memory buffer to Tkinter screen"""
  32         self.photoimage.paste(self)
  33         
  34 
  35 if __name__ == "__main__":
  36     tk = Tkinter.Tk()
  37     
  38     i = ScreenImage(tk)
  39     
  40     import math
  41     
  42     for x in range(640):
  43         y = 240 + 120 * math.sin((x - 320) / 320.0 * 4 * math.pi)     
  44         i.putpixel((x, y) , (0,0,0))
  45     i.update()
  46     tk.mainloop()