1 /**
2  * Copyright: Mike Wey 2011
3  * License:   zlib (See accompanying LICENSE file)
4  * Authors:   Mike Wey
5  */
6 
7 module dmagick.ColorCMYK;
8 
9 import std.algorithm;
10 
11 import dmagick.Color;
12 
13 import dmagick.c.magickType;
14 import dmagick.c.quantum;
15 
16 /**
17  * The CMY(K) color model describes a color space with subtractive color
18  * composition as it is used for the color printing process, e.g. used by
19  * ink or laser printers. Each color is described by the color components
20  * cyan (C), magenta (M) and yellow (Y). The additional component black (K)
21  * is used for better gray and black reproduction.
22  * 
23  * Note: This class doesn't use ICC or ICM profiles for the converson of
24  *       CMYK to RGB.
25  */
26 class ColorCMYK : Color
27 {
28 	/** */
29 	this()
30 	{
31 		super();
32 	}
33 
34 	/**
35 	 * Create a CMYK Color from the specified doubles.
36 	 */
37 	this(double cyan, double magenta, double yellow, double black)
38 	{
39 		Quantum red, green, blue;
40 
41 		convertCMYKToRGB(cyan, magenta, yellow, black, red, green, blue);
42 
43 		super(red, green, blue);
44 	}
45 
46 	/**
47 	 * The value for cyan.
48 	 */
49 	void cyan(double cyan)
50 	{
51 		double oldCyan, magenta, yellow, black;
52 
53 		convertRGBToCMYK(packet.red, packet.green, packet.blue, oldCyan, magenta, yellow, black);
54 		convertCMYKToRGB(cyan, magenta, yellow, black, packet.red, packet.green, packet.blue);	
55 	}
56 	///ditto
57 	double cyan()
58 	{
59 		double cyan, magenta, yellow, black;
60 
61 		convertRGBToCMYK(packet.red, packet.green, packet.blue, cyan, magenta, yellow, black);
62 
63 		return cyan;
64 	}
65 
66 	/**
67 	 * The value for magenta.
68 	 */
69 	void magenta(double magenta)
70 	{
71 		double cyan, oldMagenta, yellow, black;
72 
73 		convertRGBToCMYK(packet.red, packet.green, packet.blue, cyan, oldMagenta, yellow, black);
74 		convertCMYKToRGB(cyan, magenta, yellow, black, packet.red, packet.green, packet.blue);	
75 	}
76 	///ditto
77 	double magenta()
78 	{
79 		double cyan, magenta, yellow, black;
80 
81 		convertRGBToCMYK(packet.red, packet.green, packet.blue, cyan, magenta, yellow, black);
82 
83 		return magenta;
84 	}
85 
86 	/**
87 	 * The value for yellow.
88 	 */
89 	void yellow(double yellow)
90 	{
91 		double cyan, magenta, oldYellow, black;
92 
93 		convertRGBToCMYK(packet.red, packet.green, packet.blue, cyan, magenta, oldYellow, black);
94 		convertCMYKToRGB(cyan, magenta, yellow, black, packet.red, packet.green, packet.blue);	
95 	}
96 	///ditto
97 	double yellow()
98 	{
99 		double cyan, magenta, yellow, black;
100 
101 		convertRGBToCMYK(packet.red, packet.green, packet.blue, cyan, magenta, yellow, black);
102 
103 		return yellow;
104 	}
105 
106 	/**
107 	 * The value for black.
108 	 */
109 	void black(double black)
110 	{
111 		double cyan, magenta, yellow, oldBlack;
112 
113 		convertRGBToCMYK(packet.red, packet.green, packet.blue, cyan, magenta, yellow, oldBlack);
114 		convertCMYKToRGB(cyan, magenta, yellow, black, packet.red, packet.green, packet.blue);	
115 	}
116 	///ditto
117 	double black()
118 	{
119 		double cyan, magenta, yellow, black;
120 
121 		convertRGBToCMYK(packet.red, packet.green, packet.blue, cyan, magenta, yellow, black);
122 
123 		return black;
124 	}
125 
126 	/**
127 	 * Convert an RGB value to a CMYK value.
128 	 */
129 	private void convertRGBToCMYK(Quantum red, Quantum green, Quantum blue, ref double cyan, ref double magenta, ref double yellow, ref double black)
130 	{
131 		double r = scaleQuantumToDouble(red);
132 		double g = scaleQuantumToDouble(green);
133 		double b = scaleQuantumToDouble(blue);
134 
135 		black = min(1 - r, 1 - g, 1 - b);
136 
137 		cyan    = (1 - r - black) / (1 - black);
138 		magenta = (1 - g - black) / (1 - black);
139 		yellow  = (1 - b - black) / (1 - black);
140 	}
141 
142 	/**
143 	 * Convert an CMYK value to a RGB value.
144 	 */
145 	private void convertCMYKToRGB(double cyan, double magenta, double yellow, double black, ref Quantum red, ref Quantum green, ref Quantum blue)
146 	in
147 	{
148 		assert(cyan    <= 1 && cyan    >= 0);
149 		assert(magenta <= 1 && magenta >= 0);
150 		assert(yellow  <= 1 && yellow  >= 0);
151 		assert(black   <= 1 && black   >= 0);
152 	}
153 	body
154 	{
155 		double r = 1 - min(1, cyan    * (1 - black) + black);
156 		double g = 1 - min(1, magenta * (1 - black) + black);
157 		double b = 1 - min(1, yellow  * (1 - black) + black);
158 
159 		red   = scaleDoubleToQuantum(r);
160 		green = scaleDoubleToQuantum(g);
161 		blue  = scaleDoubleToQuantum(b);
162 	}
163 }
164 
165 unittest
166 {
167 	assert(new ColorCMYK(0,   1,   1,   0  ) == new Color("red"));
168 
169 	auto color1 = new ColorCMYK(0.5, 0.5, 0.5, 0.5);
170 	auto color2 = new Color("gray25");
171 
172 	//Compare the colors a bytes, to compensate for rounding errors.
173 	assert(ScaleQuantumToChar(color1.redQuantum)   == ScaleQuantumToChar(color2.redQuantum));
174 	assert(ScaleQuantumToChar(color1.greenQuantum) == ScaleQuantumToChar(color2.greenQuantum));
175 	assert(ScaleQuantumToChar(color1.blueQuantum)  == ScaleQuantumToChar(color2.blueQuantum));
176 }