2
0

layerfx_innershadow.py 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. # Layer effect > Inner shadow
  2. # (fr) Effet de calque > Ombre intérieure
  3. from lazpaint import dialog
  4. try:
  5. from tkinter import Tk, Frame, Label, Scale, HORIZONTAL, Button, RIGHT, W, E
  6. except ImportError:
  7. dialog.show_message("Please install tkinter. On Debian distributions, use the command: apt install python3-tk")
  8. exit()
  9. from lazpaint import colors, image, layer, filters, tools, selection
  10. import math
  11. translation = dialog.translate_dict(["Layer is empty", "Radius", "Angle", "Opacity", "Ok", "Cancel"])
  12. if layer.is_empty():
  13. dialog.show_message(translation["Layer is empty"])
  14. exit()
  15. ############ image processing
  16. FRIENDLY_NAME = dialog.get_script_name()
  17. REGISTRY_NAME = "innershadow"
  18. OPPOSITE_REGISTRY_NAME = "innerlight"
  19. DEFAULT_ANGLE = 135
  20. DEFAULT_COLOR = colors.BLACK
  21. MAX_RADIUS = 200
  22. MAX_OPACITY = 255
  23. MAX_ANGLE = 360
  24. source_layer_id = layer.get_registry(REGISTRY_NAME+"-source-layer-id")
  25. if source_layer_id is not None:
  26. layer.select_id(source_layer_id)
  27. else:
  28. source_layer_id = layer.get_id()
  29. source_layer_name = layer.get_name()
  30. chosen_radius = layer.get_registry(REGISTRY_NAME+"-radius")
  31. if chosen_radius == None:
  32. chosen_radius = layer.get_registry(OPPOSITE_REGISTRY_NAME+"-radius")
  33. if chosen_radius == None:
  34. chosen_radius = image.get_registry(REGISTRY_NAME+"-radius")
  35. if chosen_radius == None:
  36. chosen_radius = image.get_registry(OPPOSITE_REGISTRY_NAME+"-radius")
  37. if chosen_radius == None:
  38. chosen_radius = 20
  39. chosen_angle = layer.get_registry(REGISTRY_NAME+"-angle")
  40. if chosen_angle == None:
  41. chosen_angle = layer.get_registry(OPPOSITE_REGISTRY_NAME+"-angle")
  42. if chosen_angle is not None:
  43. chosen_angle = (chosen_angle+180) % 360
  44. if chosen_angle == None:
  45. chosen_angle = image.get_registry(REGISTRY_NAME+"-angle")
  46. if chosen_angle == None:
  47. chosen_angle = image.get_registry(OPPOSITE_REGISTRY_NAME+"-angle")
  48. if chosen_angle is not None:
  49. chosen_angle = (chosen_angle+180) % 360
  50. if chosen_angle == None:
  51. chosen_angle = DEFAULT_ANGLE
  52. shadow_layer_id = layer.get_registry(REGISTRY_NAME+"-layer-id")
  53. if image.get_layer_index(shadow_layer_id) == None:
  54. shadow_layer_id = None
  55. if shadow_layer_id is not None:
  56. layer.select_id(shadow_layer_id)
  57. chosen_opacity = layer.get_opacity()
  58. overlay_color = colors.str_to_RGBA(layer.get_registry("overlay-color"))
  59. layer.select_id(source_layer_id)
  60. else:
  61. chosen_opacity = layer.get_opacity()*2/3
  62. overlay_color = None
  63. if overlay_color is None:
  64. overlay_color = DEFAULT_COLOR
  65. def create_shadow_layer():
  66. global shadow_layer_id
  67. image.do_begin()
  68. if shadow_layer_id != None:
  69. layer.select_id(shadow_layer_id)
  70. layer.remove()
  71. layer.select_id(source_layer_id)
  72. layer.duplicate()
  73. layer.rasterize()
  74. layer.set_name(FRIENDLY_NAME+" - "+source_layer_name)
  75. layer.set_registry(REGISTRY_NAME+"-source-layer-id", source_layer_id)
  76. shadow_layer_id = layer.get_id()
  77. layer.set_registry("overlay-color", overlay_color)
  78. layer.set_opacity(chosen_opacity)
  79. image.do_end()
  80. blur_done = False
  81. opacity_done = False
  82. def apply_blur():
  83. global blur_done, opacity_done
  84. if opacity_done:
  85. image.undo()
  86. opacity_done = False
  87. if blur_done:
  88. image.undo()
  89. blur_done = False
  90. image.do_begin()
  91. if chosen_radius == 0:
  92. filters.filter_function(alpha=0, gamma_correction=False)
  93. else:
  94. layer.duplicate()
  95. layer.set_opacity(255)
  96. filters.filter_function(red="alpha", green="alpha", blue="alpha", alpha=1, gamma_correction=False)
  97. mask_layer_id = layer.get_id()
  98. layer.select_id(shadow_layer_id)
  99. filters.filter_function(red=overlay_color.red/255, green=overlay_color.green/255, blue=overlay_color.blue/255, gamma_correction=False)
  100. tools.choose(tools.MOVE_LAYER)
  101. offset = (math.sin(chosen_angle*math.pi/180)*chosen_radius, -math.cos(chosen_angle*math.pi/180)*chosen_radius)
  102. tools.mouse([(0,0), (offset[0],offset[1])])
  103. layer.select_id(mask_layer_id)
  104. layer.duplicate()
  105. mask_layer_id2 = layer.get_id()
  106. layer.select_id(mask_layer_id)
  107. tools.choose(tools.MOVE_LAYER)
  108. tools.mouse([(offset[0]/2,offset[1]/2), (0,0)])
  109. colors.linear_negative()
  110. layer.set_blend_op(layer.BLEND_MASK)
  111. layer.merge_over()
  112. mask_layer_id = mask_layer_id2
  113. filters.blur(radius=chosen_radius)
  114. layer.select_id(mask_layer_id)
  115. layer.set_blend_op(layer.BLEND_MASK)
  116. layer.merge_over()
  117. blur_done = image.do_end()
  118. apply_opacity()
  119. def apply_opacity():
  120. global opacity_done
  121. if opacity_done:
  122. image.undo()
  123. opacity_done = False
  124. image.do_begin()
  125. layer.set_opacity(chosen_opacity)
  126. opacity_done = image.do_end()
  127. ######## interface
  128. def button_ok_click():
  129. global source_layer_id, chosen_radius, chosen_angle
  130. layer.select_id(source_layer_id)
  131. layer.set_registry(REGISTRY_NAME+"-radius", chosen_radius)
  132. layer.set_registry(REGISTRY_NAME+"-angle", chosen_angle)
  133. layer.set_registry(REGISTRY_NAME+"-layer-id", shadow_layer_id)
  134. image.set_registry(REGISTRY_NAME+"-radius", chosen_radius)
  135. image.set_registry(REGISTRY_NAME+"-angle", chosen_angle)
  136. image.do_end()
  137. exit()
  138. def button_cancel_click():
  139. if image.do_end():
  140. image.undo()
  141. layer.select_id(source_layer_id)
  142. exit()
  143. scale_radius_update_job = None
  144. def scale_radius_update_do():
  145. global scale_radius_update_job, chosen_radius, scale_radius
  146. new_radius = scale_radius.get()
  147. if new_radius != chosen_radius:
  148. chosen_radius = new_radius
  149. apply_blur()
  150. scale_radius_update_job = None
  151. def scale_radius_update(event):
  152. global window, scale_radius_update_job
  153. if scale_radius_update_job:
  154. window.after_cancel(scale_radius_update_job)
  155. scale_radius_update_job = window.after(800, scale_radius_update_do)
  156. scale_angle_update_job = None
  157. def scale_angle_update_do():
  158. global scale_angle_update_job, chosen_angle, scale_angle
  159. new_angle = scale_angle.get()
  160. if new_angle != chosen_angle:
  161. chosen_angle = new_angle
  162. apply_blur()
  163. scale_angle_update_job = None
  164. def scale_angle_update(event):
  165. global window, scale_angle_update_job
  166. if scale_angle_update_job:
  167. window.after_cancel(scale_angle_update_job)
  168. scale_angle_update_job = window.after(800, scale_angle_update_do)
  169. scale_opacity_update_job = None
  170. def scale_opacity_update_do():
  171. global chosen_opacity
  172. new_opacity = scale_opacity.get()
  173. if new_opacity != chosen_opacity:
  174. chosen_opacity = new_opacity
  175. apply_opacity()
  176. scale_opacity_update_job = None
  177. def scale_opacity_update(event):
  178. global window, scale_opacity_update_job
  179. if scale_opacity_update_job:
  180. window.after_cancel(scale_opacity_update_job)
  181. scale_opacity_update_job = window.after(100, scale_opacity_update_do)
  182. window = Tk()
  183. window.title(FRIENDLY_NAME)
  184. window.resizable(False, False)
  185. frame = Frame(window)
  186. frame.pack()
  187. label_radius = Label(frame, text=translation["Radius"])
  188. label_radius.grid(column=0, row=0)
  189. scale_radius = Scale(frame, from_=0, to=MAX_RADIUS, orient=HORIZONTAL, command=scale_radius_update)
  190. scale_radius.grid(column=1, row=0, sticky=W+E, padx=10)
  191. scale_radius.set(chosen_radius)
  192. label_angle = Label(frame, text=translation["Angle"])
  193. label_angle.grid(column=0, row=1)
  194. scale_angle = Scale(frame, from_=0, to=MAX_ANGLE, orient=HORIZONTAL, command=scale_angle_update)
  195. scale_angle.grid(column=1, row=1, sticky=W+E, padx=10)
  196. scale_angle.set(chosen_angle)
  197. label_opacity = Label(frame, text=translation["Opacity"])
  198. label_opacity.grid(column=0, row=2)
  199. scale_opacity = Scale(frame, from_=0, to=MAX_OPACITY, orient=HORIZONTAL, command=scale_opacity_update)
  200. scale_opacity.grid(column=1, row=2, sticky=W+E, padx=10)
  201. scale_opacity.set(chosen_opacity)
  202. frame.columnconfigure(0, pad=20)
  203. frame.columnconfigure(1, minsize=250)
  204. frame.rowconfigure(0, pad=20)
  205. frame.rowconfigure(1, pad=20)
  206. frame.rowconfigure(2, pad=20)
  207. button_ok = Button(window, text=translation["Ok"], command=button_ok_click)
  208. button_ok.pack(side=RIGHT, padx=10, pady=10)
  209. button_cancel = Button(window, text=translation["Cancel"], command=button_cancel_click)
  210. button_cancel.pack(side=RIGHT, pady=10)
  211. image.do_begin()
  212. selection.deselect()
  213. create_shadow_layer()
  214. apply_blur()
  215. window.update()
  216. window_width = window.winfo_width()
  217. screen_width = window.winfo_screenwidth()
  218. window.geometry('+%d+0' % (int((screen_width - window_width) / 2)))
  219. window.lift()
  220. window.attributes('-topmost',True)
  221. window.after_idle(window.attributes,'-topmost',False)
  222. window.mainloop()
  223. button_cancel_click()