Попытка сохранить сгенерированную тепловую карту в хранилище Azure

У меня есть тепловая карта, которая в настоящее время работает на отдельном сервере, который я переношу в хранилище Azure. Как мне сохранить файл Butmap в хранилище Azure. Первоначально у меня была запись в моем файле web.config, которая указывала кеш изображения на прямой путь на другом диске (IE). Теперь все будет в папке ~/map_cache в учетной записи хранения. Как я могу модифицировать это для локального хранения в Azure.

protected void Page_Load(object sender, EventArgs e)
{
    xxxxxxxdb = new xxxxxxx(ConfigurationManager.AppSettings["xxxxxxx"]);

    string imageCachePath = Server.MapPath("/map_cache/HotSpots");
    int fileExpirationTime = int.Parse(ConfigurationManager.AppSettings["HotspotImageExpirationTime"]);
    Bitmap bitmap;

    string requestParam = Page.Request.Params["id"];
    string bitmapFileName = Path.Combine(imageCachePath, requestParam + ".png");
    if (File.Exists(bitmapFileName) && File.GetCreationTime(bitmapFileName) > DateTime.Now.AddHours(-fileExpirationTime))
    {
        bitmap = (Bitmap)Image.FromFile(bitmapFileName);
    }
    else
    {
        int zoomLevel = requestParam.Length;

        double tileX = 0;
        double tileY = 0;
        for (int index = 0; index < zoomLevel; index++)
        {
            int digit = int.Parse(requestParam[index].ToString());
            tileY += ((digit & 2) / 2) * Math.Pow(2, (zoomLevel - index - 1));
            tileX += (digit & 1) * Math.Pow(2, (zoomLevel - index - 1));
        }
        double pixelXMin = tileX * 256;
        double pixelYMin = tileY * 256;
        double pixelXMax = (tileX + 1) * 256 - 1;
        double pixelYMax = (tileY + 1) * 256 - 1;

        double longMin = ((pixelXMin * 360) / (256 * Math.Pow(2, zoomLevel))) - 180;
        double longMax = ((pixelXMax * 360) / (256 * Math.Pow(2, zoomLevel))) - 180;
        double latMin = Math.Asin((Math.Exp((0.5 - pixelYMin / 256 / Math.Pow(2, zoomLevel)) * 4 * Math.PI) - 1) /
                                  (Math.Exp((0.5 - pixelYMin / 256 / Math.Pow(2, zoomLevel)) * 4 * Math.PI) + 1)) * 180 /
                        Math.PI;
        double latMax = Math.Asin((Math.Exp((0.5 - pixelYMax / 256 / Math.Pow(2, zoomLevel)) * 4 * Math.PI) - 1) /
                                  (Math.Exp((0.5 - pixelYMax / 256 / Math.Pow(2, zoomLevel)) * 4 * Math.PI) + 1)) * 180 /
                        Math.PI;

        double pixelResolution = (Math.Cos(latMax * Math.PI / 180) * 2 * Math.PI * 6378137) / (256 * Math.Pow(2, zoomLevel));
        double pixelArea = Math.Pow(pixelResolution, 2);

        double maxHotspotDensity = Math.Max(120.0 / zoomLevel, 3.0) / pixelArea;

        bitmap = GenerateBlankBitmap();

        var accidents = from hs in db.cs_PT_VEGeoDatas
                        where hs.Latitude <= latMin && hs.Latitude >= latMax
                              && hs.Longitude >= longMin && hs.Longitude <= longMax
                        select new { hs.Latitude, hs.Longitude };

        Dictionary<Point, HotSpot> hotSpots = new Dictionary<Point, HotSpot>();
        foreach (var accident in accidents)
        {
            int pixelX, pixelY;
            LatLongToPixelXY(accident.Latitude, accident.Longitude, zoomLevel, out pixelX, out pixelY);
            pixelX %= 256;
            pixelY %= 256;
            for (int ix = -doublePixelSize; ix <= doublePixelSize; ix++)
            {
                for (int iy = -doublePixelSize; iy <= doublePixelSize; iy++)
                {
                    Point point;
                    bool borderPoint = false;
                    if (zoomLevel < doublePixelZoomLevel)
                    {
                        point = new Point(pixelX, pixelY);
                    }
                    else
                    {
                        if (pixelX + ix >= 0 && pixelX + ix <= 255 && pixelY + iy >= 0 && pixelY + iy <= 255)
                        {
                            point = new Point(pixelX + ix, pixelY + iy);
                            borderPoint = (ix == -doublePixelSize) || (iy == -doublePixelSize) ||
                                              (ix == doublePixelSize) || (iy == doublePixelSize);
                        }
                        else
                        {
                            break;
                        }
                    }
                    HotSpot hotSpot;
                    if (hotSpots.ContainsKey(point))
                    {
                        hotSpot = hotSpots[point];
                        hotSpot.borderPoint &= borderPoint;
                        hotSpot.count += 1;
                    }
                    else
                    {
                        hotSpot = new HotSpot { borderPoint = borderPoint, count = 1 };
                        hotSpots.Add(point, hotSpot);
                    }
                    if (zoomLevel < doublePixelZoomLevel)
                    {
                        break;
                    }
                }
                if (zoomLevel < doublePixelZoomLevel)
                {
                    break;
                }
            }
        }
        foreach (var hotspotPixel in hotSpots)
        {
            double hc = hotspotPixel.Value.count;
            double hcDensity = hc / pixelArea;

            Color color;
            if (!hotspotPixel.Value.borderPoint)
            {
                color = Color.FromArgb(255, 255,
                                       (int)
                                       Math.Max((maxHotspotDensity - hcDensity) / maxHotspotDensity * 255, 0.0),
                                       0);
            }
            else
            {
                color = Color.Black;
            }
            bitmap.SetPixel(hotspotPixel.Key.X, hotspotPixel.Key.Y, color);
        }
        bitmap.Save(bitmapFileName);
    }

    WritePngToStream(bitmap, Response.OutputStream);
}

В настоящее время я получаю следующее сообщение об ошибке

A generic error occurred in GDI+.

Описание: во время выполнения текущего веб-запроса возникло необработанное исключение. Пожалуйста, просмотрите трассировку стека для получения дополнительной информации об ошибке и о том, где она возникла в коде.

Сведения об исключении: System.Runtime.InteropServices.ExternalException: общая ошибка в GDI+.

Ошибка источника:

Во время выполнения текущего веб-запроса возникло необработанное исключение. Информацию о происхождении и расположении исключения можно определить с помощью приведенной ниже трассировки стека исключений.

Трассировки стека:

[ExternalException (0x80004005): в GDI+ произошла общая ошибка.] System.Drawing.Image.Save(строковое имя файла, кодировщик ImageCodecInfo, EncoderParameters encoderParams) +772265 HotSpotTileServer.Page_Load(отправитель объекта, EventArgs e) в C:\Projects\xxx \xxx\SpeedTrap\HotSpotTileServer.aspx.cs:141 System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp, Object o, Object t, EventArgs e) +25 System.EventHandler.Invoke(отправитель объекта, EventArgs e) +0 System.Web.UI.Control.LoadRecursive() +71 System.Web.UI.Page.ProcessRequestMain (логическое значение includeStagesBeforeAsyncPoint, логическое значение includeStagesAfterAsyncPoint) +3048

Информация о версии: Версия Microsoft .NET Framework: 4.0.30319; Версия ASP.NET: 4.0.30319.1


person BlindingDawn    schedule 14.04.2011    source источник


Ответы (2)


Есть три вещи, которые вы можете попробовать:

Я определенно рекомендую последний из них — он быстрый, гибкий и масштабируемый.

person Stuart    schedule 14.04.2011

(Я согласен со Стюартом на 100%.) Вот еще причины, по которым я рекомендую вам рассмотреть возможность использования хранилища BLOB-объектов Azure для хранения PNG-файла тепловой карты:

  1. Надежность локального жесткого диска не гарантируется. (Однако это может быть не важно для вас, если их можно легко регенерировать.)
  2. Блобы можно сделать общедоступными (так, например, на них можно напрямую ссылаться из HTML-кода с помощью тега img).
  3. Большие двоичные объекты можно легко сделать доступными в CDN AppFabric (для повышения производительности, включая около 24 глобальных точек распространения).
  4. Большие двоичные объекты будут масштабироваться так, как нельзя использовать локальную файловую систему. Например, если вы когда-нибудь захотите масштабировать свой сайт для использования более одного экземпляра роли генератора тепловых карт (запустив 2 из них на разных компьютерах в облаке), вам нужно будет использовать хранилище BLOB-объектов, поскольку ни один из других вариантов не будет работать.
  5. Большие двоичные объекты оптимизированы для облачного масштабирования, надежности и высокой доступности.

Я рекомендую вам использовать очень удобный Windows Azure SDK для написания больших двоичных объектов. SDK объединяет официальные интерфейсы REST с очень хорошим набором классов, которые действительно легко использовать из кода .NET. В частности, вы должны использовать класс CloudBlobClient и метод UploadByteArray. Пакет Azure SDK 1.4 можно загрузить здесь< /а>.

person codingoutloud    schedule 16.04.2011