colors.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. import collections, math
  2. from lazpaint import dialog, command, filters
  3. GAMMA = 2.2
  4. ALPHA_OPAQUE = 255
  5. ALPHA_TRANSPARENT = 0
  6. if __name__ == "__main__":
  7. dialog.show_message("Library defining colors.")
  8. def to_linear(std_value: int): #0..255
  9. return math.pow(std_value/255, GAMMA)
  10. def to_std(linear_value: float):
  11. return round(math.pow(linear_value, 1/GAMMA)*255)
  12. CustomRGBA = collections.namedtuple("RGBA", "red, green, blue, alpha")
  13. class RGBA(CustomRGBA):
  14. def __repr__(self):
  15. if self.alpha != 255:
  16. return '#{:02X}{:02X}{:02X}{:02X}'.format(self.red,self.green,self.blue,self.alpha)
  17. else:
  18. return '#{:02X}{:02X}{:02X}'.format(self.red,self.green,self.blue)
  19. def __str__(self):
  20. return '{:02X}{:02X}{:02X}{:02X}'.format(self.red,self.green,self.blue,self.alpha)
  21. def __eq__(self, other):
  22. if isinstance(other, RGBA):
  23. return (other.red == self.red) and (other.green == self.green) and (other.blue == self.blue) and (other.alpha == self.alpha)
  24. else:
  25. return NotImplemented
  26. def negative(self):
  27. return RGBA(to_std(1-to_linear(self.red)), to_std(1-to_linear(self.green)), to_std(1-to_linear(self.blue)), self.alpha)
  28. def linear_negative(self):
  29. return RGBA(255-self.red, 255-self.green, 255-self.blue, self.alpha)
  30. def swap_red_blue(self):
  31. return RGBA(self.blue, self.green, self.red, self.alpha)
  32. def grayscale(self):
  33. gray = to_std(to_linear(self.red)*0.299 + to_linear(self.green)*0.587 + to_linear(self.blue)*0.114)
  34. return RGBA(gray, gray, gray, self.alpha)
  35. def RGB(red: int, green: int, blue: int): #0..255
  36. return RGBA(red, green, blue, 255)
  37. def str_to_RGBA(s):
  38. if s is None:
  39. return None
  40. elif isinstance(s, list):
  41. return [str_to_RGBA(c) for c in s]
  42. else:
  43. if s[0:1] == "#":
  44. s = s[1:]
  45. if len(s) == 6:
  46. return RGBA(int(s[0:2],16), int(s[2:4],16), int(s[4:6],16), 255)
  47. elif len(s) == 8:
  48. return RGBA(int(s[0:2],16), int(s[2:4],16), int(s[4:6],16), int(s[6:8],16))
  49. else:
  50. raise ValueError("Invalid color string")
  51. TRANSPARENT = RGBA(0,0,0,0)
  52. #VGA color names
  53. BLACK = RGB(0,0,0)
  54. BLUE = RGB(0,0,255)
  55. LIME = RGB(0,255,0)
  56. AQUA = RGB(0,255,255)
  57. RED = RGB(255,0,0)
  58. FUCHSIA = RGB(255,0,255)
  59. ORANGE = RGB(255,165,0)
  60. YELLOW = RGB(255,255,0)
  61. WHITE = RGB(255,255,255)
  62. GRAY = RGB(128,128,128)
  63. NAVY = RGB(0,0,128)
  64. GREEN = RGB(0,128,0)
  65. TEAL = RGB(0,128,128)
  66. MAROON = RGB(128,0,0)
  67. PURPLE = RGB(128,0,128)
  68. OLIVE = RGB(128,128,0)
  69. SILVER = RGB(192,192,192)
  70. def get_curve(points: list, posterize=False):
  71. return {'Points': points, 'Posterize': posterize}
  72. def curves(red=[], red_posterize=False, green=[], green_posterize=False, blue=[], blue_posterize=False, hue=[], hue_posterize=False, saturation=[], saturation_posterize=False, lightness=[], lightness_posterize=False, validate=True):
  73. command.send('ColorCurves', Red=get_curve(red, red_posterize), Green=get_curve(green, green_posterize), Blue=get_curve(blue, blue_posterize), Hue=get_curve(hue, hue_posterize), Saturation=get_curve(saturation, saturation_posterize), Lightness=get_curve(lightness, lightness_posterize), Validate=validate)
  74. def posterize(levels=None, by_lightness=True, validate=True):
  75. command.send('ColorPosterize', Levels=levels, ByLightness=by_lightness, Validate=validate)
  76. def colorize(hue_angle=None, saturation=None, correction=None, validate=True): #saturation: 0..1
  77. command.send('ColorColorize', Hue=hue_angle, Saturation=saturation, Correction=correction, Validate=validate)
  78. def complementary():
  79. filters.run(filters.COLOR_COMPLEMENTARY)
  80. def shift(hue_angle=None, saturation=None, correction=None, validate=True): #saturation shift: -2..2
  81. command.send('ColorShiftColors', Hue=hue_angle, Saturation=saturation, Correction=correction, Validate=validate)
  82. def intensity(factor=None, shift=None, validate=True): #factor and shift: -2..2
  83. command.send('ColorIntensity', Factor=factor, Shift=shift, Validate=validate)
  84. def lightness(factor=None, shift=None, validate=True): #factor and shift: -2..2
  85. command.send('ColorLightness', Factor=factor, Shift=shift, Validate=validate)
  86. def negative():
  87. filters.run(filters.COLOR_NEGATIVE)
  88. def linear_negative():
  89. filters.run(filters.COLOR_LINEAR_NEGATIVE)
  90. def normalize():
  91. filters.run(filters.COLOR_NORMALIZE)
  92. def grayscale():
  93. filters.run(filters.COLOR_GRAYSCALE)
  94. def show_dialog(color=None): #-> RGBA
  95. result_str = dialog.show_color_dialog(color)
  96. if result_str is None or len(result_str) == 0:
  97. return None
  98. else:
  99. return str_to_RGBA(result_str)