layerfx_shadow.py 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. # Layer effect > Drop shadow
  2. # (fr) Effet de calque > Ombre portée
  3. # (es) Efectos de capa > Sombra paralela
  4. # (de) Ebeneneffekte > Schlagschatten
  5. from lazpaint import dialog
  6. try:
  7. from tkinter import *
  8. except ImportError:
  9. dialog.show_message("Please install tkinter. On Debian distributions, use the command: apt install python3-tk")
  10. exit()
  11. from lazpaint import colors, image, layer, filters, tools, selection
  12. if layer.is_empty():
  13. dialog.show_message("Layer is empty")
  14. exit()
  15. ############ image processing
  16. MAX_RADIUS = 100
  17. MAX_OFFSET = 100
  18. MAX_OPACITY = 255
  19. source_layer_id = layer.get_registry("shadow-source-layer-id")
  20. if source_layer_id is not None:
  21. layer.select_id(source_layer_id)
  22. else:
  23. source_layer_id = layer.get_id()
  24. source_layer_name = layer.get_name()
  25. chosen_radius = layer.get_registry("shadow-radius")
  26. if chosen_radius == None:
  27. chosen_radius = image.get_registry("shadow-radius")
  28. if chosen_radius == None:
  29. chosen_radius = 10
  30. chosen_offset = layer.get_registry("shadow-offset")
  31. if chosen_offset == None or len(chosen_offset) != 2:
  32. chosen_offset = image.get_registry("shadow-offset")
  33. if chosen_offset == None or len(chosen_offset) != 2:
  34. chosen_offset = (10, 10)
  35. shadow_layer_id = layer.get_registry("shadow-layer-id")
  36. if image.get_layer_index(shadow_layer_id) == None:
  37. shadow_layer_id = None
  38. if shadow_layer_id is not None:
  39. layer.select_id(shadow_layer_id)
  40. chosen_opacity = layer.get_opacity()
  41. overlay_color = colors.str_to_RGBA(layer.get_registry("overlay-color"))
  42. layer.select_id(source_layer_id)
  43. else:
  44. chosen_opacity = layer.get_opacity()*2/3
  45. overlay_color = None
  46. if overlay_color is None:
  47. overlay_color = colors.BLACK
  48. def create_shadow_layer():
  49. global shadow_layer_id
  50. image.do_begin()
  51. if shadow_layer_id != None:
  52. layer.select_id(shadow_layer_id)
  53. layer.remove()
  54. layer.select_id(source_layer_id)
  55. layer.duplicate()
  56. layer.set_name("Shadow of "+source_layer_name)
  57. layer.set_registry("shadow-source-layer-id", source_layer_id)
  58. shadow_layer_id = layer.get_id()
  59. shadow_index = image.get_layer_index()
  60. image.move_layer_index(shadow_index, shadow_index-1)
  61. filters.filter_function(red=overlay_color.red/255, green=overlay_color.green/255, blue=overlay_color.blue/255, gamma_correction=False)
  62. layer.set_registry("overlay-color", overlay_color)
  63. layer.set_opacity(chosen_opacity)
  64. image.do_end()
  65. blur_done = False
  66. offset_done = False
  67. def apply_blur():
  68. global blur_done, offset_done
  69. if offset_done:
  70. image.undo()
  71. offset_done = False
  72. if blur_done:
  73. image.undo()
  74. blur_done = False
  75. image.do_begin()
  76. filters.blur(radius=chosen_radius)
  77. blur_done = image.do_end()
  78. apply_offset()
  79. def apply_offset():
  80. global offset_done
  81. if offset_done:
  82. image.undo()
  83. offset_done = False
  84. image.do_begin()
  85. tools.choose(tools.MOVE_LAYER)
  86. tools.mouse([(0,0), chosen_offset])
  87. layer.set_opacity(chosen_opacity)
  88. offset_done = image.do_end()
  89. ######## interface
  90. def button_ok_click():
  91. global source_layer_id, chosen_radius, chosen_offset
  92. layer.select_id(source_layer_id)
  93. layer.set_registry("shadow-radius", chosen_radius)
  94. layer.set_registry("shadow-offset", chosen_offset)
  95. layer.set_registry("shadow-layer-id", shadow_layer_id)
  96. image.set_registry("shadow-radius", chosen_radius)
  97. image.set_registry("shadow-offset", chosen_offset)
  98. image.do_end()
  99. exit()
  100. def button_cancel_click():
  101. if image.do_end():
  102. image.undo()
  103. layer.select_id(source_layer_id)
  104. exit()
  105. scale_radius_update_job = None
  106. def scale_radius_update_do():
  107. global scale_radius_update_job, chosen_radius, scale_radius
  108. new_radius = scale_radius.get()
  109. if new_radius != chosen_radius:
  110. chosen_radius = new_radius
  111. apply_blur()
  112. scale_radius_update_job = None
  113. def scale_radius_update(event):
  114. global window, scale_radius_update_job
  115. if scale_radius_update_job:
  116. window.after_cancel(scale_radius_update_job)
  117. scale_radius_update_job = window.after(500, scale_radius_update_do)
  118. scale_offset_update_job = None
  119. def scale_offset_update_do():
  120. global chosen_offset
  121. new_offset = (scale_offset_x.get(), scale_offset_y.get())
  122. if new_offset != chosen_offset:
  123. chosen_offset = new_offset
  124. apply_offset()
  125. scale_offset_update_job = None
  126. def scale_offset_update(event):
  127. global window, scale_offset_update_job
  128. if scale_offset_update_job:
  129. window.after_cancel(scale_offset_update_job)
  130. scale_offset_update_job = window.after(100, scale_offset_update_do)
  131. scale_opacity_update_job = None
  132. def scale_opacity_update_do():
  133. global chosen_opacity
  134. new_opacity = scale_opacity.get()
  135. if new_opacity != chosen_opacity:
  136. chosen_opacity = new_opacity
  137. apply_offset()
  138. scale_opacity_update_job = None
  139. def scale_opacity_update(event):
  140. global window, scale_opacity_update_job
  141. if scale_opacity_update_job:
  142. window.after_cancel(scale_opacity_update_job)
  143. scale_opacity_update_job = window.after(100, scale_opacity_update_do)
  144. window = Tk()
  145. window.title("Layer shadow")
  146. window.resizable(False, False)
  147. frame = Frame(window)
  148. frame.pack()
  149. label_radius = Label(frame, text="Radius:")
  150. label_radius.grid(column=0, row=0)
  151. scale_radius = Scale(frame, from_=0, to=MAX_RADIUS, orient=HORIZONTAL, command=scale_radius_update)
  152. scale_radius.grid(column=1, row=0, sticky=W+E, padx=10)
  153. scale_radius.set(chosen_radius)
  154. label_offset = Label(frame, text="Offset:")
  155. label_offset.grid(column=0, row=1)
  156. scale_offset_x = Scale(frame, from_=-MAX_OFFSET, to=MAX_OFFSET, orient=HORIZONTAL, command=scale_offset_update)
  157. scale_offset_x.grid(column=1, row=1, sticky=W+E, padx=10)
  158. scale_offset_x.set(chosen_offset[0])
  159. scale_offset_y = Scale(frame, from_=-MAX_OFFSET, to=MAX_OFFSET, orient=HORIZONTAL, command=scale_offset_update)
  160. scale_offset_y.grid(column=1, row=2, sticky=W+E, padx=10)
  161. scale_offset_y.set(chosen_offset[1])
  162. label_opacity = Label(frame, text="Opacity:")
  163. label_opacity.grid(column=0, row=3)
  164. scale_opacity = Scale(frame, from_=0, to=MAX_OPACITY, orient=HORIZONTAL, command=scale_opacity_update)
  165. scale_opacity.grid(column=1, row=3, sticky=W+E, padx=10)
  166. scale_opacity.set(chosen_opacity)
  167. frame.columnconfigure(0, pad=20)
  168. frame.columnconfigure(1, minsize=250)
  169. frame.rowconfigure(0, pad=20)
  170. frame.rowconfigure(1, pad=20)
  171. frame.rowconfigure(2, pad=20)
  172. frame.rowconfigure(3, pad=20)
  173. button_ok = Button(window, text="Ok", command=button_ok_click)
  174. button_ok.pack(side=RIGHT, padx=10, pady=10)
  175. button_cancel = Button(window, text="Cancel", command=button_cancel_click)
  176. button_cancel.pack(side=RIGHT, pady=10)
  177. image.do_begin()
  178. selection.deselect()
  179. create_shadow_layer()
  180. apply_blur()
  181. window.update()
  182. window_width = window.winfo_width()
  183. screen_width = window.winfo_screenwidth()
  184. window.geometry('+%d+0' % (int((screen_width - window_width) / 2)))
  185. window.lift()
  186. window.attributes('-topmost',True)
  187. window.after_idle(window.attributes,'-topmost',False)
  188. window.mainloop()
  189. button_cancel_click()