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"));