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