1# Copyright 2004-2021 Tom Rothamel <pytom@bishoujo.us> 2# 3# Permission is hereby granted, free of charge, to any person 4# obtaining a copy of this software and associated documentation files 5# (the "Software"), to deal in the Software without restriction, 6# including without limitation the rights to use, copy, modify, merge, 7# publish, distribute, sublicense, and/or sell copies of the Software, 8# and to permit persons to whom the Software is furnished to do so, 9# subject to the following conditions: 10# 11# The above copyright notice and this permission notice shall be 12# included in all copies or substantial portions of the Software. 13# 14# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 22# This contains ColorMatrix and the various *Matrix classes. 23 24init -1500 python: 25 import math as _math 26 27 class _BaseMatrix(object): 28 """ 29 :undocumented: 30 31 Documented in text. The base class for various *Matrix classes 32 that are intended to return a Matrix, both ColorMatrix and 33 TransformMatrix. 34 """ 35 36 def __init__(self, value=1.0): 37 self.value = value 38 39 def __call__(self, other, done): 40 41 if type(other) is not type(self): 42 return self.get(self.value) 43 44 value = other.value + (self.value - other.value) * done 45 return self.get(value) 46 47 def __mul__(self, other): 48 return _MultiplyMatrix(self, other) 49 50 def __eq__(self, other): 51 if type(self) != type(other): 52 return False 53 54 return self.__dict__ == other.__dict__ 55 56 def __ne__(self, other): 57 return not (self == other) 58 59 class ColorMatrix(_BaseMatrix): 60 """ 61 :undocumented: 62 63 Documented in text. The base class for various *Matrix classes 64 that are intended to return a Matrix that transforms colors. 65 """ 66 67 pass 68 69 class _MultiplyMatrix(ColorMatrix): 70 """ 71 :undocumented: 72 73 This created when two ColorMatrixes are multiplied together. 74 """ 75 76 def __init__(self, left, right): 77 self.left = left 78 self.right = right 79 self.value = 1.0 80 81 def __call__(self, other, done): 82 if type(other) is not type(self): 83 return self.left(None, 1.0) * self.right(None, 1.0) 84 85 return self.left(other.left, done) * self.right(other.right, done) 86 87 88 class IdentityMatrix(ColorMatrix): 89 """ 90 :doc: colormatrix 91 :args: () 92 93 A ColorMatrix that can be used with :tpref:`matrixcolor` that does not 94 change the color or alpha of what is supplied to it. 95 96 `value` 97 Is ignored. 98 """ 99 100 def get(self, value): 101 return Matrix([ 1.0, 0.0, 0.0, 0.0, 102 0.0, 1.0, 0.0, 0.0, 103 0.0, 0.0, 1.0, 0.0, 104 0.0, 0.0, 0.0, 1.0, ]) 105 106 107 class SaturationMatrix(ColorMatrix): 108 """ 109 :doc: colormatrix 110 111 A ColorMatrix that can be used with :tpref:`matrixcolor` that alters 112 the saturation of an image, while leaving the alpha channel 113 alone. 114 115 `value` 116 The amount of saturation in the resulting image. 1.0 is 117 the unaltered image, while 0.0 is grayscale. 118 119 `desat` 120 This is a 3-element tuple that controls how much of the 121 red, green, and blue channels will be placed into all 122 three channels of a fully desaturated image. The default 123 is based on the constants used for the luminance channel 124 of an NTSC television signal. Since the human eye is 125 mostly sensitive to green, more of the green channel is 126 kept then the other two channels. 127 """ 128 129 def __init__(self, value, desat=(0.2126, 0.7152, 0.0722)): 130 self.value = value 131 self.desat = desat 132 133 def get(self, value): 134 r, g, b = self.desat 135 136 def I(a, b): 137 return a + (b - a) * value 138 139 return Matrix([ I(r, 1), I(g, 0), I(b, 0), 0, 140 I(r, 0), I(g, 1), I(b, 0), 0, 141 I(r, 0), I(g, 0), I(b, 1), 0, 142 0, 0, 0, 1 ]) 143 144 class TintMatrix(ColorMatrix): 145 """ 146 :doc: colormatrix 147 148 A ColorMatrix can be used with :tpref:`matrixcolor` to tint 149 an image, while leaving the alpha channel alone. 150 151 `color` 152 The color that the matrix will tint things to. This is passed 153 to :func:`Color`, and so may be anything that Color supports 154 as its first argument. 155 156 """ 157 158 def __init__(self, color): 159 self.color = Color(color) 160 161 def __call__(self, other, done): 162 163 if type(other) is not type(self): 164 165 # When not using an old color, we can take 166 # r, g, b, and a from self.color. 167 r, g, b, a = self.color.rgba 168 169 else: 170 171 # Otherwise, we have to extract from self.color 172 # and other.color, and interpolate the results. 173 oldr, oldg, oldb, olda = other.color.rgba 174 r, g, b, a = self.color.rgba 175 176 r = oldr + (r - oldr) * done 177 g = oldg + (g - oldg) * done 178 b = oldb + (b - oldb) * done 179 a = olda + (a - olda) * done 180 181 # To properly handle premultiplied alpha, the color channels 182 # have to be multiplied by the alpha channel. 183 r *= a 184 g *= a 185 b *= a 186 187 # Return a Matrix. 188 return Matrix([ r, 0, 0, 0, 189 0, g, 0, 0, 190 0, 0, b, 0, 191 0, 0, 0, a ]) 192 193 class BrightnessMatrix(ColorMatrix): 194 """ 195 :doc: colormatrix 196 197 A ColorMatrix that can be used with :tpref:`matrixcolor` to change 198 the brightness of an image, while leaving the Alpha channel 199 alone. 200 201 `value` 202 The amount of change in image brightness. This should be 203 a number between -1 and 1, with -1 the darkest possible 204 image and 1 the brightest. 205 """ 206 207 def get(self, value): 208 209 return Matrix([ 1, 0, 0, value, 210 0, 1, 0, value, 211 0, 0, 1, value, 212 0, 0, 0, 1 ]) 213 214 class OpacityMatrix(ColorMatrix): 215 """ 216 :doc: colormatrix 217 218 A ColorMatrix that can be used with :tpref:`matrixcolor` to change 219 the opacity of an image, while leaving color channels alone. 220 221 `value` 222 The amount the alpha channel should be multiplied by, 223 a number between 0.0 and 1.0. 224 """ 225 226 def get(self, value): 227 228 return Matrix([ value, 0, 0, 0, 229 0, value, 0, 0, 230 0, 0, value, 0, 231 0, 0, 0, value, ]) 232 233 234 235 class ContrastMatrix(ColorMatrix): 236 """ 237 :doc: colormatrix 238 239 A ColorMatrix that can be used with :tpref:`matrixcolor` to change 240 the brightness of an image, while leaving the Alpha channel 241 alone. 242 243 `value` 244 The contrast value. Values between 0.0 and 1.0 decrease 245 the contrast, while values above 1.0 increase the contrast. 246 """ 247 248 def get(self, value): 249 d = value 250 v = value / -2.0 + .5 251 252 return Matrix([ d, 0, 0, v, 253 0, d, 0, v, 254 0, 0, d, v, 255 0, 0, 0, 1, ]) 256 257 258 class ColorizeMatrix(ColorMatrix): 259 """ 260 :doc: colormatrix 261 262 A ColorMatrix that can be used with :tpref:`matrixcolor` to colorize 263 black and white displayables. It uses the color of each pixel 264 in the black and white to interpolate between the black color 265 and the white color. 266 267 The alpha channel is not touched. 268 269 This is inteded for use with a black and white image (or one that 270 has been desaturated with :func:`SaturationMatrix`), and will yield 271 strange results when used with images that are not black and white. 272 273 `black_color`, `white_color` 274 The colors used in the interpolation. 275 """ 276 277 def __init__(self, black_color, white_color): 278 self.black = Color(black_color) 279 self.white = Color(white_color) 280 281 282 def __call__(self, other, done): 283 284 if type(other) is not type(self): 285 other = self 286 287 # Break the colors up into variables. 288 obr, obg, obb = other.black.rgb 289 owr, owg, owb = other.white.rgb 290 nbr, nbg, nbb = self.black.rgb 291 nwr, nwg, nwb = self.white.rgb 292 293 # Interpolate to get black and white colors. 294 br = obr + (nbr - obr) * done 295 bg = obg + (nbg - obg) * done 296 bb = obb + (nbb - obb) * done 297 wr = owr + (nwr - owr) * done 298 wg = owg + (nwg - owg) * done 299 wb = owb + (nwb - owb) * done 300 301 # Return the matrix. 302 return Matrix([ (wr - br), 0, 0, br, 303 0, (wg - bg), 0, bg, 304 0, 0, (wb - bb), bb, 305 0, 0, 0, 1, ]) 306 307 308 class HueMatrix(ColorMatrix): 309 """ 310 :doc: colormatrix 311 312 A ColorMatrix that can be used with :tpref:`matrixcolor` to rotate the hue by 313 `value` degrees. While `value` can be any number, positive or negative, 314 360 degrees makes a complete rotation. The alpha channel is left alone. 315 """ 316 317 # from http://www.gskinner.com/blog/archives/2005/09/flash_8_source.html 318 319 def get(self, value): 320 321 h = _math.pi * value / 180.0 322 323 cosVal = _math.cos(h) 324 sinVal = _math.sin(h) 325 326 lumR = 0.213 327 lumG = 0.715 328 lumB = 0.072 329 330 return Matrix([ 331 lumR + cosVal * (1 - lumR) + sinVal * (-lumR), lumG + cosVal * (-lumG) + sinVal * (-lumG), lumB + cosVal * (-lumB) + sinVal * (1 - lumB), 0.0, 332 lumR + cosVal * (-lumR) + sinVal * (0.143), lumG + cosVal * (1 - lumG) + sinVal * (0.140), lumB + cosVal * (-lumB) + sinVal * (-0.283), 0.0, 333 lumR + cosVal * (-lumR) + sinVal * (-(1 - lumR)), lumG + cosVal * (-lumG) + sinVal * (lumG), lumB + cosVal * (1 - lumB) + sinVal * (lumB), 0.0, 334 0, 0, 0, 1.0 ]) 335 336 337 class InvertMatrix(ColorMatrix): 338 """ 339 :doc: colormatrix 340 341 A ColorMatrix that can be used with :tpref:`matrixcolor` to invert 342 each of the color channels. The alpha channel is left alone. 343 344 `value` 345 The amount to inverty by. 0.0 is not inverted, 1.0 is fully 346 inverted. Used to animate inversion. 347 """ 348 349 def get(self, value): 350 d = 1.0 - 2 * value 351 v = value 352 353 return Matrix([ d, 0, 0, v, 354 0, d, 0, v, 355 0, 0, d, v, 356 0, 0, 0, 1, ]) 357 358 def SepiaMatrix(tint="#ffeec2", desat=(0.2126, 0.7152, 0.0722)): 359 """ 360 :doc: colormatrix 361 362 A function that returns a ColorMatrix that can be used with :tpref:`matrixcolor` 363 to sepia-tone a displayable. This is the equivalent of:: 364 365 TintMatrix(tint) * SaturationMatrix(0.0, desat) 366 """ 367 368 return TintMatrix(tint) * SaturationMatrix(0.0, desat) 369