SkiaAntialiasing.vb
C# VB
'''' This code is part of Document Solutions for Imaging demos.'' Copyright (c) MESCIUS inc. All rights reserved.''Imports System.DrawingImports System.IOImports System.LinqImports System.NumericsImports GrapeCity.Documents.DrawingImports GrapeCity.Documents.TextImports GrapeCity.Documents.Imaging.SkiaImports GCTEXT = GrapeCity.Documents.TextImports GCDRAW = GrapeCity.Documents.Drawing
'' Text is always rendered with anti-aliasing in Skia.'' Graphics rendering on the other hand can be controlled by'' setting the GcSkiaGraphics.Aliased property.'' This example shows the difference between shapes drawn'' with that property set to false (which is the default)'' and true. Note the more jagged appearance of some lines'' in the lower part of the image (drawn with Aliased set'' to false).Public Class SkiaAntialiasing Public Shared ReadOnly Property IsSkiaOnly As Boolean = True
Private _font As GCTEXT.Font = Nothing
'' Helper method to draw a polygon and a caption beneath it. '' Can also be used to just calculate the points without actual drawing. '' startAngle is for the first point, clockwise from (1,0). Private Function DrawPolygon(g As GcGraphics, center As PointF, r As Single, n As Integer, startAngle As Single, pen As GCDRAW.Pen, Optional caption As String = Nothing) As PointF() Dim pts As PointF() = New PointF(n - 1) {} For i = 0 To n - 1 pts(i) = New PointF(center.X + CSng(r * Math.Cos(startAngle + 2 * Math.PI * i / n)), center.Y + CSng(r * Math.Sin(startAngle + 2 * Math.PI * i / n))) Next If pen IsNot Nothing Then g.DrawPolygon(pts, pen) End If If Not String.IsNullOrEmpty(caption) Then DrawCaption(g, center, r, caption) End If Return pts End Function
'' Helper method to draw a caption beneath a shape: Private Sub DrawCaption(g As GcGraphics, center As PointF, r As Single, caption As String) g.DrawString(caption, New TextFormat() With { .Font = _font, .FontSize = 12 }, New RectangleF(center.X - r, center.Y - r, r * 2, r * 2), TextAlignment.Center, ParagraphAlignment.Center, False) End Sub
'' Main entry point. Public Function GenerateImageStream(targetMime As String, pixelSize As Size, dpi As Single, opaque As Boolean, Optional sampleParams As String() = Nothing) As Stream Select Case targetMime Case Util.MimeTypes.JPEG, Util.MimeTypes.PNG, Util.MimeTypes.WEBP '' OK Case Else Throw New Exception("This sample uses Skia to create the image, and only supports JPEG, PNG and WEBP output formats.") End Select
_font = GCTEXT.Font.FromFile(Path.Combine("Resources", "Fonts", "FreeSerif.ttf")) Dim Inch = dpi Dim bmp = New GcSkiaBitmap(pixelSize.Width, pixelSize.Height, opaque) Using g = bmp.CreateGraphics(Color.White) DrawShapes(g, bmp.PixelWidth, bmp.PixelHeight, False) DrawShapes(g, bmp.PixelWidth, bmp.PixelHeight, True) End Using
'' Done: Dim ms = New MemoryStream() Select Case targetMime Case Util.MimeTypes.JPEG bmp.SaveAsJpeg(ms) Case Util.MimeTypes.PNG bmp.SaveAsPng(ms) Case Util.MimeTypes.WEBP bmp.SaveAsWebp(ms) Case Else System.Diagnostics.Debug.Assert(False) End Select Return ms End Function
Private Sub DrawShapes(g As GcGraphics, pixelWidth As Integer, pixelHeight As Integer, aliased As Boolean) Dim gskia = TryCast(g, GcSkiaGraphics) If gskia IsNot Nothing Then gskia.Aliased = aliased End If
'' Set up the helper layout grid: Dim Inch = g.Resolution Dim grid = New With { .Cols = 4, .Rows = 3, .MarginX = Inch / 6, .MarginY = Inch / 4, .Radius = Inch * 0.6F, .StepX = (pixelWidth - Inch / 2) / 4, .StepY = (pixelHeight - Inch / 4) / 7F }
'' Insertion point of the next figure's center: Dim startIp As PointF = New PointF(grid.MarginX + grid.StepX / 2, grid.MarginY + grid.StepY / 2 + 10) If aliased Then startIp.Y += pixelHeight \ 2 End If
Dim ip As PointF = startIp
'' Header: Dim pad = 8 Dim bord = New RectangleF(pad, pad + If(aliased, pixelHeight \ 2, 0), pixelWidth - pad * 2, pixelHeight \ 2 - pad * 2) g.DrawString($"Shapes (Skia) - Aliased is {aliased}", New TextFormat() With { .Font = _font, .FontSize = 14 }, bord, TextAlignment.Center, ParagraphAlignment.Near) g.DrawRoundRect(bord, pad, Color.MediumPurple, 2, DashStyle.DashDot)
'' Pen used to draw shapes: Dim pen = New GCDRAW.Pen(Color.Orange, 1) pen.LineJoin = PenLineJoin.Round Dim fill = 100 '' Surfaces fill alpha
'' Circle: g.DrawEllipse(New RectangleF(ip.X - grid.Radius, ip.Y - grid.Radius, grid.Radius * 2, grid.Radius * 2), pen) DrawCaption(g, ip, grid.Radius, "Circle") ip.X += grid.StepX
'' Ellipse: g.DrawEllipse(New RectangleF(ip.X - grid.Radius * 1.4F, ip.Y - grid.Radius / 2, grid.Radius * 2 * 1.4F, grid.Radius), pen) DrawCaption(g, ip, grid.Radius, "Ellipse") ip.X += grid.StepX
'' Cylinder: Dim radX As Single = grid.Radius / 1.4F Dim radY As Single = grid.Radius / 6 Dim height As Single = grid.Radius * 1.8F g.DrawEllipse(New RectangleF(ip.X - radX, ip.Y - height / 2, radX * 2, radY * 2), pen) g.FillEllipse(New RectangleF(ip.X - radX, ip.Y + height / 2 - radY * 2, radX * 2, radY * 2), Color.FromArgb(fill, pen.Color)) g.DrawEllipse(New RectangleF(ip.X - radX, ip.Y + height / 2 - radY * 2, radX * 2, radY * 2), pen) g.DrawLine(New PointF(ip.X - radX, ip.Y - height / 2 + radY), New PointF(ip.X - radX, ip.Y + height / 2 - radY), pen) g.DrawLine(New PointF(ip.X + radX, ip.Y - height / 2 + radY), New PointF(ip.X + radX, ip.Y + height / 2 - radY), pen) DrawCaption(g, ip, grid.Radius, "Cylinder") pen.Color = Color.Indigo ip.X += grid.StepX
'' Cube: Dim cubex As Single = 6 Dim cubePtsFar = DrawPolygon(g, New PointF(ip.X - cubex, ip.Y - cubex), grid.Radius, 4, CSng(-Math.PI) / 4, pen) Dim cubePtsNear = DrawPolygon(g, New PointF(ip.X + cubex, ip.Y + cubex), grid.Radius, 4, CSng(-Math.PI) / 4, pen) g.DrawLine(cubePtsFar(0), cubePtsNear(0), pen) g.DrawLine(cubePtsFar(1), cubePtsNear(1), pen) g.DrawLine(cubePtsFar(2), cubePtsNear(2), pen) g.DrawLine(cubePtsFar(3), cubePtsNear(3), pen) g.FillPolygon(New PointF() {cubePtsFar(1), cubePtsFar(2), cubePtsNear(2), cubePtsNear(1)}, Color.FromArgb(fill, pen.Color)) DrawCaption(g, ip, grid.Radius, "Cube") pen.Color = Color.DarkGreen ip.X = startIp.X ip.Y += grid.StepY
'' Pentagon: DrawPolygon(g, ip, grid.Radius, 5, CSng(-Math.PI) / 2, pen, "Pentagon") ip.X += grid.StepX
'' Hexagon: '' For sample sake, we apply a transform to make the hexagon wider and shorter: g.Transform = Matrix3x2.CreateScale(1.4F, 0.8F) * Matrix3x2.CreateTranslation(ip.X, ip.Y) DrawPolygon(g, PointF.Empty, grid.Radius, 6, 0, pen, Nothing) g.Transform = Matrix3x2.Identity DrawCaption(g, ip, grid.Radius, "Hexagon") ip.X += grid.StepX
'' Octagon: DrawPolygon(g, ip, grid.Radius, 8, CSng(-Math.PI) / 8, pen, "Octagon") pen.Color = Color.DarkRed ip.X += grid.StepX
'' Triangle: DrawPolygon(g, ip, grid.Radius, 3, CSng(-Math.PI) / 2, pen, "Triangle") ip.X = startIp.X ip.Y += grid.StepY
'' Filled pentagram: Dim pts = DrawPolygon(g, ip, grid.Radius, 5, CSng(-Math.PI) / 2, pen, "Pentagram") pts = New PointF() {pts(0), pts(2), pts(4), pts(1), pts(3)} g.FillPolygon(pts, Color.FromArgb(fill, pen.Color)) g.DrawPolygon(pts, pen) ip.X += grid.StepX
'' Set up a simple kind of oblique projection to draw a pyramid: Dim angle = Math.PI / 6 Dim s As Single = CSng(Math.Sin(angle)) Dim c As Single = CSng(Math.Cos(angle)) Dim project As Func(Of Single, Single, Single, PointF) = Function(x_, y_, z_) New PointF(x_ - c * y_ * 0.5F, -(z_ - s * y_ * 0.5F)) Dim p3d As Func(Of Vector3, PointF) = Function(v_) project(v_.X, v_.Y, v_.Z) Dim hedge As Single = grid.Radius '' 1/2 edge '' Debug - draw the 3 axis: '' g.DrawLine(project(0, 0, 0), project(100, 0, 0), Color.Red); '' g.DrawLine(project(0, 0, 0), project(0, 100, 0), Color.Green); '' g.DrawLine(project(0, 0, 0), project(0, 0, 100), Color.Blue); '' 3d points forming a square pyramid: Dim pts3d = New Vector3() { New Vector3(-hedge, -hedge, 0), New Vector3(hedge, -hedge, 0), New Vector3(hedge, hedge, 0), New Vector3(-hedge, hedge, 0), New Vector3(0, 0, hedge * 2) } '' project the points to draw the pyramid: pts = pts3d.Select(Function(v_) p3d(v_)).ToArray() g.Transform = Matrix3x2.CreateTranslation(ip.X, ip.Y + hedge * 0.7F) '' Visible edges: g.DrawPolygon(New PointF() {pts(4), pts(1), pts(2), pts(3), pts(4), pts(2)}, pen) '' Invisible edges: pen.Width /= 2 pen.Color = Color.FromArgb(fill, pen.Color) g.DrawLine(pts(0), pts(4), pen) g.DrawLine(pts(0), pts(1), pen) g.DrawLine(pts(0), pts(3), pen) g.FillPolygon(pts.Take(4).ToArray(), pen.Color) '' g.Transform = Matrix3x2.Identity DrawCaption(g, ip, grid.Radius, "Pyramid") ip.X += grid.StepX pen.Width *= 2 pen.Color = Color.Green
'' Cone: Dim baseh As Single = grid.Radius * 0.3F pts = DrawPolygon(g, ip, grid.Radius, 3, CSng(-Math.PI) / 2, Nothing, "Cone") g.DrawLines(New PointF() {pts(2), pts(0), pts(1)}, pen) Dim rect = New RectangleF(pts(2).X, pts(2).Y - baseh / 2, pts(1).X - pts(2).X, baseh) g.FillEllipse(rect, Color.FromArgb(fill, pen.Color)) g.DrawEllipse(rect, pen) ip.X += grid.StepX
'' Trapezoid (use DrawPolygon to just get the points of the square): Dim dx As Single = 10 pts = DrawPolygon(g, ip, grid.Radius, 4, CSng(-Math.PI) / 4, Nothing, "Trapezoid") pts(0).X -= dx pts(1).X += dx pts(2).X -= dx pts(3).X += dx g.DrawPolygon(pts, pen) End SubEnd Class