SvgToGrayscale.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 GrapeCity.Documents.Drawing
Imports GrapeCity.Documents.Text
Imports GrapeCity.Documents.Imaging
Imports GrapeCity.Documents.Svg
Imports GCTEXT = GrapeCity.Documents.Text
Imports GCDRAW = GrapeCity.Documents.Drawing

'' This sample is similar to SvgClipArt, but after loading each SVG image
'' it converts all strokes and fills in it to grayscale.
''
'' The SVG clip art used in this sample is from freesvg.org.
Public Class SvgToGrayscale
    Private Sub ToGrayscale(elements As SvgElementCollection)
        For Each el In elements
            If TypeOf el Is SvgGraphicsElement Then
                Dim elg = DirectCast(el, SvgGraphicsElement)
                elg.Stroke = PaintToGrayscale(elg.Stroke)
                elg.Fill = PaintToGrayscale(elg.Fill)
            End If
            ToGrayscale(el.Children)
        Next
    End Sub

    '' Simplified conversion of an SvgPaint to grayscale
    '' (Y formula from https://goodcalculators.com/rgb-to-grayscale-conversion-calculator/):
    Private Function PaintToGrayscale(src As SvgPaint) As SvgPaint
        If src Is Nothing Then
            Return Nothing
        ElseIf src.PaintType = SvgPaintType.Color Then
            Dim rgb = src.Color.Rgb
            Dim Y As Integer = CInt(Math.Round(0.299 * rgb.R + 0.587 * rgb.G + 0.114 * rgb.B))
            Return New SvgPaint(Color.FromArgb(Y, Y, Y))
        Else
            Return New SvgPaint(Color.Gray)
        End If
    End Function

    '' Main entry point.
    Public Function GenerateImage(pixelSize As Size, dpi As Single, opaque As Boolean, Optional sampleParams As String() = Nothing) As GcBitmap
        Const rows As Integer = 4
        Const cols As Integer = 4
        Dim margin As Single = dpi / 2.0F
        Dim sMargin As Single = margin / 4.0F

        '' Load images from the resources folder:
        Dim fnames As New List(Of String)(Directory.GetFiles(Path.Combine("Resources", "SvgClipArt"), "*", SearchOption.AllDirectories))
        fnames.Shuffle()

        Dim images As New List(Of Tuple(Of String, GcSvgDocument))()
        For Each fname In fnames.Take(rows * cols)
            Dim svg = GcSvgDocument.FromFile(fname)
            ToGrayscale(svg.RootSvg.Children)
            images.Add(Tuple.Create(Path.GetFileName(fname), svg))
        Next

        '' Font and format for captions:
        Dim font = GCTEXT.Font.FromFile(Path.Combine("Resources", "Fonts", "FreeSans.ttf"))
        Dim tf = New TextFormat() With {.Font = font, .FontSize = sMargin * 0.65F}

        '' Set up a 4x4 layout grid:
        Dim gapx As Single = margin / 4.0F, gapy As Single = gapx
        Dim sWidth As Single = (pixelSize.Width - margin * 2 + gapx) / cols
        Dim sHeight As Single = (pixelSize.Height - margin * 2 + gapy) / rows
        If sWidth > sHeight Then
            gapx += sWidth - sHeight
            sWidth = sHeight
        Else
            gapy += sHeight - sWidth
            sHeight = sWidth
        End If
        Dim ip As New PointF(margin, margin)

        '' Resulting bitmap:
        Dim bmp = New GcBitmap(pixelSize.Width, pixelSize.Height, opaque, dpi, dpi)

        '' Render all images within the grid:
        Using g = bmp.CreateGraphics(Color.White)
            For i As Integer = 0 To images.Count() - 1
                '' Draw border around image:
                Dim rect As New RectangleF(ip, New SizeF(sWidth - gapx, sHeight - gapy))
                g.FillRectangle(rect, Color.LightGray)
                g.DrawRectangle(rect, Color.Black, 0.5F)
                rect.Inflate(-sMargin, -sMargin)

                '' Draw the SVG:
                Dim svg = images(i).Item2
                Dim s = svg.GetIntrinsicSize(SvgLengthUnits.Points)
                If s.Width > 0 AndAlso s.Height > 0 Then
                    '' If image proportions are different from our target rectangle,
                    '' we resize the rectangle centering the image in it:
                    Dim qSrc = s.Width / s.Height
                    Dim qTgt = rect.Width / rect.Height
                    If qSrc < qTgt Then
                        rect.Inflate(rect.Width * (qSrc / qTgt - 1) / 2.0F, 0)
                    ElseIf qSrc > qTgt Then
                        rect.Inflate(0, rect.Height * (qTgt / qSrc - 1) / 2.0F)
                    End If
                End If
                '' Render the SVG:
                g.DrawSvg(svg, rect)

                '' Print image file name as caption in the bottom slide margin:
                g.DrawString(Path.GetFileName(images(i).Item1), tf,
                             New RectangleF(rect.X, rect.Bottom, rect.Width, sMargin),
                             TextAlignment.Center, ParagraphAlignment.Near, False)

                ip.X += sWidth
                If (ip.X + sWidth > pixelSize.Width) AndAlso (i < images.Count() - 1) Then
                    ip.X = margin
                    ip.Y += sHeight
                End If
            Next
        End Using

        '' Dispose images after saving the result:
        images.ForEach(Sub(t_) t_.Item2.Dispose())

        '' Done:
        Return bmp
    End Function
End Class