SvgMergedShapes.vb
'' '' This code is part of Document Solutions for Imaging demos. '' Copyright (c) MESCIUS inc. All rights reserved. '' Imports System Imports System.IO Imports System.Drawing Imports System.Collections.Generic Imports System.Linq Imports System.Numerics Imports System.Xml Imports GrapeCity.Documents.Drawing Imports GrapeCity.Documents.Text Imports GrapeCity.Documents.Imaging Imports GrapeCity.Documents.Svg '' This example shows how to combine SVG elements to create clipping paths '' that are used to effectively merge geometric figures. '' Parts of the image are associated with SVG title elements which show '' as tooltips if the SVG is displayed in a browser. Public Class SvgMergedShapes Public ReadOnly Property DefaultMime As String Get Return Util.MimeTypes.SVG End Get End Property Public Function GenerateImageStream( ByVal targetMime As String, ByVal pixelSize As Size, ByVal dpi As Single, ByVal opaque As Boolean, Optional ByVal sampleParams As String() = Nothing) As Stream If targetMime <> Util.MimeTypes.SVG Then Throw New Exception("This sample only supports SVG output format.") End If Using svgDoc As New GcSvgDocument() Dim svg = svgDoc.RootSvg Dim items = svg.Children Dim width = New SvgLength(pixelSize.Width) Dim height = New SvgLength(pixelSize.Height) svg.Width = width svg.Height = height '' Root title: Dim title = New SvgTitleElement() items.Add(title) title.Children.Add(New SvgContentElement(XmlNodeType.Text) With { .Content = "Root SVG Title" }) '' Root bounds: Dim bounds = New SvgRectElement() With { .X = New SvgLength(0), .Y = New SvgLength(0), .Width = width, .Height = height, .Stroke = New SvgPaint(New SvgColor(Color.DarkBlue)), .Fill = New SvgPaint(New SvgColor(Color.DarkSeaGreen)) } items.Add(bounds) '' Geometry: Dim centerX As Single = 200.0F Dim centerY As Single = 200.0F Dim radius As Single = 190.0F Dim polyWidth As Single = 180.0F Dim polyHeight As Single = 320.0F Dim polyD As Single = 30.0F Dim pad As Single = 10.0F '' We add an outer group to hold everything else, '' so that it can be easily positioned within the overall bounds: Dim outerGroup = New SvgGroupElement() items.Add(outerGroup) items = outerGroup.Children '' Center the group: Dim outerGroupTranslateX = New SvgLength(pixelSize.Width / 2.0F - centerX) Dim outerGroupTranslateY = New SvgLength(pixelSize.Height / 2.0F - centerY - polyHeight / 2.0F) outerGroup.Transform = New List(Of SvgTransform) From { New SvgTranslateTransform() With {.TranslateX = outerGroupTranslateX, .TranslateY = outerGroupTranslateY} } '' Add a 'defs' element containing clipPath elements '' that will be used to merge various geometric figures '' to provide a complex clipping path: Dim defs = New SvgDefsElement() items.Add(defs) '' Create the outer clip built by adding a circle and a polygon '' resembling an inverted keystone, so that the union of the two figures '' looks like a keyhole: Dim clipPathOuter = New SvgClipPathElement() With {.ID = "outerClip"} defs.Children.Add(clipPathOuter) clipPathOuter.Children.Add(New SvgCircleElement() With { .CenterX = New SvgLength(centerX), .CenterY = New SvgLength(centerY), .Radius = New SvgLength(radius) }) clipPathOuter.Children.Add(New SvgPolygonElement() With { .Points = New List(Of SvgPoint) From { New SvgPoint(New SvgLength(centerX - polyWidth / 2.0F), New SvgLength(centerY + radius * 0.8F)), New SvgPoint(New SvgLength(centerX - polyWidth / 2.0F - polyD), New SvgLength(centerY + radius + polyHeight)), New SvgPoint(New SvgLength(centerX + polyWidth / 2.0F + polyD), New SvgLength(centerY + radius + polyHeight)), New SvgPoint(New SvgLength(centerX + polyWidth / 2.0F), New SvgLength(centerY + radius * 0.8F)) } }) '' Create the inner clip by adding a smaller circle and a rectangle '' that is smaller than the keystone polygon: Dim clipPathInner = New SvgClipPathElement() With {.ID = "innerClip"} defs.Children.Add(clipPathInner) clipPathInner.Children.Add(New SvgCircleElement() With { .CenterX = New SvgLength(centerX), .CenterY = New SvgLength(centerY), .Radius = New SvgLength(radius - pad) }) clipPathInner.Children.Add(New SvgRectElement() With { .X = New SvgLength(centerX - polyWidth / 2.0F + pad), .Y = New SvgLength(centerY + radius * 0.8F), .Width = New SvgLength(polyWidth - pad * 2.0F), .Height = New SvgLength(polyHeight - pad * 2.0F) }) '' A filled rectangle taking up the whole SVG area (100%x100%) '' but clipped by the "outerClip" figure: Dim rcOuter = New SvgRectElement() With { .Width = New SvgLength(width.Value - outerGroupTranslateX.Value), .Height = New SvgLength(height.Value - outerGroupTranslateY.Value), .Fill = New SvgPaint(Color.DarkBlue), .ClipPath = New SvgReference("outerClip") } items.Add(rcOuter) Dim descR = New SvgTitleElement() descR.Children.Add(New SvgContentElement(XmlNodeType.Text) With { .Content = "Title of the dark blue rectangle" }) rcOuter.Children.Add(descR) '' Group clipped by the "innerClip", this will contain '' a yellow fill and a rotated semi-transparent raster image: Dim groupEl = New SvgGroupElement() With { .ClipPath = New SvgReference("innerClip") } items.Add(groupEl) '' We add to the group clipped by "innerClip" '' a filled rectangle taking up the whole area (100%x100%): Dim rcInner = New SvgRectElement() With { .Width = New SvgLength(width.Value - outerGroupTranslateX.Value), .Height = New SvgLength(height.Value - outerGroupTranslateY.Value), .Fill = New SvgPaint(Color.DarkOrange) } groupEl.Children.Add(rcInner) Dim desc = New SvgTitleElement() rcInner.Children.Add(desc) desc.Children.Add(New SvgContentElement(XmlNodeType.Text) With { .Content = "Title of the dark orange rectangle" }) '' We also add to the group an image that is rotated '' and drawn semi-transparently: Dim imagePath = Path.Combine("Resources", "Images", "colosseum-resized.jpg") Dim bmp = New GcBitmap(imagePath) Dim imgTranslateX = New SvgLength(188) Dim imgTranslateY = New SvgLength(-55) Dim img = New SvgImageElement() With { .Href = New SvgReference(bmp, True) With {.InJpegFormat = True}, .Width = New SvgLength(400), .Height = New SvgLength(525), .Transform = New List(Of SvgTransform) From { New SvgTranslateTransform() With {.TranslateX = imgTranslateX, .TranslateY = imgTranslateY}, New SvgRotateTransform() With {.Angle = New SvgAngle(30)} }, .Opacity = 0.8F } groupEl.Children.Add(img) Dim descImg = New SvgTitleElement() img.Children.Add(descImg) descImg.Children.Add(New SvgContentElement(XmlNodeType.Text) With { .Content = "Title of the image" }) '' Save SVG to the output Stream Dim ms As New MemoryStream() svgDoc.Save(ms, New XmlWriterSettings() With {.Indent = True}) ms.Seek(0, SeekOrigin.Begin) Return ms End Using End Function End Class