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