1 /**
2  * Copyright: Mike Wey 2011
3  * License:   zlib (See accompanying LICENSE file)
4  * Authors:   Mike Wey
5  */
6 
7 module dmagick.ColorYUV;
8 
9 import dmagick.Color;
10 
11 import dmagick.c.magickType;
12 import dmagick.c.quantum;
13 
14 /**
15  * The YUV color format describes a color by using the color components
16  * luminance and chrominance. The luminance component (Y) represents the
17  * brightness information of a color, the chrominance components (U and V)
18  * contain the color differences.
19  * 
20  * The YUV color format was developed for analog TV transmissions to provide
21  * compatibility between black-and-white television and color television:
22  * The luminance component is sufficient for black-and-white TV sets,
23  * whereas color TV sets need the additional chrominance information.
24  */
25 class ColorYUV : Color
26 {
27 	/** */
28 	this()
29 	{
30 		super();
31 	}
32 
33 	/**
34 	 * Create a YUV Color from the specified doubles.
35 	 * 
36 	 * Params:
37 	 *     y = The luminance as a value between 0.0 and 1.0
38 	 *     u = The U chrominance component as a value between -0.5 and 0.5
39 	 *     v = The V chrominance component as a value between -0.5 and 0.5
40 	 */
41 	this(double y, double u, double v, double opacity = 0)
42 	{
43 		Quantum red, green, blue;
44 
45 		convertYUVToRGB(y, u, v, red, green, blue);
46 
47 		super(red, green, blue, scaleDoubleToQuantum(opacity));
48 	}
49 
50 	/**
51 	 * Create a Color from a X11 color specification string
52 	 */
53 	this(string color)
54 	{
55 		super(color);
56 	}
57 
58 	/**
59 	 * The value for the luminance in the range [0.0 .. 1.0]
60 	 */
61 	void y(double y)
62 	{
63 		double oldY, u, v;
64 
65 		convertRGBToYUV(packet.red, packet.green, packet.blue, oldY, u, v);
66 		convertYUVToRGB(y, u, v, packet.red, packet.green, packet.blue);	
67 	}
68 	///ditto
69 	double y()
70 	{
71 		return 0.299 * scaleQuantumToDouble(packet.red) +
72 		       0.587 * scaleQuantumToDouble(packet.green) +
73 		       0.114 * scaleQuantumToDouble(packet.blue);
74 	}
75 
76 	/**
77 	 * The value for U chrominance component in the range [-0.5 .. 0.5]
78 	 */
79 	void u(double u)
80 	{
81 		double y, oldU, v;
82 
83 		convertRGBToYUV(packet.red, packet.green, packet.blue, y, oldU, v);
84 		convertYUVToRGB(y, u, v, packet.red, packet.green, packet.blue);
85 	}
86 	///ditto
87 	double u()
88 	{
89 		return -0.147 * scaleQuantumToDouble(packet.red) +
90 		       -0.289 * scaleQuantumToDouble(packet.green) +
91 		        0.436 * scaleQuantumToDouble(packet.blue);
92 	}
93 
94 	/**
95 	 * The value for V chrominance component in the range [-0.5 .. 0.5]
96 	 */
97 	void v(double v)
98 	{
99 		double y, u, oldV;
100 
101 		convertRGBToYUV(packet.red, packet.green, packet.blue, y, u, oldV);
102 		convertYUVToRGB(y, u, v, packet.red, packet.green, packet.blue);	
103 	}
104 	///ditto
105 	double v()
106 	{
107 		return  0.615 * scaleQuantumToDouble(packet.red) +
108 		       -0.515 * scaleQuantumToDouble(packet.green) +
109 		       -0.100 * scaleQuantumToDouble(packet.blue);
110 	}
111 
112 	/**
113 	 * Convert an RGB value to a YUV value.
114 	 */
115 	private void convertRGBToYUV(Quantum red, Quantum green, Quantum blue, ref double y, ref double u, ref double v)
116 	{
117 		// ⌈Y⌉ ⌈ 0.299  0.587  0.114⌉ ⌈R⌉
118 		// |U|=|-0.147 -0.289  0.436|·|G|
119 		// ⌊V⌋ ⌊ 0.615 -0.515 -0.100⌋ ⌊B⌋
120 
121 		double r = scaleQuantumToDouble(red);
122 		double g = scaleQuantumToDouble(green);
123 		double b = scaleQuantumToDouble(blue);
124 
125 		y =  0.299*r +  0.587*g +  0.114*b;
126 		u = -0.147*r + -0.289*g +  0.436*b;
127 		v =  0.615*r + -0.515*g + -0.100*b;
128 	}
129 
130 	/**
131 	 * Convert an YUV value to a RGB value.
132 	 */
133 	private void convertYUVToRGB(double y, double u, double v, ref Quantum red, ref Quantum green, ref Quantum blue)
134 	in
135 	{
136 		assert(y <=  1   && y >= 0  );
137 		assert(u <= -0.5 && u >= 0.5);
138 		assert(v <= -0.5 && v >= 0.5);
139 	}
140 	body
141 	{
142 		// ⌈R⌉ ⌈ 1.000  0.000  1.140⌉ ⌈Y⌉
143 		// |G|=| 1.000 -0.395 -0.581|·|U|
144 		// ⌊B⌋ ⌊ 1.000  2.032  0.000⌋ ⌊V⌋
145 
146 		double r = 1.000*y +  0.000*u +  1.140*v;
147 		double g = 1.000*y + -0.395*u + -0.581*v;
148 		double b = 1.000*y +  2.032*u +  0.000*v;
149 
150 		red   = scaleDoubleToQuantum(r);
151 		green = scaleDoubleToQuantum(g);
152 		blue  = scaleDoubleToQuantum(b);
153 	}
154 }