1 module dimage.types;
2 
3 import std.bitmanip : bitfields;
4 //import std.conv : roundTo;
5 
6 ///Sets the byteorder of
7 enum Endianness {
8 	Little,
9 	Big
10 }
11 
12 alias ARGB8888 = ARGB8888Templ!(Endianness.Little);
13 alias ARGB8888BE = ARGB8888Templ!(Endianness.Big);
14 
15 /**
16  * 4 * 32 bit floating point pixel representation.
17  * Used for RGBA conversion and other things.
18  */
19 struct RGBA_f32 {
20 	float	fR;
21 	float	fG;
22 	float	fB;
23 	float	fA;
24 	///Standard CTOR
25 	this(float fR, float fG, float fB, float fA) @safe @nogc pure nothrow {
26 		this.fR = fR;
27 		this.fG = fG;
28 		this.fB = fB;
29 		this.fA = fA;
30 	}
31 	///Conversion CTOR
32 	this(ColorType)(ColorType orig) @safe @nogc pure nothrow {
33 		this.fR = orig.fR;
34 		this.fG = orig.fG;
35 		this.fB = orig.fB;
36 		this.fA = orig.fA;
37 	}
38 	///Conversion CTOR from monochrome
39 	this(float fY, float fA = 1.0) @safe @nogc pure nothrow {
40 		this.fR = fY;
41 		this.fG = fY;
42 		this.fB = fY;
43 		this.fA = fA;
44 	}
45 }
46 /**
47  * Standard 32 bit pixel representation.
48  */
49 struct ARGB8888Templ (Endianness byteOrder = Endianness.Little) {
50 	union{
51 		ubyte[4] bytes;     /// BGRA
52 		uint base;          /// Direct address
53 	}
54 	static if (byteOrder == Endianness.Big) {
55 		///Red
56 		@safe @nogc @property nothrow pure ref auto r() inout { return bytes[1]; }
57 		///Green
58 		@safe @nogc @property nothrow pure ref auto g() inout { return bytes[2]; }
59 		///Blue
60 		@safe @nogc @property nothrow pure ref auto b() inout { return bytes[3]; }
61 		///Alpha
62 		@safe @nogc @property nothrow pure ref auto a() inout { return bytes[0]; }
63 	} else {
64 		///Red
65 		@safe @nogc @property nothrow pure ref auto r() inout { return bytes[2]; }
66 		///Green
67 		@safe @nogc @property nothrow pure ref auto g() inout { return bytes[1]; }
68 		///Blue
69 		@safe @nogc @property nothrow pure ref auto b() inout { return bytes[0]; }
70 		///Alpha
71 		@safe @nogc @property nothrow pure ref auto a() inout { return bytes[3]; }
72 	}
73 	static immutable double fRStepping = 1.0 / 255;	///Floating-point red stepping
74 	static immutable double fGStepping = 1.0 / 255;	///Floating-point green stepping
75 	static immutable double fBStepping = 1.0 / 255;	///Floating-point blue stepping
76 	static immutable double fAStepping = 1.0 / 255;	///Floating-point alpha stepping
77 	///Returns the red channel as a normalized floating-point value
78 	@property float fR() @safe @nogc pure nothrow const {
79 		return r * fRStepping;
80 	}
81 	///Returns the green channel as a normalized floating-point value
82 	@property float fG() @safe @nogc pure nothrow const {
83 		return g * fGStepping;
84 	}
85 	///Returns the blue channel as a normalized floating-point value
86 	@property float fB() @safe @nogc pure nothrow const {
87 		return b * fBStepping;
88 	}
89 	///Returns the alpha channel as a normalized floating-point value
90 	@property float fA() @safe @nogc pure nothrow const {
91 		return a * fAStepping;
92 	}
93 	///Sets the red value channel a normalized floating-point value
94 	///Returns the new requantized value
95 	@property float fR(float val) @safe @nogc pure nothrow {
96 		//if(val >= 1) r = 255;
97 		//else 
98 		r = cast(ubyte)(val / fRStepping);
99 		return fR;
100 	}
101 	///Sets the green value channel a normalized floating-point value
102 	///Returns the new requantized value
103 	@property float fG(float val) @safe @nogc pure nothrow {
104 		g = cast(ubyte)(val / fGStepping);
105 		return fG;
106 	}
107 	///Sets the blue value channel a normalized floating-point value
108 	///Returns the new requantized value
109 	@property float fB(float val) @safe @nogc pure nothrow {
110 		b = cast(ubyte)(val / fBStepping);
111 		return fB;
112 	}
113 	///Sets the alpha value channel a normalized floating-point value
114 	///Returns the new requantized value
115 	@property float fA(float val) @safe @nogc pure nothrow {
116 		a = cast(ubyte)(val / fAStepping);
117 		return fA;
118 	}
119 	///Creates a standard pixel representation out from a 4 element array
120 	this(ubyte[4] bytes) @safe @nogc pure nothrow {
121 		this.bytes = bytes;
122 	}
123 	///Creates a standard pixel representation out from 4 separate values
124 	this(ubyte r, ubyte g, ubyte b, ubyte a) @safe @nogc pure nothrow {
125 		this.b = b;
126 		this.g = g;
127 		this.r = r;
128 		this.a = a;
129 	}
130 	///Standard CTOR
131 	this(float fR, float fG, float fB, float fA) @safe @nogc pure nothrow {
132 		this.fR = fR;
133 		this.fG = fG;
134 		this.fB = fB;
135 		this.fA = fA;
136 	}
137 	///Template for pixel conversion
138 	this(ColorType)(ColorType orig) @safe @nogc pure nothrow {
139 		this.fB = orig.fB;
140 		this.fG = orig.fG;
141 		this.fR = orig.fR;
142 		this.fA = orig.fA;
143 	}
144 	///Conversion CTOR from monochrome
145 	this(float fY, float fA = 1.0) @safe @nogc pure nothrow {
146 		this.fR = fY;
147 		this.fG = fY;
148 		this.fB = fY;
149 		this.fA = fA;
150 	}
151 	///Conversion from 8bit monochrome
152 	this(ubyte p) @safe @nogc pure nothrow {
153 		this.b = p;
154 		this.g = p;
155 		this.r = p;
156 		this.a = 0xFF;
157 	}
158 	///String representation of this struct
159 	string toString() const {
160 		import std.conv : to;
161 		return to!string(r) ~ "," ~ to!string(g) ~ "," ~ to!string(b) ~ "," ~ to!string(a);
162 	}
163 	///Returns true if type has alpha channel support
164 	static bool hasAlphaChannelSupport() {
165 		return true;
166 	}
167 
168 }
169 
170 alias RGBA8888BE = RGBA8888Templ!(Endianness.Big);
171 alias RGBA8888 = RGBA8888Templ!(Endianness.Little);
172 /**
173  * Standard 32 bit pixel representation.
174  */
175 struct RGBA8888Templ (Endianness byteOrder = Endianness.Little) {
176 	union{
177 		ubyte[4] bytes;     /// RGBA
178 		uint base;          /// Direct address
179 	}
180 	static if (byteOrder == Endianness.Big) {
181 		///Red
182 		@safe @nogc @property pure ref auto r() inout { return bytes[0]; }
183 		///Green
184 		@safe @nogc @property pure ref auto g() inout { return bytes[1]; }
185 		///Blue
186 		@safe @nogc @property pure ref auto b() inout { return bytes[2]; }
187 		///Alpha
188 		@safe @nogc @property pure ref auto a() inout { return bytes[3]; }
189 	} else {
190 		///Red
191 		@safe @nogc @property pure ref auto r() inout { return bytes[3]; }
192 		///Green
193 		@safe @nogc @property pure ref auto g() inout { return bytes[2]; }
194 		///Blue
195 		@safe @nogc @property pure ref auto b() inout { return bytes[1]; }
196 		///Alpha
197 		@safe @nogc @property pure ref auto a() inout { return bytes[0]; }
198 	}
199 	static immutable double fRStepping = 1.0 / 255;	///Floating-point red stepping
200 	static immutable double fGStepping = 1.0 / 255;	///Floating-point green stepping
201 	static immutable double fBStepping = 1.0 / 255;	///Floating-point blue stepping
202 	static immutable double fAStepping = 1.0 / 255;	///Floating-point alpha stepping
203 	///Returns the red channel as a normalized floating-point value
204 	@property float fR() @safe @nogc pure nothrow const {
205 		return r * fRStepping;
206 	}
207 	///Returns the green channel as a normalized floating-point value
208 	@property float fG() @safe @nogc pure nothrow const {
209 		return g * fGStepping;
210 	}
211 	///Returns the blue channel as a normalized floating-point value
212 	@property float fB() @safe @nogc pure nothrow const {
213 		return b * fBStepping;
214 	}
215 	///Returns the alpha channel as a normalized floating-point value
216 	@property float fA() @safe @nogc pure nothrow const {
217 		return a * fAStepping;
218 	}
219 	///Sets the red value channel a normalized floating-point value
220 	///Returns the new requantized value
221 	@property float fR(float val) @safe @nogc pure nothrow {
222 		r = cast(ubyte)(val / fRStepping);
223 		return fR;
224 	}
225 	///Sets the green value channel a normalized floating-point value
226 	///Returns the new requantized value
227 	@property float fG(float val) @safe @nogc pure nothrow {
228 		g = cast(ubyte)(val / fGStepping);
229 		return fG;
230 	}
231 	///Sets the blue value channel a normalized floating-point value
232 	///Returns the new requantized value
233 	@property float fB(float val) @safe @nogc pure nothrow {
234 		b = cast(ubyte)(val / fBStepping);
235 		return fB;
236 	}
237 	///Sets the alpha value channel a normalized floating-point value
238 	///Returns the new requantized value
239 	@property float fA(float val) @safe @nogc pure nothrow {
240 		a = cast(ubyte)(val / fAStepping);
241 		return fA;
242 	}
243 	///Creates a standard pixel representation out from a 4 element array
244 	this(ubyte[4] bytes) @safe @nogc pure nothrow {
245 		this.bytes = bytes;
246 	}
247 	///Creates a standard pixel representation out from 4 separate values
248 	this(ubyte r, ubyte g, ubyte b, ubyte a) @safe @nogc pure nothrow {
249 		bytes[0] = r;
250 		bytes[1] = g;
251 		bytes[2] = b;
252 		bytes[3] = a;
253 	}
254 	///Standard CTOR
255 	this(float fR, float fG, float fB, float fA) @safe @nogc pure nothrow {
256 		this.fR = fR;
257 		this.fG = fG;
258 		this.fB = fB;
259 		this.fA = fA;
260 	}
261 	///Conversion CTOR from monochrome
262 	this(float fY, float fA = 1.0) @safe @nogc pure nothrow {
263 		this.fR = fY;
264 		this.fG = fY;
265 		this.fB = fY;
266 		this.fA = fA;
267 	}
268 	///Template for pixel conversion
269 	this(ColorType)(ColorType orig) @safe @nogc pure nothrow {
270 		this.fB = orig.fB;
271 		this.fG = orig.fG;
272 		this.fR = orig.fR;
273 		this.fA = orig.fA;
274 	}
275 	///Conversion from 8bit monochrome
276 	this(ubyte p) @safe @nogc pure nothrow {
277 		this.b = p;
278 		this.g = p;
279 		this.r = p;
280 		this.a = 0xFF;
281 	}
282 	///Returns true if type has alpha channel support
283 	static bool hasAlphaChannelSupport() {
284 		return true;
285 	}
286 }
287 alias YA88 = YA88Templ!(Endianness.Little);
288 alias YA88BE = YA88Templ!(Endianness.Big);
289 /**
290  * For monochrome images with a single channel
291  */
292 struct YA88Templ (Endianness byteOrder = Endianness.Little) {
293 	union{
294 		ushort		base;		/// direct access
295 		ubyte[2]	channels;	/// individual access
296 	}
297 	static immutable double fRStepping = 1.0 / 255;	///Floating-point red stepping
298 	static immutable double fGStepping = 1.0 / 255;	///Floating-point green stepping
299 	static immutable double fBStepping = 1.0 / 255;	///Floating-point blue stepping
300 	static immutable double fAStepping = 1.0 / 255;	///Floating-point alpha stepping
301 	///Returns the red channel as a normalized floating-point value
302 	@property float fR() @safe @nogc pure nothrow const {
303 		return y * fRStepping;
304 	}
305 	///Returns the green channel as a normalized floating-point value
306 	@property float fG() @safe @nogc pure nothrow const {
307 		return y * fGStepping;
308 	}
309 	///Returns the blue channel as a normalized floating-point value
310 	@property float fB() @safe @nogc pure nothrow const {
311 		return y * fBStepping;
312 	}
313 	///Returns the alpha channel as a normalized floating-point value
314 	@property float fA() @safe @nogc pure nothrow const {
315 		return a * fAStepping;
316 	}
317 	///Sets the red value channel a normalized floating-point value
318 	///Returns the new requantized value
319 	@property float fR(float val) @safe @nogc pure nothrow {
320 		y = cast(ubyte)(val / fRStepping);
321 		return fR;
322 	}
323 	///Sets the green value channel a normalized floating-point value
324 	///Returns the new requantized value
325 	@property float fG(float val) @safe @nogc pure nothrow {
326 		y = cast(ubyte)(val / fGStepping);
327 		return fG;
328 	}
329 	///Sets the blue value channel a normalized floating-point value
330 	///Returns the new requantized value
331 	@property float fB(float val) @safe @nogc pure nothrow {
332 		y = cast(ubyte)(val / fBStepping);
333 		return fB;
334 	}
335 	///Sets the alpha value channel a normalized floating-point value
336 	///Returns the new requantized value
337 	@property float fA(float val) @safe @nogc pure nothrow {
338 		a = cast(ubyte)(val / fAStepping);
339 		return fA;
340 	}
341 	///Standard CTOR
342 	this(ubyte y, ubyte a) @safe @nogc pure nothrow {
343 		this.y = y;
344 		this.a = a;
345 	}
346 	///Standard CTOR
347 	this(float fR, float fG, float fB, float fA) @safe @nogc pure nothrow {
348 		this.fB = 0.2125 * fR + 0.7154 * fG + 0.0721 * fB;
349 		this.fA = fA;
350 	}
351 	///Template for pixel conversion
352 	///Uses mathematical average to calculate the new values
353 	this(ColorType)(ColorType orig) @safe @nogc pure nothrow {
354 		this.fB = 0.2125 * orig.fR + 0.7154 * orig.fG + 0.0721 * orig.fB;
355 		this.fA = orig.fA;
356 	}
357 	///Conversion CTOR from monochrome
358 	this(float fY, float fA = 1.0) @safe @nogc pure nothrow {
359 		this.fR = fY;
360 		this.fA = fA;
361 	}
362 	///Conversion from 8bit monochrome
363 	this(ubyte p) @safe @nogc pure nothrow {
364 		this.y = p;
365 		this.a = 0xFF;
366 	}
367 	/// luminance
368 	nothrow @safe @nogc @property pure ref auto y() inout { 
369 		static if(byteOrder == Endianness.Big) {
370 			return channels[1]; 
371 		} else {
372 			return channels[0]; 
373 		}
374 	}
375 	/// alpha
376 	nothrow @safe @nogc @property pure ref auto a() inout { 
377 		static if(byteOrder == Endianness.Big) {
378 			return channels[0]; 
379 		} else {
380 			return channels[1]; 
381 		}
382 	}
383 	/// pseudo-red (output only)
384 	nothrow @safe @nogc @property pure ubyte r() const { return y; }
385 	/// pseudo-green (output only)
386 	nothrow @safe @nogc @property pure ubyte g() const { return y; }
387 	/// pseudo-blue (output only)
388 	nothrow @safe @nogc @property pure ubyte b() const { return y; }
389 	///Returns true if type has alpha channel support
390 	static bool hasAlphaChannelSupport() {
391 		return true;
392 	}
393 }
394 alias YA16_16 = YA16_16Templ!(Endianness.Little);
395 alias YA16_16BE = YA16_16Templ!(Endianness.Big);
396 /**
397  * For monochrome images with a single channel
398  */
399 struct YA16_16Templ (Endianness byteOrder = Endianness.Little) {
400 	union{
401 		uint		base;		/// direct access
402 		ushort[2]	channels;	/// individual access
403 	}
404 	static immutable double fRStepping = 1.0 / 65_535;	///Floating-point red stepping
405 	static immutable double fGStepping = 1.0 / 65_535;	///Floating-point green stepping
406 	static immutable double fBStepping = 1.0 / 65_535;	///Floating-point blue stepping
407 	static immutable double fAStepping = 1.0 / 65_535;	///Floating-point alpha stepping
408 	///Returns the red channel as a normalized floating-point value
409 	@property float fR() @safe @nogc pure nothrow const {
410 		return y * fRStepping;
411 	}
412 	///Returns the green channel as a normalized floating-point value
413 	@property float fG() @safe @nogc pure nothrow const {
414 		return y * fGStepping;
415 	}
416 	///Returns the blue channel as a normalized floating-point value
417 	@property float fB() @safe @nogc pure nothrow const {
418 		return y * fBStepping;
419 	}
420 	///Returns the alpha channel as a normalized floating-point value
421 	@property float fA() @safe @nogc pure nothrow const {
422 		return a * fAStepping;
423 	}
424 	///Sets the red value channel a normalized floating-point value
425 	///Returns the new requantized value
426 	@property float fR(float val) @safe @nogc pure nothrow {
427 		y = cast(ubyte)(val / fRStepping);
428 		return fR;
429 	}
430 	///Sets the green value channel a normalized floating-point value
431 	///Returns the new requantized value
432 	@property float fG(float val) @safe @nogc pure nothrow {
433 		y = cast(ubyte)(val / fGStepping);
434 		return fG;
435 	}
436 	///Sets the blue value channel a normalized floating-point value
437 	///Returns the new requantized value
438 	@property float fB(float val) @safe @nogc pure nothrow {
439 		y = cast(ubyte)(val / fBStepping);
440 		return fB;
441 	}
442 	///Sets the alpha value channel a normalized floating-point value
443 	///Returns the new requantized value
444 	@property float fA(float val) @safe @nogc pure nothrow {
445 		a = cast(ubyte)(val / fAStepping);
446 		return fA;
447 	}
448 	///Standard CTOR
449 	this(ushort y, ushort a) @safe @nogc pure nothrow {
450 		this.y = y;
451 		this.a = a;
452 	}
453 	///Standard CTOR
454 	this(float fR, float fG, float fB, float fA) @safe @nogc pure nothrow {
455 		this.fB = 0.2125 * fR + 0.7154 * fG + 0.0721 * fB;
456 		this.fA = fA;
457 	}
458 	///Template for pixel conversion
459 	///Uses mathematical average to calculate the new values
460 	this(ColorType)(ColorType orig) @safe @nogc pure nothrow {
461 		this.fB = 0.2125 * orig.fR + 0.7154 * orig.fG + 0.0721 * orig.fB;
462 		this.fA = orig.fA;
463 	}
464 	///Conversion CTOR from monochrome
465 	this(float fY, float fA = 1.0) @safe @nogc pure nothrow {
466 		this.fR = fY;
467 		this.fA = fA;
468 	}
469 	///Conversion from 8bit monochrome
470 	this(ubyte p) @safe @nogc pure nothrow {
471 		this.y = p;
472 		this.a = 0xFF;
473 	}
474 	/// luminance
475 	nothrow @safe @nogc @property pure ref auto y() inout { 
476 		static if(byteOrder == Endianness.Big) {
477 			return channels[1]; 
478 		} else {
479 			return channels[0]; 
480 		}
481 	}
482 	/// alpha
483 	nothrow @safe @nogc @property pure ref auto a() inout { 
484 		static if(byteOrder == Endianness.Big) {
485 			return channels[0]; 
486 		} else {
487 			return channels[1]; 
488 		}
489 	}
490 	/// pseudo-red (output only)
491 	nothrow @safe @nogc @property pure ushort r() const { return y; }
492 	/// pseudo-green (output only)
493 	nothrow @safe @nogc @property pure ushort g() const { return y; }
494 	/// pseudo-blue (output only)
495 	nothrow @safe @nogc @property pure ushort b() const { return y; }
496 	///Returns true if type has alpha channel support
497 	static bool hasAlphaChannelSupport() {
498 		return true;
499 	}
500 }
501 /**
502  * 16 Bit colorspace with a single bit alpha. This is should be used with RGBX5551 with channel `a` ignored
503  */
504 struct RGBA5551 {
505 	union{
506 		ushort base;			/// direct access
507 		mixin(bitfields!(
508 			ubyte, "_b", 5,
509 			ubyte, "_g", 5,
510 			ubyte, "_r", 5,
511 			bool, "_a", 1,
512 		));
513 	}
514 	static immutable double fRStepping = 1.0 / 31;	///Floating-point red stepping
515 	static immutable double fGStepping = 1.0 / 31;	///Floating-point green stepping
516 	static immutable double fBStepping = 1.0 / 31;	///Floating-point blue stepping
517 	static immutable double fAStepping = 1.0;		///Floating-point alpha stepping
518 	///Returns the red channel as a normalized floating-point value
519 	@property float fR() @safe @nogc pure nothrow const {
520 		return _r * fRStepping;
521 	}
522 	///Returns the green channel as a normalized floating-point value
523 	@property float fG() @safe @nogc pure nothrow const {
524 		return _g * fGStepping;
525 	}
526 	///Returns the blue channel as a normalized floating-point value
527 	@property float fB() @safe @nogc pure nothrow const {
528 		return _b * fBStepping;
529 	}
530 	///Returns the alpha channel as a normalized floating-point value
531 	@property float fA() @safe @nogc pure nothrow const {
532 		return _a ? 1.0 : 0.0;
533 	}
534 	///Sets the red value channel a normalized floating-point value
535 	///Returns the new requantized value
536 	@property float fR(float val) @safe @nogc pure nothrow {
537 		_r = cast(ubyte)(val / fRStepping);
538 		return fR;
539 	}
540 	///Sets the green value channel a normalized floating-point value
541 	///Returns the new requantized value
542 	@property float fG(float val) @safe @nogc pure nothrow {
543 		_g = cast(ubyte)(val / fGStepping);
544 		return fG;
545 	}
546 	///Sets the blue value channel a normalized floating-point value
547 	///Returns the new requantized value
548 	@property float fB(float val) @safe @nogc pure nothrow {
549 		_b = cast(ubyte)(val / fBStepping);
550 		return fB;
551 	}
552 	///Sets the alpha value channel a normalized floating-point value
553 	///Returns the new requantized value
554 	@property float fA(float val) @safe @nogc pure nothrow {
555 		_a = val == 0.0;
556 		return fA;
557 	}
558 	/// Standard CTOR with 8bit normalized inputs
559 	this(ubyte r, ubyte g, ubyte b, ubyte a) @safe @nogc pure nothrow {
560 		_r = r>>3;
561 		_g = g>>3;
562 		_b = b>>3;
563 		_a = a != 0;
564 	}
565 	///Standard CTOR
566 	this(float fR, float fG, float fB, float fA) @safe @nogc pure nothrow {
567 		this.fR = fR;
568 		this.fG = fG;
569 		this.fB = fB;
570 		this.fA = fA;
571 	}
572 	///Conversion CTOR from monochrome
573 	this(float fY, float fA = 1.0) @safe @nogc pure nothrow {
574 		this.fR = fY;
575 		this.fG = fY;
576 		this.fB = fY;
577 		this.fA = fA;
578 	}
579 	///Template for pixel conversion
580 	this(ColorType)(ColorType orig) @safe @nogc pure {
581 		this.fB = orig.fB;
582 		this.fG = orig.fG;
583 		this.fR = orig.fR;
584 		this.fA = orig.fA;
585 	}
586 	///Conversion from 8bit monochrome
587 	this(ubyte p) @safe @nogc pure nothrow {
588 		_b = p>>3;
589 		_g = p>>3;
590 		_r = p>>3;
591 		_a = true;
592 	}
593 	/// upconverted-red (output only)
594 	nothrow @safe @nogc @property pure ubyte r() const { return cast(ubyte)(_r << 3 | _r >>> 2); }
595 	/// upconverted-green (output only)
596 	nothrow @safe @nogc @property pure ubyte g() const { return cast(ubyte)(_g << 3 | _g >>> 2); }
597 	/// upconverted-blue (output only)
598 	nothrow @safe @nogc @property pure ubyte b() const { return cast(ubyte)(_b << 3 | _b >>> 2); }
599 	/// upconverted-alpha
600 	nothrow @safe @nogc @property pure ubyte a() const { return _a ? 0xFF : 0x00; }
601 	///Returns true if type has alpha channel support
602 	static bool hasAlphaChannelSupport() {
603 		return true;
604 	}
605 }
606 /**
607  * 16 Bit RGB565 colorspace with no alpha.
608  */
609 struct RGB565 {
610 	union{
611 		ushort base;			/// direct access
612 		mixin(bitfields!(
613 			ubyte, "_b", 5,
614 			ubyte, "_g", 6,
615 			ubyte, "_r", 5,
616 		));
617 	}
618 	static immutable double fRStepping = 1.0 / 31;	///Floating-point red stepping
619 	static immutable double fGStepping = 1.0 / 63;	///Floating-point green stepping
620 	static immutable double fBStepping = 1.0 / 31;	///Floating-point blue stepping
621 	static immutable double fAStepping = 1.0;		///Floating-point alpha stepping
622 	///Returns the red channel as a normalized floating-point value
623 	@property float fR() @safe @nogc pure nothrow const {
624 		return _r * fRStepping;
625 	}
626 	///Returns the green channel as a normalized floating-point value
627 	@property float fG() @safe @nogc pure nothrow const {
628 		return _g * fGStepping;
629 	}
630 	///Returns the blue channel as a normalized floating-point value
631 	@property float fB() @safe @nogc pure nothrow const {
632 		return _b * fBStepping;
633 	}
634 	///Returns the alpha channel as a normalized floating-point value
635 	@property float fA() @safe @nogc pure nothrow const {
636 		return 1.0;
637 	}
638 	///Sets the red value channel a normalized floating-point value
639 	///Returns the new requantized value
640 	@property float fR(float val) @safe @nogc pure nothrow {
641 		_r = cast(ubyte)(val / fRStepping);
642 		return fR;
643 	}
644 	///Sets the green value channel a normalized floating-point value
645 	///Returns the new requantized value
646 	@property float fG(float val) @safe @nogc pure nothrow {
647 		_g = cast(ubyte)(val / fGStepping);
648 		return fG;
649 	}
650 	///Sets the blue value channel a normalized floating-point value
651 	///Returns the new requantized value
652 	@property float fB(float val) @safe @nogc pure nothrow {
653 		_b = cast(ubyte)(val / fBStepping);
654 		return fB;
655 	}
656 	///Sets the alpha value channel a normalized floating-point value
657 	///Returns the new requantized value
658 	@property float fA(float val) @safe @nogc pure nothrow {
659 		return 1.0;
660 	}
661 	/// Standard CTOR with 8bit normalized inputs
662 	this(ubyte r, ubyte g, ubyte b) @safe @nogc pure nothrow {
663 		_r = r>>3;
664 		_g = g>>2;
665 		_b = b>>3;
666 	}
667 	///Standard CTOR
668 	this(float fR, float fG, float fB, float fA) @safe @nogc pure nothrow {
669 		this.fR = fR;
670 		this.fG = fG;
671 		this.fB = fB;
672 		this.fA = fA;
673 	}
674 	///Template for pixel conversion
675 	this(ColorType)(ColorType orig) @safe @nogc pure nothrow {
676 		this.fB = orig.fB;
677 		this.fG = orig.fG;
678 		this.fR = orig.fR;
679 		this.fA = orig.fA;
680 	}
681 	///Conversion CTOR from monochrome
682 	this(float fY, float fA = 1.0) @safe @nogc pure nothrow {
683 		this.fR = fY;
684 		this.fG = fY;
685 		this.fB = fY;
686 		this.fA = fA;
687 	}
688 	///Conversion from 8bit monochrome
689 	this(ubyte p) @safe @nogc pure nothrow {
690 		_b = p>>3;
691 		_g = p>>2;
692 		_r = p>>3;
693 	}
694 	/// upconverted-red (output only)
695 	nothrow @safe @nogc @property pure ubyte r() const { return cast(ubyte)(_r << 3 | _r >>> 2); }
696 	/// upconverted-green (output only)
697 	nothrow @safe @nogc @property pure ubyte g() const { return cast(ubyte)(_g << 2 | _g >>> 4); }
698 	/// upconverted-blue (output only)
699 	nothrow @safe @nogc @property pure ubyte b() const { return cast(ubyte)(_b << 3 | _b >>> 2); }
700 	//pseudo-alpha (output only)
701 	nothrow @safe @nogc @property pure ubyte a() const { return 0xFF; }
702 	///Returns true if type has alpha channel support
703 	static bool hasAlphaChannelSupport() {
704 		return false;
705 	}
706 }
707 alias RGB888 = RGB888Templ!(Endianness.Little);
708 alias RGB888BE = RGB888Templ!(Endianness.Big);
709 /**
710  * 24 Bit colorspace
711  */
712 align(1) struct RGB888Templ (Endianness byteOrder = Endianness.Little) {
713 	ubyte[3] bytes;				///individual access
714 	static if (byteOrder == Endianness.Big) {
715 		///red
716 		nothrow @safe @nogc @property pure ref auto r() inout { return bytes[0]; }
717 		///green
718 		nothrow @safe @nogc @property pure ref auto g() inout { return bytes[1]; }
719 		///blue
720 		nothrow @safe @nogc @property pure ref auto b() inout { return bytes[2]; }
721 	} else {
722 		///red
723 		nothrow @safe @nogc @property pure ref auto r() inout { return bytes[2]; }
724 		///green
725 		nothrow @safe @nogc @property pure ref auto g() inout { return bytes[1]; }
726 		///blue
727 		nothrow @safe @nogc @property pure ref auto b() inout { return bytes[0]; }
728 	}
729 	static immutable double fRStepping = 1.0 / 255;	///Floating-point red stepping
730 	static immutable double fGStepping = 1.0 / 255;	///Floating-point green stepping
731 	static immutable double fBStepping = 1.0 / 255;	///Floating-point blue stepping
732 	static immutable double fAStepping = 1.0;	///Floating-point alpha stepping
733 	///Returns the red channel as a normalized floating-point value
734 	@property float fR() @safe @nogc pure nothrow const {
735 		return r * fRStepping;
736 	}
737 	///Returns the green channel as a normalized floating-point value
738 	@property float fG() @safe @nogc pure nothrow const {
739 		return g * fGStepping;
740 	}
741 	///Returns the blue channel as a normalized floating-point value
742 	@property float fB() @safe @nogc pure nothrow const {
743 		return b * fBStepping;
744 	}
745 	///Returns the alpha channel as a normalized floating-point value
746 	@property float fA() @safe @nogc pure nothrow const {
747 		return 1.0;
748 	}
749 	///Sets the red value channel a normalized floating-point value
750 	///Returns the new requantized value
751 	@property float fR(float val) @safe @nogc pure nothrow {
752 		r = cast(ubyte)(val / fRStepping);
753 		return fR;
754 	}
755 	///Sets the green value channel a normalized floating-point value
756 	///Returns the new requantized value
757 	@property float fG(float val) @safe @nogc pure nothrow {
758 		g = cast(ubyte)(val / fGStepping);
759 		return fG;
760 	}
761 	///Sets the blue value channel a normalized floating-point value
762 	///Returns the new requantized value
763 	@property float fB(float val) @safe @nogc pure nothrow {
764 		b = cast(ubyte)(val / fBStepping);
765 		return fB;
766 	}
767 	///Sets the alpha value channel a normalized floating-point value
768 	///Returns the new requantized value
769 	@property float fA(float val) @safe @nogc pure nothrow {
770 		return 1.0;
771 	}
772 	///Standard CTOR
773 	this(ubyte r, ubyte g, ubyte b) pure nothrow @safe @nogc {
774 		this.r = r;
775 		this.g = g;
776 		this.b = b;
777 	}
778 	///Standard CTOR
779 	this(float fR, float fG, float fB, float fA) {
780 		this.fR = fR;
781 		this.fG = fG;
782 		this.fB = fB;
783 		this.fA = fA;
784 	}
785 	///Conversion CTOR from monochrome
786 	this(float fY, float fA = 1.0) {
787 		this.fR = fY;
788 		this.fG = fY;
789 		this.fB = fY;
790 		this.fA = fA;
791 	}
792 	///Template for pixel conversion
793 	this(ColorType)(ColorType orig) @safe @nogc pure {
794 		this.fB = orig.fB;
795 		this.fG = orig.fG;
796 		this.fR = orig.fR;
797 		this.fA = orig.fA;
798 	}
799 	///Conversion from 8bit monochrome
800 	this(ubyte p) @safe @nogc pure {
801 		this.b = p;
802 		this.g = p;
803 		this.r = p;
804 	}
805 	//pseudo-alpha (output only)
806 	nothrow @safe @nogc @property pure ubyte a() const { return 0xFF; }
807 	///direct access read
808 	nothrow @safe @nogc @property pure uint base(){ return 0xff_00_00_00 | r << 16 | g << 8 | b; }
809 	///Returns true if type has alpha channel support
810 	static bool hasAlphaChannelSupport() {
811 		return false;
812 	}
813 }
814 alias RGB16_16_16 = RGB16_16_16Templ!(Endianness.Little);
815 alias RGB16_16_16BE = RGB16_16_16Templ!(Endianness.Big);
816 /**
817  * 48 bit RGB colorspace with 16 bit per channel.
818  */
819 align(2) public struct RGB16_16_16Templ (Endianness byteOrder = Endianness.Little) {
820 	ushort[3] bytes;				///individual access
821 	static if (byteOrder == Endianness.Big) {
822 		///red
823 		nothrow @safe @nogc @property pure ref auto r() inout { return bytes[0]; }
824 		///green
825 		nothrow @safe @nogc @property pure ref auto g() inout { return bytes[1]; }
826 		///blue
827 		nothrow @safe @nogc @property pure ref auto b() inout { return bytes[2]; }
828 	} else {
829 		///red
830 		nothrow @safe @nogc @property pure ref auto r() inout { return bytes[2]; }
831 		///green
832 		nothrow @safe @nogc @property pure ref auto g() inout { return bytes[1]; }
833 		///blue
834 		nothrow @safe @nogc @property pure ref auto b() inout { return bytes[0]; }
835 	}
836 	static immutable double fRStepping = 1.0 / 65_535;///Floating-point red stepping
837 	static immutable double fGStepping = 1.0 / 65_535;///Floating-point green stepping
838 	static immutable double fBStepping = 1.0 / 65_535;///Floating-point blue stepping
839 	static immutable double fAStepping = 1.0;		///Floating-point alpha stepping
840 	///Returns the red channel as a normalized floating-point value
841 	@property float fR() @safe @nogc pure nothrow const {
842 		return r * fRStepping;
843 	}
844 	///Returns the green channel as a normalized floating-point value
845 	@property float fG() @safe @nogc pure nothrow const {
846 		return g * fGStepping;
847 	}
848 	///Returns the blue channel as a normalized floating-point value
849 	@property float fB() @safe @nogc pure nothrow const {
850 		return b * fBStepping;
851 	}
852 	///Returns the alpha channel as a normalized floating-point value
853 	@property float fA() @safe @nogc pure nothrow const {
854 		return 1.0;
855 	}
856 	///Sets the red value channel a normalized floating-point value
857 	///Returns the new requantized value
858 	@property float fR(float val) @safe @nogc pure nothrow {
859 		r = cast(ushort)(val / fRStepping);
860 		return fR;
861 	}
862 	///Sets the green value channel a normalized floating-point value
863 	///Returns the new requantized value
864 	@property float fG(float val) @safe @nogc pure nothrow {
865 		g = cast(ushort)(val / fGStepping);
866 		return fG;
867 	}
868 	///Sets the blue value channel a normalized floating-point value
869 	///Returns the new requantized value
870 	@property float fB(float val) @safe @nogc pure nothrow {
871 		b = cast(ushort)(val / fBStepping);
872 		return fB;
873 	}
874 	///Sets the alpha value channel a normalized floating-point value
875 	///Returns the new requantized value
876 	@property float fA(float val) @safe @nogc pure nothrow {
877 		return 1.0;
878 	}
879 	///Standard CTOR
880 	this(ushort r, ushort g, ushort b) pure nothrow @safe @nogc {
881 		this.r = r;
882 		this.g = g;
883 		this.b = b;
884 	}
885 	///Standard CTOR
886 	this(float fR, float fG, float fB, float fA) {
887 		this.fR = fR;
888 		this.fG = fG;
889 		this.fB = fB;
890 		this.fA = fA;
891 	}
892 	///Conversion CTOR from monochrome
893 	this(float fY, float fA = 1.0) {
894 		this.fR = fY;
895 		this.fG = fY;
896 		this.fB = fY;
897 		this.fA = fA;
898 	}
899 	///Template for pixel conversion
900 	this(ColorType)(ColorType orig) @safe @nogc pure {
901 		this.fB = orig.fB;
902 		this.fG = orig.fG;
903 		this.fR = orig.fR;
904 		this.fA = orig.fA;
905 	}
906 	///Returns true if type has alpha channel support
907 	static bool hasAlphaChannelSupport() {
908 		return false;
909 	}
910 }
911 alias RGBA16_16_16_16 = RGBA16_16_16_16Templ!(Endianness.Little);
912 alias RGBA16_16_16_16BE = RGBA16_16_16_16Templ!(Endianness.Big);
913 /**
914  * 48 bit RGB colorspace with 16 bit per channel.
915  */
916 align(2) public struct RGBA16_16_16_16Templ (Endianness byteOrder = Endianness.Little) {
917 	ushort[4] bytes;				///individual access
918 	static if (byteOrder == Endianness.Big) {
919 		///red
920 		nothrow @safe @nogc @property pure ref auto r() inout { return bytes[0]; }
921 		///green
922 		nothrow @safe @nogc @property pure ref auto g() inout { return bytes[1]; }
923 		///blue
924 		nothrow @safe @nogc @property pure ref auto b() inout { return bytes[2]; }
925 		///alpha
926 		nothrow @safe @nogc @property pure ref auto a() inout { return bytes[3]; }
927 	} else {
928 		///red
929 		nothrow @safe @nogc @property pure ref auto r() inout { return bytes[3]; }
930 		///green
931 		nothrow @safe @nogc @property pure ref auto g() inout { return bytes[2]; }
932 		///blue
933 		nothrow @safe @nogc @property pure ref auto b() inout { return bytes[1]; }
934 		///alpha
935 		nothrow @safe @nogc @property pure ref auto a() inout { return bytes[0]; }
936 	}
937 	static immutable double fRStepping = 1.0 / 65_535;///Floating-point red stepping
938 	static immutable double fGStepping = 1.0 / 65_535;///Floating-point green stepping
939 	static immutable double fBStepping = 1.0 / 65_535;///Floating-point blue stepping
940 	static immutable double fAStepping = 1.0 / 65_535;///Floating-point alpha stepping
941 	///Returns the red channel as a normalized floating-point value
942 	@property float fR() @safe @nogc pure nothrow const {
943 		return r * fRStepping;
944 	}
945 	///Returns the green channel as a normalized floating-point value
946 	@property float fG() @safe @nogc pure nothrow const {
947 		return g * fGStepping;
948 	}
949 	///Returns the blue channel as a normalized floating-point value
950 	@property float fB() @safe @nogc pure nothrow const {
951 		return b * fBStepping;
952 	}
953 	///Returns the alpha channel as a normalized floating-point value
954 	@property float fA() @safe @nogc pure nothrow const {
955 		return a * fAStepping;
956 	}
957 	///Sets the red value channel a normalized floating-point value
958 	///Returns the new requantized value
959 	@property float fR(float val) @safe @nogc pure nothrow {
960 		r = cast(ushort)(val / fRStepping);
961 		return fR;
962 	}
963 	///Sets the green value channel a normalized floating-point value
964 	///Returns the new requantized value
965 	@property float fG(float val) @safe @nogc pure nothrow {
966 		g = cast(ushort)(val / fGStepping);
967 		return fG;
968 	}
969 	///Sets the blue value channel a normalized floating-point value
970 	///Returns the new requantized value
971 	@property float fB(float val) @safe @nogc pure nothrow {
972 		b = cast(ushort)(val / fBStepping);
973 		return fB;
974 	}
975 	///Sets the alpha value channel a normalized floating-point value
976 	///Returns the new requantized value
977 	@property float fA(float val) @safe @nogc pure nothrow {
978 		a = cast(ushort)(val / fAStepping);
979 		return fB;
980 	}
981 	///Standard CTOR
982 	this(ushort r, ushort g, ushort b, ushort a) pure nothrow @safe @nogc {
983 		this.r = r;
984 		this.g = g;
985 		this.b = b;
986 		this.a = a;
987 	}
988 	///Standard CTOR
989 	this(float fR, float fG, float fB, float fA) {
990 		this.fR = fR;
991 		this.fG = fG;
992 		this.fB = fB;
993 		this.fA = fA;
994 	}
995 	///Conversion CTOR from monochrome
996 	this(float fY, float fA = 1.0) {
997 		this.fR = fY;
998 		this.fG = fY;
999 		this.fB = fY;
1000 		this.fA = fA;
1001 	}
1002 	///Template for pixel conversion
1003 	this(ColorType)(ColorType orig) @safe @nogc pure {
1004 		this.fB = orig.fB;
1005 		this.fG = orig.fG;
1006 		this.fR = orig.fR;
1007 		this.fA = orig.fA;
1008 	}
1009 	///Returns true if type has alpha channel support
1010 	static bool hasAlphaChannelSupport() {
1011 		return false;
1012 	}
1013 }
1014 /**
1015  * Pixel format flags.
1016  * Undefined should be used for all indexed bitmaps, except 16 bit big endian ones, in which case a single BigEndian bit should be set high.
1017  * Lower 16 bits should be used for general identification, upper 16 bits are general identificators (endianness, valid alpha channel, etc).
1018  * 0x01 - 0x1F are reserved for 16 bit truecolor, 0x20 - 0x2F are reserved for 24 bit truecolor, 0x30 - 3F are reserved for integer grayscale,
1019  * 0x40 - 0x5F are reserved for 32 bit truecolor, 0xF00-0xF0F are reserved for "chunky" indexed images, 0xF10-0xF1F are reserved for planar 
1020  * indexed images.
1021  */
1022 enum PixelFormat : uint {
1023 	BigEndian		=	0x00_01_00_00,		///Always little endian if bit not set
1024 	ValidAlpha		=	0x00_02_00_00,		///If set, alpha is used
1025 	SeparateAlphaField	=	0x00_04_00_00,	///If set, then there's a separate alpha field
1026 	RGBX5551		=	0x1,
1027 	RGBA5551		=	RGBX5551 | ValidAlpha,
1028 	RGB565			=	0x2,
1029 	RGB888			=	0x20,
1030 	Grayscale1Bit	=	0x30,
1031 	Grayscale2Bit	=	0x31,
1032 	Grayscale4Bit	=	0x32,
1033 	Grayscale8Bit	=	0x33,
1034 	Grayscale16Bit	=	0x34,
1035 	YX88			=	0x3A,
1036 	YA88			=	YX88 | ValidAlpha,
1037 	YX16_16			=	0x3B,
1038 	YA16_16			=	YX16_16 | ValidAlpha,
1039 	RGBX8888		=	0x40,
1040 	RGBA8888		=	RGBX8888 | ValidAlpha,
1041 	XRGB8888		=	0x41,
1042 	ARGB8888		=	XRGB8888 | ValidAlpha,
1043 	RGB16_16_16		=	0x60,
1044 	RGBX16_16_16_16	=	0x61,
1045 	RGBA16_16_16_16	=	RGBX16_16_16_16 | ValidAlpha,
1046 	RGBX_f32		=	0x101,
1047 	RGBA_f32		=	RGBX_f32 | ValidAlpha,
1048 	Indexed1Bit		=	0xF00,
1049 	Indexed2Bit		=	0xF01,
1050 	Indexed4Bit		=	0xF02,
1051 	Indexed8Bit		=	0xF03,
1052 	Indexed16Bit	=	0xF04,
1053 	Planar2Color	=	0xF10,
1054 	Planar4Color	=	0xF11,
1055 	Planar8Color	=	0xF12,
1056 	Planar16Color	=	0xF13,
1057 	Planar32Color	=	0xF14,
1058 	Planar64Color	=	0xF15,
1059 	Planar128Color	=	0xF16,
1060 	Planar256Color	=	0xF17,
1061 	Planar512Color	=	0xF18,
1062 	Planar1024Color	=	0xF19,
1063 	Planar2048Color	=	0xF1A,
1064 	Planar4096Color	=	0xF1B,
1065 	Planar8192Color	=	0xF1C,
1066 	Planar16384Color=	0xF1D,
1067 	Planar32768Color=	0xF1E,
1068 	Planar65536Color=	0xF1F,
1069 	
1070 	Undefined		=	0,
1071 }
1072 /**
1073  * Returns the bitdepth of a format.
1074  */
1075 public ubyte getBitDepth(uint format) @nogc @safe pure nothrow {
1076 	format &= 0xFF_FF;
1077 	switch (format) {
1078 		case 0x00_01: .. case 0x00_1F: case 0x0F_04, 0x00_3A:
1079 			return 16;
1080 		case 0x00_20: .. case 0x00_2F:
1081 			return 24;
1082 		case 0x00_40: .. case 0x00_5F:
1083 			return 32;
1084 		case 0x00_60:
1085 			return 48;
1086 		case 0x0F_00: 
1087 			return 1;
1088 		case 0x0F_01:
1089 			return 2;
1090 		case 0x0F_02, 0x00_31:
1091 			return 4;
1092 		case 0x0F_03, 0x00_30:
1093 			return 8;
1094 		case 0x0F_10: .. case 0x0F_1F:
1095 			return cast(ubyte)(format & 0x0F);
1096 		default: 
1097 			return 0;
1098 	}
1099 }
1100 
1101 @safe unittest {
1102 	import std.conv : to;
1103 	assert(ARGB8888.sizeof == 4);
1104 	ARGB8888 test0 = ARGB8888(1.0,1.0,1.0,1.0);
1105 	assert(test0.base == 0xFF_FF_FF_FF, to!string(test0.base));
1106 	test0.fR = test0.fR - ARGB8888.fRStepping;
1107 	assert(test0.r == 0xFE, to!string(test0.r));
1108 	test0.r = 0xFF;
1109 	assert(test0.fR == 1.0, to!string(test0.fR));
1110 	RGB16_16_16 test1 = RGB16_16_16(test0);
1111 	assert(test1.r == 0xFF_FF, to!string(test1.r));
1112 	assert(test1.g == 0xFF_FF, to!string(test1.g));
1113 	assert(test1.b == 0xFF_FF, to!string(test1.b));
1114 }