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 }