1 /++ 2 Color manipulation module. Mixing, converting, parsing colors. 3 4 For mixing use implementations: $(LREF BlendImpl), using 5 $(HREF #BlendFactor, factors) you will get the desired mixing result as 6 a function. An example would be the simplest blending by alpha value: 7 --- 8 BlendImpl!(BlendFactor.SrcAlpha, BlendFactor.OneMinusSrcAlpha, Type). 9 --- 10 11 If you need to convert a set of bytes to a set of colors, 12 use the $(LREF fromColors) function. 13 14 Macros: 15 LREF = <a href="#$1">$1</a> 16 HREF = <a href="$1">$2</a> 17 18 Authors: $(HREF https://github.com/TodNaz,TodNaz) 19 Copyright: Copyright (c) 2020 - 2021, TodNaz. 20 License: $(HREF https://github.com/TodNaz/Tida/blob/master/LICENSE,MIT) 21 +/ 22 module tida.color; 23 24 import std.traits; 25 26 enum CannotDetectAuto = 27 "The format cannot be detected automatically!"; 28 29 /// Pixel representation format. 30 enum PixelFormat : int 31 { 32 None, /// None format 33 Auto, /// Automatic detection 34 RGB, /// Red-Green-Blue 35 RGBA, /// Red-Green-Blue-Alpha 36 ARGB, /// Alpha-Red-Green-Blue 37 BGRA, /// Blue-Green-Red-Alpha 38 BGR /// Blur-Green-Red 39 } 40 41 /++ 42 Whether the pixel format is valid for the job. 43 +/ 44 template isValidFormat(int pixelformat) 45 { 46 enum isValidFormat = pixelformat != PixelFormat.None && 47 pixelformat != PixelFormat.Auto && 48 pixelformat <= PixelFormat.max; 49 } 50 51 unittest 52 { 53 assert(isValidFormat!(PixelFormat.BGRA)); 54 assert(!isValidFormat!(30)); 55 } 56 57 /++ 58 Shows how many bytes are contained in a color unit. 59 +/ 60 template bytesPerColor(int pixelformat, T = ubyte) 61 { 62 static assert(isValidFormat!pixelformat, "Invalid or unknown pixel format!"); 63 64 static if ( pixelformat == PixelFormat.RGBA || 65 pixelformat == PixelFormat.ARGB || 66 pixelformat == PixelFormat.BGRA) 67 { 68 enum bytesPerColor = 4 * T.sizeof; 69 }else 70 { 71 enum bytesPerColor = 3 * T.sizeof; 72 } 73 } 74 75 unittest 76 { 77 assert(bytesPerColor!(PixelFormat.RGBA) == 4); 78 assert(bytesPerColor!(PixelFormat.RGBA, int) == 4 * int.sizeof); 79 assert(bytesPerColor!(PixelFormat.BGR, int) == 3 * int.sizeof); 80 assert(bytesPerColor!(PixelFormat.ARGB, long) == 4 * long.sizeof); 81 assert(bytesPerColor!(PixelFormat.RGB, float) == 3 * float.sizeof); 82 } 83 84 T hexTo(T, R)(R hexData) @safe nothrow pure 85 if (isSomeString!R) 86 { 87 import std.math : pow; 88 89 enum hexNumer = "0123456789"; 90 enum hexWord = "ABCDEF"; 91 enum hexSmallWord = "abcdef"; 92 93 T result = T.init; 94 int index = -1; 95 96 hexDataEach: foreach_reverse (e; hexData) 97 { 98 index++; 99 immutable rindex = (cast(int) hexData.length) - index; 100 immutable ai = pow(16, index); 101 102 foreach (el; hexNumer) 103 { 104 if (e == el) 105 { 106 result += (e - 48) * (ai == 0 ? 1 : ai); 107 continue hexDataEach; 108 } 109 } 110 111 foreach (el; hexWord) 112 { 113 if (e == el) 114 { 115 result += (e - 55) * (ai == 0 ? 1 : ai); 116 continue hexDataEach; 117 } 118 } 119 120 foreach (el; hexSmallWord) 121 { 122 if (e == el) 123 { 124 result += (e - 87) * (ai == 0 ? 1 : ai); 125 continue hexDataEach; 126 } 127 } 128 } 129 130 return result; 131 } 132 133 unittest 134 { 135 assert(hexTo!long("FF0000") == (0xFF0000)); 136 assert(hexTo!long("0A0A1F") == (0x0A0A1f)); 137 assert(hexTo!int("3AF124") == (0x3AF124)); 138 assert(hexTo!int("f1aB11") == (0xf1aB11)); 139 assert(hexTo!int("fffff3a") == (0xfffff3a)); 140 } 141 142 /++ 143 Creates an RGB color. 144 145 Params: 146 red = Red. 147 green = Green. 148 blue = Blue. 149 150 Returns: RGBA 151 +/ 152 Color!ubyte rgb(ubyte red, ubyte green, ubyte blue) @safe nothrow pure 153 { 154 return Color!ubyte(red, green, blue, ubyte.max); 155 } 156 157 Color!ubyte rgb(ubyte[] data) @safe nothrow pure 158 { 159 return Color!ubyte(data[0], data[1], data[2]); 160 } 161 162 Color!ubyte rgba(ubyte[] data) @safe nothrow pure 163 { 164 return Color!ubyte(data); 165 } 166 167 Color!ubyte grayscale(ubyte value) @safe nothrow pure 168 { 169 return Color!ubyte(value, value, value, Color!ubyte.Max); 170 } 171 172 /++ 173 Creates an RGBA color. 174 175 Params: 176 red = Red. 177 green = Green. 178 blue = Blue. 179 alpha = Alpha. 180 181 Returns: RGBA 182 +/ 183 Color!ubyte rgba(ubyte red, ubyte green, ubyte blue, ubyte alpha) @safe nothrow pure 184 { 185 return Color!ubyte(red, green, blue, alpha); 186 } 187 188 /++ 189 Recognizes a hex format string, converting it to RGBA representation as a 190 `Color!ubyte` structure. 191 192 Params: 193 hex = The same performance. The following formats can be used: 194 * `0xRRGGBBAA` / `0xRRGGBB` 195 * `#RRGGBBAA` / `#RRGGBB` 196 format = Pixel format. 197 198 Returns: `Color!ubyte` 199 +/ 200 Color!C parseColor(int format = PixelFormat.Auto, C = ubyte, T)(T hex) 201 @safe nothrow pure 202 { 203 static if (isSomeString!T) 204 { 205 import std.conv : to; 206 import std.bigint; 207 208 size_t cv = 0; 209 if (hex[0] == '#') 210 cv++; 211 else 212 if (hex[0 .. 2] == "0x") 213 cv += 2; 214 215 static if (format == PixelFormat.Auto) 216 { 217 const alpha = hex[cv .. $].length > 6; 218 219 return Color!C( 220 hex[cv .. cv + 2].hexTo!C, 221 hex[cv + 2 .. cv + 4].hexTo!C, 222 hex[cv + 4 .. cv + 6].hexTo!C, 223 alpha ? hex[cv + 6 .. cv + 8].hexTo!C : Color!C.Max 224 ); 225 }else 226 static if (format == PixelFormat.RGB) 227 { 228 return Color!C( 229 hex[cv .. cv + 2].hexTo!C, 230 hex[cv + 2 .. cv + 4].hexTo!C, 231 hex[cv + 4 .. cv + 6].hexTo!C 232 ); 233 }else 234 static if (format == PixelFormat.RGBA) 235 { 236 assert(hex[cv .. $].length > 6,"This is not alpha-channel hex color!"); 237 238 return Color!C( 239 hex[cv .. cv + 2].hexTo!C, 240 hex[cv + 2 .. cv + 4].hexTo!C, 241 hex[cv + 4 .. cv + 6].hexTo!C, 242 hex[cv + 6 .. cv + 8].hexTo!C 243 ); 244 }else 245 static if (format == PixelFormat.ARGB) 246 { 247 assert(hex[cv .. $].length > 6,"This is not alpha-channel hex color!"); 248 249 return Color!C( 250 hex[cv + 2 .. cv + 4].hexTo!C, 251 hex[cv + 4 .. cv + 6].hexTo!C, 252 hex[cv + 6 .. cv + 8].hexTo!C, 253 hex[cv .. cv + 2].hexTo!C 254 ); 255 }else 256 static if (format == PixelFormat.BGRA) 257 { 258 assert(hex[cv .. $].length > 6,"This is not alpha-channel hex color!"); 259 260 return Color!C( 261 hex[cv + 4 .. cv + 6].hexTo!C, 262 hex[cv + 2 .. cv + 4].hexTo!C, 263 hex[cv .. cv + 2].hexTo!C, 264 hex[cv + 6 .. cv + 8].hexTo!C 265 ); 266 }else 267 static if (format == PixelFormat.BGR) 268 { 269 return Color!C( 270 hex[cv + 6 .. cv + 8].hexTo!C, 271 hex[cv + 2 .. cv + 4].hexTo!C, 272 hex[cv .. cv + 2].hexTo!C); 273 }else 274 static assert(null,"Unknown pixel format"); 275 }else 276 static if (isIntegral!T) 277 { 278 Color!C result; 279 280 static if (format == PixelFormat.RGBA) 281 { 282 result.r = (hex & 0xFF000000) >> 24; 283 result.g = (hex & 0x00FF0000) >> 16; 284 result.b = (hex & 0x0000FF00) >> 8; 285 result.a = (hex & 0x000000FF); 286 287 return result; 288 }else 289 static if (format == PixelFormat.RGB) 290 { 291 result.r = (hex & 0xFF0000) >> 16; 292 result.g = (hex & 0x00FF00) >> 8; 293 result.b = (hex & 0x0000FF); 294 result.a = 255; 295 296 return result; 297 }else 298 static if (format == PixelFormat.ARGB) 299 { 300 result.a = (hex & 0xFF000000) >> 24; 301 result.r = (hex & 0x00FF0000) >> 16; 302 result.g = (hex & 0x0000FF00) >> 8; 303 result.b = (hex & 0x000000FF); 304 305 return result; 306 }else 307 static if (format == PixelFormat.BGRA) 308 { 309 result.b = (hex & 0xFF000000) >> 24; 310 result.g = (hex & 0x00FF0000) >> 16; 311 result.r = (hex & 0x0000FF00) >> 8; 312 result.a = (hex & 0x000000FF); 313 314 return result; 315 }else 316 static if (format == PixelFormat.BGR) 317 { 318 result.b = (hex & 0XFF0000) >> 16; 319 result.g = (hex & 0x00FF00) >> 8; 320 result.r = (hex & 0x0000FF); 321 result.a = Color!C.Max; 322 323 return result; 324 }else 325 static if (format == PixelFormat.Auto) { 326 return parseColor!(PixelFormat.RGB, C, T)(hex); 327 }else 328 static assert(null, "Unknown pixel format!"); 329 }else 330 static assert(null, "Unknown type hex!"); 331 } 332 333 unittest 334 { 335 assert(parseColor(0xFFFFFF) == (Color!ubyte(255, 255, 255))); 336 assert(parseColor("#f9004c") == (Color!ubyte(249, 0, 76))); 337 assert(parseColor("#f9004cf9") == (Color!ubyte(249, 0, 76, 249))); 338 339 assert(parseColor!(PixelFormat.RGBA)(0xc1f4a1b4) == (Color!ubyte(193, 244, 161, 180))); 340 assert(parseColor!(PixelFormat.BGRA)("FF0000FF") == (Color!ubyte(0, 0, 255, 255))); 341 assert(parseColor!(PixelFormat.ARGB)("f9ff00ff") == (Color!ubyte(255, 0, 255, 249))); 342 assert(parseColor!(PixelFormat.BGR)(0xf900ff) == (Color!ubyte(255, 0, 249, 255))); 343 } 344 345 /++ 346 Color description structure. 347 +/ 348 struct Color(T) 349 if (isIntegral!T || isFloatingPoint!T) 350 { 351 alias Type = T; 352 353 static if (isIntegral!T) 354 { 355 enum Max = T.max; 356 enum Min = 0; 357 } 358 else 359 static if (isFloatingPoint!T) 360 { 361 enum Max = 1.0f; 362 enum Min = 0.0f; 363 } 364 365 public: 366 T red; /// Red component 367 T green; /// Green component 368 T blue; /// Blue component 369 T alpha = Max; /// Alpha component 370 371 alias r = red; 372 alias g = green; 373 alias b = blue; 374 alias a = alpha; 375 376 @safe nothrow pure: 377 /++ 378 Color constructor for four components, the latter which is optional. 379 +/ 380 this(T red, T green, T blue, T alpha = Max) 381 { 382 this.red = red; 383 this.green = green; 384 this.blue = blue; 385 this.alpha = alpha; 386 } 387 388 /++ 389 Parses a color from the input. 390 +/ 391 this(R)(R value) 392 if (isIntegral!R || isSomeString!R || isArray!R) 393 { 394 static if (isArray!R && !isSomeString!R) 395 { 396 this.red = cast(T) value[0]; 397 this.green = cast(T) value[1]; 398 this.blue = cast(T) value[2]; 399 this.alpha = cast(T) (value.length > 3 ? value[3] : Max); 400 } 401 else 402 this = parseColor!(PixelFormat.Auto, T, R)(value); 403 } 404 405 void opAssign(R)(R value) 406 if (isIntegral!R || isSomeString!R || isArray!R) 407 { 408 static if (isArray!R && !isSomeString!R) 409 { 410 this.red = value[0]; 411 this.green = value[1]; 412 this.blue = value[2]; 413 this.alpha = value.length > 3 ? value[3] : Max; 414 } 415 else 416 this = parseColor!(PixelFormat.Auto, T, R)(value); 417 } 418 419 R to(R, int format = PixelFormat.RGBA)() inout 420 { 421 static if (isIntegral!R && !isFloatingPoint!T) 422 { 423 static if(format == PixelFormat.RGBA) 424 return cast(R) (((r & 0xff) << 24) + ((g & 0xff) << 16) + ((b & 0xff) << 8) + (a & 0xff)); 425 else 426 static if(format == PixelFormat.RGB) 427 return cast(R) ((r & 0xff) << 16) + ((g & 0xff) << 8) + ((b & 0xff)); 428 else 429 static if(format == PixelFormat.ARGB) 430 return cast(R) (((a & 0xff) << 24) + ((r & 0xff) << 16) + ((g & 0xff) << 8) + (b & 0xff)); 431 else 432 static if(format == PixelFormat.BGRA) 433 return cast(R) (((b & 0xff) << 24) + ((g & 0xff) << 16) + ((r & 0xff) << 8) + (a & 0xff)); 434 else 435 static if(format == PixelFormat.BGR) 436 return cast(R) (((b & 0xff) << 16) + ((g & 0xff) << 8) + ((r & 0xff))); 437 else 438 return 0; 439 }else 440 static if (isSomeString!R) 441 { 442 static if (isFloatingPoint!T) 443 return ""; 444 else 445 { 446 import std.digest : toHexString; 447 448 return cast(R) toBytes!(format).toHexString; 449 } 450 } 451 } 452 453 /++ 454 Returns an array of components. 455 456 Params: 457 format = Pixel format. 458 +/ 459 T[] toBytes(int format)() inout 460 { 461 static assert(isValidFormat!format, CannotDetectAuto); 462 463 static if (format == PixelFormat.RGBA) 464 return [r,g,b,a]; 465 else 466 static if (format == PixelFormat.RGB) 467 return [r,g,b]; 468 else 469 static if (format == PixelFormat.ARGB) 470 return [a,r,g,b]; 471 else 472 static if (format == PixelFormat.BGRA) 473 return [b,g,r,a]; 474 else 475 static if (format == PixelFormat.BGR) 476 return [b,g,r]; 477 } 478 479 Color!T opBinary(string op)(T koe) inout 480 { 481 import std.conv : to; 482 483 static if (op == "+") 484 return Color!T( cast(T) (r + koe), 485 cast(T) (g + koe), 486 cast(T) (b + koe), 487 cast(T) (a + koe)); 488 else 489 static if (op == "-") 490 return Color!T( cast(T) (r - koe), 491 cast(T) (g - koe), 492 cast(T) (b - koe), 493 cast(T) (a - koe)); 494 else 495 static if (op == "*") 496 return Color!T( cast(T) (r * koe), 497 cast(T) (g * koe), 498 cast(T) (b * koe), 499 cast(T) (a * koe)); 500 else 501 static if (op == "/") 502 return Color!T( cast(T) (r / koe), 503 cast(T) (g / koe), 504 cast(T) (b / koe), 505 cast(T) (a / koe)); 506 else 507 static assert(0, "Operator `" ~ op ~ "` not implemented."); 508 } 509 510 Color!T opBinary(string op)(float koe) inout 511 { 512 import std.conv : to; 513 514 static if (op == "+") 515 return Color!T( cast(T) (r + koe), 516 cast(T) (g + koe), 517 cast(T) (b + koe), 518 cast(T) (a + koe)); 519 else 520 static if (op == "-") 521 return Color!T( cast(T) (r - koe), 522 cast(T) (g - koe), 523 cast(T) (b - koe), 524 cast(T) (a - koe)); 525 else 526 static if (op == "*") 527 return Color!T( cast(T) (r * koe), 528 cast(T) (g * koe), 529 cast(T) (b * koe), 530 cast(T) (a * koe)); 531 else 532 static if (op == "/") 533 return Color!T( cast(T) (r / koe), 534 cast(T) (g / koe), 535 cast(T) (b / koe), 536 cast(T) (a / koe)); 537 else 538 static assert(0, "Operator `" ~ op ~ "` not implemented."); 539 } 540 541 Color!T opBinary(string op)(Color!T color) inout 542 { 543 static if (op == "+") { 544 return Color!T( cast(T) (r + color.r), 545 cast(T) (g + color.g), 546 cast(T) (b + color.b), 547 cast(T) (a + color.a)); 548 } 549 else 550 static if (op == "-") 551 return Color!T( cast(T) (r - color.r), 552 cast(T) (g - color.g), 553 cast(T) (b - color.b), 554 cast(T) (a - color.a)); 555 else 556 static if (op == "*") 557 return Color!T( cast(T) r * color.r, 558 g * color.g, 559 b * color.b, 560 a * color.a); 561 else 562 static if (op == "/") 563 return Color!T( cast(T) r / color.r, 564 g / color.g, 565 b / color.b, 566 a / color.a); 567 else 568 static assert(0, "Operator `" ~ op ~ "` not implemented."); 569 } 570 571 /// Converts the color to black and white. 572 float toGrayscaleFloat() inout 573 { 574 return (rf * 0.299 + gf * 0.587 + bf * 0.144); 575 } 576 577 /// Whether the color is dark. 578 bool isDark() inout 579 { 580 return toGrayscaleFloat < 0.5f; 581 } 582 583 /// Whether the color is light. 584 bool isLight() inout 585 { 586 return toGrayscaleFloat > 0.5f; 587 } 588 589 /// Converts the color to black and white. 590 T toGrayscaleNumber() inout 591 { 592 return cast(T) (Max * toGrayscaleFloat()); 593 } 594 595 /// Converts the color to black and white. 596 Color!T toGrayscale() inout 597 { 598 auto graycolor = toGrayscaleNumber(); 599 600 return Color!T(graycolor, graycolor, graycolor, alpha); 601 } 602 603 /// Will return the color opposite to itself. 604 @property Color!T inverted() inout 605 { 606 return Color!T(Max - r, Max - g, Max - b, a); 607 } 608 609 /// Invert alpha value 610 @property T invertAlpha() inout 611 { 612 return Max - alpha; 613 } 614 615 /// Red value in the form of a range from 0 to 1. 616 @property float rf() inout 617 { 618 return cast(float) r / cast(float) Max; 619 } 620 621 /// ditto 622 @property float rf(float value) 623 { 624 this.r = cast(T) (Max * value); 625 626 return value; 627 } 628 629 /// Green value in the form of a range from 0 to 1. 630 @property float gf() inout 631 { 632 return cast(float) g / cast(float) Max; 633 } 634 635 /// ditto 636 @property float gf(float value) 637 { 638 this.g = cast(T) (Max * value); 639 640 return value; 641 } 642 643 /// Alpha value in the form of a range from 0 to 1. 644 @property float bf() inout 645 { 646 return cast(float) b / cast(float) Max; 647 } 648 649 /// ditto 650 @property float bf(float value) 651 { 652 this.b = cast(T) (Max * value); 653 654 return value; 655 } 656 657 /// Returns a alpha value in the form of a range from 0 to 1. 658 @property float af() inout 659 { 660 return cast(float) a / cast(float) Max; 661 } 662 /// ditto 663 @property float af(float value) 664 { 665 this.a = cast(T) (Max * value); 666 667 return value; 668 } 669 } 670 671 unittest 672 { 673 Color!ubyte color = "#f9004c"; 674 assert(color == (Color!ubyte(249, 0, 76))); 675 676 color = 0xf9004c; 677 assert(color == (Color!ubyte(249, 0, 76))); 678 679 color = Color!ubyte([249, 0, 76]); 680 assert(color == (Color!ubyte(249, 0, 76))); 681 682 } 683 684 /++ 685 Will change the byte sequence to color. 686 687 Params: 688 format = Pixel format. 689 bytes = byte sequence. 690 +/ 691 Color!ubyte fromColor(int format)(ubyte[] bytes) @safe nothrow pure 692 { 693 bytes = bytes.fromFormat!(format,PixelFormat.RGBA); 694 695 return Color!ubyte(bytes[0],bytes[1],bytes[2],bytes[3]); 696 } 697 698 /++ 699 Will change the sequence of bytes into a collection of colors. 700 701 Params: 702 format = Pixel format. 703 bytes = byte sequence. 704 +/ 705 Color!ubyte[] fromColors(int format)(ubyte[] bytes) @safe nothrow pure 706 { 707 Color!ubyte[] result; 708 709 for(size_t i = 0; i < bytes.length; i += bytesPerColor!format) 710 { 711 result ~= bytes[i .. i + bytesPerColor!format].fromColor!(format); 712 } 713 714 return result; 715 } 716 717 unittest 718 { 719 assert([54, 13, 85, 255].fromColor!(PixelFormat.RGBA) == (rgb(54, 13, 85))); 720 721 assert([54, 13, 85, 255, 128, 54, 9, 255].fromColors!(PixelFormat.RGBA) == ([rgb(54, 13, 85), rgb(128, 54, 9)])); 722 } 723 724 /++ 725 Checks if the structure is a color. 726 +/ 727 template isColor(T) 728 { 729 enum isColor = __traits(hasMember, T, "r") && 730 __traits(hasMember, T, "g") && 731 __traits(hasMember, T, "b") && 732 __traits(hasMember, T, "a"); 733 } 734 735 /++ 736 Converts one sample color to another. 737 738 Params: 739 From = From color. 740 To = To color. 741 color = color structre. 742 743 Returns: 744 Converted color. 745 +/ 746 Color!To convert(From, To)(Color!From color) @safe nothrow pure 747 { 748 static if (isFloatingPoint!From) 749 { 750 static if (isFloatingPoint!To) 751 { 752 return Color!To( 753 cast(To) color.red, 754 cast(To) color.green, 755 cast(To) color.blue, 756 cast(To) color.alpha 757 ); 758 }else 759 static if (isIntegral!To) 760 { 761 return Color!To( 762 cast(To) (color.red * Color!To.Max), 763 cast(To) (color.green * Color!To.Max), 764 cast(To) (color.blue * Color!To.Max), 765 cast(To) (color.alpha * Color!To.Max) 766 ); 767 } 768 }else 769 static if (isIntegral!From) 770 { 771 static if (isFloatingPoint!To) 772 { 773 return Color!To( 774 cast(To) (color.rf), 775 cast(To) (color.gf), 776 cast(To) (color.bf), 777 cast(To) (color.af) 778 ); 779 }else 780 static if (isIntegral!From) 781 { 782 return Color!To( 783 cast(To) color.red, 784 cast(To) color.green, 785 cast(To) color.blue, 786 cast(To) color.alpha 787 ); 788 } 789 } 790 } 791 792 unittest 793 { 794 assert(Color!ubyte(255, 255, 255, 255) 795 .convert!(ubyte, float) == (Color!float(1.0f, 1.0f, 1.0f, 1.0f))); 796 797 assert(Color!float(1.0f, 1.0f, 1.0f, 1.0f) 798 .convert!(float, ubyte) == (Color!ubyte(255, 255, 255, 255))); 799 } 800 801 /++ 802 Checks if the byte array is valid for the color description. 803 +/ 804 bool validateBytes(int format)(inout(ubyte[]) pixels) @safe nothrow pure 805 { 806 return (pixels.length % bytesPerColor!format) == 0; 807 } 808 809 /// Mixing factor of two colors. 810 enum BlendFactor 811 { 812 Zero, 813 One, 814 SrcColor, 815 OneMinusSrcColor, 816 DstColor, 817 OneMinusDstColor, 818 SrcAlpha, 819 OneMinusSrcAlpha, 820 DstAlpha, 821 OneMinusDstAlpha, 822 ConstantColor, 823 OneMinusConstantColor, 824 ConstantAlpha, 825 OneMinusConstanceAlpha 826 } 827 828 /++ 829 Color mixing implementations. 830 831 Params: 832 fac1 = First factor mixing. 833 fac2 = Second factor mixing. 834 T = Two colors type. 835 orig = Original color mixing. 836 color = Second color mixing. 837 +/ 838 Color!T BlendImpl(int fac1, int fac2, T)(Color!T orig, Color!T color) @safe nothrow pure 839 { 840 Color!float origf = convert!(T, float)(orig); 841 Color!float colorf = convert!(T, float)(color); 842 843 Color!float srcf, drtf; 844 845 // Factory 1 846 static if(fac1 == BlendFactor.Zero) 847 srcf = Color!float(0.0f, 0.0f, 0.0f, 0.0f); 848 else 849 static if(fac1 == BlendFactor.One) 850 srcf = Color!float(1.0f, 1.0f, 1.0f, 1.0f); 851 else 852 static if(fac1 == BlendFactor.SrcColor) 853 srcf = Color!float(origf.r, origf.g, origf.b, 1.0f); 854 else 855 static if(fac1 == BlendFactor.OneMinusSrcAlpha) 856 srcf = Color!float(1.0f - origf.r, 1.0f - origf.g, 1.0f - origf.b, 1.0f); 857 else 858 static if(fac1 == BlendFactor.DstColor) 859 srcf = Color!float(colorf.r, colorf.g, colorf.b, 1.0f); 860 else 861 static if(fac1 == BlendFactor.OneMinusDstColor) 862 srcf = Color!float(1.0f - colorf.r, 1.0f - colorf.g, 1.0f - colorf.b, 1.0f); 863 else 864 static if(fac1 == BlendFactor.SrcAlpha) 865 srcf = Color!float(origf.a, origf.a, origf.a, origf.a); 866 else 867 static if(fac1 == BlendFactor.OneMinusSrcAlpha) 868 srcf = Color!float(1.0f - origf.a, 1.0f - origf.a, 1.0f - origf.a, 1.0f - origf.a); 869 else 870 static if(fac1 == BlendFactor.DstAlpha) 871 srcf = Color!float(colorf.a, colorf.a, colorf.a, colorf.a); 872 else 873 static if(fac1 == BlendFactor.OneMinusDstAlpha) 874 srcf = Color!float(1.0f - colorf.a, 1.0f - colorf.a, 1.0f - colorf.a, 1.0f - colorf.a); 875 876 // Factory 2 877 static if(fac2 == BlendFactor.Zero) 878 drtf = Color!float(0.0f, 0.0f, 0.0f, 0.0f); 879 else 880 static if(fac2 == BlendFactor.One) 881 drtf = Color!float(1.0f, 1.0f, 1.0f, 1.0f); 882 else 883 static if(fac2 == BlendFactor.SrcColor) 884 drtf = Color!float(origf.r, origf.g, origf.b, 1.0f); 885 else 886 static if(fac2 == BlendFactor.OneMinusSrcAlpha) 887 drtf = Color!float(1.0f - origf.r, 1.0f - origf.g, 1.0f - origf.b, 1.0f); 888 else 889 static if(fac2 == BlendFactor.DstColor) 890 drtf = Color!float(colorf.r, colorf.g, colorf.b, 1.0f); 891 else 892 static if(fac2 == BlendFactor.OneMinusDstColor) 893 drtf = Color!float(1.0f - colorf.r, 1.0f - colorf.g, 1.0f - colorf.b, 1.0f); 894 else 895 static if(fac2 == BlendFactor.SrcAlpha) 896 drtf = Color!float(origf.a, origf.a, origf.a, origf.a); 897 else 898 static if(fac2 == BlendFactor.OneMinusSrcAlpha) 899 drtf = Color!float(1.0f - origf.a, 1.0f - origf.a, 1.0f - origf.a, 1.0f - origf.a); 900 else 901 static if(fac2 == BlendFactor.DstAlpha) 902 drtf = Color!float(colorf.a, colorf.a, colorf.a, colorf.a); 903 else 904 static if(fac2 == BlendFactor.OneMinusDstAlpha) 905 drtf = Color!float(1.0f - colorf.a, 1.0f - colorf.a, 1.0f - colorf.a, 1.0f - colorf.a); 906 907 Color!float trace = (origf * srcf) + (colorf * drtf); 908 return convert!(float, T)(trace); 909 } 910 911 alias mix(T) = BlendMultiply!T; 912 alias BlendAlpha(T) = BlendImpl!(BlendFactor.SrcAlpha, BlendFactor.OneMinusSrcAlpha, T); 913 alias BlendAdd(T) = BlendImpl!(BlendFactor.One, BlendFactor.One, T); 914 alias BlendMultiply(T) = BlendImpl!(BlendFactor.DstColor, BlendFactor.Zero, T); 915 alias BlendSrc2DST(T) = BlendImpl!(BlendFactor.SrcColor, BlendFactor.One, T); 916 alias BlendAddMul(T) = BlendImpl!(BlendFactor.OneMinusDstColor, BlendFactor.One, T); 917 alias BlendAddAlpha(T) = BlendImpl!(BlendFactor.SrcAlpha, BlendFactor.One, T); 918 919 alias FuncBlend(T) = Color!T function(Color!T,Color!T) @safe nothrow pure; 920 921 /++ 922 Returns a reference to a function that implements mixing two colors 923 by mixing factors. 924 +/ 925 FuncBlend!T BlendFunc(T)(int fac1, int fac2) @trusted nothrow pure 926 { 927 if (fac1 == BlendFactor.Zero) 928 { 929 if (fac2 == BlendFactor.Zero) 930 return &BlendImpl!(BlendFactor.Zero, BlendFactor.Zero, T); 931 else 932 if (fac2 == BlendFactor.One) 933 return &BlendImpl!(BlendFactor.Zero, BlendFactor.One, T); 934 else 935 if (fac2 == BlendFactor.SrcColor) 936 return &BlendImpl!(BlendFactor.Zero, BlendFactor.SrcColor, T); 937 else 938 if (fac2 == BlendFactor.OneMinusSrcColor) 939 return &BlendImpl!(BlendFactor.Zero, BlendFactor.OneMinusSrcColor, T); 940 else 941 if (fac2 == BlendFactor.DstColor) 942 return &BlendImpl!(BlendFactor.Zero, BlendFactor.DstColor, T); 943 else 944 if (fac2 == BlendFactor.OneMinusDstColor) 945 return &BlendImpl!(BlendFactor.Zero, BlendFactor.OneMinusDstColor, T); 946 else 947 if (fac2 == BlendFactor.SrcAlpha) 948 return &BlendImpl!(BlendFactor.Zero, BlendFactor.SrcAlpha, T); 949 else 950 if (fac2 == BlendFactor.OneMinusSrcAlpha) 951 return &BlendImpl!(BlendFactor.Zero, BlendFactor.OneMinusSrcAlpha, T); 952 else 953 if (fac2 == BlendFactor.DstAlpha) 954 return &BlendImpl!(BlendFactor.Zero, BlendFactor.DstAlpha, T); 955 else 956 if (fac2 == BlendFactor.OneMinusDstAlpha) 957 return &BlendImpl!(BlendFactor.Zero, BlendFactor.OneMinusDstAlpha, T); 958 }else 959 if (fac1 == BlendFactor.One) 960 { 961 if (fac2 == BlendFactor.Zero) 962 return &BlendImpl!(BlendFactor.One, BlendFactor.Zero, T); 963 else 964 if (fac2 == BlendFactor.One) 965 return &BlendImpl!(BlendFactor.One, BlendFactor.One, T); 966 else 967 if (fac2 == BlendFactor.SrcColor) 968 return &BlendImpl!(BlendFactor.One, BlendFactor.SrcColor, T); 969 else 970 if (fac2 == BlendFactor.OneMinusSrcColor) 971 return &BlendImpl!(BlendFactor.One, BlendFactor.OneMinusSrcColor, T); 972 else 973 if (fac2 == BlendFactor.DstColor) 974 return &BlendImpl!(BlendFactor.One, BlendFactor.DstColor, T); 975 else 976 if (fac2 == BlendFactor.OneMinusDstColor) 977 return &BlendImpl!(BlendFactor.One, BlendFactor.OneMinusDstColor, T); 978 else 979 if (fac2 == BlendFactor.SrcAlpha) 980 return &BlendImpl!(BlendFactor.One, BlendFactor.SrcAlpha, T); 981 else 982 if (fac2 == BlendFactor.OneMinusSrcAlpha) 983 return &BlendImpl!(BlendFactor.One, BlendFactor.OneMinusSrcAlpha, T); 984 else 985 if (fac2 == BlendFactor.DstAlpha) 986 return &BlendImpl!(BlendFactor.One, BlendFactor.DstAlpha, T); 987 else 988 if (fac2 == BlendFactor.OneMinusDstAlpha) 989 return &BlendImpl!(BlendFactor.One, BlendFactor.OneMinusDstAlpha, T); 990 }else 991 if (fac1 == BlendFactor.SrcColor) 992 { 993 if (fac2 == BlendFactor.Zero) 994 return &BlendImpl!(BlendFactor.SrcColor, BlendFactor.Zero, T); 995 else 996 if (fac2 == BlendFactor.One) 997 return &BlendImpl!(BlendFactor.SrcColor, BlendFactor.One, T); 998 else 999 if (fac2 == BlendFactor.SrcColor) 1000 return &BlendImpl!(BlendFactor.SrcColor, BlendFactor.SrcColor, T); 1001 else 1002 if (fac2 == BlendFactor.OneMinusSrcColor) 1003 return &BlendImpl!(BlendFactor.SrcColor, BlendFactor.OneMinusSrcColor, T); 1004 else 1005 if (fac2 == BlendFactor.DstColor) 1006 return &BlendImpl!(BlendFactor.SrcColor, BlendFactor.DstColor, T); 1007 else 1008 if (fac2 == BlendFactor.OneMinusDstColor) 1009 return &BlendImpl!(BlendFactor.SrcColor, BlendFactor.OneMinusDstColor, T); 1010 else 1011 if (fac2 == BlendFactor.SrcAlpha) 1012 return &BlendImpl!(BlendFactor.SrcColor, BlendFactor.SrcAlpha, T); 1013 else 1014 if (fac2 == BlendFactor.OneMinusSrcAlpha) 1015 return &BlendImpl!(BlendFactor.SrcColor, BlendFactor.OneMinusSrcAlpha, T); 1016 else 1017 if (fac2 == BlendFactor.DstAlpha) 1018 return &BlendImpl!(BlendFactor.SrcColor, BlendFactor.DstAlpha, T); 1019 else 1020 if (fac2 == BlendFactor.OneMinusDstAlpha) 1021 return &BlendImpl!(BlendFactor.SrcColor, BlendFactor.OneMinusDstAlpha, T); 1022 }else 1023 if (fac1 == BlendFactor.OneMinusSrcColor) 1024 { 1025 if (fac2 == BlendFactor.Zero) 1026 return &BlendImpl!(BlendFactor.OneMinusSrcColor, BlendFactor.Zero, T); 1027 else 1028 if (fac2 == BlendFactor.One) 1029 return &BlendImpl!(BlendFactor.OneMinusSrcColor, BlendFactor.One, T); 1030 else 1031 if (fac2 == BlendFactor.SrcColor) 1032 return &BlendImpl!(BlendFactor.OneMinusSrcColor, BlendFactor.SrcColor, T); 1033 else 1034 if (fac2 == BlendFactor.OneMinusSrcColor) 1035 return &BlendImpl!(BlendFactor.OneMinusSrcColor, BlendFactor.OneMinusSrcColor, T); 1036 else 1037 if (fac2 == BlendFactor.DstColor) 1038 return &BlendImpl!(BlendFactor.OneMinusSrcColor, BlendFactor.DstColor, T); 1039 else 1040 if (fac2 == BlendFactor.OneMinusDstColor) 1041 return &BlendImpl!(BlendFactor.OneMinusSrcColor, BlendFactor.OneMinusDstColor, T); 1042 else 1043 if (fac2 == BlendFactor.SrcAlpha) 1044 return &BlendImpl!(BlendFactor.OneMinusSrcColor, BlendFactor.SrcAlpha, T); 1045 else 1046 if (fac2 == BlendFactor.OneMinusSrcAlpha) 1047 return &BlendImpl!(BlendFactor.OneMinusSrcColor, BlendFactor.OneMinusSrcAlpha, T); 1048 else 1049 if (fac2 == BlendFactor.DstAlpha) 1050 return &BlendImpl!(BlendFactor.OneMinusSrcColor, BlendFactor.DstAlpha, T); 1051 else 1052 if (fac2 == BlendFactor.OneMinusDstAlpha) 1053 return &BlendImpl!(BlendFactor.OneMinusSrcColor, BlendFactor.OneMinusDstAlpha, T); 1054 }else 1055 if(fac1 == BlendFactor.DstColor) 1056 { 1057 if (fac2 == BlendFactor.Zero) 1058 return &BlendImpl!(BlendFactor.DstColor, BlendFactor.Zero, T); 1059 else 1060 if (fac2 == BlendFactor.One) 1061 return &BlendImpl!(BlendFactor.DstColor, BlendFactor.One, T); 1062 else 1063 if (fac2 == BlendFactor.SrcColor) 1064 return &BlendImpl!(BlendFactor.DstColor, BlendFactor.SrcColor, T); 1065 else 1066 if (fac2 == BlendFactor.OneMinusSrcColor) 1067 return &BlendImpl!(BlendFactor.DstColor, BlendFactor.OneMinusSrcColor, T); 1068 else 1069 if (fac2 == BlendFactor.DstColor) 1070 return &BlendImpl!(BlendFactor.DstColor, BlendFactor.DstColor, T); 1071 else 1072 if (fac2 == BlendFactor.OneMinusDstColor) 1073 return &BlendImpl!(BlendFactor.DstColor, BlendFactor.OneMinusDstColor, T); 1074 else 1075 if (fac2 == BlendFactor.SrcAlpha) 1076 return &BlendImpl!(BlendFactor.DstColor, BlendFactor.SrcAlpha, T); 1077 else 1078 if (fac2 == BlendFactor.OneMinusSrcAlpha) 1079 return &BlendImpl!(BlendFactor.DstColor, BlendFactor.OneMinusSrcAlpha, T); 1080 else 1081 if (fac2 == BlendFactor.DstAlpha) 1082 return &BlendImpl!(BlendFactor.DstColor, BlendFactor.DstAlpha, T); 1083 else 1084 if (fac2 == BlendFactor.OneMinusDstAlpha) 1085 return &BlendImpl!(BlendFactor.DstColor, BlendFactor.OneMinusDstAlpha, T); 1086 }else 1087 if (fac1 == BlendFactor.OneMinusDstColor) 1088 { 1089 if (fac2 == BlendFactor.Zero) 1090 return &BlendImpl!(BlendFactor.OneMinusDstColor, BlendFactor.Zero, T); 1091 else 1092 if (fac2 == BlendFactor.One) 1093 return &BlendImpl!(BlendFactor.OneMinusDstColor, BlendFactor.One, T); 1094 else 1095 if (fac2 == BlendFactor.SrcColor) 1096 return &BlendImpl!(BlendFactor.OneMinusDstColor, BlendFactor.SrcColor, T); 1097 else 1098 if (fac2 == BlendFactor.OneMinusSrcColor) 1099 return &BlendImpl!(BlendFactor.OneMinusDstColor, BlendFactor.OneMinusSrcColor, T); 1100 else 1101 if (fac2 == BlendFactor.DstColor) 1102 return &BlendImpl!(BlendFactor.OneMinusDstColor, BlendFactor.DstColor, T); 1103 else 1104 if (fac2 == BlendFactor.OneMinusDstColor) 1105 return &BlendImpl!(BlendFactor.OneMinusDstColor, BlendFactor.OneMinusDstColor, T); 1106 else 1107 if (fac2 == BlendFactor.SrcAlpha) 1108 return &BlendImpl!(BlendFactor.OneMinusDstColor, BlendFactor.SrcAlpha, T); 1109 else 1110 if (fac2 == BlendFactor.OneMinusSrcAlpha) 1111 return &BlendImpl!(BlendFactor.OneMinusDstColor, BlendFactor.OneMinusSrcAlpha, T); 1112 else 1113 if (fac2 == BlendFactor.DstAlpha) 1114 return &BlendImpl!(BlendFactor.OneMinusDstColor, BlendFactor.DstAlpha, T); 1115 else 1116 if (fac2 == BlendFactor.OneMinusDstAlpha) 1117 return &BlendImpl!(BlendFactor.OneMinusDstColor, BlendFactor.OneMinusDstAlpha, T); 1118 }else 1119 if (fac1 == BlendFactor.SrcAlpha) 1120 { 1121 if (fac2 == BlendFactor.Zero) 1122 return &BlendImpl!(BlendFactor.SrcAlpha, BlendFactor.Zero, T); 1123 else 1124 if (fac2 == BlendFactor.One) 1125 return &BlendImpl!(BlendFactor.SrcAlpha, BlendFactor.One, T); 1126 else 1127 if (fac2 == BlendFactor.SrcColor) 1128 return &BlendImpl!(BlendFactor.SrcAlpha, BlendFactor.SrcColor, T); 1129 else 1130 if (fac2 == BlendFactor.OneMinusSrcColor) 1131 return &BlendImpl!(BlendFactor.SrcAlpha, BlendFactor.OneMinusSrcColor, T); 1132 else 1133 if (fac2 == BlendFactor.DstColor) 1134 return &BlendImpl!(BlendFactor.SrcAlpha, BlendFactor.DstColor, T); 1135 else 1136 if (fac2 == BlendFactor.OneMinusDstColor) 1137 return &BlendImpl!(BlendFactor.SrcAlpha, BlendFactor.OneMinusDstColor, T); 1138 else 1139 if (fac2 == BlendFactor.SrcAlpha) 1140 return &BlendImpl!(BlendFactor.SrcAlpha, BlendFactor.SrcAlpha, T); 1141 else 1142 if (fac2 == BlendFactor.OneMinusSrcAlpha) 1143 return &BlendImpl!(BlendFactor.SrcAlpha, BlendFactor.OneMinusSrcAlpha, T); 1144 else 1145 if (fac2 == BlendFactor.DstAlpha) 1146 return &BlendImpl!(BlendFactor.SrcAlpha, BlendFactor.DstAlpha, T); 1147 else 1148 if (fac2 == BlendFactor.OneMinusDstAlpha) 1149 return &BlendImpl!(BlendFactor.SrcAlpha, BlendFactor.OneMinusDstAlpha, T); 1150 }else 1151 if (fac1 == BlendFactor.OneMinusSrcAlpha) 1152 { 1153 if (fac2 == BlendFactor.Zero) 1154 return &BlendImpl!(BlendFactor.OneMinusSrcAlpha, BlendFactor.Zero, T); 1155 else 1156 if (fac2 == BlendFactor.One) 1157 return &BlendImpl!(BlendFactor.OneMinusSrcAlpha, BlendFactor.One, T); 1158 else 1159 if (fac2 == BlendFactor.SrcColor) 1160 return &BlendImpl!(BlendFactor.OneMinusSrcAlpha, BlendFactor.SrcColor, T); 1161 else 1162 if (fac2 == BlendFactor.OneMinusSrcColor) 1163 return &BlendImpl!(BlendFactor.OneMinusSrcAlpha, BlendFactor.OneMinusSrcColor, T); 1164 else 1165 if (fac2 == BlendFactor.DstColor) 1166 return &BlendImpl!(BlendFactor.OneMinusSrcAlpha, BlendFactor.DstColor, T); 1167 else 1168 if (fac2 == BlendFactor.OneMinusDstColor) 1169 return &BlendImpl!(BlendFactor.OneMinusSrcAlpha, BlendFactor.OneMinusDstColor, T); 1170 else 1171 if (fac2 == BlendFactor.SrcAlpha) 1172 return &BlendImpl!(BlendFactor.OneMinusSrcAlpha, BlendFactor.SrcAlpha, T); 1173 else 1174 if (fac2 == BlendFactor.OneMinusSrcAlpha) 1175 return &BlendImpl!(BlendFactor.OneMinusSrcAlpha, BlendFactor.OneMinusSrcAlpha, T); 1176 else 1177 if (fac2 == BlendFactor.DstAlpha) 1178 return &BlendImpl!(BlendFactor.OneMinusSrcAlpha, BlendFactor.DstAlpha, T); 1179 else 1180 if (fac2 == BlendFactor.OneMinusDstAlpha) 1181 return &BlendImpl!(BlendFactor.OneMinusSrcAlpha, BlendFactor.OneMinusDstAlpha, T); 1182 }else 1183 if (fac1 == BlendFactor.DstAlpha) 1184 { 1185 if (fac2 == BlendFactor.Zero) 1186 return &BlendImpl!(BlendFactor.DstAlpha, BlendFactor.Zero, T); 1187 else 1188 if (fac2 == BlendFactor.One) 1189 return &BlendImpl!(BlendFactor.DstAlpha, BlendFactor.One, T); 1190 else 1191 if (fac2 == BlendFactor.SrcColor) 1192 return &BlendImpl!(BlendFactor.DstAlpha, BlendFactor.SrcColor, T); 1193 else 1194 if (fac2 == BlendFactor.OneMinusSrcColor) 1195 return &BlendImpl!(BlendFactor.DstAlpha, BlendFactor.OneMinusSrcColor, T); 1196 else 1197 if (fac2 == BlendFactor.DstColor) 1198 return &BlendImpl!(BlendFactor.DstAlpha, BlendFactor.DstColor, T); 1199 else 1200 if (fac2 == BlendFactor.OneMinusDstColor) 1201 return &BlendImpl!(BlendFactor.DstAlpha, BlendFactor.OneMinusDstColor, T); 1202 else 1203 if (fac2 == BlendFactor.SrcAlpha) 1204 return &BlendImpl!(BlendFactor.DstAlpha, BlendFactor.SrcAlpha, T); 1205 else 1206 if (fac2 == BlendFactor.OneMinusSrcAlpha) 1207 return &BlendImpl!(BlendFactor.DstAlpha, BlendFactor.OneMinusSrcAlpha, T); 1208 else 1209 if (fac2 == BlendFactor.DstAlpha) 1210 return &BlendImpl!(BlendFactor.DstAlpha, BlendFactor.DstAlpha, T); 1211 else 1212 if (fac2 == BlendFactor.OneMinusDstAlpha) 1213 return &BlendImpl!(BlendFactor.DstAlpha, BlendFactor.OneMinusDstAlpha, T); 1214 }else 1215 if (fac1 == BlendFactor.OneMinusDstAlpha) 1216 { 1217 if (fac2 == BlendFactor.Zero) 1218 return &BlendImpl!(BlendFactor.OneMinusDstAlpha, BlendFactor.Zero, T); 1219 else 1220 if (fac2 == BlendFactor.One) 1221 return &BlendImpl!(BlendFactor.OneMinusDstAlpha, BlendFactor.One, T); 1222 else 1223 if (fac2 == BlendFactor.SrcColor) 1224 return &BlendImpl!(BlendFactor.OneMinusDstAlpha, BlendFactor.SrcColor, T); 1225 else 1226 if (fac2 == BlendFactor.OneMinusSrcColor) 1227 return &BlendImpl!(BlendFactor.OneMinusDstAlpha, BlendFactor.OneMinusSrcColor, T); 1228 else 1229 if (fac2 == BlendFactor.DstColor) 1230 return &BlendImpl!(BlendFactor.OneMinusDstAlpha, BlendFactor.DstColor, T); 1231 else 1232 if (fac2 == BlendFactor.OneMinusDstColor) 1233 return &BlendImpl!(BlendFactor.OneMinusDstAlpha, BlendFactor.OneMinusDstColor, T); 1234 else 1235 if (fac2 == BlendFactor.SrcAlpha) 1236 return &BlendImpl!(BlendFactor.OneMinusDstAlpha, BlendFactor.SrcAlpha, T); 1237 else 1238 if (fac2 == BlendFactor.OneMinusSrcAlpha) 1239 return &BlendImpl!(BlendFactor.OneMinusDstAlpha, BlendFactor.OneMinusSrcAlpha, T); 1240 else 1241 if (fac2 == BlendFactor.DstAlpha) 1242 return &BlendImpl!(BlendFactor.OneMinusDstAlpha, BlendFactor.DstAlpha, T); 1243 else 1244 if (fac2 == BlendFactor.OneMinusDstAlpha) 1245 return &BlendImpl!(BlendFactor.OneMinusDstAlpha, BlendFactor.OneMinusDstAlpha, T); 1246 } 1247 1248 assert(null, "Unknown blend factor's!"); 1249 } 1250 1251 /++ 1252 Converts the format of a sequence of color bytes. 1253 1254 Params: 1255 format1 = What is the original format. 1256 format2 = What format should be converted. 1257 pixels = Sequence of color bytes. 1258 1259 Returns: 1260 An array of bytes in the order specified in the pattern according to 1261 the pixel format. 1262 +/ 1263 ubyte[] fromFormat(int format1, int format2)(ubyte[] pixels) @safe nothrow pure 1264 in 1265 { 1266 assert(validateBytes!format1(pixels), "The input pixels data is incorrect!"); 1267 } 1268 out(r; validateBytes!format2(r), "The out pixels data is incorrect!") 1269 do 1270 { 1271 static assert(isValidFormat!format1, CannotDetectAuto); 1272 static assert(isValidFormat!format2, CannotDetectAuto); 1273 1274 static if (format1 == format2) 1275 return pixels; 1276 1277 static if (format1 == PixelFormat.RGB) 1278 { 1279 static if (format2 == PixelFormat.RGBA) 1280 { 1281 ubyte[] result; 1282 1283 for (size_t i = 0; i < pixels.length; i += 3) 1284 { 1285 result ~= pixels[i .. i + 3] ~ 255; 1286 } 1287 1288 return result; 1289 }else 1290 static if (format2 == PixelFormat.ARGB) 1291 { 1292 ubyte[] result; 1293 1294 for (size_t i = 0; i < pixels.length; i += 3) 1295 { 1296 result ~= 255 ~ pixels[i .. i + 3]; 1297 } 1298 1299 return result; 1300 }else 1301 static if (format2 == PixelFormat.BGRA) 1302 { 1303 import std.algorithm : reverse; 1304 1305 size_t count = 0; 1306 ubyte[] result; 1307 1308 for (size_t i = 3; i <= pixels.length; i += 3) 1309 { 1310 result ~= pixels[i - 3 .. i].reverse ~ 255; 1311 } 1312 1313 return result; 1314 } 1315 }else 1316 static if (format1 == PixelFormat.RGBA) 1317 { 1318 static if (format2 == PixelFormat.RGB) 1319 { 1320 ubyte[] result; 1321 1322 for (size_t i = 0; i < pixels.length; i += 4) 1323 { 1324 result ~= pixels[i .. i + 3]; 1325 } 1326 1327 return result; 1328 }else 1329 static if (format2 == PixelFormat.ARGB) 1330 { 1331 ubyte[] result; 1332 1333 for (size_t i = 0; i < pixels.length; i += 4) 1334 { 1335 result ~= pixels[i + 3] ~ pixels[i .. i + 3]; 1336 } 1337 1338 return result; 1339 }else 1340 static if (format2 == PixelFormat.BGRA) 1341 { 1342 import std.algorithm : reverse; 1343 1344 ubyte[] result; 1345 1346 for (size_t i = 0; i < pixels.length; i += 4) 1347 { 1348 result ~= pixels[i .. i + 3].reverse ~ pixels[i + 3]; 1349 } 1350 1351 return result; 1352 }else 1353 static if (format2 == PixelFormat.BGR) 1354 { 1355 import std.algorithm : reverse; 1356 1357 ubyte[] result; 1358 1359 for (size_t i = 0; i < pixels.length; i += 4) 1360 { 1361 result ~= pixels[i .. i + 3].reverse; 1362 } 1363 1364 return result; 1365 } 1366 }else 1367 static if (format1 == PixelFormat.ARGB) 1368 { 1369 static if (format2 == PixelFormat.RGB) 1370 { 1371 ubyte[] result; 1372 1373 for (size_t i = 0; i < pixels.length; i += 4) 1374 { 1375 result ~= pixels[i + 1 .. i + 4]; 1376 } 1377 1378 return result; 1379 }else 1380 static if (format2 == PixelFormat.RGBA) 1381 { 1382 ubyte[] result; 1383 1384 for(size_t i = 0; i < pixels.length; i += 4) 1385 { 1386 result ~= pixels[i + 3] ~ pixels[i .. i + 3]; 1387 } 1388 1389 return result; 1390 }else 1391 static if (format2 == PixelFormat.BGRA) 1392 { 1393 import std.algorithm : reverse; 1394 1395 ubyte[] result; 1396 1397 for (size_t i = 0; i < pixels.length; i += 4) 1398 { 1399 result = pixels[i + 3] ~ pixels[i .. i + 3].reverse; 1400 } 1401 1402 return result; 1403 }else 1404 static if (format2 == PixelFormat.BGR) 1405 { 1406 import std.algorithm : reverse; 1407 1408 ubyte[] result; 1409 1410 for (size_t i = 0; i < pixels.length; i += 4) 1411 { 1412 result ~= pixels[i + 1 .. i + 4].reverse; 1413 } 1414 1415 return result; 1416 } 1417 }else 1418 static if (format1 == PixelFormat.BGRA) 1419 { 1420 import std.algorithm : reverse; 1421 1422 static if (format2 == PixelFormat.RGB) 1423 { 1424 ubyte[] result; 1425 1426 for (size_t i = 0; i < pixels.length; i += 4) 1427 { 1428 result ~= pixels[i .. i + 3].reverse; 1429 } 1430 1431 return result; 1432 }else 1433 static if (format2 == PixelFormat.RGBA) 1434 { 1435 ubyte[] result; 1436 1437 for (size_t i = 0; i < pixels.length; i += 4) 1438 { 1439 result ~= pixels[i .. i + 3].reverse ~ pixels[i + 3]; 1440 } 1441 1442 return result; 1443 }else 1444 static if (format2 == PixelFormat.ARGB) 1445 { 1446 ubyte[] result; 1447 1448 for (size_t i = 0; i < pixels.length; i += 4) 1449 { 1450 result ~= pixels[i + 1 .. i + 4].reverse ~ pixels[i]; 1451 } 1452 1453 return result; 1454 } 1455 }else 1456 static if (format1 == PixelFormat.BGR) 1457 { 1458 import std.algorithm : reverse; 1459 1460 static if (format2 == PixelFormat.RGB) 1461 { 1462 ubyte[] result; 1463 1464 for (size_t i = 0; i < pixels.length; i += 3) 1465 { 1466 result ~= pixels[i .. i + 3].reverse; 1467 } 1468 1469 return result; 1470 }else 1471 static if (format2 == PixelFormat.RGBA) 1472 { 1473 ubyte[] result; 1474 1475 for (size_t i = 0; i < pixels.length; i += 3) 1476 { 1477 result ~= pixels[i .. i + 3].reverse ~ 255; 1478 } 1479 1480 return result; 1481 }else 1482 static if (format2 == PixelFormat.ARGB) 1483 { 1484 ubyte[] result; 1485 1486 for (size_t i = 0; i < pixels.length; i += 3) 1487 { 1488 result ~= 255 ~ pixels[i .. i + 3].reverse; 1489 } 1490 1491 return result; 1492 }else 1493 static if (format2 == PixelFormat.BGRA) 1494 { 1495 ubyte[] result; 1496 1497 for (size_t i = 0; i < pixels.length; i += 3) 1498 { 1499 result ~= pixels[i .. i + 3] ~ 255; 1500 } 1501 1502 return result; 1503 } 1504 } 1505 } 1506 1507 unittest 1508 { 1509 assert([255, 0, 0, 255].fromFormat!(PixelFormat.RGBA, PixelFormat.BGRA) == ([0, 0, 255, 255])); 1510 1511 assert([255, 0, 0, 255, 128, 0, 0, 255].fromFormat!(PixelFormat.RGBA, PixelFormat.BGR) == ([0, 0, 255, 0, 0, 128])); 1512 1513 assert([128, 32, 32].fromFormat!(PixelFormat.BGR, PixelFormat.RGBA) == ([32, 32, 128, 255])); 1514 1515 assert([128, 32, 32, 96].fromFormat!(PixelFormat.BGRA, PixelFormat.RGB) == ([32, 32, 128])); 1516 1517 assert([128, 32, 32].fromFormat!(PixelFormat.BGR, PixelFormat.RGB) == ([32, 32, 128])); 1518 1519 assert([128, 32, 32, 96].fromFormat!(PixelFormat.ARGB, PixelFormat.BGR) == ([96, 32, 32])); 1520 }