1 /**
2  * Image module.
3  *
4  * License:
5  *     MIT. See LICENSE for full details.
6  */
7 module tkd.image.image;
8 
9 /**
10  * Imports.
11  */
12 import tkd.element.element;
13 
14 /**
15  * The image base class.
16  */
17 class Image : Element
18 {
19 	/**
20 	 * Construct the image.
21 	 */
22 	public this()
23 	{
24 		super();
25 		this._elementId = "image";
26 
27 		this._tk.eval("image create photo %s", this.id);
28 	}
29 
30 	/**
31 	 * This method embeds the image as a base64 encoded string into the 
32 	 * application at compile-time. The path to the image must be passed to the 
33 	 * compiler using the -J switch.
34 	 *
35 	 * Params:
36 	 *     filename = The filename to read the data from.
37 	 *
38 	 * Returns:
39 	 *     This image to aid method chaining.
40 	 */
41 	protected auto embedBase64Data(string filename, this T)()
42 	{
43 		this.setData(base64Encode!(filename));
44 
45 		return cast(T) this;
46 	}
47 
48 	/**
49 	 * Clears the image of all pixel data and effectively makes it transparent.
50 	 *
51 	 * Returns:
52 	 *     This image to aid method chaining.
53 	 */
54 	public auto blank(this T)()
55 	{
56 		this._tk.eval("%s blank", this.id);
57 
58 		return cast(T) this;
59 	}
60 
61 	/**
62 	 * Specifies the contents of the image as a string. The string should 
63 	 * contain binary data or, for some formats, base64-encoded data (this is 
64 	 * currently guaranteed to be supported for PNG and GIF images). A set 
65 	 * file takes precedence over the setting of data.
66 	 *
67 	 * Params:
68 	 *     data = The image data.
69 	 *
70 	 * Returns:
71 	 *     This image to aid method chaining.
72 	 */
73 	public auto setData(this T)(string data)
74 	{
75 		this._tk.eval("%s configure -data {%s}", this.id, data);
76 
77 		return cast(T) this;
78 	}
79 
80 	/**
81 	 * Get the image data.
82 	 *
83 	 * Returns:
84 	 *     Base64 encoded image data.
85 	 */
86 	public string getData()
87 	{
88 		this._tk.eval("%s cget -data", this.id);
89 		return this._tk.getResult!(string);
90 	}
91 
92 	/**
93 	 * Set the image format.
94 	 * Once set the image only accepts files or data in this format.
95 	 *
96 	 * Params:
97 	 *     format = A valid image format.
98 	 *
99 	 * Returns:
100 	 *     This image to aid method chaining.
101 	 *
102 	 * See_Also:
103 	 *     $(LINK2 ./imageformat.html, tkd.image.imageformat) for supported formats.
104 	 */
105 	public auto setFormat(this T)(string format)
106 	{
107 		this._tk.eval("%s configure -format {%s}", this.id, format);
108 
109 		return cast(T) this;
110 	}
111 
112 	/**
113 	 * Get the image format.
114 	 *
115 	 * Returns:
116 	 *     The image format.
117 	 *
118 	 * See_Also:
119 	 *     $(LINK2 ./imageformat.html, tkd.image.imageformat) for returned formats.
120 	 */
121 	public string getFormat()
122 	{
123 		this._tk.eval("%s cget -format", this.id);
124 		return this._tk.getResult!(string);
125 	}
126 
127 	/**
128 	 * Set the image file.
129 	 *
130 	 * Params:
131 	 *     file = The name of the file.
132 	 *
133 	 * Returns:
134 	 *     This image to aid method chaining.
135 	 */
136 	public auto setFile(this T)(string file)
137 	{
138 		this._tk.eval("%s configure -file {%s}", this.id, file);
139 
140 		return cast(T) this;
141 	}
142 
143 	/**
144 	 * Get the image file.
145 	 *
146 	 * Returns:
147 	 *     The file that was loaded for this image.
148 	 */
149 	public string getFile()
150 	{
151 		this._tk.eval("%s cget -file", this.id);
152 		return this._tk.getResult!(string);
153 	}
154 
155 	/**
156 	 * Set the image gamma.
157 	 *
158 	 * Params:
159 	 *     gamma = The destination gamma.
160 	 *
161 	 * Returns:
162 	 *     This image to aid method chaining.
163 	 */
164 	public auto setGamma(this T)(double gamma)
165 	{
166 		if (gamma < 0)
167 		{
168 			gamma = 1;
169 		}
170 
171 		this._tk.eval("%s configure -gamma %s", this.id, gamma);
172 
173 		return cast(T) this;
174 	}
175 
176 	/**
177 	 * Get the current image gamma.
178 	 *
179 	 * Returns:
180 	 *     A string containing the image gamma setting.
181 	 */
182 	public string getGamma()
183 	{
184 		this._tk.eval("%s cget -gamma", this.id);
185 		return this._tk.getResult!(string);
186 	}
187 
188 	/**
189 	 * Set the image height.
190 	 *
191 	 * Params:
192 	 *     height = The height to crop the image to.
193 	 *
194 	 * Returns:
195 	 *     This image to aid method chaining.
196 	 */
197 	public auto setHeight(this T)(int height)
198 	{
199 		this._tk.eval("%s configure -height %s", this.id, height);
200 
201 		return cast(T) this;
202 	}
203 
204 	/**
205 	 * Get the current cropped image height.
206 	 *
207 	 * Returns:
208 	 *     The current cropped image height. Returns 0 if no cropping is taking place.
209 	 */
210 	public string getHeight()
211 	{
212 		this._tk.eval("%s cget -height", this.id);
213 		return this._tk.getResult!(string);
214 	}
215 
216 	/**
217 	 * Set the image palette. This setting set how many levels of color/gray are used.
218 	 *
219 	 * Sample_Palettes:
220 	 *     $(UL
221 	 *         $(LI "16" = 16 levels of gray)
222 	 *         $(LI "16/16/16" = 16 levels of RGB)
223 	 *     )
224 	 *
225 	 * Params:
226 	 *     palette = A string describing the palette to use.
227 	 *
228 	 * Returns:
229 	 *     This image to aid method chaining.
230 	 */
231 	public auto setPalette(this T)(string palette)
232 	{
233 		this._tk.eval("%s configure -palette {%s}", this.id, palette);
234 
235 		return cast(T) this;
236 	}
237 
238 	/**
239 	 * Get the current palette.
240 	 *
241 	 * Returns:
242 	 *     A string describing the palette.
243 	 */
244 	public string getPalette()
245 	{
246 		this._tk.eval("%s cget -palette", this.id);
247 		return this._tk.getResult!(string);
248 	}
249 
250 	/**
251 	 * Set the image width.
252 	 *
253 	 * Params:
254 	 *     width = The width to crop the image to.
255 	 *
256 	 * Returns:
257 	 *     This image to aid method chaining.
258 	 */
259 	public auto setWidth(this T)(int width)
260 	{
261 		this._tk.eval("%s configure -width %s", this.id, width);
262 
263 		return cast(T) this;
264 	}
265 
266 	/**
267 	 * Get the current cropped image height.
268 	 *
269 	 * Returns:
270 	 *     The current cropped image height. Returns 0 if no cropping is taking place.
271 	 */
272 	public string getWidth()
273 	{
274 		this._tk.eval("%s cget -width", this.id);
275 		return this._tk.getResult!(string);
276 	}
277 
278 	/**
279 	 * Destroy this image.
280 	 *
281 	 * Caveats:
282 	 *     Once an image is destroyed it can no longer be referenced in your 
283 	 *     code or a segmentation fault will occur and potentially crash your 
284 	 *     program.
285 	 */
286 	public void destroy()
287 	{
288 		this._tk.eval("image delete %s", this.id);
289 		super.destroy();
290 	}
291 }
292 
293 /**
294  * Template to base64 encode files at compile time.
295  *
296  * Params:
297  *     file = The file name to encode and embed.
298  */
299 private template base64Encode(string file)
300 {
301 	import std.base64;
302 
303 	private string getData()
304 	{
305 		return Base64.encode(cast(ubyte[])import(file));
306 	}
307 
308 	enum base64Encode = getData();
309 }