//
// This code is part of Document Solutions for Imaging demos.
// Copyright (c) MESCIUS inc. All rights reserved.
//
using System;
using System.IO;
using System.Drawing;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using GrapeCity.Documents.Drawing;
using GrapeCity.Documents.Text;
using GrapeCity.Documents.Imaging;
using GrapeCity.Documents.Svg;
using DsImagingWeb.Demos.Common;
using System.Xml;
namespace DsImagingWeb.Demos
{
// 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 string DefaultMime { get => Common.Util.MimeTypes.SVG; }
public Stream GenerateImageStream(string targetMime, Size pixelSize, float dpi, bool opaque, string[] sampleParams = null)
{
if (targetMime != Common.Util.MimeTypes.SVG)
throw new Exception("This sample only supports SVG output format.");
using var svgDoc = new GcSvgDocument();
var svg = svgDoc.RootSvg;
var items = svg.Children;
var width = new SvgLength(pixelSize.Width);
var height = new SvgLength(pixelSize.Height);
svg.Width = width;
svg.Height = height;
// Root title:
var title = new SvgTitleElement();
items.Add(title);
title.Children.Add(new SvgContentElement(XmlNodeType.Text)
{
Content = "Root SVG Title"
});
// Root bounds:
var bounds = new SvgRectElement()
{
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:
float
centerX = 200,
centerY = 200,
radius = 190,
polyWidth = 180,
polyHeight = 320,
polyD = 30,
pad = 10;
// We add an outer group to hold everything else,
// so that it can be easily positioned within the overall bounds:
var outerGroup = new SvgGroupElement();
items.Add(outerGroup);
items = outerGroup.Children;
// Center the group:
var outerGroupTranslateX = new SvgLength(pixelSize.Width / 2 - centerX);
var outerGroupTranslateY = new SvgLength(pixelSize.Height / 2 - centerY - polyHeight / 2);
outerGroup.Transform = new List<SvgTransform>()
{
new SvgTranslateTransform() { 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:
var 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:
var clipPathOuter = new SvgClipPathElement() { ID = "outerClip" };
defs.Children.Add(clipPathOuter);
clipPathOuter.Children.Add(new SvgCircleElement()
{
CenterX = new SvgLength(centerX),
CenterY = new SvgLength(centerY),
Radius = new SvgLength(radius)
});
clipPathOuter.Children.Add(new SvgPolygonElement()
{
Points = new List<SvgPoint>()
{
new SvgPoint(new SvgLength(centerX - polyWidth / 2), new SvgLength(centerY + radius * 0.8f)),
new SvgPoint(new SvgLength(centerX - polyWidth / 2 - polyD), new SvgLength(centerY + radius + polyHeight)),
new SvgPoint(new SvgLength(centerX + polyWidth / 2 + polyD), new SvgLength(centerY + radius + polyHeight)),
new SvgPoint(new SvgLength(centerX + polyWidth / 2), 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:
var clipPathInner = new SvgClipPathElement() { ID = "innerClip" };
defs.Children.Add(clipPathInner);
clipPathInner.Children.Add(new SvgCircleElement()
{
CenterX = new SvgLength(centerX),
CenterY = new SvgLength(centerY),
Radius = new SvgLength(radius - pad)
});
clipPathInner.Children.Add(new SvgRectElement()
{
X = new SvgLength(centerX - polyWidth / 2 + pad),
Y = new SvgLength(centerY + radius * 0.8f),
Width = new SvgLength(polyWidth - pad * 2),
Height = new SvgLength(polyHeight - pad * 2)
});
// A filled rectangle taking up the whole SVG area (100%x100%)
// but clipped by the "outerClip" figure:
var rcOuter = new SvgRectElement()
{
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);
var descR = new SvgTitleElement();
descR.Children.Add(new SvgContentElement(XmlNodeType.Text)
{
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:
var group = new SvgGroupElement()
{
ClipPath = new SvgReference("innerClip")
};
items.Add(group);
// We add to the group clipped by "innerClip"
// a filled rectangle taking up the whole area (100%x100%):
var rcInner = new SvgRectElement()
{
Width = new SvgLength(width.Value - outerGroupTranslateX.Value),
Height = new SvgLength(height.Value - outerGroupTranslateY.Value),
Fill = new SvgPaint(Color.DarkOrange),
};
group.Children.Add(rcInner);
var desc = new SvgTitleElement();
rcInner.Children.Add(desc);
desc.Children.Add(new SvgContentElement(XmlNodeType.Text)
{
Content = "Title of the dark orange rectangle"
});
// We also add to the group an image that is rotated
// and drawn semi-transparently:
var imagePath = Path.Combine("Resources", "Images", "colosseum-resized.jpg");
var bmp = new GcBitmap(imagePath);
var imgTranslateX = new SvgLength(188);
var imgTranslateY = new SvgLength(-55);
var img = new SvgImageElement()
{
Href = new SvgReference(bmp, true) { InJpegFormat = true },
Width = new SvgLength(400),
Height = new SvgLength(525),
Transform = new List<SvgTransform>()
{
new SvgTranslateTransform() { TranslateX = imgTranslateX, TranslateY = imgTranslateY },
new SvgRotateTransform() { Angle = new SvgAngle(30) }
},
Opacity = 0.8f,
};
group.Children.Add(img);
var descImg = new SvgTitleElement();
img.Children.Add(descImg);
descImg.Children.Add(new SvgContentElement(XmlNodeType.Text)
{
Content = "Title of the image"
});
// Save SVG to the output Stream
var ms = new MemoryStream();
svgDoc.Save(ms, new XmlWriterSettings() { Indent = true });
ms.Seek(0, SeekOrigin.Begin);
return ms;
}
}
}