Beispiel #1
0
        public static async Task DrawLayerAsync(
            ITileSource source,
            int width,
            int height,
            Models.Bounds boundingBox,
            SKCanvas outputCanvas,
            bool isTransparent,
            uint backgroundColor)
        {
            // TODO: check SRS support in source
            if ((String.Compare(source.Configuration.Type, SourceConfiguration.TypeWms, StringComparison.OrdinalIgnoreCase) == 0) &&
                (source.Configuration.Cache == null))
            {
                // Cascading GetMap request to WMS source as single GetMap request
                var imageData = await((TileSources.HttpTileSource)source).GetWmsMapAsync(width, height, boundingBox, isTransparent, backgroundColor);
                if (imageData != null)
                {
                    WmsHelper.DrawImageUnscaledToRasterCanvas(outputCanvas, imageData);
                }
            }
            else
            {
                var tileCoordinates = WmsHelper.BuildTileCoordinatesList(boundingBox, width);
                var sourceTiles     = await GetSourceTilesAsync(source, tileCoordinates);

                if (sourceTiles.Count > 0)
                {
                    WmsHelper.DrawWebMercatorTilesToRasterCanvas(outputCanvas, width, height, boundingBox, sourceTiles, backgroundColor, U.WebMercator.TileSize);
                }
            }
        }
Beispiel #2
0
        private async Task <byte[]> CreateMapImageAsync(
            int width,
            int height,
            Models.Bounds boundingBox,
            string mediaType,
            bool isTransparent,
            uint backgroundColor,
            IList <string> layerNames)
        {
            var imageInfo = new SKImageInfo(
                width: width,
                height: height,
                colorType: SKColorType.Rgba8888,
                alphaType: SKAlphaType.Premul);

            using var surface = SKSurface.Create(imageInfo);
            using var canvas  = surface.Canvas;
            canvas.Clear(new SKColor(backgroundColor));

            foreach (var layerName in layerNames)
            {
                if (this.tileSourceFabric.Contains(layerName))
                {
                    await WmsHelper.DrawLayerAsync( // TODO: ? pass required format to avoid conversions
                        this.tileSourceFabric.Get(layerName),
                        width,
                        height,
                        boundingBox,
                        canvas,
                        isTransparent,
                        backgroundColor);
                }
            }

            using SKImage image = surface.Snapshot();

            if (String.Compare(mediaType, MediaTypeNames.Image.Tiff, StringComparison.OrdinalIgnoreCase) == 0)
            {
                using var bitmap = SKBitmap.FromImage(image);
                // TODO: improve performance of pixels processing, maybe using unsafe/pointers
                var pixels = bitmap.Pixels.SelectMany(p => new byte[] { p.Red, p.Green, p.Blue, p.Alpha }).ToArray();
                var tiff   = ImageHelper.CreateTiffImage(pixels, image.Width, image.Height);
                return(tiff);
            }
            else
            {
                var imageFormat = U.ImageHelper.SKEncodedImageFormatFromMediaType(mediaType);
                using SKData data = image.Encode(imageFormat, 90); // TODO: ? quality parameter
                return(data.ToArray());
            }
        }
Beispiel #3
0
        private static void DrawWebMercatorTilesToRasterCanvas(
            SKCanvas outputCanvas,
            int width,
            int height,
            Models.Bounds boundingBox,
            IList <Models.TileDataset> sourceTiles,
            uint backgroundColor,
            int tileSize)
        {
            var zoom         = sourceTiles[0].Z;
            var tileMinX     = sourceTiles.Min(t => t.X);
            var tileMinY     = sourceTiles.Min(t => t.Y);
            var tilesCountX  = sourceTiles.Max(t => t.X) - tileMinX + 1;
            var tilesCountY  = sourceTiles.Max(t => t.Y) - tileMinY + 1;
            var canvasWidth  = tilesCountX * tileSize;
            var canvasHeight = tilesCountY * tileSize;

            var imageInfo = new SKImageInfo(
                width: canvasWidth,
                height: canvasHeight,
                colorType: SKColorType.Rgba8888,
                alphaType: SKAlphaType.Premul);

            using var surface = SKSurface.Create(imageInfo);
            using var canvas  = surface.Canvas;
            canvas.Clear(new SKColor(backgroundColor));

            // Draw all tiles
            foreach (var sourceTile in sourceTiles)
            {
                var offsetX = (sourceTile.X - tileMinX) * tileSize;
                var offsetY = (sourceTile.Y - tileMinY) * tileSize;
                using var sourceImage = SKImage.FromEncodedData(sourceTile.ImageData);
                canvas.DrawImage(sourceImage, SKRect.Create(offsetX, offsetY, tileSize, tileSize)); // Source tile scaled to dest rectangle, if needed
            }

            // Clip and scale to requested size of output image
            var geoBBox         = EntitiesConverter.MapRectangleToGeographicalBounds(boundingBox);
            var pixelOffsetX    = WebMercator.LongitudeToPixelXAtZoom(geoBBox.MinLongitude, zoom) - tileSize * tileMinX;
            var pixelOffsetY    = WebMercator.LatitudeToPixelYAtZoom(geoBBox.MaxLatitude, zoom) - tileSize * tileMinY;
            var pixelWidth      = WebMercator.LongitudeToPixelXAtZoom(geoBBox.MaxLongitude, zoom) - WebMercator.LongitudeToPixelXAtZoom(geoBBox.MinLongitude, zoom);
            var pixelHeight     = WebMercator.LatitudeToPixelYAtZoom(geoBBox.MinLatitude, zoom) - WebMercator.LatitudeToPixelYAtZoom(geoBBox.MaxLatitude, zoom);
            var sourceRectangle = SKRect.Create((float)pixelOffsetX, (float)pixelOffsetY, (float)pixelWidth, (float)pixelHeight);
            var destRectangle   = SKRect.Create(0, 0, width, height);

            using SKImage canvasImage = surface.Snapshot();
            outputCanvas.DrawImage(canvasImage, sourceRectangle, destRectangle, new SKPaint {
                FilterQuality = SKFilterQuality.High,
            });
        }
Beispiel #4
0
        public static List <Models.TileCoordinates> BuildTileCoordinatesList(Models.Bounds boundingBox, int width)
        {
            var geoBBox      = EntitiesConverter.MapRectangleToGeographicalBounds(boundingBox);
            var zoomLevel    = FindOptimalTileZoomLevel(width, geoBBox);
            var tileCoordMin = GetTileCoordinatesAtPoint(geoBBox.MinLongitude, geoBBox.MinLatitude, zoomLevel);
            var tileCoordMax = GetTileCoordinatesAtPoint(geoBBox.MaxLongitude, geoBBox.MaxLatitude, zoomLevel);

            var tileCoordinates = new List <Models.TileCoordinates>();

            for (var tileX = tileCoordMin.X; tileX <= tileCoordMax.X; tileX++)
            {
                for (var tileY = tileCoordMax.Y; tileY <= tileCoordMin.Y; tileY++)
                {
                    tileCoordinates.Add(new Models.TileCoordinates(tileX, tileY, zoomLevel));
                }
            }

            return(tileCoordinates);
        }
Beispiel #5
0
        internal async Task <byte[]?> GetWmsMapAsync(
            int width,
            int height,
            Models.Bounds boundingBox,
            bool isTransparent,
            uint backgroundColor)
        {
            if (this.client == null)
            {
                throw new InvalidOperationException("HTTP client was not initialized.");
            }

            if (String.IsNullOrEmpty(this.configuration.Location))
            {
                throw new InvalidOperationException("configuration.Location is null or empty");
            }

            var url      = Wms.QueryUtility.GetMapUrl(this.configuration, width, height, boundingBox, isTransparent, backgroundColor);
            var response = await client.GetAsync(url);

            if (response.StatusCode == HttpStatusCode.OK)
            {
                if (response.Content.Headers.ContentType != null &&
                    response.Content.Headers.ContentType.MediaType == MediaTypeNames.Application.OgcServiceExceptionXml)
                {
                    var message = await response.Content.ReadAsStringAsync();

                    System.Diagnostics.Debug.WriteLine(message); // TODO: write error details to log
                    return(null);
                }

                // TODO: more checks of Content-Type, response size, etc.

                var data = await response.Content.ReadAsByteArrayAsync();

                return(data);
            }
            else
            {
                return(null);
            }
        }
Beispiel #6
0
        public static string GetMapUrl(
            SourceConfiguration configuration,
            int width,
            int height,
            Models.Bounds boundingBox,
            bool isTransparent,
            uint backgroundColor)
        {
            var location = configuration.Location;

            if (String.IsNullOrWhiteSpace(location))
            {
                throw new ArgumentException("Location must be valid string");
            }

            var baseUri = Utils.UrlHelper.GetQueryBase(location);
            var items   = Utils.UrlHelper.GetQueryParameters(location);

            // Version
            var wmsVersion = Identifiers.Version111; // Default WMS version is 1.1.1

            if (configuration.Wms != null && !String.IsNullOrWhiteSpace(configuration.Wms.Version))
            {
                wmsVersion = configuration.Wms.Version;
            }
            else if (items.Any(kvp => kvp.Key == WmsQueryVersion))
            {
                wmsVersion = items.First(kvp => kvp.Key == WmsQueryVersion).Value;
            }

            // Layers
            var layers = String.Empty;

            if (configuration.Wms != null && !String.IsNullOrWhiteSpace(configuration.Wms.Layer))
            {
                layers = configuration.Wms.Layer; // TODO: ? multiple layers
            }
            else if (items.Any(kvp => kvp.Key == WmsQueryLayers))
            {
                layers = items.First(kvp => kvp.Key == WmsQueryLayers).Value;
            }

            // Format
            var format = MediaTypeNames.Image.Png;

            if (!String.IsNullOrWhiteSpace(configuration.ContentType))
            {
                format = configuration.ContentType;
            }

            RemoveKnownParameters(items);

            var qb = new QueryBuilder(items)
            {
                { WmsQueryService, Identifiers.Wms },
                { WmsQueryRequest, Identifiers.GetMap },
                { WmsQueryVersion, wmsVersion },
                { WmsQueryLayers, layers },
                { (wmsVersion == Identifiers.Version130) ? WmsQueryCrs : WmsQuerySrs, EPSG3857 }, // TODO: EPSG:4326 support
                { WmsQueryBBox, boundingBox.ToBBoxString() },
                { WmsQueryWidth, width.ToString(CultureInfo.InvariantCulture) },
                { WmsQueryHeight, height.ToString(CultureInfo.InvariantCulture) },
                { WmsQueryFormat, format },
            };

            if (isTransparent)
            {
                qb.Add(WmsQueryTransparent, "true");
            }

            qb.Add(WmsQueryBackgroundColor, "0x" + backgroundColor.ToString("X8"));

            return(baseUri + qb.ToQueryString());
        }