Raster or TileLayer Opacity

Editor
Feb 7, 2014 at 2:15 PM
Hi,

Is there a way to set th opacity of a tilelayer?

I'm getting a weather layer from this service and I would like to make it 50% transparent so I can see the map below it. Any Ideas?

var clouds = new BruTile.TileSource(new BruTile.Web.WebTileProvider(
    new BruTile.Web.TmsRequest(new Uri("http://undefined.tile.openweathermap.org/map/clouds"), "png"), new BruTile.Cache.FileCache(@"c:\temp\BruTile\clouds", "png")), new BruTile.PreDefined.SphericalMercatorInvertedWorldSchema());

        var Casync = new SharpMap.Layers.TileLayer(clouds, "Clouds");
        Casync.Enabled = true;


        map.Layers.Add(Casync);

Thanks
Coordinator
Feb 8, 2014 at 7:27 AM
Edited Feb 9, 2014 at 8:32 AM
Atm you can set a color that should be treated as transparent.
If that is not enough you need to override tile(async)layer.
Editor
Feb 11, 2014 at 9:53 AM
Hi Felix,

I created a new layer type that acts as a proxy between the real layer and the map and applies the transparency to it. It works well.

Here is a copy of the code for anyone else wanting to do this. The value 0.2f in the image matrix is the float that controls the transparency. 1.0 will be opaque, and 0.0 will be completely transparent.

Thanks
public class TransparencyLayer:Layer
{
    private readonly Layer _baseLayer;

    public TransparencyLayer(Layer baseLayer)
    {
        _baseLayer = baseLayer;
    }

    public override GeoAPI.Geometries.Envelope Envelope
    {
        get { return _baseLayer.Envelope; }
    }

    public override void Render(Graphics g, Map map)
    {
        var img = new Bitmap(map.Size.Width, map.Size.Height);
        var gg = Graphics.FromImage(img);

        //draw base layer to graphics buffer
        _baseLayer.Render(gg,map);

        // apply transparency to image and draw to map graphics object
        float[][] pnt =
        {   new float[] {1, 0, 0, 0, 0},
            new float[] {0, 1, 0, 0, 0},
            new float[] {0, 0, 1, 0, 0},
            new float[] {0, 0, 0, 0.2f, 0},
            new float[] {0, 0, 0, 0, 1}};

        var clm = new ColorMatrix(pnt);
        var att = new ImageAttributes();
        att.SetColorMatrix(clm, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);

        g.DrawImage(img, new Rectangle((int)0, (int)0, img.Size.Width, img.Size.Height),
            0, 0, img.Width, img.Height, GraphicsUnit.Pixel, att);

        base.Render(g,map);
    }
}
Coordinator
Feb 11, 2014 at 11:09 AM
Edited Feb 11, 2014 at 12:08 PM
Good catch!

Maybe a more general approach could be used:
  • keep a private ImageAttributes field, that is instantiated by the constructor.
  • factory methods to build the proxy class by some opacity value, a colormap, a colormatrix...
In any way, you need to dispose your ImageAttributes class.
Editor
Feb 11, 2014 at 3:45 PM
OK, try this.

public class TransparencyLayer : Layer
{
    private readonly Layer _baseLayer;
    private readonly ImageAttributes _imageAttributes;

    public TransparencyLayer(Layer baseLayer, float transparency)
    {
        _baseLayer = baseLayer;
        Transparency = transparency;
        // apply transparency to image and draw to map graphics object
        float[][] pnt =
        {
            new float[] {1, 0, 0, 0, 0},
            new float[] {0, 1, 0, 0, 0},
            new float[] {0, 0, 1, 0, 0},
            new float[] {0, 0, 0, Transparency, 0},
            new float[] {0, 0, 0, 0, 1}
        };

        var colorMatrix = new ColorMatrix(pnt);
        _imageAttributes = new ImageAttributes();
        _imageAttributes.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);

    }

    public float Transparency { get; set; }

    public new void Dispose()
    {
        if (_imageAttributes != null)
        {
            _imageAttributes.Dispose();
        }
    }


you can also use this matrix to convert the baseLayer to grey scale.
        ColorMatrix colorMatrix = new ColorMatrix(
           new float[][] 
  {
     new float[] {.3f, .3f, .3f, 0, 0},
     new float[] {.59f, .59f, .59f, 0, 0},
     new float[] {.11f, .11f, .11f, 0, 0},
     new float[] {0, 0, 0, 1, 0},
     new float[] {0, 0, 0, 0, 1}
  });


    public override GeoAPI.Geometries.Envelope Envelope
    {
        get { return _baseLayer.Envelope; }
    }

    public override void Render(Graphics g, Map map)
    {
        var img = new Bitmap(map.Size.Width, map.Size.Height);
        var gg = Graphics.FromImage(img);

        //draw base layer to graphics buffer
        _baseLayer.Render(gg,map);

        g.DrawImage(img, new Rectangle(0, 0, img.Size.Width, img.Size.Height),
            0, 0, img.Width, img.Height, GraphicsUnit.Pixel, _imageAttributes);

        base.Render(g,map);
    }
}
Coordinator
Feb 12, 2014 at 9:41 AM
Editor
Feb 12, 2014 at 11:18 AM
HI Felix,

I see you've renamed it to GdiImageLayerProxy. This might be a little misleading to some as this can actually take any layer type (except async layers as you rightly catch).

Perhaps something like MatrixTransformLayerProxy or something might be more suitable.

Thanks,

Rob