1 module magicalrainbows.raw;
2 
3 import std.conv;
4 
5 import magicalrainbows.formats;
6 import magicalrainbows.utils;
7 
8 enum SupportedFormat { bgr555, bgr565, rgb888, rgba8888, bgr222, bgr333md }
9 
10 /++
11 + Reads and converts a colour from a raw byte array to a specified colour format.
12 +
13 + Params: format = data format to read
14 +		data = raw data to read from
15 +		ColourFormat = colour format to convert to
16 + Returns: a colour in the specified format
17 +/
18 ColourFormat bytesToColor(ColourFormat = RGB888)(const ubyte[] data, SupportedFormat format) if (isColourFormat!ColourFormat) {
19 	static ColourFormat getColour(T)(const ubyte[] data) {
20 		assert(data.length == T.sizeof, "Data length does not match colour size");
21 		return data.to!(ubyte[T.sizeof]).read!T().convert!ColourFormat();
22 	}
23 	final switch (format) {
24 		case SupportedFormat.bgr222:
25 			return getColour!BGR222(data);
26 		case SupportedFormat.bgr333md:
27 			return getColour!BGR333MD(data);
28 		case SupportedFormat.bgr555:
29 			return getColour!BGR555(data);
30 		case SupportedFormat.bgr565:
31 			return getColour!BGR565(data);
32 		case SupportedFormat.rgb888:
33 			return getColour!RGB888(data);
34 		case SupportedFormat.rgba8888:
35 			return getColour!RGBA8888(data);
36 	}
37 }
38 ///
39 @safe pure unittest {
40 	assert(bytesToColor([0xA9, 0xFF], SupportedFormat.bgr555) == RGB888(72, 232, 248));
41 	assert(bytesToColor([0xA9, 0xFF], SupportedFormat.bgr565) == RGB888(72, 244, 248));
42 	assert(bytesToColor([72, 244, 248], SupportedFormat.rgb888) == RGB888(72, 244, 248));
43 }
44 ColourFormat[] bytesToColors(ColourFormat = RGB888)(const ubyte[] data, SupportedFormat format) if (isColourFormat!ColourFormat) {
45 	import std.algorithm.iteration : map;
46 	import std.array: array;
47 	import std.range : chunks;
48 	static ColourFormat[] getPalette(T)(const ubyte[] data) {
49 		return data.chunks(T.sizeof).map!(x => x.read!T.convert!ColourFormat).array;
50 
51 	}
52 	final switch (format) {
53 		case SupportedFormat.bgr222:
54 			return getPalette!BGR222(data);
55 		case SupportedFormat.bgr333md:
56 			return getPalette!BGR333MD(data);
57 		case SupportedFormat.bgr555:
58 			return getPalette!BGR555(data);
59 		case SupportedFormat.bgr565:
60 			return getPalette!BGR565(data);
61 		case SupportedFormat.rgb888:
62 			return getPalette!RGB888(data);
63 		case SupportedFormat.rgba8888:
64 			return getPalette!RGBA8888(data);
65 	}
66 }
67 ///
68 @safe pure unittest {
69 	assert(bytesToColors([0xA9, 0xFF], SupportedFormat.bgr555) == [RGB888(72, 232, 248)]);
70 	assert(bytesToColors([0xA9, 0xFF, 0x0, 0x0], SupportedFormat.bgr555) == [RGB888(72, 232, 248), RGB888(0, 0, 0)]);
71 	assert(bytesToColors([0xA9, 0xFF], SupportedFormat.bgr565) == [RGB888(72, 244, 248)]);
72 	assert(bytesToColors([72, 244, 248], SupportedFormat.rgb888) == [RGB888(72, 244, 248)]);
73 }
74 
75 ubyte[Format.sizeof] colourToBytes(Format)(Format data) if (isColourFormat!Format) {
76 	return data.asBytes();
77 }
78 ///
79 @safe pure unittest {
80 	assert(colourToBytes(BGR555(9, 29, 31)) == [0xA9, 0x7F]);
81 	assert(colourToBytes(BGR565(9, 58, 31)) == [0x49, 0xFF]);
82 	assert(colourToBytes(RGB888(72, 232, 248)) == [72, 232, 248]);
83 }
84 
85 ubyte[] colourToBytes(T)(T red, T green, T blue, SupportedFormat format) {
86 	ubyte[] output;
87 	final switch (format) {
88 		case SupportedFormat.bgr222:
89 			output = colourToBytes(BGR222(red, green, blue))[].dup;
90 			break;
91 		case SupportedFormat.bgr333md:
92 			output = colourToBytes(BGR333MD(red, green, blue))[].dup;
93 			break;
94 		case SupportedFormat.bgr555:
95 			output = colourToBytes(BGR555(red, green, blue))[].dup;
96 			break;
97 		case SupportedFormat.bgr565:
98 			output = colourToBytes(BGR565(red, green, blue))[].dup;
99 			break;
100 		case SupportedFormat.rgb888:
101 			output = colourToBytes(RGB888(red, green, blue))[].dup;
102 			break;
103 		case SupportedFormat.rgba8888:
104 			output = colourToBytes(RGBA8888(red, green, blue))[].dup;
105 			break;
106 	}
107 	return output;
108 }
109 ///
110 @safe unittest {
111 	assert(colourToBytes(9, 29, 31, SupportedFormat.bgr555) == [0xA9, 0x7F]);
112 	assert(colourToBytes(72, 232, 248, SupportedFormat.rgb888) == [72, 232, 248]);
113 }
114 
115 ubyte[] colourToBytes(T)(T data, SupportedFormat format) if (isColourFormat!T) {
116 	ubyte[] output;
117 	final switch (format) {
118 		case SupportedFormat.bgr222:
119 			output = colourToBytes(data.convert!BGR222)[].dup;
120 			break;
121 		case SupportedFormat.bgr333md:
122 			output = colourToBytes(data.convert!BGR333MD)[].dup;
123 			break;
124 		case SupportedFormat.bgr555:
125 			output = colourToBytes(data.convert!BGR555)[].dup;
126 			break;
127 		case SupportedFormat.bgr565:
128 			output = colourToBytes(data.convert!BGR565)[].dup;
129 			break;
130 		case SupportedFormat.rgb888:
131 			output = colourToBytes(data.convert!RGB888)[].dup;
132 			break;
133 		case SupportedFormat.rgba8888:
134 			output = colourToBytes(data.convert!RGBA8888)[].dup;
135 			break;
136 	}
137 	return output;
138 }
139 ///
140 @safe pure unittest {
141 	assert(colourToBytes(RGB888(72, 232, 248), SupportedFormat.bgr555) == [0xA9, 0x7F]);
142 	assert(colourToBytes(RGB888(72, 232, 248), SupportedFormat.bgr565) == [0x49, 0xFF]);
143 	assert(colourToBytes(RGB888(72, 232, 248), SupportedFormat.rgb888) == [72, 232, 248]);
144 }
145