9.6. Изображения

Image это структура данных, которая содержит рисунок. Эти рисунки могут быть использованы в различных местах.

Image могут быть созданы из Pixbuf, Pixmaps, файлов изображений (XPM, PNG, JPEG, TIFF, и т.д.) и даже файлов-анимаций.

Image создаётся с помощью функции:

  image = gtk.Image()

Картинка может быть загружена в виджет Image с помощью одного из следующих методов:

  image.set_from_pixbuf(pixbuf)
image.set_from_pixmap(pixmap, mask)
image.set_from_image(image)
image.set_from_file(filename)
image.set_from_stock(stock_id, size)
image.set_from_icon_set(icon_set, size)
image.set_from_animation(animation)

Где pixbuf это gtk.gdk.Pixbuf; pixmap и mask это gtk.gdk.Pixmap; image это gtk.gdk.Image; stock_id это имя gtk.StockItem; icon_set это gtk.IconSet; и animation это gtk.gdk.PixbufAnimation. Аргумент size один из:

 ICON_SIZE_MENU
ICON_SIZE_SMALL_TOOLBAR
ICON_SIZE_LARGE_TOOLBAR
ICON_SIZE_BUTTON
ICON_SIZE_DND
ICON_SIZE_DIALOG

Простейший способ создания изображения - это использование метода set_from_file() который автоматически определяет тип картинки и загружает её.

Программа images.py показывает загрузку разных типов картинок (goalie.gif, apple-red.png, chaos.jpg, important.tif, soccerball.gif) в виджеты Image для размещения их на кнопках.

Рисунок 9.5. Пример изображений на кнопках

Example Images in Buttons

Исходный код:

  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3. # example images.py
  4.  
  5. import pygtk
  6. pygtk.require('2.0')
  7. import gtk
  8.  
  9. class ImagesExample:
  10. # Когда вызывается (например по сигналу delete_event), закрывает приложение.
  11. def close_application(self, widget, event, data=None):
  12. gtk.main_quit()
  13. return False
  14.  
  15. # Вызывается по шелчку по кнопке. Просто выводит сообщение.
  16. def button_clicked(self, widget, data=None):
  17. print "button %s clicked" % data
  18.  
  19. def __init__(self):
  20. # Создаёт основное окно, и присоединяет сигнал delete_event для
  21. # завершения работы программы
  22. window = gtk.Window(gtk.WINDOW_TOPLEVEL)
  23. window.connect("delete_event", self.close_application)
  24. window.set_border_width(10)
  25. window.show()
  26.  
  27. # горизонтальная коробка для кнопок
  28. hbox = gtk.HBox()
  29. hbox.show()
  30. window.add(hbox)
  31.  
  32. pixbufanim = gtk.gdk.PixbufAnimation("goalie.gif")
  33. image = gtk.Image()
  34. image.set_from_animation(pixbufanim)
  35. image.show()
  36. # кнопка для виджета image
  37. button = gtk.Button()
  38. button.add(image)
  39. button.show()
  40. hbox.pack_start(button)
  41. button.connect("clicked", self.button_clicked, "1")
  42.  
  43. # создаёт несколько изображений из файлов и загружает их в
  44. # кнопки
  45. image = gtk.Image()
  46. image.set_from_file("apple-red.png")
  47. image.show()
  48. # кнопка для виджета image
  49. button = gtk.Button()
  50. button.add(image)
  51. button.show()
  52. hbox.pack_start(button)
  53. button.connect("clicked", self.button_clicked, "2")
  54.  
  55. image = gtk.Image()
  56. image.set_from_file("chaos.jpg")
  57. image.show()
  58. # кнопка для виджета image
  59. button = gtk.Button()
  60. button.add(image)
  61. button.show()
  62. hbox.pack_start(button)
  63. button.connect("clicked", self.button_clicked, "3")
  64.  
  65. image = gtk.Image()
  66. image.set_from_file("important.tif")
  67. image.show()
  68. # кнопка для виджета image
  69. button = gtk.Button()
  70. button.add(image)
  71. button.show()
  72. hbox.pack_start(button)
  73. button.connect("clicked", self.button_clicked, "4")
  74.  
  75. image = gtk.Image()
  76. image.set_from_file("soccerball.gif")
  77. image.show()
  78. # кнопка для виджета image
  79. button = gtk.Button()
  80. button.add(image)
  81. button.show()
  82. hbox.pack_start(button)
  83. button.connect("clicked", self.button_clicked, "5")
  84.  
  85.  
  86. def main():
  87. gtk.main()
  88. return 0
  89.  
  90. if __name__ == "__main__":
  91. ImagesExample()
  92. main()
  93.  

9.6.1. Pixmap и Bitmap

Pixmap это структура данных для хранения рисунков. Эти рисунки могут быть использованы в различных местах, но чаще всего используются как иконки для рабочего стола X, или как курсоры.

Pixmap имеющий только 2 цвета называется bitmap, и имеет несколько режимов для особых условий.

Для того, чтобы понять pixmap'ы, нужно понять как работает система X Window.  Под X, приложениям не нужно при запуске перехватывать все действия пользователя. За исключением различных приложений называемых "клиенты", которые взаимодействуют с программой, отображающей графику и обрабатывющей клавиатуру и мышь. Эта программа взаимодействует напрямую с пользователем, и называется "Desktop server" или "X server". Когда взаимодействия могут происходить через сеть, важно хранить некоторую информацию в сервере X. Например Pixmap сохраняются в память Х Сервера. Это означает что когда задано значение pixmap, нет нужды передавать его через сеть, вместо этого отправляется команда "отобразите pixmap номер XYZ здесь." Даже если вы не используете X с GTK+, использование таких конструкций как Pixmap поможет вашим программам лучше работать в X.

Для использования pixmap в PyGTK, мы должны создать gtk.gdk.Pixmap используя функции gtk.gdk в PyGTK. Pixmap может быть создан из данных в памяти или считан из файла. Мы разберём оба этих вызова.

  pixmap = gtk.gdk.pixmap_create_from_data(window, data, width, height, depth, fg, bg)

Этот шаблон используется для создания pixmap из data в памяти с глубиной цвета задаваемой depth. Если depth равна -1, то используется глубина цвета window. Каждый пиксель использует биты depth для отображения цвета. Width и height в пикселях. Аргумент window должен ссылаться на gtk.gdk.Window, т.к. ресурсы pixmap используются только в пределах экрана на котором отображаются fg и bg цвета переднего и заднего плана.

Pixmap может быть создан из файла XPM, используя:

  pixmap, mask = gtk.gdk.pixmap_create_from_xpm(window, transparent_color, filename)

Формат XPM это читаемое отображение pixmap для системы X Window. Он широко распространён, и для создания изображений этого формата существует много разных утилит. В функции pixmap_create_from_xpm() первый аргумент имеет тип gtk.gdk.window. (Большинство виджетов GTK+ имеют в основе gtk.gdk.Window, которое может быть получено из поля виджета window.) Файл, указанный в filename, должен содержать картинку в формате XPM, тогда картинка загрузится в структуру pixmap. mask это bitmap, который показывает какие пиксели pixmap непрозрачны создаётся функцией. Все остальные пиксели, окрашенные в цвет, указанный в transparent_color прозрачны. Пример использования функции ниже.

Pixmap также могут создаваться из данных в памяти используя функцию:

  pixmap, mask = gtk.gdk.pixmap_create_from_xpm_d(window, transparent_color, data)

Маленькие картинки могут быть встроены в программу как данные в формате XPM. Pixmap можно создать из этих данных, вместо чтения из файла. Пример таких данных:

  xpm_data = [
"16 16 3 1",
" c None",
". c #000000000000",
"X c #FFFFFFFFFFFF",
" ",
" ...... ",
" .XXX.X. ",
" .XXX.XX. ",
" .XXX.XXX. ",
" .XXX..... ",
" .XXXXXXX. ",
" .XXXXXXX. ",
" .XXXXXXX. ",
" .XXXXXXX. ",
" .XXXXXXX. ",
" .XXXXXXX. ",
" .XXXXXXX. ",
" ......... ",
" ",
" "
]

И последний способ создаёт пустой pixmap используемый для некоторых рисующих операций:

  pixmap = gtk.gdk.Pixmap(window, width, height, depth=-1)

window это либо gtk.gdk.Window. либо None. Если window этоgtk.gdk.Window, тогда depth может быть -1 для получения глубины цвета из окна. Если window равно None, тогда depth должна быть указана.

Программа pixmap.py пример использования pixmap в кнопке. Рисунок 9.6, “Пример Pixmap в кнопке” показывает получаемое окно:

Рисунок 9.6. Пример Pixmap в кнопке

Pixmap in a Button Example

Исходный код:

  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3. # example pixmap.py
  4.  
  5. import pygtk
  6. pygtk.require('2.0')
  7. import gtk
  8.  
  9. # XPM данные
  10. xpm_data = [
  11. "16 16 3 1",
  12. " c None",
  13. ". c #000000000000",
  14. "X c #FFFFFFFFFFFF",
  15. " ",
  16. " ...... ",
  17. " .XXX.X. ",
  18. " .XXX.XX. ",
  19. " .XXX.XXX. ",
  20. " .XXX..... ",
  21. " .XXXXXXX. ",
  22. " .XXXXXXX. ",
  23. " .XXXXXXX. ",
  24. " .XXXXXXX. ",
  25. " .XXXXXXX. ",
  26. " .XXXXXXX. ",
  27. " .XXXXXXX. ",
  28. " ......... ",
  29. " ",
  30. " "
  31. ]
  32.  
  33. class PixmapExample:
  34. # когда вызывается (например по сигналу delete_event), закрывает приложение.
  35. def close_application(self, widget, event, data=None):
  36. gtk.main_quit()
  37. return False
  38.  
  39. # вызывается по нажатию на кнопку. Просто пишет сообщение.
  40. def button_clicked(self, widget, data=None):
  41. print "button clicked"
  42.  
  43. def __init__(self):
  44. # Создание основного окна, и присоединение сигнала delete_event
  45. # для зыкрытия приложения
  46. window = gtk.Window(gtk.WINDOW_TOPLEVEL)
  47. window.connect("delete_event", self.close_application)
  48. window.set_border_width(10)
  49. window.show()
  50.  
  51. # Теперь pixmap из данных XPM
  52. pixmap, mask = gtk.gdk.pixmap_create_from_xpm_d(window.window,
  53. None,
  54. xpm_data)
  55.  
  56. # Image для хранения pixmap
  57. image = gtk.Image()
  58. image.set_from_pixmap(pixmap, mask)
  59. image.show()
  60.  
  61. # Кнопка для изображения
  62. button = gtk.Button()
  63. button.add(image)
  64. window.add(button)
  65. button.show()
  66.  
  67. button.connect("clicked", self.button_clicked)
  68.  
  69. def main():
  70. gtk.main()
  71. return 0
  72.  
  73. if __name__ == "__main__":
  74. PixmapExample()
  75. main()
  76.  

Недостатком использования pixmap является то, что отображаемый объект всегда прямоугольный, независимо от изображения. Мы желаем создавать приложения с иконками имеющими более естественные формы. Например для интерфейса игры, мы захотим использовать круглые кнопки. Для того чтобы сделать это - можно использовать фигурные окна.

Фигурное окно это обычный pixmap, где пиксели заднего плана прозрачны. Таким образом, мы не заменяем задний план прямоугольником, и не имеем рамки вокруд изображения. Пример wheelbarrow.py показывает изображение, заполненной тачки на рабочем столе. Рисунок 9.7, “Пример фигурного окна - тачка” показывает тачку над окном текстового редактора:

Рисунок 9.7. Пример фигурного окна - тачка

Wheelbarrow Example Shaped Window

Исходный код для wheelbarrow.py:

  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3. # example wheelbarrow.py
  4.  
  5. import pygtk
  6. pygtk.require('2.0')
  7. import gtk
  8.  
  9. # XPM
  10. WheelbarrowFull_xpm = [
  11. "48 48 64 1",
  12. " c None",
  13. ". c #DF7DCF3CC71B",
  14. "X c #965875D669A6",
  15. "o c #71C671C671C6",
  16. "O c #A699A289A699",
  17. "+ c #965892489658",
  18. "@ c #8E38410330C2",
  19. "# c #D75C7DF769A6",
  20. "$ c #F7DECF3CC71B",
  21. "% c #96588A288E38",
  22. "& c #A69992489E79",
  23. "* c #8E3886178E38",
  24. "= c #104008200820",
  25. "- c #596510401040",
  26. "; c #C71B30C230C2",
  27. ": c #C71B9A699658",
  28. "> c #618561856185",
  29. ", c #20811C712081",
  30. "< c #104000000000",
  31. "1 c #861720812081",
  32. "2 c #DF7D4D344103",
  33. "3 c #79E769A671C6",
  34. "4 c #861782078617",
  35. "5 c #41033CF34103",
  36. "6 c #000000000000",
  37. "7 c #49241C711040",
  38. "8 c #492445144924",
  39. "9 c #082008200820",
  40. "0 c #69A618611861",
  41. "q c #B6DA71C65144",
  42. "w c #410330C238E3",
  43. "e c #CF3CBAEAB6DA",
  44. "r c #71C6451430C2",
  45. "t c #EFBEDB6CD75C",
  46. "y c #28A208200820",
  47. "u c #186110401040",
  48. "i c #596528A21861",
  49. "p c #71C661855965",
  50. "a c #A69996589658",
  51. "s c #30C228A230C2",
  52. "d c #BEFBA289AEBA",
  53. "f c #596545145144",
  54. "g c #30C230C230C2",
  55. "h c #8E3882078617",
  56. "j c #208118612081",
  57. "k c #38E30C300820",
  58. "l c #30C2208128A2",
  59. "z c #38E328A238E3",
  60. "x c #514438E34924",
  61. "c c #618555555965",
  62. "v c #30C2208130C2",
  63. "b c #38E328A230C2",
  64. "n c #28A228A228A2",
  65. "m c #41032CB228A2",
  66. "M c #104010401040",
  67. "N c #492438E34103",
  68. "B c #28A2208128A2",
  69. "V c #A699596538E3",
  70. "C c #30C21C711040",
  71. "Z c #30C218611040",
  72. "A c #965865955965",
  73. "S c #618534D32081",
  74. "D c #38E31C711040",
  75. "F c #082000000820",
  76. " ",
  77. " .XoO ",
  78. " +@#$%o& ",
  79. " *=-;#::o+ ",
  80. " >,<12#:34 ",
  81. " 45671#:X3 ",
  82. " +89<02qwo ",
  83. "e* >,67;ro ",
  84. "ty> 459@>+&& ",
  85. "$2u+ ><ipas8* ",
  86. "%$;=* *3:.Xa.dfg> ",
  87. "Oh$;ya *3d.a8j,Xe.d3g8+ ",
  88. " Oh$;ka *3d$a8lz,,xxc:.e3g54 ",
  89. " Oh$;kO *pd$%svbzz,sxxxxfX..&wn> ",
  90. " Oh$@mO *3dthwlsslszjzxxxxxxx3:td8M4 ",
  91. " Oh$@g& *3d$XNlvvvlllm,mNwxxxxxxxfa.:,B* ",
  92. " Oh$@,Od.czlllllzlmmqV@V#V@fxxxxxxxf:%j5& ",
  93. " Oh$1hd5lllslllCCZrV#r#:#2AxxxxxxxxxcdwM* ",
  94. " OXq6c.%8vvvllZZiqqApA:mq:Xxcpcxxxxxfdc9* ",
  95. " 2r<6gde3bllZZrVi7S@SV77A::qApxxxxxxfdcM ",
  96. " :,q-6MN.dfmZZrrSS:#riirDSAX@Af5xxxxxfevo",
  97. " +A26jguXtAZZZC7iDiCCrVVii7Cmmmxxxxxx%3g",
  98. " *#16jszN..3DZZZZrCVSA2rZrV7Dmmwxxxx&en",
  99. " p2yFvzssXe:fCZZCiiD7iiZDiDSSZwwxx8e*>",
  100. " OA1<jzxwwc:$d%NDZZZZCCCZCCZZCmxxfd.B ",
  101. " 3206Bwxxszx%et.eaAp77m77mmmf3&eeeg* ",
  102. " @26MvzxNzvlbwfpdettttttttttt.c,n& ",
  103. " *;16=lsNwwNwgsvslbwwvccc3pcfu<o ",
  104. " p;<69BvwwsszslllbBlllllllu<5+ ",
  105. " OS0y6FBlvvvzvzss,u=Blllj=54 ",
  106. " c1-699Blvlllllu7k96MMMg4 ",
  107. " *10y8n6FjvllllB<166668 ",
  108. " S-kg+>666<M<996-y6n<8* ",
  109. " p71=4 m69996kD8Z-66698&& ",
  110. " &i0ycm6n4 ogk17,0<6666g ",
  111. " N-k-<> >=01-kuu666> ",
  112. " ,6ky& &46-10ul,66, ",
  113. " Ou0<> o66y<ulw<66& ",
  114. " *kk5 >66By7=xu664 ",
  115. " <<M4 466lj<Mxu66o ",
  116. " *>> +66uv,zN666* ",
  117. " 566,xxj669 ",
  118. " 4666FF666> ",
  119. " >966666M ",
  120. " oM6668+ ",
  121. " *4 ",
  122. " ",
  123. " "
  124. ]
  125.  
  126. class WheelbarrowExample:
  127. # Когда вызывается (например при сигнале delete_event), закрывает приложение
  128. def close_application(self, widget, event, data=None):
  129. gtk.main_quit()
  130. return False
  131.  
  132. def __init__(self):
  133. # Создаёт основное окно, присоединяет сигнал delete_event для закрытия
  134. # приложения. заметим что основное окно не имеет заголовка.
  135. # т.к. мы создали его с аргументом popup gtk.WINDOW_POPUP.
  136. window = gtk.Window(gtk.WINDOW_POPUP)
  137. window.connect("delete_event", self.close_application)
  138. window.set_events(window.get_events() | gtk.gdk.BUTTON_PRESS_MASK)
  139. window.connect("button_press_event", self.close_application)
  140. window.show()
  141.  
  142. # Теперь Pixmap и виджет Image
  143. pixmap, mask = gtk.gdk.pixmap_create_from_xpm_d(
  144. window.window, None, WheelbarrowFull_xpm)
  145. image = gtk.Image()
  146. image.set_from_pixmap(pixmap, mask)
  147. image.show()
  148.  
  149. # Для отображения картинки мы используем виджет fixed
  150. fixed = gtk.Fixed()
  151. fixed.set_size_request(200, 200)
  152. fixed.put(image, 0, 0)
  153. window.add(fixed)
  154. fixed.show()
  155.  
  156. # Делает прозрачным всё кроме изображения
  157. window.shape_combine_mask(mask, 0, 0)
  158.  
  159. # показываем окно
  160. window.set_position(gtk.WIN_POS_CENTER_ALWAYS)
  161. window.show()
  162.  
  163. def main():
  164. gtk.main()
  165. return 0
  166.  
  167. if __name__ == "__main__":
  168. WheelbarrowExample()
  169. main()
  170.  

Для того, чтобы сделать изображение тачки чувствительным, мы присоединили сигнал "button_press_event" для выхода из программы. Строки 138-139 делают картинку чувствительной к щелчку мыши и присоединяют метод close_application().