SvgToGrayscale.vb
''
'' このコードは、DioDocs for Imaging のサンプルの一部として提供されています。
'' © 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
'' @このサンプルは @{SvgClipArt} と類似していますが、
'' 各 SVG 画像を読み込んだ後、すべてのストロークおよび塗りつぶしをグレースケールに変換します。
''
'' 本サンプルで使用している SVG のクリップアートは、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
'' SvgPaintをグレースケールに変換するための簡易的なメソッド
'' (Yの計算式は 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
'' メインのエントリポイント
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
'' リソースフォルダから画像を読み込みます。
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
'' キャプション用のフォントと書式を設定します。
Dim font = GCTEXT.Font.FromFile(Path.Combine("Resources", "Fonts", "FreeSans.ttf"))
Dim tf = New TextFormat() With {.Font = font, .FontSize = sMargin * 0.65F}
'' 4x4のレイアウトグリッドを設定します。
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)
'' 結果として出力されるビットマップ
Dim bmp = New GcBitmap(pixelSize.Width, pixelSize.Height, opaque, dpi, dpi)
'' グリッド内にすべてのサンプル画像を描画します。
Using g = bmp.CreateGraphics(Color.White)
For i As Integer = 0 To images.Count() - 1
'' サンプル画像の周囲に境界線を描画します。
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)
'' SVGを描画します。
Dim svg = images(i).Item2
Dim s = svg.GetIntrinsicSize(SvgLengthUnits.Points)
If s.Width > 0 AndAlso s.Height > 0 Then
'' サンプル画像の比率がターゲットとなる矩形と異なる場合、
'' 矩形内の中央に配置されるように矩形をリサイズします。
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
'' SVGを描画します。
g.DrawSvg(svg, rect)
'' 下側の余白に画像ファイル名をキャプションとして描画します。
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
'' 結果を保存した後、画像を破棄します。
images.ForEach(Sub(t_) t_.Item2.Dispose())
Return bmp
End Function
End Class