colorm.go (13542B)
1 // Copyright 2014 Hajime Hoshi 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package affine 16 17 import ( 18 "image/color" 19 "math" 20 ) 21 22 // ColorMDim is a dimension of a ColorM. 23 const ColorMDim = 5 24 25 var ( 26 colorMIdentityBody = []float32{ 27 1, 0, 0, 0, 28 0, 1, 0, 0, 29 0, 0, 1, 0, 30 0, 0, 0, 1, 31 } 32 colorMIdentityTranslate = []float32{ 33 0, 0, 0, 0, 34 } 35 ) 36 37 // A ColorM represents a matrix to transform coloring when rendering an image. 38 // 39 // A ColorM is applied to the source alpha color 40 // while an Image's pixels' format is alpha premultiplied. 41 // Before applying a matrix, a color is un-multiplied, and after applying the matrix, 42 // the color is multiplied again. 43 // 44 // The nil and initial value is identity. 45 type ColorM struct { 46 // When elements is nil, this matrix is identity. 47 // elements are immutable and a new array must be created when updating. 48 body []float32 49 translate []float32 50 } 51 52 func clamp(x float32) float32 { 53 if x > 1 { 54 return 1 55 } 56 if x < 0 { 57 return 0 58 } 59 return x 60 } 61 62 func (c *ColorM) isInited() bool { 63 return c != nil && (c.body != nil || c.translate != nil) 64 } 65 66 func (c *ColorM) ScaleOnly() bool { 67 if c == nil { 68 return true 69 } 70 if c.body != nil { 71 if c.body[1] != 0 { 72 return false 73 } 74 if c.body[2] != 0 { 75 return false 76 } 77 if c.body[3] != 0 { 78 return false 79 } 80 if c.body[4] != 0 { 81 return false 82 } 83 if c.body[6] != 0 { 84 return false 85 } 86 if c.body[7] != 0 { 87 return false 88 } 89 if c.body[8] != 0 { 90 return false 91 } 92 if c.body[9] != 0 { 93 return false 94 } 95 if c.body[11] != 0 { 96 return false 97 } 98 if c.body[12] != 0 { 99 return false 100 } 101 if c.body[13] != 0 { 102 return false 103 } 104 if c.body[14] != 0 { 105 return false 106 } 107 } 108 if c.translate != nil { 109 for _, e := range c.translate { 110 if e != 0 { 111 return false 112 } 113 } 114 } 115 return true 116 } 117 118 func (c *ColorM) Apply(clr color.Color) color.Color { 119 if !c.isInited() { 120 return clr 121 } 122 r, g, b, a := clr.RGBA() 123 rf, gf, bf, af := float32(0.0), float32(0.0), float32(0.0), float32(0.0) 124 // Unmultiply alpha 125 if a > 0 { 126 rf = float32(r) / float32(a) 127 gf = float32(g) / float32(a) 128 bf = float32(b) / float32(a) 129 af = float32(a) / 0xffff 130 } 131 eb := c.body 132 if eb == nil { 133 eb = colorMIdentityBody 134 } 135 et := c.translate 136 if et == nil { 137 et = colorMIdentityTranslate 138 } 139 rf2 := eb[0]*rf + eb[4]*gf + eb[8]*bf + eb[12]*af + et[0] 140 gf2 := eb[1]*rf + eb[5]*gf + eb[9]*bf + eb[13]*af + et[1] 141 bf2 := eb[2]*rf + eb[6]*gf + eb[10]*bf + eb[14]*af + et[2] 142 af2 := eb[3]*rf + eb[7]*gf + eb[11]*bf + eb[15]*af + et[3] 143 rf2 = clamp(rf2) 144 gf2 = clamp(gf2) 145 bf2 = clamp(bf2) 146 af2 = clamp(af2) 147 return color.NRGBA64{ 148 R: uint16(rf2 * 0xffff), 149 G: uint16(gf2 * 0xffff), 150 B: uint16(bf2 * 0xffff), 151 A: uint16(af2 * 0xffff), 152 } 153 } 154 155 func (c *ColorM) UnsafeElements() ([]float32, []float32) { 156 if !c.isInited() { 157 return colorMIdentityBody, colorMIdentityTranslate 158 } 159 eb := c.body 160 if eb == nil { 161 eb = colorMIdentityBody 162 } 163 et := c.translate 164 if et == nil { 165 et = colorMIdentityTranslate 166 } 167 return eb, et 168 } 169 170 func (c *ColorM) det() float32 { 171 if !c.isInited() { 172 return 1 173 } 174 175 m00 := c.body[0] 176 m01 := c.body[1] 177 m02 := c.body[2] 178 m03 := c.body[3] 179 m10 := c.body[4] 180 m11 := c.body[5] 181 m12 := c.body[6] 182 m13 := c.body[7] 183 m20 := c.body[8] 184 m21 := c.body[9] 185 m22 := c.body[10] 186 m23 := c.body[11] 187 m30 := c.body[12] 188 m31 := c.body[13] 189 m32 := c.body[14] 190 m33 := c.body[15] 191 192 b234234 := m22*m33 - m23*m32 193 b134234 := m21*m33 - m23*m31 194 b124234 := m21*m32 - m22*m31 195 b034234 := m20*m33 - m23*m30 196 b024234 := m20*m32 - m22*m30 197 b014234 := m20*m31 - m21*m30 198 199 return m00*(m11*b234234-m12*b134234+m13*b124234) - 200 m01*(m10*b234234-m12*b034234+m13*b024234) + 201 m02*(m10*b134234-m11*b034234+m13*b014234) - 202 m03*(m10*b124234-m11*b024234+m12*b014234) 203 } 204 205 // IsInvertible returns a boolean value indicating 206 // whether the matrix c is invertible or not. 207 func (c *ColorM) IsInvertible() bool { 208 return c.det() != 0 209 } 210 211 // Invert inverts the matrix. 212 // If c is not invertible, Invert panics. 213 func (c *ColorM) Invert() *ColorM { 214 if !c.isInited() { 215 return nil 216 } 217 218 det := c.det() 219 if det == 0 { 220 panic("affine: c is not invertible") 221 } 222 223 m00 := c.body[0] 224 m01 := c.body[1] 225 m02 := c.body[2] 226 m03 := c.body[3] 227 228 m10 := c.body[4] 229 m11 := c.body[5] 230 m12 := c.body[6] 231 m13 := c.body[7] 232 233 m20 := c.body[8] 234 m21 := c.body[9] 235 m22 := c.body[10] 236 m23 := c.body[11] 237 238 m30 := c.body[12] 239 m31 := c.body[13] 240 m32 := c.body[14] 241 m33 := c.body[15] 242 243 m40 := c.translate[0] 244 m41 := c.translate[1] 245 m42 := c.translate[2] 246 m43 := c.translate[3] 247 248 a2334 := m32*m43 - m33*m42 249 a1334 := m31*m43 - m33*m41 250 a1234 := m31*m42 - m32*m41 251 a0334 := m30*m43 - m33*m40 252 a0234 := m30*m42 - m32*m40 253 a0134 := m30*m41 - m31*m40 254 a2324 := m22*m43 - m23*m42 255 a1324 := m21*m43 - m23*m41 256 a1224 := m21*m42 - m22*m41 257 a0324 := m20*m43 - m23*m40 258 a0224 := m20*m42 - m22*m40 259 a0124 := m20*m41 - m21*m40 260 261 b234234 := m22*m33 - m23*m32 262 b134234 := m21*m33 - m23*m31 263 b124234 := m21*m32 - m22*m31 264 b123234 := m21*a2334 - m22*a1334 + m23*a1234 265 b034234 := m20*m33 - m23*m30 266 b024234 := m20*m32 - m22*m30 267 b023234 := m20*a2334 - m22*a0334 + m23*a0234 268 b014234 := m20*m31 - m21*m30 269 b013234 := m20*a1334 - m21*a0334 + m23*a0134 270 b012234 := m20*a1234 - m21*a0234 + m22*a0134 271 b234134 := m12*m33 - m13*m32 272 b134134 := m11*m33 - m13*m31 273 b124134 := m11*m32 - m12*m31 274 b123134 := m11*a2334 - m12*a1334 + m13*a1234 275 b234124 := m12*m23 - m13*m22 276 b134124 := m11*m23 - m13*m21 277 b124124 := m11*m22 - m12*m21 278 b123124 := m11*a2324 - m12*a1324 + m13*a1224 279 b034134 := m10*m33 - m13*m30 280 b024134 := m10*m32 - m12*m30 281 b023134 := m10*a2334 - m12*a0334 + m13*a0234 282 b034124 := m10*m23 - m13*m20 283 b024124 := m10*m22 - m12*m20 284 b023124 := m10*a2324 - m12*a0324 + m13*a0224 285 b014134 := m10*m31 - m11*m30 286 b013134 := m10*a1334 - m11*a0334 + m13*a0134 287 b014124 := m10*m21 - m11*m20 288 b013124 := m10*a1324 - m11*a0324 + m13*a0124 289 b012134 := m10*a1234 - m11*a0234 + m12*a0134 290 b012124 := m10*a1224 - m11*a0224 + m12*a0124 291 292 m := &ColorM{ 293 body: make([]float32, 16), 294 translate: make([]float32, 4), 295 } 296 297 idet := 1 / det 298 299 m.body[0] = idet * (m11*b234234 - m12*b134234 + m13*b124234) 300 m.body[1] = idet * -(m01*b234234 - m02*b134234 + m03*b124234) 301 m.body[2] = idet * (m01*b234134 - m02*b134134 + m03*b124134) 302 m.body[3] = idet * -(m01*b234124 - m02*b134124 + m03*b124124) 303 m.body[4] = idet * -(m10*b234234 - m12*b034234 + m13*b024234) 304 m.body[5] = idet * (m00*b234234 - m02*b034234 + m03*b024234) 305 m.body[6] = idet * -(m00*b234134 - m02*b034134 + m03*b024134) 306 m.body[7] = idet * (m00*b234124 - m02*b034124 + m03*b024124) 307 m.body[8] = idet * (m10*b134234 - m11*b034234 + m13*b014234) 308 m.body[9] = idet * -(m00*b134234 - m01*b034234 + m03*b014234) 309 m.body[10] = idet * (m00*b134134 - m01*b034134 + m03*b014134) 310 m.body[11] = idet * -(m00*b134124 - m01*b034124 + m03*b014124) 311 m.body[12] = idet * -(m10*b124234 - m11*b024234 + m12*b014234) 312 m.body[13] = idet * (m00*b124234 - m01*b024234 + m02*b014234) 313 m.body[14] = idet * -(m00*b124134 - m01*b024134 + m02*b014134) 314 m.body[15] = idet * (m00*b124124 - m01*b024124 + m02*b014124) 315 m.translate[0] = idet * (m10*b123234 - m11*b023234 + m12*b013234 - m13*b012234) 316 m.translate[1] = idet * -(m00*b123234 - m01*b023234 + m02*b013234 - m03*b012234) 317 m.translate[2] = idet * (m00*b123134 - m01*b023134 + m02*b013134 - m03*b012134) 318 m.translate[3] = idet * -(m00*b123124 - m01*b023124 + m02*b013124 - m03*b012124) 319 return m 320 } 321 322 // Element returns a value of a matrix at (i, j). 323 func (c *ColorM) Element(i, j int) float32 { 324 b, t := c.UnsafeElements() 325 if j < ColorMDim-1 { 326 return b[i+j*(ColorMDim-1)] 327 } 328 return t[i] 329 } 330 331 // SetElement sets an element at (i, j). 332 func (c *ColorM) SetElement(i, j int, element float32) *ColorM { 333 newC := &ColorM{ 334 body: make([]float32, 16), 335 translate: make([]float32, 4), 336 } 337 copy(newC.body, colorMIdentityBody) 338 copy(newC.translate, colorMIdentityTranslate) 339 if c.isInited() { 340 if c.body != nil { 341 copy(newC.body, c.body) 342 } 343 if c.translate != nil { 344 copy(newC.translate, c.translate) 345 } 346 } 347 if j < (ColorMDim - 1) { 348 newC.body[i+j*(ColorMDim-1)] = element 349 } else { 350 newC.translate[i] = element 351 } 352 return newC 353 } 354 355 func (c *ColorM) Equals(other *ColorM) bool { 356 if !c.isInited() && !other.isInited() { 357 return true 358 } 359 360 lhsb := colorMIdentityBody 361 lhst := colorMIdentityTranslate 362 rhsb := colorMIdentityBody 363 rhst := colorMIdentityTranslate 364 if other.isInited() { 365 if other.body != nil { 366 lhsb = other.body 367 } 368 if other.translate != nil { 369 lhst = other.translate 370 } 371 } 372 if c.isInited() { 373 if c.body != nil { 374 rhsb = c.body 375 } 376 if c.translate != nil { 377 rhst = c.translate 378 } 379 } 380 if &lhsb == &rhsb && &lhst == &rhst { 381 return true 382 } 383 384 for i := range lhsb { 385 if lhsb[i] != rhsb[i] { 386 return false 387 } 388 } 389 for i := range lhst { 390 if lhst[i] != rhst[i] { 391 return false 392 } 393 } 394 return true 395 } 396 397 // Concat multiplies a color matrix with the other color matrix. 398 // This is same as muptiplying the matrix other and the matrix c in this order. 399 func (c *ColorM) Concat(other *ColorM) *ColorM { 400 if !c.isInited() { 401 return other 402 } 403 if !other.isInited() { 404 return c 405 } 406 407 lhsb := colorMIdentityBody 408 lhst := colorMIdentityTranslate 409 rhsb := colorMIdentityBody 410 rhst := colorMIdentityTranslate 411 if other.isInited() { 412 if other.body != nil { 413 lhsb = other.body 414 } 415 if other.translate != nil { 416 lhst = other.translate 417 } 418 } 419 if c.isInited() { 420 if c.body != nil { 421 rhsb = c.body 422 } 423 if c.translate != nil { 424 rhst = c.translate 425 } 426 } 427 428 return &ColorM{ 429 // TODO: This is a temporary hack to calculate multiply of transposed matrices. 430 // Fix mulSquare implmentation and swap the arguments. 431 body: mulSquare(rhsb, lhsb, ColorMDim-1), 432 translate: []float32{ 433 lhsb[0]*rhst[0] + lhsb[4]*rhst[1] + lhsb[8]*rhst[2] + lhsb[12]*rhst[3] + lhst[0], 434 lhsb[1]*rhst[0] + lhsb[5]*rhst[1] + lhsb[9]*rhst[2] + lhsb[13]*rhst[3] + lhst[1], 435 lhsb[2]*rhst[0] + lhsb[6]*rhst[1] + lhsb[10]*rhst[2] + lhsb[14]*rhst[3] + lhst[2], 436 lhsb[3]*rhst[0] + lhsb[7]*rhst[1] + lhsb[11]*rhst[2] + lhsb[15]*rhst[3] + lhst[3], 437 }, 438 } 439 } 440 441 // Add is deprecated. 442 func (c *ColorM) Add(other *ColorM) *ColorM { 443 lhsb := colorMIdentityBody 444 lhst := colorMIdentityTranslate 445 rhsb := colorMIdentityBody 446 rhst := colorMIdentityTranslate 447 if other.isInited() { 448 if other.body != nil { 449 lhsb = other.body 450 } 451 if other.translate != nil { 452 lhst = other.translate 453 } 454 } 455 if c.isInited() { 456 if c.body != nil { 457 rhsb = c.body 458 } 459 if c.translate != nil { 460 rhst = c.translate 461 } 462 } 463 464 newC := &ColorM{ 465 body: make([]float32, 16), 466 translate: make([]float32, 4), 467 } 468 for i := range lhsb { 469 newC.body[i] = lhsb[i] + rhsb[i] 470 } 471 for i := range lhst { 472 newC.translate[i] = lhst[i] + rhst[i] 473 } 474 475 return newC 476 } 477 478 // Scale scales the matrix by (r, g, b, a). 479 func (c *ColorM) Scale(r, g, b, a float32) *ColorM { 480 if !c.isInited() { 481 return &ColorM{ 482 body: []float32{ 483 r, 0, 0, 0, 484 0, g, 0, 0, 485 0, 0, b, 0, 486 0, 0, 0, a, 487 }, 488 } 489 } 490 eb := make([]float32, len(colorMIdentityBody)) 491 if c.body != nil { 492 copy(eb, c.body) 493 for i := 0; i < ColorMDim-1; i++ { 494 eb[i*(ColorMDim-1)] *= r 495 eb[i*(ColorMDim-1)+1] *= g 496 eb[i*(ColorMDim-1)+2] *= b 497 eb[i*(ColorMDim-1)+3] *= a 498 } 499 } else { 500 eb[0] = r 501 eb[5] = g 502 eb[10] = b 503 eb[15] = a 504 } 505 506 et := make([]float32, len(colorMIdentityTranslate)) 507 if c.translate != nil { 508 et[0] = c.translate[0] * r 509 et[1] = c.translate[1] * g 510 et[2] = c.translate[2] * b 511 et[3] = c.translate[3] * a 512 } 513 514 return &ColorM{ 515 body: eb, 516 translate: et, 517 } 518 } 519 520 // Translate translates the matrix by (r, g, b, a). 521 func (c *ColorM) Translate(r, g, b, a float32) *ColorM { 522 if !c.isInited() { 523 return &ColorM{ 524 translate: []float32{r, g, b, a}, 525 } 526 } 527 es := make([]float32, len(colorMIdentityTranslate)) 528 if c.translate != nil { 529 copy(es, c.translate) 530 } 531 es[0] += r 532 es[1] += g 533 es[2] += b 534 es[3] += a 535 return &ColorM{ 536 body: c.body, 537 translate: es, 538 } 539 } 540 541 var ( 542 // The YCbCr value ranges are: 543 // Y: [ 0 - 1 ] 544 // Cb: [-0.5 - 0.5] 545 // Cr: [-0.5 - 0.5] 546 547 rgbToYCbCr = &ColorM{ 548 body: []float32{ 549 0.2990, -0.1687, 0.5000, 0, 550 0.5870, -0.3313, -0.4187, 0, 551 0.1140, 0.5000, -0.0813, 0, 552 0, 0, 0, 1, 553 }, 554 } 555 yCbCrToRgb = &ColorM{ 556 body: []float32{ 557 1, 1, 1, 0, 558 0, -0.34414, 1.77200, 0, 559 1.40200, -0.71414, 0, 0, 560 0, 0, 0, 1, 561 }, 562 } 563 ) 564 565 // ChangeHSV changes HSV (Hue-Saturation-Value) elements. 566 // hueTheta is a radian value to ratate hue. 567 // saturationScale is a value to scale saturation. 568 // valueScale is a value to scale value (a.k.a. brightness). 569 // 570 // This conversion uses RGB to/from YCrCb conversion. 571 func (c *ColorM) ChangeHSV(hueTheta float64, saturationScale float32, valueScale float32) *ColorM { 572 sin, cos := math.Sincos(hueTheta) 573 s32, c32 := float32(sin), float32(cos) 574 c = c.Concat(rgbToYCbCr) 575 c = c.Concat(&ColorM{ 576 body: []float32{ 577 1, 0, 0, 0, 578 0, c32, s32, 0, 579 0, -s32, c32, 0, 580 0, 0, 0, 1, 581 }, 582 }) 583 s := saturationScale 584 v := valueScale 585 c = c.Scale(v, s*v, s*v, 1) 586 c = c.Concat(yCbCrToRgb) 587 return c 588 }