1 module rip.concepts.surface;
2 
3 private
4 {
5 	import std.algorithm;
6 	import std.conv;
7 	import std.range : array, iota, zip;
8 	import std.stdio : File;
9 	import std.string;
10 	import std.array;
11 
12 	import rip.concepts.color;
13 	import rip.concepts.ranges;
14 	import rip.concepts.templates;
15 }
16 
17 /++
18 +  	Digital mplementation of images.
19 +/
20 class Surface  {
21 	private
22 	{
23 		RGBColor[] pixels;
24 		size_t width;
25 		size_t height;
26 
27 		// Расчет одномерного индекса,с учетом возможного выхода за границы
28 		auto calculateRealIndex(T)(T i)
29 		{
30 			auto N = cast(size_t) i;
31 			auto S = width * height;
32 
33 			return clamp(N, 0, S);
34 		}
35 
36 		// Перевод двумерных индексов в одномерный индекс, с учетом возможного выхода за границы
37 		auto calculateRealIndex(T, U)(T i, U j)
38 			if (allArithmetic!(T, U))
39 		{
40 			auto W = cast(size_t) clamp(i, 0, width - 1);
41 			auto H = cast(size_t) clamp(j, 0, height - 1);
42 			auto S = width * height;
43 
44 			return clamp(W + H * width, 0, S);
45 		}
46 	}
47 
48 	/++
49 	+   Params:
50 	+     width =   	width of image
51 	+     height =      height of image
52 	+	  rgbColor =    main color
53 	+/
54 	this(T, U)(T width, U height)
55 		if (allArithmetic!(T, U))
56 	{
57 		assert(width > 0);
58 		assert(height > 0);
59 
60 		this.width = width;
61 		this.height = height;
62 
63 		pixels = uninitializedArray!(RGBColor[])(width * height);
64 	}
65 
66 	void initialize(RGBColor color = RGBColor.getColor(0, 0, 0)) {
67 		pixels = map!(a => color)(iota(width * height)).array;
68 	}
69 
70 	/++ Parametrized getter +/
71 	mixin(addTypedGetter!("width", "getWidth"));
72 
73 	mixin(addTypedGetter!("height", "getHeight"));
74 
75 	// Общее количество пикселей в изображении
76 	mixin(addTypedGetter!("(width * height)", "getArea"));
77 
78 	@property
79 	{
80 		/++
81 		+   Returns:
82 		+     duplicate of surface
83 		+/
84 		Surface dup()
85 		{
86 			auto duplicateImage = new Surface(width, height);
87 
88 			foreach (i; 0 .. width)
89 			{
90 				foreach (j; 0 .. height)
91 				{
92 					duplicateImage[i, j] = pixels[calculateRealIndex(i, j)];
93 				}
94 			}
95 
96 			return duplicateImage;
97 		}
98 
99 		/++
100 		+   Returns:
101 		+     immutable duplicate of surface
102 		+/
103 		immutable(Surface) idup()
104 		{
105 			return cast(immutable) this.dup;
106 		}
107 	}
108 
109 	/++
110 	+	Params:
111 	+		i 	= index of pixel
112 	+   Returns:
113 	+     	pixel
114 	+	Example:
115 	+	-----------------
116 	+	Surface sur = new Surface[10, 10];
117 	+	RGBColor pixel = sur[45];
118 	+	-----------------
119 	+/
120 	RGBColor opIndex(T)(T i)
121 		if (allArithmetic!T)
122 	{
123 		return pixels[calculateRealIndex(i)];
124 	}
125 
126 	/++
127 	+	Like opIndex. For two indexes
128 	+	Params:
129 	+		i 	= first index of pixel
130 	+		j 	= second index of pixel
131 	+   Returns:
132 	+     	Pixel
133 	+	Example:
134 	+	-----------------
135 	+	Surface sur = new Surface[10, 10];
136 	+	RGBColor pixel = sur[4, 6];
137 	+	----------------
138 	+/
139 	RGBColor opIndex(T, U)(T i, U j)
140 		if (allArithmetic!(T, U))
141 	{
142 		return pixels[calculateRealIndex(i, j)];
143 	}
144 
145 	/++
146 	+	Params:
147 	+		rgbColor 	= new color of pixel
148 	+		i 	= first index of pixel
149 	+		j 	= second index of pixel
150 	+   Returns:
151 	+     	Pixel
152 	+	Example:
153 	+	-----------------
154 	+	Surface sur = new Surface[10, 10];
155 	+	sur[45] = new RGBColor(0, 45, 65);
156 	+	-----------------
157 	+/
158 	void opIndexAssign(T)(RGBColor rgbColor, T i)
159 		if (allArithmetic!T)
160 	{
161 		pixels[calculateRealIndex(i)] = rgbColor;
162 	}
163 
164 	/++
165 	+	Like opIndexAssign. For two indexes.
166 	+	Params:
167 	+		rgbColor 	= new color of pixel
168 	+		i 	= first index of pixel
169 	+		j 	= second index of pixel
170 	+   Returns:
171 	+     	Pixel
172 	+	Example:
173 	+	-----------------
174 	+	Surface sur = new Surface[10, 10];
175 	+	sur[4, 5] = new RGBColor(0, 45, 65);
176 	+	-----------------
177 	+/
178 	void opIndexAssign(T, U)(RGBColor rgbColor, T i, U j)
179 		if (allArithmetic!(T, U))
180 	{
181 		pixels[calculateRealIndex(i, j)] = rgbColor;
182 	}
183 
184 
185 	/++
186 	+ 	Create pixel's range and return it;
187 	+   Returns:
188 	+     	PixelsRange
189 	+/
190 	auto getPixelsRange() {
191 		return createPixels(pixels);
192 	}
193 
194 	/++
195 	+   Returns:
196 	+     	Array of pixels
197 	+/
198 	auto getPixels() const {
199 		return pixels;
200 	}
201 }
202 
203 
204 // Сложение двух картинок
205 mixin(addBinaryImageOperation!("+","add"));
206 
207 // Вычитание двух картинок
208 mixin(addBinaryImageOperation!("-","subtract"));
209 
210 // Умножение двух картинок
211 mixin(addBinaryImageOperation!("*","multiply"));
212 
213 // Деление двух картинок
214 mixin(addBinaryImageOperation!("/","divide"));
215 
216 // Остаток от деление одной картинки на другую
217 mixin(addBinaryImageOperation!("%","mod"));
218 
219 // Возведение в степень
220 mixin(addBinaryImageOperation!("^^","power"));
221 
222 // Логическое "И" двух картинок
223 mixin(addBinaryImageOperation!("&","and"));
224 
225 // Логическое "ИЛИ" двух картинок
226 mixin(addBinaryImageOperation!("|","or"));
227 
228 // Исключающее "ИЛИ" двух картинок
229 mixin(addBinaryImageOperation!("^","xor"));