Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert SQL Server Geography to PNG image

We have an API which converts MS SQL geography type to well-known text, and sends it to the front end, which then sends WKT to OpenLayer maps, which renders canvas (borders, regions etc).

I am looking a way to reduce payload to the client and convert polygons, multypoligons, and maps in general to png on the backend side.

What I tried is to convert canvas to base64, and save it as PNG. That works well, but I need a full backend solution.

I tried to play around with SharpMap, but it's quite old, it's causing me dependency issues, and I did not manage to get it working.

I found a test SHP file and tried to render it to PictureBox in windows forms for a test, and all I got was an empty white box.

SharpMap.Map myMap = new SharpMap.Map(new Size(600, 300));
myMap.BackColor = Color.White;
var shapeFileProvider = new SharpMap.Data.Providers.ShapeFile(@"C:\Users\test\Downloads\FRA_adm\FRA_adm1.shp", true);

SharpMap.Layers.VectorLayer myLayer = new SharpMap.Layers.VectorLayer("World Countries");
myMap.Layers.Add(myLayer);
myMap.ZoomToExtents();
myLayer.DataSource = shapeFileProvider;
pictureBox1.Image = myMap.GetMap();

Any ideas on how to tackle this issue?

EDIT: I even tried geoserver, but it looks like it does not support Spatial Geography, but only geometry.

I need to find a way to convert borders, regions, countries to images in c# backend.

Edit 2: U am using SHP file for testing, but what I really want is to render it from Sql Server Geography type.

like image 415
Robert Avatar asked Nov 30 '25 01:11

Robert


1 Answers

SharpMap is still maintained, but the nuget packages are not. And the packages (dated 2014) are not compatible with all the dependencies (GeoAPI, ProjNet, etc.) current nuget versions. What I suggest is:

  1. don't use SharpMap nuget, build your own SharpMap assemblies from github (most of the assemblies compile w/o any issue, especially the main one, SharpMap)
  2. reference that assembly (and only that one)
  3. reference the latest versions of the dependency assemblies manually one by one when you need it.

Here is your WinForms code adapted with the latest SharpMap, GeoAPI and ProjNet:

public partial class Form1 : Form
{
    public Form1()
    {
        // just add a PictureBox on the Winform.
        InitializeComponent();
        DrawMap();
    }

    private void DrawMap()
    {
        Session.Instance.SetCoordinateSystemServices(
            new CoordinateSystemServices(
                    new CoordinateSystemFactory(),
                    new CoordinateTransformationFactory(),
                    SpatialReference.GetAllReferenceSystems()));

        var map = new Map(pictureBox1.Size);
        map.BackColor = Color.White;
        var file = new ShapeFile(@"D:\Downloads\FRA_adm\FRA_adm1.shp", true);
        var layer = new VectorLayer("France", file);
        map.Layers.Add(layer);
        map.ZoomToExtents();
        pictureBox1.Image = map.GetMap();
    }
}

This will display this:

enter image description here

As you see, the map looks funny, if you happen to know France contours :-). If you want the correct projection, you need to add this code to the layer:

layer.CoordinateTransformation = Wgs84ToGoogle;

...

// Wgs84 to Google Mercator Coordinate Transformation
// this code comes from SharpMap\Examples\WinFormSamples\LayerTools.cs
private ICoordinateTransformation _wgs84ToGoogle;
public ICoordinateTransformation Wgs84ToGoogle
{
    get
    {
        if (_wgs84ToGoogle == null)
        {
            var csFac = new CoordinateSystemFactory();
            var ctFac = new CoordinateTransformationFactory();

            var wgs84 = csFac.CreateGeographicCoordinateSystem(
              "WGS 84", AngularUnit.Degrees, HorizontalDatum.WGS84, PrimeMeridian.Greenwich,
              new AxisInfo("north", AxisOrientationEnum.North), new AxisInfo("east", AxisOrientationEnum.East));

            var parameters = new List<ProjectionParameter>();
            parameters.Add(new ProjectionParameter("semi_major", 6378137.0));
            parameters.Add(new ProjectionParameter("semi_minor", 6378137.0));
            parameters.Add(new ProjectionParameter("latitude_of_origin", 0.0));
            parameters.Add(new ProjectionParameter("central_meridian", 0.0));
            parameters.Add(new ProjectionParameter("scale_factor", 1.0));
            parameters.Add(new ProjectionParameter("false_easting", 0.0));
            parameters.Add(new ProjectionParameter("false_northing", 0.0));

            var projection = csFac.CreateProjection("Google Mercator", "mercator_1sp", parameters);
            var epsg900913 = csFac.CreateProjectedCoordinateSystem(
              "Google Mercator", wgs84, projection, LinearUnit.Metre, new AxisInfo("East", AxisOrientationEnum.East),
              new AxisInfo("North", AxisOrientationEnum.North));

            ((CoordinateSystem)epsg900913).DefaultEnvelope = new[] { -20037508.342789, -20037508.342789, 20037508.342789, 20037508.342789 };

            _wgs84ToGoogle = ctFac.CreateFromCoordinateSystems(wgs84, epsg900913);
        }
        return _wgs84ToGoogle;
    }
}

And you now will get this:

enter image description here

SharpMap may be a bit bloated, but it still provides valuable code and the samples work. Since the documentation is hard to find, if you use it, you may have to dig in the source.

Also, you want to know that GDI+, which SharpMap uses, is not officially supported by Microsoft on server side. It doesn't mean it doesn't work, you'll have to try by yourself in your own context.

like image 91
Simon Mourier Avatar answered Dec 01 '25 16:12

Simon Mourier