Register  |  Login
ThinkGeo - GPS Tracking and Mapping Solutions  |  Visit the Wiki  |  Find us on: Twitter Facebook Google+ LinkedIn

Discussion Forums

The online community for users of Map Suite GIS components

Adding transparency to complex area style ?
Last Post 08-09-2012 05:07 AM by David. 8 Replies.
Printer Friendly
Sort:
PrevPrev NextNext
You are not authorized to post a reply.
Author Messages
Lars I.User is Offline
Level 4
Level 4
Posts:141
Avatar

--
07-06-2012 07:22 AM

Hi,

I've built a series of classes to handle complex styling as read from a textual representation in a database. The classes are utilized on top of each other, so a single style may consists of multiple classes deferring control to lower level classes. This "daisy-chain" may be 4 classes deep.

This work as expected.

However, I'd now like to add transparency to such area styles, and do it on top level only, so I don't have to implement it as a hack in classes at all levels.

Is this possible, and if so, how ? What are the caveats ?

An AreaStyle object contain both a FillSolidBrush, an Advanced.FillCustomBrush and a collection named CustomAreaStyles. Either of these may be in use, depending on the actual style constructed.

Would it be feasable to replace the Color component in either/all of these, adding transparency to it ?

(The original styles does not include transparency at all.)

TIA

 

Lars I. Nielsen Hvenegaard, DK
Lars I.User is Offline
Level 4
Level 4
Posts:141
Avatar

--
07-06-2012 08:35 AM

HI again,

I created this function designed to alter an AreaStyle, adding transparency to all colors found.

However it doesn't work :-(


    Private Function AddTransparency(ByRef oldStyle As AreaStyle, ByVal alphaValue As Integer, ByVal canvas As ThinkGeo.MapSuite.Core.GeoCanvas) As AreaStyle

        Dim newStyle As AreaStyle = oldStyle.CloneDeep

        If newStyle.FillSolidBrush IsNot Nothing Then
            newStyle.FillSolidBrush.Color = New GeoColor(alphaValue, newStyle.FillSolidBrush.Color)
        End If

        If newStyle.Advanced.FillCustomBrush IsNot Nothing Then
            Dim brs = newStyle.Advanced.FillCustomBrush

            If TypeOf brs Is GeoSolidBrush Then
                Dim b2 As GeoSolidBrush = brs
                b2.Color = New GeoColor(alphaValue, b2.Color)
                newStyle.Advanced.FillCustomBrush = b2

            ElseIf TypeOf brs Is GeoTextureBrush Then
                Dim b2 As GeoTextureBrush = brs
                'no colors, but make image semi-transparent by making each pixel color semi-transparent
                If canvas IsNot Nothing Then
                    Dim img = b2.GeoImage.GetImageStream(canvas)
                    Dim new_img As New System.Drawing.Bitmap(img) 'cloned

                    For y = 0 To new_img.Height - 1
                        For x = 0 To new_img.Width - 1
                            Dim clr = new_img.GetPixel(x, y)
                            new_img.SetPixel(x, y, Color.FromArgb(alphaValue, clr))
                        Next
                    Next

                    Dim ms = New MemoryStream()
                    new_img.Save(ms, System.Drawing.Imaging.ImageFormat.Tiff) 'must be TIFF (see: GeoImage(stream))

                    newStyle.Advanced.FillCustomBrush = New GeoTextureBrush(New GeoImage(ms))
                End If

            ElseIf TypeOf brs Is GeoHatchBrush Then
                Dim b2 As GeoHatchBrush = brs
                b2.ForegroundColor = New GeoColor(alphaValue, b2.ForegroundColor)
                b2.BackgroundColor = New GeoColor(alphaValue, b2.BackgroundColor)
                newStyle.Advanced.FillCustomBrush = b2

            ElseIf TypeOf brs Is GeoLinearGradientBrush Then
                Dim b2 As GeoLinearGradientBrush = brs
                b2.StartColor = New GeoColor(alphaValue, b2.StartColor)
                b2.EndColor = New GeoColor(alphaValue, b2.EndColor)
                newStyle.Advanced.FillCustomBrush = b2

            End If
        End If

        For Each cas In newStyle.CustomAreaStyles
            newStyle = AddTransparency(newStyle, alphaValue, canvas)
        Next

        Return newStyle

    End Function

Suggestions for improvement (if at all possible) will be greatly appreciated.

 

Lars I. Nielsen Hvenegaard, DK
Lars I.User is Offline
Level 4
Level 4
Posts:141
Avatar

--
07-06-2012 08:41 AM

BTW:

Why is "canvas" necessary when extracting the bytes in a GeoImage stream ?

I.e. in GeoTextureBrush.GeoImage.GetImageStream(canvas)

TIA

 

Lars I. Nielsen Hvenegaard, DK
DavidUser is Offline
MVP
MVP
Posts:1534
Avatar

--
07-06-2012 09:28 AM

 Lars,

 
  This is a bit tricky and depending on your code it could be accomplished using a few different techniques.  The one thing to consider is the effect that you want in the end.  It is a different result if all of the polygons styles you draw are transparent and then composed versus drawing them as solids first then making the final result transparent.  
 
  One way I might accomplish this is inside of the highest level style before the big loop where you go through all the features create a custom GeoCanvas that inherits from the GdiPlusGeoCanvas.  Inside your custom geocanvas you override the core methods for drawing that takes the GeoColor.  Inside the overload you clone the geocolor and change the alpha of it then call into the base function to do all the work.  You pass this geocanvas into the lower level classes so they draw on this.  After all of the drawing you call the EndDrawing on the GeoCanvas and then you superimpose the bitmap of the styles that just drew onto the regular geocanvas.  Just an idea.
 
  Another way would be to modify all of your lower level classes to take a master transparency value and they use that to tweak the geocolor when they go to draw.  This might be a bit time consuming.
 
Included below is some sample code of the first way.  I ran it and it seems to do what I want as long as the sub styles all use the temp canvas to draw everything will be transparent.  I hope you can see my meaning. I originally wrote it in CSharp, included as well as a vb.net translation.
 
David
 

Public Class TransparentStyle
    Inherits ThinkGeo.MapSuite.Core.Style

    Protected Overrides Sub DrawCore(features As System.Collections.Generic.IEnumerable(Of Feature), canvas As GeoCanvas, labelsInThisLayer As Collection(Of SimpleCandidate), labelsInAllLayers As Collection(Of SimpleCandidate))
        Dim tempCanvas As New TransparentGdiPlusGeoCanvas()
        Dim transparentBitmap As Bitmap = Nothing
        Dim returnStream As Stream = Nothing
        Dim image As GeoImage = Nothing

        Try
            transparentBitmap = New Bitmap(CInt(canvas.Width), CInt(canvas.Height), PixelFormat.Format32bppPArgb)
            tempCanvas.BeginDrawing(transparentBitmap, canvas.CurrentWorldExtent, canvas.MapUnit)

            Dim areaStyle As New AreaStyle(New GeoSolidBrush(GeoColor.StandardColors.Red))

            areaStyle.Draw(features, tempCanvas, labelsInThisLayer, labelsInAllLayers)
            tempCanvas.EndDrawing()
            returnStream = New MemoryStream()
            transparentBitmap.Save(returnStream, ImageFormat.Png)
            returnStream.Seek(0, SeekOrigin.Begin)

            image = New GeoImage(returnStream)

            canvas.DrawScreenImageWithoutScaling(image, canvas.Width / 2, canvas.Height / 2, DrawingLevel.LevelOne, 0, 0, _
                0)
        Finally
            If transparentBitmap IsNot Nothing Then
                transparentBitmap.Dispose()
            End If
            If returnStream IsNot Nothing Then
                returnStream.Dispose()
            End If
            If image IsNot Nothing Then
                image.Dispose()
            End If
        End Try
    End Sub
End Class

Public Class TransparentGdiPlusGeoCanvas
    Inherits GdiPlusGeoCanvas
    Protected Overrides Sub DrawAreaCore(screenPoints As IEnumerable(Of ScreenPointF()), outlinePen As GeoPen, fillBrush As GeoBrush, drawingLevel As DrawingLevel, xOffset As Single, yOffset As Single, _
        penBrushDrawingOrder As PenBrushDrawingOrder)
        If outlinePen IsNot Nothing Then
            outlinePen.Color = New GeoColor(100, outlinePen.Color.RedComponent, outlinePen.Color.GreenComponent, outlinePen.Color.BlueComponent)
        End If

        If TypeOf fillBrush Is GeoSolidBrush Then
            Dim castedFillBrush As GeoSolidBrush = DirectCast(fillBrush, GeoSolidBrush)
            castedFillBrush.Color = New GeoColor(100, castedFillBrush.Color.RedComponent, castedFillBrush.Color.GreenComponent, castedFillBrush.Color.BlueComponent)
        End If
        ' Handle the other brushes

        MyBase.DrawAreaCore(screenPoints, outlinePen, fillBrush, drawingLevel, xOffset, yOffset, _
            penBrushDrawingOrder)
    End Sub

    Protected Overrides Sub DrawEllipseCore(screenPoint As ScreenPointF, width As Single, height As Single, outlinePen As GeoPen, fillBrush As GeoBrush, drawingLevel As DrawingLevel, _
        xOffset As Single, yOffset As Single, penBrushDrawingOrder As PenBrushDrawingOrder)
        If outlinePen IsNot Nothing Then
            outlinePen.Color = New GeoColor(100, outlinePen.Color.RedComponent, outlinePen.Color.GreenComponent, outlinePen.Color.BlueComponent)
        End If

        If TypeOf fillBrush Is GeoSolidBrush Then
            Dim castedFillBrush As GeoSolidBrush = DirectCast(fillBrush, GeoSolidBrush)
            castedFillBrush.Color = New GeoColor(100, castedFillBrush.Color.RedComponent, castedFillBrush.Color.GreenComponent, castedFillBrush.Color.BlueComponent)
        End If
        ' Handle the other brushes

        MyBase.DrawEllipseCore(screenPoint, width, height, outlinePen, fillBrush, drawingLevel, _
            xOffset, yOffset, penBrushDrawingOrder)
    End Sub

    Protected Overrides Sub DrawLineCore(screenPoints As IEnumerable(Of ScreenPointF), linePen As GeoPen, drawingLevel As DrawingLevel, xOffset As Single, yOffset As Single)
        linePen.Color = New GeoColor(100, linePen.Color.RedComponent, linePen.Color.GreenComponent, linePen.Color.BlueComponent)

        MyBase.DrawLineCore(screenPoints, linePen, drawingLevel, xOffset, yOffset)
    End Sub
End Class

   public class TransparentStyle : ThinkGeo.MapSuite.Core.Style
    {

        protected override void DrawCore(System.Collections.Generic.IEnumerable<Feature> features, GeoCanvas canvas, Collection<SimpleCandidate> labelsInThisLayer, Collection<SimpleCandidate> labelsInAllLayers)
        {
            TransparentGdiPlusGeoCanvas tempCanvas = new TransparentGdiPlusGeoCanvas();
            Bitmap transparentBitmap = null;
            Stream returnStream = null;
            GeoImage image = null;

            try
            {
                transparentBitmap = new Bitmap((int)canvas.Width, (int)canvas.Height, PixelFormat.Format32bppPArgb);
                tempCanvas.BeginDrawing(transparentBitmap, canvas.CurrentWorldExtent, canvas.MapUnit);

                AreaStyle areaStyle = new AreaStyle(new GeoSolidBrush(GeoColor.StandardColors.Red));

                areaStyle.Draw(features, tempCanvas, labelsInThisLayer, labelsInAllLayers);
                tempCanvas.EndDrawing();
                returnStream = new MemoryStream();
                transparentBitmap.Save(returnStream, ImageFormat.Png);
                returnStream.Seek(0, SeekOrigin.Begin);

                image = new GeoImage(returnStream);

                canvas.DrawScreenImageWithoutScaling(image, canvas.Width / 2, canvas.Height / 2, DrawingLevel.LevelOne, 0, 0, 0);
            }
            finally
            {
                if (transparentBitmap != null) { transparentBitmap.Dispose(); }
                if (returnStream != null) { returnStream.Dispose(); }
                if (image != null) { image.Dispose(); }
            }
        }
    }

    public class TransparentGdiPlusGeoCanvas : GdiPlusGeoCanvas
    {
        protected override void DrawAreaCore(IEnumerable<ScreenPointF[]> screenPoints, GeoPen outlinePen, GeoBrush fillBrush, DrawingLevel drawingLevel, float xOffset, float yOffset, PenBrushDrawingOrder penBrushDrawingOrder)
        {
            if (outlinePen != null)
                outlinePen.Color = new GeoColor(100, outlinePen.Color.RedComponent, outlinePen.Color.GreenComponent, outlinePen.Color.BlueComponent);

            if (fillBrush is GeoSolidBrush)
            {
                GeoSolidBrush castedFillBrush = (GeoSolidBrush)fillBrush;
                castedFillBrush.Color = new GeoColor(100, castedFillBrush.Color.RedComponent, castedFillBrush.Color.GreenComponent, castedFillBrush.Color.BlueComponent);
            }
            // Handle the other brushes

            base.DrawAreaCore(screenPoints, outlinePen, fillBrush, drawingLevel, xOffset, yOffset, penBrushDrawingOrder);
        }

        protected override void DrawEllipseCore(ScreenPointF screenPoint, float width, float height, GeoPen outlinePen, GeoBrush fillBrush, DrawingLevel drawingLevel, float xOffset, float yOffset, PenBrushDrawingOrder penBrushDrawingOrder)
        {
            if (outlinePen != null)
                outlinePen.Color = new GeoColor(100, outlinePen.Color.RedComponent, outlinePen.Color.GreenComponent, outlinePen.Color.BlueComponent);
            
            if (fillBrush is GeoSolidBrush)
            {
                GeoSolidBrush castedFillBrush = (GeoSolidBrush)fillBrush;
                castedFillBrush.Color = new GeoColor(100, castedFillBrush.Color.RedComponent, castedFillBrush.Color.GreenComponent, castedFillBrush.Color.BlueComponent);
            }
            // Handle the other brushes

            base.DrawEllipseCore(screenPoint, width, height, outlinePen, fillBrush, drawingLevel, xOffset, yOffset, penBrushDrawingOrder);
        }

        protected override void DrawLineCore(IEnumerable<ScreenPointF> screenPoints, GeoPen linePen, DrawingLevel drawingLevel, float xOffset, float yOffset)
        {
            linePen.Color = new GeoColor(100, linePen.Color.RedComponent, linePen.Color.GreenComponent, linePen.Color.BlueComponent);

            base.DrawLineCore(screenPoints, linePen, drawingLevel, xOffset, yOffset);
        }
    }
- Need sample code? Check out the Map Suite Code Community at http://code.thinkgeo.com
Lars I.User is Offline
Level 4
Level 4
Posts:141
Avatar

--
07-06-2012 03:49 PM

Thanks David, I'll look into this as soon as possible.

So what you're essentially saying is, that the GeoCanvas also needs to be transparent, not just all the colors in the AreaStyles ?

Where in your code does the merging of the original canvas and the transparent canvas take place ?

 

Lars I. Nielsen Hvenegaard, DK
Lars I.User is Offline
Level 4
Level 4
Posts:141
Avatar

--
07-11-2012 10:09 AM
David,

Any response to my questions ?

Lars I. Nielsen Hvenegaard, DK
DavidUser is Offline
MVP
MVP
Posts:1534
Avatar

--
07-11-2012 10:19 AM


Lars,

I'm not making the GeoCanvas transparent exactly, what I am doing is inheriting from the GdiPlusGeoCanvas and whenever I get a command to draw something like a polygon I intercept the color and make the color transparent temporary. I do this on a temporary bitmap inside the style. I call the bitmap TransparentBitmap. After I have drawn all of the styles onto that bitmap I call the original canvas, the one passed into the Style.DrawCore and call canvas.DrawScreenImageWithoutScaling and draw the temporary bitmap right int he middle of the real canvas. I happen to make the temporary bitmap transparent so when I composite it on top of the canvas it will still show other things drawn on the canvas.

I you are still having a hard time I can put together a small sample video for you.

David
- Need sample code? Check out the Map Suite Code Community at http://code.thinkgeo.com
Lars I.User is Offline
Level 4
Level 4
Posts:141
Avatar

--
08-09-2012 04:55 AM
Ah,

After closer examination - and after my brain has been rebooted by some weeks of summer vacation relief :-) - I get the idea. Your code sample hard codes the alpha component to be 100, but that's easily made settable with a suitable constructor argument.

Thanks for your effort, David. I'll implement this shortly.
Lars I. Nielsen Hvenegaard, DK
DavidUser is Offline
MVP
MVP
Posts:1534
Avatar

--
08-09-2012 05:07 AM
Lars,

I'm glad it clicked, after reading this I almost forgot I wrote it. :-) It all came back to me so if you do have problems just let me know and I can help. Transparency is a tricky thing as making the pens and brushes transparent is a very different thing than making the composite image transparent.

David
- Need sample code? Check out the Map Suite Code Community at http://code.thinkgeo.com
You are not authorized to post a reply.

Active Forums 4.2