33 using System.Collections.Generic;
35 using System.Drawing.Imaging;
38 using System.Reflection;
39 using System.Threading;
45 using OpenSim.Framework;
46 using OpenSim.Framework.Console;
47 using OpenSim.Services.Interfaces;
54 private static readonly ILog m_log =
56 MethodBase.GetCurrentMethod().DeclaringType);
57 #pragma warning disable 414
58 private string LogHeader =
"[MAP IMAGE SERVICE]";
59 #pragma warning restore 414
61 private const int ZOOM_LEVELS = 8;
62 private const int IMAGE_WIDTH = 256;
63 private const int HALF_WIDTH = 128;
64 private const int JPEG_QUALITY = 80;
66 private static string m_TilesStoragePath =
"maptiles";
68 private static object m_Sync =
new object();
69 private static bool m_Initialized =
false;
70 private static string m_WaterTileFile = string.Empty;
71 private static Color m_Watercolor = Color.FromArgb(29, 71, 95);
72 private static Bitmap m_WaterBitmap = null;
73 private static byte[] m_WaterBytes = null;
80 m_log.Debug(
"[MAP IMAGE SERVICE]: Starting MapImage service");
82 IConfig serviceConfig = config.Configs[
"MapImageService"];
83 if (serviceConfig != null)
85 m_TilesStoragePath = serviceConfig.GetString(
"TilesStoragePath", m_TilesStoragePath);
86 if (!Directory.Exists(m_TilesStoragePath))
87 Directory.CreateDirectory(m_TilesStoragePath);
90 m_WaterTileFile = Path.Combine(m_TilesStoragePath,
"water.jpg");
91 if (!
File.Exists(m_WaterTileFile))
93 Bitmap waterTile =
new Bitmap(IMAGE_WIDTH, IMAGE_WIDTH);
94 FillImage(waterTile, m_Watercolor);
95 waterTile.Save(m_WaterTileFile, ImageFormat.Jpeg);
96 m_WaterBitmap = waterTile;
99 if (
File.Exists(m_WaterTileFile))
101 m_WaterBitmap =
new Bitmap(m_WaterTileFile);
102 using (MemoryStream ms =
new MemoryStream())
104 m_WaterBitmap.Save(ms,ImageFormat.Jpeg);
105 ms.Seek(0, SeekOrigin.Begin);
106 m_WaterBytes = ms.ToArray();
113 #region IMapImageService
115 public bool AddMapTile(
int x,
int y, byte[] imageData, UUID scopeID, out
string reason)
117 reason = string.Empty;
118 string fileName = GetFileName(1, x, y, scopeID);
124 using (FileStream f = File.Open(fileName, FileMode.OpenOrCreate, FileAccess.Write))
125 f.Write(imageData, 0, imageData.Length);
129 m_log.WarnFormat(
"[MAP IMAGE SERVICE]: Unable to save image file {0}: {1}", fileName, e);
135 return UpdateMultiResolutionFiles(x, y, scopeID, out reason);
140 reason = String.Empty;
141 string fileName = GetFileName(1, x, y, scopeID);
147 File.Delete(fileName);
152 m_log.WarnFormat(
"[MAP IMAGE SERVICE]: Unable to save delete file {0}: {1}", fileName, e);
157 return UpdateMultiResolutionFiles(x, y, scopeID, out reason);
165 private class mapToMultiRez
170 public mapToMultiRez(
int pX,
int pY, UUID pscopeID)
177 private Queue<mapToMultiRez> multiRezToBuild =
new Queue<mapToMultiRez>();
179 private bool UpdateMultiResolutionFiles(
int x,
int y, UUID scopeID, out
string reason)
181 reason = String.Empty;
183 lock (multiRezToBuild)
186 multiRezToBuild.Enqueue(
new mapToMultiRez(x, y, scopeID));
187 if (multiRezToBuild.Count == 1)
189 DoUpdateMultiResolutionFilesAsync);
195 private void DoUpdateMultiResolutionFilesAsync(
object o)
198 Thread.Sleep(60 * 1000);
200 while (multiRezToBuild.Count > 0)
202 mapToMultiRez toMultiRez = null;
203 lock (multiRezToBuild)
205 if (multiRezToBuild.Count > 0)
206 toMultiRez = multiRezToBuild.Dequeue();
208 if (toMultiRez != null)
210 int x = toMultiRez.xx;
211 int y = toMultiRez.yy;
212 UUID scopeID = toMultiRez.scopeID;
218 for (uint zoomLevel = 2; zoomLevel <= ZOOM_LEVELS; zoomLevel++)
223 int x1 = x - (x % width);
224 int y1 = y - (y % width);
228 if (!CreateTile(zoomLevel, x1, y1, scopeID))
230 m_log.WarnFormat(
"[MAP IMAGE SERVICE]: Unable to create tile for {0},{1} at zoom level {1}", x, y, zoomLevel);
245 string fullName = Path.Combine(m_TilesStoragePath, scopeID.ToString());
246 fullName = Path.Combine(fullName, fileName);
247 if (
File.Exists(fullName))
249 format = Path.GetExtension(fileName).ToLower();
251 return File.ReadAllBytes(fullName);
253 else if (m_WaterBytes != null)
255 return (byte[])m_WaterBytes.Clone();
259 m_log.DebugFormat(
"[MAP IMAGE SERVICE]: unable to get file {0}", fileName);
267 private string GetFileName(uint zoomLevel,
int x,
int y, UUID scopeID)
269 string extension =
"jpg";
270 string path = Path.Combine(m_TilesStoragePath, scopeID.ToString());
271 Directory.CreateDirectory(path);
272 return Path.Combine(path, string.Format(
"map-{0}-{1}-{2}-objects.{3}", zoomLevel, x, y, extension));
275 private Bitmap GetInputTileImage(
string fileName)
279 if (
File.Exists(fileName))
280 return new Bitmap(fileName);
284 m_log.WarnFormat(
"[MAP IMAGE SERVICE]: Unable to read image data from {0}: {1}", fileName, e);
290 private Bitmap GetOutputTileImage(
string fileName)
294 if (
File.Exists(fileName))
295 return new Bitmap(fileName);
300 Bitmap bm =
new Bitmap(IMAGE_WIDTH, IMAGE_WIDTH, PixelFormat.Format24bppRgb);
307 m_log.WarnFormat(
"[MAP IMAGE SERVICE]: Unable to read image data from {0}: {1}", fileName, e);
313 private bool CreateTile(uint zoomLevel,
int x,
int y, UUID scopeID)
316 int prevWidth = (int)Math.Pow(2, (
double)zoomLevel - 2);
317 int thisWidth = (int)Math.Pow(2, (
double)zoomLevel - 1);
320 int xIn = x - (x % prevWidth);
321 int yIn = y - (y % prevWidth);
324 int xOut = x - (x % thisWidth);
325 int yOut = y - (y % thisWidth);
328 Bitmap inputBL = GetInputTileImage(GetFileName(zoomLevel - 1, xIn, yIn, scopeID));
329 Bitmap inputBR = GetInputTileImage(GetFileName(zoomLevel - 1, xIn + prevWidth, yIn, scopeID));
330 Bitmap inputTL = GetInputTileImage(GetFileName(zoomLevel - 1, xIn, yIn + prevWidth, scopeID));
331 Bitmap inputTR = GetInputTileImage(GetFileName(zoomLevel - 1, xIn + prevWidth, yIn + prevWidth, scopeID));
334 string outputFile = GetFileName(zoomLevel, xOut, yOut, scopeID);
337 Bitmap output = (Bitmap)m_WaterBitmap.Clone();
341 ImageCopyResampled(output, inputBL, 0, HALF_WIDTH, 0, 0);
347 ImageCopyResampled(output, inputBR, HALF_WIDTH, HALF_WIDTH, 0, 0);
353 ImageCopyResampled(output, inputTL, 0, 0, 0, 0);
359 ImageCopyResampled(output, inputTR, HALF_WIDTH, 0, 0, 0);
366 File.Delete(outputFile);
373 output.Save(outputFile, ImageFormat.Jpeg);
377 m_log.WarnFormat(
"[MAP IMAGE SERVICE]: Oops on saving {0} {1}", outputFile, e);
385 #region Image utilities
387 private void FillImage(Bitmap bm, Color c)
389 for (
int x = 0; x < bm.Width; x++)
390 for (
int y = 0; y < bm.Height; y++)
391 bm.SetPixel(x, y, c);
394 private void ImageCopyResampled(Bitmap output, Bitmap input,
int destX,
int destY,
int srcX,
int srcY)
396 int resamplingRateX = 2;
397 int resamplingRateY = 2;
399 for (
int x = destX; x < destX + HALF_WIDTH; x++)
400 for (
int y = destY; y < destY + HALF_WIDTH; y++)
402 Color p = input.GetPixel(srcX + (x - destX) * resamplingRateX, srcY + (y - destY) * resamplingRateY);
403 output.SetPixel(x, y, p);
MapImageService(IConfigSource config)
bool AddMapTile(int x, int y, byte[] imageData, UUID scopeID, out string reason)
Interactive OpenSim region server
bool RemoveMapTile(int x, int y, UUID scopeID, out string reason)
byte[] GetMapTile(string fileName, UUID scopeID, out string format)