ここから本文です
ベランダ菜園とWindows用アプリ作成とExcel用アプリ(アドイン)作成

書庫全体表示

記事検索
検索
イメージ 1
できた



イメージ 2
アプリのウィンドウに画像ファイルをドロップで

イメージ 3
画像とその色相のグラフが表示される


色相範囲分割数
イメージ 4
12分割は360/12=30度区切り

イメージ 5
360分割、こっちのほうがより正確なはず、だけど見た目的には72くらいが面白いかな



イメージ 6
色相がない無彩色画像は

イメージ 7
グラフが表示されない



イメージ 8
色相0(赤)の単色画像の
12分割表示
イメージ 9
360/12=30度区切りになって
色相0の範囲は、0を中心にプラスマイナス15度なので
0-15=-15=-15+360=345
0+15=15
345度から時計回りに15度までの範囲で表示している

360分割表示だと
イメージ 10
359.5〜0.5度になっているはず


イメージ 11
色相90のSVグラデーション

イメージ 12
中心付近が太くなっているから色相90から少し外れた色があるみたい
これはHSVとRGBの変換誤差なのかも


イメージ 13
いつもの画像

12分割
イメージ 14
いいねえ、真円に近い
でも

72分割
イメージ 15
がたがたになる

360分割で詳しく
イメージ 16
やっぱりこの画像はこうなっているんだなあ

720分割
イメージ 17



前回はレーダーチャートふうに表示してイマイチだった
イメージ 18
これと同じ画像を同じ360分割で

イメージ 19
いいねえ

イメージ 20
こういうのを表示してみたかった
表示方法は前回のレーダーチャートとほとんど同じ、違うのは切り抜き方を扇形(パイ型)にしただけなんだよねえ


イメージ 27
イメージ 28
青系は全体の10〜20%って言われるとあっているけど、少なく見えるのは中心からの距離が遠いほどグラフの面積が大きくなるからだねえ

イメージ 29
これももっと緑が多くてもいいような
もしかして扇形(パイ型)じゃなくて円や四角形のほうがいいのかも?


今回に至るまで
色相分割範囲ごとにピクセル数を集計する方法は
2019/4/1は3日前の
画像の色相の状態をレーダーチャートふうに表示してみた ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
https://blogs.yahoo.co.jp/gogowaten/15920156.html
イメージ 24
このときのを元に

色相の集計と仕分け
イメージ 25
266行目のGetHueListの
引数PixelsはBitmapSourceクラスのCopyPixelsで得られる色情報byte配列、今回もPixelFormatsはBgra32だけが対象
RGBからHSVの変換にはMyHSV.DLLファイルを参照に追加したものを使っている、273行目
これで全ピクセルの色相のリスト完成
これをもとに切り抜き用のPathGeometryを作る


この画像を扇形(パイ型)に切り抜くための
PathGeometryを作成は
2019/4/3は昨日の
WPFで図形の円弧☽🌛、🍕扇形パイ形、🍩ドーナツ型(アーチ形)を表示してみた、ArcSegment ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
https://blogs.yahoo.co.jp/gogowaten/15922445.html
イメージ 22
分割範囲ごとの扇形(パイ型)PathGeometryを作成して、全部を連結

さっきの色相リストをMakeClipに渡して作成
イメージ 26
MyRadiusは切り抜く画像の半径
98行目、扇形(パイ型)PathGeometry作成のPieGeometryは昨日と全く同じ
連結は98行目PathGeometryクラスのAddGeometryメソッドを使ってできたので

2019/4/2はおとといのこれは必要なかった
切り抜きClip、GeometryGroupとCombinedGeometry ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
https://blogs.yahoo.co.jp/gogowaten/15921152.html
イメージ 23
必要なかった



扇形(パイ型)を連結したPathGeometryで切り抜きClipする色相環画像作成は
2019/3/25は10日前の
色相環画像作成、WriteableBitmapとImage.Clip ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
https://blogs.yahoo.co.jp/gogowaten/15913863.html
イメージ 21
この色相環画像を表示したImageのClipに指定すれば完成になる



ギットハブ
こういうグラフの名前がわからないから棒グラフになっている

アプリダウンロード先(ヤフーボックス)





デザイン画面
イメージ 30


MainWindow.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using MyHSV;

namespace _20190402_色相円の棒グラフ
{
public partial class MainWindow : Window
{

const double MyRadius = 200.0;//色相画像半径
Point MyCenter = new Point(MyRadius, MyRadius);//色相画像中心座標
byte[] MyPixels;//画像のPixelの色情報、BitmapSourceのCopyPixelsより
double[] MyHuesList;//全ピクセルの色相の配列
int DivideCount = 120;//色相分割数

public MainWindow()
{
InitializeComponent();

this.AllowDrop = true;
Drop += MainWindow_Drop;

MyGrid.Children.Add(MakeAuxLine(MyCenter));
MyHueImage.Source = MakeHueBitmap((int)(MyRadius * 2));
MyHueImage.Clip = new RectangleGeometry(new Rect(0, 0, 0, 0));


}

#region イベント
private void RadioButton_Click(object sender, RoutedEventArgs e)
{
if (MyPixels == null) { return; }
RadioButton rb = sender as RadioButton;
int divCount = int.Parse((string)rb.Content);
DivideCount = divCount;
MyHueImage.Clip = MakeClip(HuePixelCount(MyHuesList, divCount));
}

private void MainWindow_Drop(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.FileDrop) == false) { return; }
string[] filePath = (string[])e.Data.GetData(DataFormats.FileDrop);
var (pixels, bitmap) = MakeBitmapSourceAndByteArray(filePath[0], PixelFormats.Bgra32, 96, 96);

if (bitmap == null)
{
MessageBox.Show("画像ファイルじゃないみたい");
}
else
{
MyPixels = pixels;
MyHuesList = GetHueList(pixels);
var neko = HuePixelCount(MyHuesList, DivideCount);
MyHueImage.Clip = MakeClip(neko);
MyImage.Source = bitmap;
}
}
#endregion


//色相範囲ごとに仕分けられたListから🍕pie形のPathGeometry作成
private Geometry MakeClip(int[] hues)
{
double max = hues.Max();
Point center = new Point(MyRadius, MyRadius);

double divDeg = 360.0 / hues.Length;//位置分割あたりの角度
double divdivDeg = divDeg / 2.0;//その半分の角度
//各分割角度を中心にして、そこから均等に左右に分けるために使う
var clip = new PathGeometry();
clip.FillRule = FillRule.Nonzero;
for (int i = 0; i < hues.Length; i++)
{
var distance = hues[i] / max * MyRadius;//最大値からの割合を距離にする
var centerDeg = i * divDeg;//範囲の中間角度、配列のIndexが色相(角度)の割合になっている
var start = centerDeg - divdivDeg;//範囲の半分の角度マイナスが開始角度になる
var stop = start + divDeg;
//🍕PathGeometry作成して追加
clip.AddGeometry(PieGeometry(center, distance, start, stop, SweepDirection.Clockwise));
}
return clip;
}

//補助線表示用のPath作成
private Path MakeAuxLine(Point center)
{

var pg = new PathGeometry();
pg.AddGeometry(new EllipseGeometry(center, center.X, center.Y));
pg.AddGeometry(new EllipseGeometry(center, center.X * 3.0 / 4.0, center.Y * 3.0 / 4.0));
pg.AddGeometry(new EllipseGeometry(center, center.X / 2.0, center.Y / 2.0));
pg.AddGeometry(new EllipseGeometry(center, center.X / 4.0, center.Y / 4.0));
var p = new Path();
p.Stroke = Brushes.LightGray;
p.StrokeThickness = 1.0;
p.Opacity = 0.4;
p.Data = pg;

return p;
}



#region PathGeometry

//完成形、回転方向を指定できるように
/// <summary>
/// 扇(pie)型のPathGeometryを作成
/// </summary>
/// <param name="center">中心座標</param>
/// <param name="distance">中心点からの距離</param>
/// <param name="startDegrees">開始角度、0以上360以下で指定</param>
/// <param name="stopDegrees">終了角度、0以上360以下で指定</param>
/// <param name="direction">回転方向、Clockwiseが時計回り</param>
/// <returns></returns>
private PathGeometry PieGeometry(Point center, double distance, double startDegrees, double stopDegrees, SweepDirection direction)
{
Point start = MakePoint(startDegrees, center, distance);//始点座標
Point stop = MakePoint(stopDegrees, center, distance);//終点座標
//開始角度から終了角度までが180度を超えているかの判定
//超えていたらArcSegmentのIsLargeArcをtrue、なければfalseで作成
double diffDegrees = (direction == SweepDirection.Clockwise) ? stopDegrees - startDegrees : startDegrees - stopDegrees;
if (diffDegrees < 0) { diffDegrees += 360.0; }
bool isLarge = (diffDegrees >= 180) ? true : false;
var arc = new ArcSegment(stop, new Size(distance, distance), 0, isLarge, direction, true);

//PathFigure作成
//ArcSegmentとその両端と中心点をつなぐ直線LineSegment
var fig = new PathFigure();
fig.StartPoint = start;//始点座標
fig.Segments.Add(arc);//ArcSegment追加
fig.Segments.Add(new LineSegment(center, true));//円弧の終点から中心への直線
fig.Segments.Add(new LineSegment(start, true));//中心から円弧の始点への直線
fig.IsClosed = true;//Pathを閉じる、必須

//PathGeometryを作成してPathFigureを追加して完成
var pg = new PathGeometry();
pg.Figures.Add(fig);
return pg;
}


/// <summary>
/// 距離と角度からその座標を返す
/// </summary>
/// <param name="degrees">360以上は359.99になる</param>
/// <param name="center">中心点</param>
/// <param name="distance">中心点からの距離</param>
/// <returns></returns>
private Point MakePoint(double degrees, Point center, double distance)
{
if (degrees >= 360) { degrees = 359.99; }
var rad = Radian(degrees);
var cos = Math.Cos(rad);
var sin = Math.Sin(rad);
var x = center.X + cos * distance;
var y = center.Y + sin * distance;
return new Point(x, y);
}

private double Radian(double degree)
{
return Math.PI / 180.0 * degree;
}

#endregion

#region 色相環
/// <summary>
/// pixelsFormats.Rgb24の色相環作成用のBitmap作成
/// 右が赤、時計回り
/// </summary>
/// <param name="size"></param>
/// <returns></returns>
private BitmapSource MakeHueBitmap(int size)
{
var wb = new WriteableBitmap(size, size, 96, 96, PixelFormats.Rgb24, null);
//色情報用のバイト配列作成
int stride = wb.BackBufferStride;//横一列のバイト数、24bit = 8byteに横ピクセル数をかけた値
byte[] pixels = new byte[size * stride * 8];//*8はbyteをbitにするから

//100x100のとき中心は50,50
//ピクセル位置と画像の中心との差
double xDiff = size / 2.0;
double yDiff = size / 2.0;
int p = 0;//今のピクセル位置の配列での位置
for (int y = 0; y < size; y++)//y座標
{
for (int x = 0; x < size; x++)//x座標
{
//今の位置の角度を取得、これが色相になる
double radian = Math.Atan2(y - yDiff, x - xDiff);
double kakudo = Degrees(radian);
//色相をColorに変換
Color c = HSV.HSV2Color(kakudo, 1.0, 1.0);
//バイト配列に色情報を書き込み
p = y * stride + x * 3;
pixels[p] = c.R;
pixels[p + 1] = c.G;
pixels[p + 2] = c.B;
}
}
//バイト配列をBitmapに書き込み
wb.WritePixels(new Int32Rect(0, 0, size, size), pixels, stride, 0);
return wb;
}


//ラジアンを0〜360の角度に変換
public double Degrees(double radian)
{
double deg = radian / Math.PI * 180;
if (deg < 0) deg += 360;
return deg;
}
#endregion


#region 画像系


//hueのリスト作成
private double[] GetHueList(byte[] pixels)
{
double[] hueList = new double[pixels.Length / 4];
int count = 0;
for (int i = 0; i < pixels.Length; i += 4)
{
//ピクセルの色相取得
hueList[count] = HSV.Color2HSV(pixels[i + 2], pixels[i + 1], pixels[i]).Hue;
count++;
//if (hue == 360.0) { continue; }//色相360は無彩色なのでパス
}
return hueList;
}

/// <summary>
/// GethueListから作成した色相の配列から色相の分割範囲ごとの数をカウント、
/// 分割数divCountが4なら、360/4=90度毎、範囲0(315~45)、範囲1(45~135)、範囲2(135~225)、範囲3(225~315)、
/// 配列の「Index*360/分割数」が色相になる、4分割でIndex3なら、3*360/4=270、Index3の要素は色相270の範囲のもの
/// <param name="hueList">色相の配列</param>
/// <param name="divCount">分割数</param>
/// <returns></returns>
private int[] HuePixelCount(double[] hueList, int divCount)
{
int[] table = new int[divCount];
double div = 360.0 / divCount;
double divdiv = div / 2.0;
for (int i = 0; i < hueList.Length; i++)
{
//ピクセルの色相取得
double hue = hueList[i];
if (hue == 360.0) { continue; }//色相360は無彩色なのでパス

//色相の範囲ごとにカウント
hue = Math.Floor((hue + divdiv) / div);
hue = (hue >= divCount) ? 0 : hue;
table[(int)hue]++;
}
return table;
}


/// <summary>
/// 画像ファイルからbitmapと、そのbyte配列を取得、ピクセルフォーマットを指定したものに変換
/// </summary>
/// <param name="filePath">画像ファイルのフルパス</param>
/// <param name="pixelFormat">PixelFormatsを指定</param>
/// <param name="dpiX">96が基本、指定なしなら元画像と同じにする</param>
/// <param name="dpiY">96が基本、指定なしなら元画像と同じにする</param>
/// <returns></returns>
private (byte[] array, BitmapSource source) MakeBitmapSourceAndByteArray(string filePath, PixelFormat pixelFormat, double dpiX = 0, double dpiY = 0)
{
byte[] pixels = null;
BitmapSource source = null;
try
{
using (System.IO.FileStream fs = new System.IO.FileStream(filePath, System.IO.FileMode.Open, System.IO.FileAccess.Read))
{
var bf = BitmapFrame.Create(fs);

var convertedBitmap = new FormatConvertedBitmap(bf, pixelFormat, null, 0);
int w = convertedBitmap.PixelWidth;
int h = convertedBitmap.PixelHeight;
int stride = (w * pixelFormat.BitsPerPixel + 7) / 8;
pixels = new byte[h * stride];
convertedBitmap.CopyPixels(pixels, stride, 0);
//dpi指定がなければ元の画像と同じdpiにする
if (dpiX == 0) { dpiX = bf.DpiX; }
if (dpiY == 0) { dpiY = bf.DpiY; }
//dpiを指定してBitmapSource作成
source = BitmapSource.Create(
w, h, dpiX, dpiY,
convertedBitmap.Format,
convertedBitmap.Palette, pixels, stride);
};
}
catch (Exception)
{
}
return (pixels, source);
}
#endregion

}
}


関連記事
2019/04/08は4日後
画像の色相をバブルチャート風に表示するアプリ ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
https://blogs.yahoo.co.jp/gogowaten/15926942.html


ArcSegmentを使って円弧🌙、🍕パイ形、🍩ドーナツ型(アーチ形)を表示してみた
イメージ 1
名前は円弧と扇形はいいと思うけど
ドーナツ型なのかアーチ形なのか、また別の名前があるのかも
でも🍩がいいなあってことで関数名はDonutにした

デザイン画面、MainWindow.xaml
イメージ 2


イメージ 3

MainWindow.xaml.cs

using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Shapes;
//c# - WPF Doughnut ProgressBar - Stack Overflow

namespace _20190331_円弧arcSegment
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();

double radian = 50;//半径 
Point center = new Point(radian, radian);//中心点
double distance = 50;//中心点からの距離
PathGeometry arcPathGeo;//円弧のPathGeometry


//   時計回りに0〜250度の円弧
//中心点座標が半径と同じ、中心からの距離も半径と同じ
arcPathGeo = ArcGeometry(center, distance, 0, 250, SweepDirection.Clockwise);
MyStackPanel1.Children.Add(MakePath(arcPathGeo));

//中心点座標が半径と同じ、中心からの距離が25
arcPathGeo = ArcGeometry(center, 25, 0, 250, SweepDirection.Clockwise);
MyStackPanel1.Children.Add(MakePath(arcPathGeo));

//中心点座標が(100,100)、中心からの距離は半径と同じ
arcPathGeo = ArcGeometry(new Point(100, 100), distance, 0, 250, SweepDirection.Clockwise);
MyStackPanel1.Children.Add(MakePath(arcPathGeo));

//中心点座標が(100,100)、中心からの距離が25
arcPathGeo = ArcGeometry(new Point(100, 100), 25, 0, 250, SweepDirection.Clockwise);
MyStackPanel1.Children.Add(MakePath(arcPathGeo));


//反時計回りに100〜330度
arcPathGeo = ArcGeometry(center, radian, 100, 330, SweepDirection.Counterclockwise);
MyStackPanel1.Children.Add(MakePath(arcPathGeo));


//扇形、🍕
PathGeometry piePahtGeo;
piePahtGeo = PieGeometry(center, distance, 330, 30, SweepDirection.Clockwise);
MyStackPanel1.Children.Add(MakePath(piePahtGeo));

piePahtGeo = PieGeometry(center, distance, 330, 30, SweepDirection.Counterclockwise);
MyStackPanel1.Children.Add(MakePath(piePahtGeo));


//🍩
PathGeometry donut;
donut = DonutGeometry(center, 20, distance, 20, 300, SweepDirection.Clockwise);
MyStackPanel1.Children.Add(MakePath(donut));

donut = DonutGeometry(center, 20, distance, 20, 300, SweepDirection.Counterclockwise);
MyStackPanel1.Children.Add(MakePath(donut));

}


private Path MakePath(PathGeometry geo)
{
Path path;
path = new Path
{
Data = geo,
Stroke = Brushes.PaleVioletRed,
StrokeThickness = 4,
Margin = new Thickness(4)
};
return path;
}

/// <summary>
/// ドーナツ形、アーチ形のPathGeometry作成
/// </summary>
/// <param name="center">中心座標</param>
/// <param name="width">幅</param>
/// <param name="distance">中心からの距離</param>
/// <param name="startDeg">開始角度、0以上360未満</param>
/// <param name="stopDeg">終了角度、0以上360未満</param>
/// <param name="direction">回転方向、clockwiseが時計回り</param>
/// <returns></returns>
private PathGeometry DonutGeometry(Point center, double width, double distance, double startDeg, double stopDeg, SweepDirection direction)
{
//外側の円弧終始点
Point outSideStart = MakePoint(startDeg, center, distance);
Point outSideStop = MakePoint(stopDeg, center, distance);

//内側の円弧終始点は角度と回転方向が外側とは逆になる
Point inSideStart = MakePoint(stopDeg, center, distance - width);
Point inSideStop = MakePoint(startDeg, center, distance - width);

//開始角度から終了角度までが180度を超えているかの判定
//超えていたらArcSegmentのIsLargeArcをtrue、なければfalseで作成
double diffDegrees = (direction == SweepDirection.Clockwise) ? stopDeg - startDeg : startDeg - stopDeg;
if (diffDegrees < 0) { diffDegrees += 360.0; }
bool isLarge = (diffDegrees > 180) ? true : false;

//arcSegment作成
var outSideArc = new ArcSegment(outSideStop, new Size(distance, distance), 0, isLarge, direction, true);
//内側のarcSegmentは回転方向を逆で作成
var inDirection = (direction == SweepDirection.Clockwise) ? SweepDirection.Counterclockwise : SweepDirection.Clockwise;
var inSideArc = new ArcSegment(inSideStop, new Size(distance - width, distance - width), 0, isLarge, inDirection, true);

//PathFigure作成、外側から内側で作成している
//2つのarcSegmentは、2本の直線(LineSegment)で繋げる
var fig = new PathFigure();
fig.StartPoint = outSideStart;
fig.Segments.Add(outSideArc);
fig.Segments.Add(new LineSegment(inSideStart, true));//外側終点から内側始点への直線
fig.Segments.Add(inSideArc);
fig.Segments.Add(new LineSegment(outSideStart, true));//内側終点から外側始点への直線
fig.IsClosed = true;//Pathを閉じる必須

var pg = new PathGeometry();
pg.Figures.Add(fig);
return pg;
}

/// <summary>
/// 円弧のPathGeometryを作成
/// </summary>
/// <param name="center">中心座標</param>
/// <param name="distance">中心点からの距離(半径)</param>
/// <param name="startDegrees">開始角度、0以上360未満で指定</param>
/// <param name="stopDegrees">終了角度、0以上360未満で指定</param>
/// <param name="direction">回転方向、Clockwiseが時計回り</param>
/// <returns></returns>
private PathGeometry ArcGeometry(Point center, double distance, double startDegrees, double stopDegrees, SweepDirection direction)
{
Point stop = MakePoint(stopDegrees, center, distance);//終点座標

//IsLargeの判定、
//開始角度から終了角度までが180度を超えていたらtrue、なければfalse
double diffDegrees = (direction == SweepDirection.Clockwise) ? stopDegrees - startDegrees : startDegrees - stopDegrees;
if (diffDegrees < 0) { diffDegrees += 360.0; }
bool isLarge = (diffDegrees > 180) ? true : false;

//ArcSegment作成
var arc = new ArcSegment(stop, new Size(distance, distance), 0, isLarge, direction, true);

//PathFigure作成
var fig = new PathFigure();
Point start = MakePoint(startDegrees, center, distance);//始点座標
fig.StartPoint = start;//始点座標をスタート地点に
fig.Segments.Add(arc);//ArcSegment追加

//PathGeometry作成、PathFigure追加
var pg = new PathGeometry();
pg.Figures.Add(fig);
return pg;
}



//完成形、回転方向を指定できるように
/// <summary>
/// 扇(pie)型のPathGeometryを作成
/// </summary>
/// <param name="center">中心座標</param>
/// <param name="distance">中心点からの距離</param>
/// <param name="startDegrees">開始角度、0以上360未満で指定</param>
/// <param name="stopDegrees">終了角度、0以上360未満で指定</param>
/// <param name="direction">回転方向、Clockwiseが時計回り</param>
/// <returns></returns>
private PathGeometry PieGeometry(Point center, double distance, double startDegrees, double stopDegrees, SweepDirection direction)
{
Point start = MakePoint(startDegrees, center, distance);//始点座標
Point stop = MakePoint(stopDegrees, center, distance);//終点座標
//開始角度から終了角度までが180度を超えているかの判定
//超えていたらArcSegmentのIsLargeArcをtrue、なければfalseで作成
double diffDegrees = (direction == SweepDirection.Clockwise) ? stopDegrees - startDegrees : startDegrees - stopDegrees;
if (diffDegrees < 0) { diffDegrees += 360.0; }
bool isLarge = (diffDegrees > 180) ? true : false;
var arc = new ArcSegment(stop, new Size(distance, distance), 0, isLarge, direction, true);

//PathFigure作成
//ArcSegmentとその両端と中心点をつなぐ直線LineSegment
var fig = new PathFigure();
fig.StartPoint = start;//始点座標
fig.Segments.Add(arc);//ArcSegment追加
fig.Segments.Add(new LineSegment(center, true));//円弧の終点から中心への直線
fig.Segments.Add(new LineSegment(start, true));//中心から円弧の始点への直線
fig.IsClosed = true;//Pathを閉じる、必須

//PathGeometryを作成してPathFigureを追加して完成
var pg = new PathGeometry();
pg.Figures.Add(fig);
return pg;
}


/// <summary>
/// 距離と角度からその座標を返す
/// </summary>
/// <param name="degrees">360以上は359.99になる</param>
/// <param name="center">中心点</param>
/// <param name="distance">中心点からの距離</param>
/// <returns></returns>
private Point MakePoint(double degrees, Point center, double distance)
{
if (degrees >= 360) { degrees = 359.99; }
var rad = Radian(degrees);
var cos = Math.Cos(rad);
var sin = Math.Sin(rad);
var x = center.X + cos * distance;
var y = center.Y + sin * distance;
return new Point(x, y);
}

private double Radian(double degree)
{
return Math.PI / 180.0 * degree;
}

}
}




ArcSegment

public ArcSegment (
point, 円弧の終点
size, 円弧の半径
rotationAngle, 回転?今回は0で固定
isLargeArc, 円弧が180度を超えるかどうか
sweepDirection, Clockwiseが時計回り、Counterclockwiseが反時計回り
isStroked 描くかどうか、今回はtrueで固定);

このArcSegmentを使って
円弧のPathGeometryを作成するArcGeometry
イメージ 11
指定するのは
中心座標、
中心座標からの距離(半径)、
開始角度、
終了角度、
回転方向


半径 50
中心座標(50,50)
開始角度 0
終了角度 250
回転方向 時計回り
を指定したとき
イメージ 4
こうなればいい
イメージ 5
左上が(0,0)、半径が50なので中心座標は(50,50)


イメージ 6


ArcSegmentには始点と終点の座標が必要なので
それを求めるMakePoint
イメージ 7
終点座標
角度250、中心座標(50,50)、距離は半径と同じ50
を渡すと

イメージ 8
円弧の終点は(32.9,3.0)

同じように円弧の始点も計算
イメージ 9
開始角度は0だから真横に半径のぶん移動しただけの(100,50)


イメージ 10
始点と終点座標

ArcSegment作成
作成時に渡すパラメータをもう一度見ると
public ArcSegment (
point, 円弧の終点
size, 円弧の半径
rotationAngle, 回転?今回は0で固定
isLargeArc, 円弧が180度を超えるかどうか
sweepDirection, Clockwiseが時計回り、Counterclockwiseが反時計回り
isStroked 描くかどうか、今回はtrueで固定);

Pointは終点なので(32.9,3.0)
sizeは半径の50でおk
sweepDirectionは時計回りなのでClockwise
あとは
IsLargeは回転角度は250-0=250で180以上なのでtrue
143行目〜
イメージ 12
SweepDirection回転方向によって引き算の向きを変えて計算して
マイナスだったら360足した値で判定している
これは冗長な気もするけどわからん

開始が30で終了が200で
時計回りの場合
200-30=170は180以上なのでIsLargeはfalse
反時計回りの場合
30-200=-170
-170+360=190は180以上なのでIsLargeをtrue



これでArcSegmentを作成できる
イメージ 14
ArcSegment作成できたので、それを入れるPathFigure作成

PathFigure作成
イメージ 13
PathFigureのStartPointにはさっき求めた始点座標
PathFigureのSegmentsにArcSegmentを追加

PathGeometry作成
イメージ 15
PathGeometryのFiguresにPathFigureを追加して完成、やっとできた



イメージ 16
これでで円弧のPathGeometryができたので、27行目


イメージ 17
あとはPathを作って、そのDataに指定して表示


パイ型🍕のPathGeometry作成
イメージ 18
円弧の両端に中心座標から伸びる直線
LineSegmentを足せばいい


ArcSegmentを作成するまでは円弧作成と全く同じなので
PathFigureにSegmentを加えていくところから
イメージ 19
191行目まで全く同じ、ここまでだと円弧の状態
192行目で円弧の終点から中心への直線を追加、ここまでだと
イメージ 20
終点から中心への直線追加

イメージ 21
中心から円弧の始点への直線追加、193行目

最後にPathを閉じると194行目
イメージ 22
きれいにつながる



ドーナツ型🍩
イメージ 23
🍕(パイ型)とほとんど同じ
2つの円弧ArcSegmentと直線のLineSegmentで作成
一筆書きで作ったので2つの円弧の開始角度と終了角度が逆になる
外側の円弧から開始
外側の円弧
外側の円弧の終点から内側の円弧の始点への直線
内側の円弧
内側の円弧の終点から外側の円弧の始点への直線
Pathを閉じて完了

20度から300度、時計回り


イメージ 24
distanceは距離だけど半径みたいなもの
widthは外側と内側の差
内側の円弧は開始角度と終了角度が逆になるのと
中心点からの距離がwidthのぶん短くなる、100,101行目

イメージ 25
IsLargeの判定や外側のArcSegment作成も普通の円弧と同じ、105〜110行目
内側のArcSegmentは回転方向が逆にして、112行目
sizeもwidth幅のぶんだけ小さくして作成、113行目


イメージ 26
外側の円弧、直線、内側の円弧、直線の順番で繋げる

イメージ 27



イメージ 28
//ハ゜ックマン
System.Windows.Controls.WrapPanel wrap = new System.Windows.Controls.WrapPanel();
MyStackPanel1.Children.Add(wrap);
Path pacman = new Path();
pacman.Data = PieGeometry(new Point(100, 100), 100, 30, 330, SweepDirection.Clockwise);
pacman.Fill = Brushes.Yellow;
wrap.Children.Add(pacman);
MyStackPanel1.Background = Brushes.Black;

//エサ
for (int i = 0; i < 3; i++)
{
Path esa = new Path();
esa.Data = new EllipseGeometry(new Rect(new Size(20, 20)));
esa.Fill = Brushes.Yellow;
esa.Margin = new Thickness(-20, 0, 100, 0);
esa.VerticalAlignment = VerticalAlignment.Center;
wrap.Children.Add(esa);
}




参照したところ
c# - WPF Doughnut ProgressBar - Stack Overflow
https://stackoverflow.com/questions/36752183/wpf-doughnut-progressbar
ここがなかったら今回のはできなかった


WPFにはEllipseGeometryとRectangleGeometryがあるから円と四角形は簡単に表示できるだけどねえ
円弧にはArcSegmentがあるけどこれがさっぱりわからん
ぐぐったらさっきのリンク先がわかりやすかったので助かった
これで
中心点座標と半径、開始角度、終了角度、回転方向を指定して円弧を表示することができた
もっと省略するなら中心点座標と回転方向は要らないかな、回転方向は固定でいいし中心もあとからオフセットすれば良さそう


ギットハブ


関連記事
2019/04/04は明日
画像の色相を円形ヒストグラム、扇形(パイ型)グラフで表示するアプリできた ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
https://blogs.yahoo.co.jp/gogowaten/15923169.html
イメージ 29



イメージ 1
最大3つのGeometryを組み合わせてClip
GeometryGroupではFillRule
CombinedGeometryではGeometryCombineModeをいくつか組み合わせて
四角形をClip表示してみた



コントロール要素のClipプロパティにGeometryを指定すると切り抜き表示になる

アプリ自身のClipに直径500の円のGeometryを指定
this.Clip = new EllipseGeometry(new Rect(0, 0, 500, 500));
これで実行すると
イメージ 2
円形に切り抜き
表示されない部分は透明じゃなくて黒になるんだなあ


複数のGeometryを組み合わせて使い時は
GeometryGroup、CombinedGeometry
このどちらかでできる

重なった部分の表示の仕方を指定する
GeometryGroupはFillRuleで
EvenOdd
Nonzero
のどちらか

CombinedGeometryはGeometryCombineModeで
Exclude 除外する、抜かす
Intersect 交わる、交差、横切る
Union 結合、合併
Xor 排他的論理和
4種類のモードでレッツコンバイン


元の形と単体クリップ
イメージ 3
原型とそのClipに用意した3つのGeometryを単体で使って表示したところ

用意した3つのGeometry
clip1 = RectangleGeometry(new Rect(10, 10, 60, 90));
clip2 = EllipseGeometry(new Rect(0, 0, 60, 60));
clip3 = EllipseGeometry(new Rect(50, 0, 60, 60));



GeometryGroup
イメージ 4
GeometryGroupで複数のGeometryをまとめてClip
FillRuleで塗り方が変化する

イメージ 5
まとめるときはChildren.Addで追加していく、わかりやすい



CombinedGeometry
イメージ 6
Clip1+Clip2をCombineModeを変えて表示

UnionはGeometryGroupのFillRule.Nonzeroと同じ
XorはGeometryGroupのFillRule.EvenOddと同じ
になった

イメージ 7
コンストラクタでModeと2つのGeometryを指定できるのでラク



CombinedGeometryで3つのGeometry
イメージ 8
これもUnionはNonzero、XorはEvenOddと同じ結果になった


CombineGeometryで3つ以上のGeometryをまとめるときは
イメージ 9
たぶんこうかな、2つまでしか指定できないみたい

イメージ 10
プロパティの方でもわざわざGeometry1,2って番号が振ってあるし
Addとかもなさそう


CombinedGeometry別モードとの組み合わせ
イメージ 11
使いこなすのは難しそうだけどいろいろできる


デザイン画面
MainWindow.xaml
イメージ 12


MainWindow.xaml.cs

using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
//第9回 WPFの「グラフィックス」を学ぼう(2/2):連載:WPF入門 - @IT

namespace _20190330_Clip切り抜き
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();

MyClip();
}
private void MyClip()
{
//clip用Geometry
var clip1 = new RectangleGeometry(new Rect(10, 10, 60, 90));
var clip2 = new EllipseGeometry(new Rect(0, 0, 60, 60));
var clip3 = new EllipseGeometry(new Rect(50, 0, 60, 60));

//  1clip
MyWrapPanel1.Children.Add(CreateBorderWithClip(null));//clipなしの原型
MyWrapPanel1.Children.Add(CreateBorderWithClip(clip1));
MyWrapPanel1.Children.Add(CreateBorderWithClip(clip2));
MyWrapPanel1.Children.Add(CreateBorderWithClip(clip3));



GeometryGroup geoGroup;
//  2clip
geoGroup = new GeometryGroup();
geoGroup.Children.Add(clip1);
geoGroup.Children.Add(clip2);
geoGroup.FillRule = FillRule.EvenOdd;//初期値
MyWrapPanel2.Children.Add(CreateBorderWithClip(geoGroup));

geoGroup = new GeometryGroup();
geoGroup.Children.Add(clip1);
geoGroup.Children.Add(clip2);
geoGroup.FillRule = FillRule.Nonzero;
MyWrapPanel2.Children.Add(CreateBorderWithClip(geoGroup));

//  3clip
geoGroup = new GeometryGroup();
geoGroup.Children.Add(clip1);
geoGroup.Children.Add(clip2);
geoGroup.Children.Add(clip3);
geoGroup.FillRule = FillRule.EvenOdd;
MyWrapPanel2.Children.Add(CreateBorderWithClip(geoGroup));

geoGroup = new GeometryGroup();
geoGroup.Children.Add(clip1);
geoGroup.Children.Add(clip2);
geoGroup.Children.Add(clip3);
geoGroup.FillRule = FillRule.Nonzero;
MyWrapPanel2.Children.Add(CreateBorderWithClip(geoGroup));



CombinedGeometry comboGeo;
//  2clip
comboGeo = new CombinedGeometry(GeometryCombineMode.Exclude, clip1, clip2);
MyWrapPanel3.Children.Add(CreateBorderWithClip(comboGeo));

comboGeo = new CombinedGeometry(GeometryCombineMode.Intersect, clip1, clip2);
MyWrapPanel3.Children.Add(CreateBorderWithClip(comboGeo));

comboGeo = new CombinedGeometry(GeometryCombineMode.Union, clip1, clip2);
MyWrapPanel3.Children.Add(CreateBorderWithClip(comboGeo));

comboGeo = new CombinedGeometry(GeometryCombineMode.Xor, clip1, clip2);
MyWrapPanel3.Children.Add(CreateBorderWithClip(comboGeo));


//  3clip   同じモードを2回
comboGeo = new CombinedGeometry(GeometryCombineMode.Exclude, clip1, clip2);
comboGeo = new CombinedGeometry(GeometryCombineMode.Exclude, comboGeo, clip3);
MyWrapPanel4.Children.Add(CreateBorderWithClip(comboGeo));

comboGeo = new CombinedGeometry(GeometryCombineMode.Intersect, clip1, clip2);
comboGeo = new CombinedGeometry(GeometryCombineMode.Intersect, comboGeo, clip3);
MyWrapPanel4.Children.Add(CreateBorderWithClip(comboGeo));

comboGeo = new CombinedGeometry(GeometryCombineMode.Union, clip1, clip2);
comboGeo = new CombinedGeometry(GeometryCombineMode.Union, comboGeo, clip3);
MyWrapPanel4.Children.Add(CreateBorderWithClip(comboGeo));

comboGeo = new CombinedGeometry(GeometryCombineMode.Xor, clip1, clip2);
comboGeo = new CombinedGeometry(GeometryCombineMode.Xor, comboGeo, clip3);
MyWrapPanel4.Children.Add(CreateBorderWithClip(comboGeo));


//  3clip   Excludeと他
comboGeo = new CombinedGeometry(GeometryCombineMode.Exclude, clip1, clip2);
comboGeo = new CombinedGeometry(GeometryCombineMode.Intersect, comboGeo, clip3);
MyWrapPanel5.Children.Add(CreateBorderWithClip(comboGeo));

comboGeo = new CombinedGeometry(GeometryCombineMode.Exclude, clip1, clip2);
comboGeo = new CombinedGeometry(GeometryCombineMode.Union, comboGeo, clip3);
MyWrapPanel5.Children.Add(CreateBorderWithClip(comboGeo));

comboGeo = new CombinedGeometry(GeometryCombineMode.Exclude, clip1, clip2);
comboGeo = new CombinedGeometry(GeometryCombineMode.Xor, comboGeo, clip3);
MyWrapPanel5.Children.Add(CreateBorderWithClip(comboGeo));


//  3clip   Intersectと他
comboGeo = new CombinedGeometry(GeometryCombineMode.Intersect, clip1, clip2);
comboGeo = new CombinedGeometry(GeometryCombineMode.Exclude, comboGeo, clip3);
MyWrapPanel6.Children.Add(CreateBorderWithClip(comboGeo));

comboGeo = new CombinedGeometry(GeometryCombineMode.Intersect, clip1, clip2);
comboGeo = new CombinedGeometry(GeometryCombineMode.Union, comboGeo, clip3);
MyWrapPanel6.Children.Add(CreateBorderWithClip(comboGeo));

comboGeo = new CombinedGeometry(GeometryCombineMode.Intersect, clip1, clip2);
comboGeo = new CombinedGeometry(GeometryCombineMode.Xor, comboGeo, clip3);
MyWrapPanel6.Children.Add(CreateBorderWithClip(comboGeo));

}

private Border CreateBorderWithClip(Geometry clip)
{
var r = new Border
{
Clip = clip,
Background = Brushes.MediumAquamarine,
BorderBrush = Brushes.Orchid,
BorderThickness = new Thickness(4.0),
Width = 100,
Height = 100,
Margin = new Thickness(4.0, 10.0, 4.0, 60.0),
};
return r;
}
}
}


参照したところ
第9回 WPFの「グラフィックス」を学ぼう(2/2):連載:WPF入門 - @IT
https://www.atmarkit.co.jp/ait/articles/1102/02/news100_2.html



ギットハブ


関連記事
2019/3/25は一週間くらい前
色相環画像作成、WriteableBitmapとImage.Clip ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
https://blogs.yahoo.co.jp/gogowaten/15913863.html
このときの切り抜きはPathGeometryのAddGeometryで2つのEllipseGeometryをまとめていた、今回みたくGeometryGroupを使う必要ない?


2019/04/04は明後日
画像の色相を円形ヒストグラム、扇形(パイ型)グラフで表示するアプリできた ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
https://blogs.yahoo.co.jp/gogowaten/15923169.html
イメージ 13



イメージ 1
画像の上にあるくしゃくしゃしたのがそれ
想像していたのよりしょんぼりした感じなのができあがった
要素数は360で作成

レーダーチャート
イメージ 2
エクセルのレーダーチャート
これの要素数は11

イメージ 4
HSVのSとVをMAXにしてH(色相)を際立たせた感じにする
ニセサーモグラフィティって名前がアレだけど
イメージ 3
こうしてみるとピンク〜赤〜黄色系が多くて青系も少し、緑はわずか
なのでさっきのレーダーチャートはあっていると思う
しょんぼりした感じなのは要素数が多すぎたせいもあるので
要素数を360から36に下げてみると

要素数36
イメージ 5
こっちのほうがいいねえ
もっと下げて
要素数6
イメージ 6
これでもいいくらい



作るまで
イメージ 7
この色相の四角形を作ってレーダーチャート型に切り抜く
この前の色相環作成と同じで
WriteableBitmapで色相の四角形を作ってPathGeometryで切り抜いて作る
違うのはPathGeometryの中、Segmentの作成
これを画像の色相をカウントしたものから作る

ピクセルの色を色相ごとにカウント
360分割の場合1度ごとのカウントになる
要素数は360になる
色相 カウント数
0 645
1 987
2 0
3 754
179 500
359 939


色相環画像のサイズが100x100なら
中心点は(50,50)
半径は50
のとき
色相の座標
イメージ 8
色相3の中心点からの距離は?
カウント数最大値を色相環画像の半径に合わせたいので、これを基準(1.0)にする
色相1の987が最大値なので、これを1.0とすると
色相3の754の中心点からの距離は754/987=0.763
これに半径をかけると38.1196555
これが色相3の中心点からの距離になる
754/987*50=38.196555

色相3の位置は?
cos、sinはラジアンを使うので角度からラジアンに変換して使う
ラジアン = パイ/180*角度
色相の値はそのまま角度になるので色相3のラジアンは
3.14/180*3=0.052333...

x=cos(色相3のラジアン)*距離+中心点x
y=sin(色相3のラジアン)*距離+中心点y

cos(0.052333)=0.9986295
x=0.9986295*38.19655+50=88.144202

こうして色相ごとの座標をつなげたPathGeometryで色相の四角形を切り抜けばレーダーチャートみたいなのができる



分割数4の場合
イメージ 9
360/4=90で90度毎の
0,90,180,270の色相になる
この4つのどれかに分けていく場合
例えば色相80はどこにするのか
0〜90の間だから0か90になるわけだけど
近いのは90だから90にカウントするのが良さそう
そうすると境目は90度毎の中間45度ずらしたところになる

イメージ 10
0度でカウントする色相範囲は315〜45度
90度でカウントする色相範囲は45〜135度
180度でカウントする色相範囲は135〜225度
270度でカウントする色相範囲は225〜315度
これで色相80は45〜135に入るから90度でカウントされる
あとはこれをどう書けばいいのか

イメージ 11
-45度傾けていたから、元の色相に45足してから計算
それを90で割った値の小数点以下切り捨て
その値が分割数以上なら0
これに90をかければちょうどよくなる

色相200は180度でカウントしたい
計算してみると
(200+45)/90=2.72...
切り捨てて2
2は分割数4より小さいのでそのままで
2*90=180
おk

色相316は色相0でカウントしたい
(316+45)/90=4.0111...
切り捨てて4
4は分割数より小さくないので0
0*90=0
おk

分割数6なら
360/6=60なので
0,60,120,180,240,300に分けることになる
範囲の境目は60/2=30で30度傾けた
0の範囲は330〜30
60の範囲は30〜90
120の範囲は90〜150
180の範囲は150〜210
240の範囲は210〜270
300の範囲は270〜330

色相190は180でカウントしたい
(190+30)/60=3.6666...
切り捨てて3
3は分割数6より小さいのでそのまま
3*60=180
おk


コード全部で1万文字超えたので要になる
clipにするPathGeometryを作成するとこだけ画像で
イメージ 12
↑微妙に間違っていたので
↓修正した(2019/04/02)画像だと修正するのめんどくさいいいいい
イメージ 23
レーダーチャートの要素の値になる部分、座標リスト作成

イメージ 13
BitmapクラスのCopyPixelsで得られる色のbyte配列から、色相を分割数に応じてカウント
RGBからHSVの計算はDLLファイルを参照に追加したのを使っている

イメージ 14
できあがった座標リストからPathGeometryを作成
これで色相画像の画像をクリップすればレーダーチャート型に切り抜きになる




360分割(要素数)
イメージ 15
どの画像も思った以上に極端なグラフになる
見た目の印象だともっと緑が多くても良さそうなんだけどねえ

イメージ 16
220(青色)辺りに集中、次に多い80(緑)でも青の1/10、ほかは2桁とかになっていた


12分割
イメージ 17
7が多い、7の色相は
360/12=30、7*30=210、青


12分割
イメージ 18
どの色相も同じ数だけあるはずなんだけど微妙に違うなあ

360分割
イメージ 19
よりバラついた
できあがったレーダーチャートがかっこいい

720分割
イメージ 22
たんぽぽみたいになった

3分割と4分割
イメージ 20

普通の写真画像で3分割と4分割
イメージ 21




画像の色相をレーダーチャートってのはできたわけだけど、なんか違うかなあ
良かったのは色相環画像からはかっこいいレーダーチャートができたこと

レーダーチャートっていうんだ…
ヒストグラムは棒グラフを並べた感じだから、それを円形に並べたら円形のヒストグラムだろうと思っていたら、どうも違っていてレーダーチャートっていうのがわかったのは、今回のを作り始めたあとだったからプロジェクト名がヒストグラムになっている



ギットハブ
HSV.dllを使っているので参照に追加しないと動かない
HSV.dllは同じところにある




関連記事
2019/3/25は1週間前
色相環画像作成、WriteableBitmapとImage.Clip ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
https://blogs.yahoo.co.jp/gogowaten/15913863.html


2019/04/04は3日後
画像の色相を円形ヒストグラム、扇形(パイ型)グラフで表示するアプリできた ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
https://blogs.yahoo.co.jp/gogowaten/15923169.html
イメージ 24







デザイン画面
イメージ 2

イメージ 3
画像を表示するようのImageを追加しただけ




using System.Windows;
using System.Windows.Media.Imaging;

namespace _20190331_画像埋め込み
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            System.Reflection.Assembly sra = System.Reflection.Assembly.GetExecutingAssembly();
            var bf = BitmapFrame.Create(sra.GetManifestResourceStream("_20190331_画像埋め込み.HSVRectValue.png"));
            MyImage.Source = bf;
            //1行で
            //MyImage.Source= BitmapFrame.Create(System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream("_20190331_画像埋め込み.HSVRectValue.png"));
        }

    }
}




埋め込む画像はこれ
イメージ 1
ファイルのパスは
D:\ブログ用\テスト用画像\HSVRectValue.png
だった


MainWindow.xaml.csの画面
イメージ 4
最初の画面


準備
  1. ソリューションエクスプローラーのプロジェクト名の、右クリックメニューから、追加→既存項目で画像ファイルを追加する
  2. 追加した画像の右クリックメニューからプロパティで、ビルドアクションを埋め込みリソースに変更

1. 画像ファイル追加
ソリューションエクスプローラー
イメージ 5
だいたいこんな感じになっている


埋め込む場所はプロジェクト
イメージ 6
「20190331_画像埋め込み」ってのが今回のプロジェクト名
ここに埋め込むのでここを右クリックして


イメージ 7
右クリックメニューから
追加→既存の項目クリックで

ファイル選択画面
イメージ 8


イメージ 9
ファイルのパスがわかっていればそれを入れて追加

画像を見て選ぶなら右下の
イメージ 10
ファイルの種類をイメージファイルにして

イメージ 11
選んで追加ボタンクリックで追加される


ソリューションエクスプローラーで確認
イメージ 12
プロジェクトに画像が追加された


2. ビルドアクションを埋め込みリソースに変更
イメージ 13
右クリックメニューのプロパティから


イメージ 14
ビルドアクションがResourceになっているので
右の∨をクリックして


イメージ 15
リストから埋め込みリソースを選択


イメージ 16
変更完了

これで準備が整った
イメージ 12
20190331_画像埋め込み.HSVRectValue.png


あとはC#で
MyImage.Source = BitmapFrame.Create(System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream("_20190331_画像埋め込み.HSVRectValue.png"));
これを書いて実行すると
イメージ 17
表示された!


さっき1行で書いたのを分けて書いてみると
System.Reflection.Assembly sra = System.Reflection.Assembly.GetExecutingAssembly();
var bf = BitmapFrame.Create(sra.GetManifestResourceStream("_20190331_画像埋め込み.HSVRectValue.png"));
MyImage.Source = bf;
イメージ 18

12行目、アプリの実行ファイルを取得している感じ?
イメージ 19
完全に理解した(わからん)

そこからGetManifestResourceStreamっていうメソッドに、埋め込んだ画像のパスを渡すと画像が取り出せた
画像のパスは「プロジェクト名.画像ファイル名」
イメージ 21
プロジェクト名というか4行目のnamespaceの名前でいいのかな
これに.ピリオドをつけたあとに画像ファイル名の
20190331_画像埋め込み.HSVRectValue.png
これを指定

GetManifestResourceStream
イメージ 22
わからんけど、名前の通りStreamで取り出せるみたい?

StreamからBitmapにするのにBitmapFrameのCreateメソッドを使用
イメージ 20
これでBitmapFrameとして取り出せたので
最後に
イメージ 23
ImageのSourceに指定して完了


実行ファイルだけで表示されるのか確認
イメージ 24
実行ファイルだけ別の場所にコピーして実行

イメージ 17
おk

失敗例
ビルドアクションがResourceのままだと
イメージ 25
取り出そうとしたところで無いって言われる


完走した感想
WindowsFormアプリのときに同じことがあったんだけど、WPFでは取り出しのところが違うみたいで、同じ方法ではできなかった
この前の市松模様画像もマスの大きさや色が固定でもいいなら、今回の方法で使ったほうがラクかなあ
DLLファイルも同じように埋め込んで取り出せて参照できればいいのにねえ




参照したところ

本文はここまでですこのページの先頭へ
みんなの更新記事