layerfx_innershadow.py 8.1 KB

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