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