SvgToGrayscale.cs
//
// このコードは、DioDocs for Imaging のサンプルの一部として提供されています。
// © 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 GCTEXT = GrapeCity.Documents.Text;
using GCDRAW = GrapeCity.Documents.Drawing;
using DsImagingWeb.Demos.Common;
namespace DsImagingWeb.Demos
{
// @このサンプルは @{SvgClipArt} と類似していますが、
// 各 SVG 画像を読み込んだ後、すべてのストロークおよび塗りつぶしをグレースケールに変換します。
//
// 本サンプルで使用している SVG のクリップアートは、freesvg.orgから提供されたものです。
public class SvgToGrayscale
{
void ToGrayscale(SvgElementCollection elements)
{
foreach (var el in elements)
{
if (el is SvgGraphicsElement elg)
{
elg.Stroke = PaintToGrayscale(elg.Stroke);
elg.Fill = PaintToGrayscale(elg.Fill);
}
ToGrayscale(el.Children);
}
}
// SvgPaintをグレースケールに変換するための簡易的なメソッド
// (Yの計算式は https://goodcalculators.com/rgb-to-grayscale-conversion-calculator/ に基づいています。)
SvgPaint PaintToGrayscale(SvgPaint src)
{
if (src == null)
return null;
else if (src.PaintType == SvgPaintType.Color)
{
var rgb = src.Color.Rgb;
var Y = (int)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);
}
}
// メインのエントリポイント
public GcBitmap GenerateImage(Size pixelSize, float dpi, bool opaque, string[] sampleParams = null)
{
const int rows = 4;
const int cols = 4;
float margin = dpi / 2;
float sMargin = margin / 4;
// リソースフォルダから画像を読み込みます。
var fnames = new List<string>(Directory.GetFiles(Path.Combine("Resources", "SvgClipArt"), "*", SearchOption.AllDirectories));
fnames.Shuffle();
var images = new List<(string, GcSvgDocument)>();
foreach (var fname in fnames.Take(rows * cols))
{
var svg = GcSvgDocument.FromFile(fname);
ToGrayscale(svg.RootSvg.Children);
images.Add((Path.GetFileName(fname), svg));
}
// キャプション用のフォントと書式を設定します。
var font = GCTEXT.Font.FromFile(Path.Combine("Resources", "Fonts", "FreeSans.ttf"));
var tf = new TextFormat() { Font = font, FontSize = sMargin * 0.65f };
// 4x4のレイアウトグリッドを設定します。
float gapx = margin / 4, gapy = gapx;
float sWidth = (pixelSize.Width - margin * 2 + gapx) / cols;
float sHeight = (pixelSize.Height - margin * 2 + gapy) / rows;
if (sWidth > sHeight)
{
gapx += sWidth - sHeight;
sWidth = sHeight;
}
else
{
gapy += sHeight - sWidth;
sHeight = sWidth;
}
var ip = new PointF(margin, margin);
// 結果として出力されるビットマップ
var bmp = new GcBitmap(pixelSize.Width, pixelSize.Height, opaque, dpi, dpi);
// グリッド内にすべてのサンプル画像を描画します。必要に応じて新しいページを追加します。
using var g = bmp.CreateGraphics(Color.White);
for (int i = 0; i < images.Count(); ++i)
{
// サンプル画像の周囲に境界線を描画します。
var rect = 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を描画します。
var svg = images[i].Item2;
var s = svg.GetIntrinsicSize(SvgLengthUnits.Points);
if (s.Width > 0 && s.Height > 0)
{
// サンプル画像の比率がターゲットとなる矩形と異なる場合、
// 矩形内の中央に配置されるように矩形をリサイズします。
var qSrc = s.Width / s.Height;
var qTgt = rect.Width / rect.Height;
if (qSrc < qTgt)
rect.Inflate(rect.Width * (qSrc / qTgt - 1) / 2, 0);
else if (qSrc > qTgt)
rect.Inflate(0, rect.Height * (qTgt / qSrc - 1) / 2);
}
// 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 && i < images.Count() - 1)
{
ip.X = margin;
ip.Y += sHeight;
}
}
// 結果を保存した後、画像を破棄します。
images.ForEach(t_ => t_.Item2.Dispose());
return bmp;
}
}
}