115 {
116 if (srcPixelTiles == null || !srcPixelTiles.Any())
117 return null;
118
119 try
120 {
121
122 srcPixelExtent = SafeToIntegerExtent(srcPixelExtent);
123 dstPixelExtent = SafeToIntegerExtent(dstPixelExtent);
124
125 int canvasWidth = (int)srcPixelExtent.Width;
126 int canvasHeight = (int)srcPixelExtent.Height;
127 int dstWidth = (int)dstPixelExtent.Width;
128 int dstHeight = (int)dstPixelExtent.Height;
129
130
131 if (canvasWidth <= 0 || canvasHeight <= 0)
132 {
133 Console.WriteLine($"Invalid canvas dimensions: {canvasWidth}x{canvasHeight}");
134 return null;
135 }
136
137 Image<Rgb24> canvas = new Image<Rgb24>(canvasWidth, canvasHeight);
138
139 foreach (var tile in srcPixelTiles)
140 {
141 try
142 {
143
144 if (tile?.Item2 == null || tile.Item2.Length == 0)
145 continue;
146
147
148 var tileExtent = SafeToIntegerExtent(tile.Item1);
149
150
151 if (tileExtent.Width <= 0 || tileExtent.Height <= 0)
152 continue;
153
154
155 var intersect = SafeIntersect(srcPixelExtent, tileExtent);
156
157
158 if (intersect == null || intersect.Value.Width <= 0 || intersect.Value.Height <= 0)
159 continue;
160
161
162 Image<Rgb24> tileRawData = null;
163 try
164 {
165 tileRawData = (Image<Rgb24>)CreateImageFromBytes(
166 tile.Item2,
167 (int)tileExtent.Width,
168 (int)tileExtent.Height,
169 AForge.PixelFormat.Format24bppRgb
170 );
171 }
172 catch (Exception ex)
173 {
174 Console.WriteLine($"Failed to create image from tile data: {ex.Message}");
175 continue;
176 }
177
178 if (tileRawData == null)
179 continue;
180
181
182 int tileOffsetPixelX = (int)Math.Max(0, intersect.Value.MinX - tileExtent.MinX);
183 int tileOffsetPixelY = (int)Math.Max(0, intersect.Value.MinY - tileExtent.MinY);
184 int canvasOffsetPixelX = (int)Math.Max(0, intersect.Value.MinX - srcPixelExtent.MinX);
185 int canvasOffsetPixelY = (int)Math.Max(0, intersect.Value.MinY - srcPixelExtent.MinY);
186
187
188 int copyWidth = (int)Math.Min(
189 Math.Min(intersect.Value.Width, tileRawData.Width - tileOffsetPixelX),
190 canvas.Width - canvasOffsetPixelX
191 );
192
193 int copyHeight = (int)Math.Min(
194 Math.Min(intersect.Value.Height, tileRawData.Height - tileOffsetPixelY),
195 canvas.Height - canvasOffsetPixelY
196 );
197
198
199 if (copyWidth <= 0 || copyHeight <= 0)
200 {
201 tileRawData.Dispose();
202 continue;
203 }
204
205
206 for (int y = 0; y < copyHeight; y++)
207 {
208 int canvasY = canvasOffsetPixelY + y;
209 int tileY = tileOffsetPixelY + y;
210
211
212 if (canvasY < 0 || canvasY >= canvas.Height ||
213 tileY < 0 || tileY >= tileRawData.Height)
214 break;
215
216 for (int x = 0; x < copyWidth; x++)
217 {
218 int canvasX = canvasOffsetPixelX + x;
219 int tileX = tileOffsetPixelX + x;
220
221
222 if (canvasX < 0 || canvasX >= canvas.Width ||
223 tileX < 0 || tileX >= tileRawData.Width)
224 break;
225
226 canvas[canvasX, canvasY] = tileRawData[tileX, tileY];
227 }
228 }
229
230 tileRawData.Dispose();
231 }
232 catch (Exception e)
233 {
234 Console.WriteLine($"Error processing tile: {e.Message}");
235 }
236 }
237
238
239 if (dstWidth > 0 && dstHeight > 0 &&
240 (dstWidth != canvasWidth || dstHeight != canvasHeight))
241 {
242 try
243 {
244 canvas.Mutate(x => x.Resize(dstWidth, dstHeight));
245 }
246 catch (Exception e)
247 {
248 Console.WriteLine($"Error resizing canvas: {e.Message}");
249 }
250 }
251
252 return canvas;
253 }
254 catch (Exception e)
255 {
256 Console.WriteLine($"Fatal error in JoinRGB24: {e.Message}\n{e.StackTrace}");
257 return null;
258 }
259 }