円錐形のグラデーションの描画方法が分からなかったので、
書いてみた。
本当はもっと簡単な方法があるのかもしれない。
//
// ConicalGradient 円錐形グラデーションの描画クラス
//
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
namespace DrawTest
{
class ConicalGradient
{
public static Bitmap GetBitmap(Color[] colorList, int width, int height)
{
return GetBitmap(colorList, 0, width, height, width / 2, height / 2);
}
public static Bitmap GetBitmap(Color[] colorList, double d, int width, int height)
{
return GetBitmap(colorList, d, width, height, width / 2, height / 2);
}
public static Bitmap GetBitmap(Color[] colorList, double d, int width, int height, int centerX, int centerY)
{
try
{
//Color配列が空の時はHueの値でも入れとく
if (colorList == null || colorList.Length == 0)
{
colorList = new Color[6];
colorList[0] = Color.FromArgb(255, 0, 0);
colorList[1] = Color.FromArgb(255, 255, 0);
colorList[2] = Color.FromArgb(0, 255, 0);
colorList[3] = Color.FromArgb(0, 255, 255);
colorList[4] = Color.FromArgb(0, 0, 255);
colorList[5] = Color.FromArgb(255, 0, 255);
}
Color[] colArry;
int colLength;
//色と色の間隔は最大でも256色なので×配列の要素数分の色を作っとく
colArry = new Color[colorList.Length * 256];
colLength = colArry.Length;
Parallel.For(0, colLength, delegate(int i)
{
//for (int i = 0; i < colLength; i++)
//{
colArry[i] = GetColor(colorList, ((double)i / colLength) * 360.0);
//}
});
Bitmap bmp = new Bitmap(width, height, PixelFormat.Format32bppArgb);
BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
int stride = bmpData.Stride;
byte[] bmpByte = new byte[height * stride];
const double rad = 180 / Math.PI;
Parallel.For(0, width, delegate(int i)
{
//for (int i = 0; i < width; i++)
//{
for (int j = 0; j < height; j++)
{
double angle = (Math.Atan2(centerY - j, centerX - i) * rad) + 180 + d;
angle = (angle + 360) % 360;//0~359.99…の中に収める
Color col = colArry[(int)(angle * (colLength / 360.0))];
bmpByte[(i * 4) + (j * stride) + 3] = col.A;
bmpByte[(i * 4) + (j * stride) + 2] = col.R;
bmpByte[(i * 4) + (j * stride) + 1] = col.G;
bmpByte[(i * 4) + (j * stride) + 0] = col.B;
}
//}
});
Marshal.Copy(bmpByte, 0, bmpData.Scan0, bmpByte.Length);
bmp.UnlockBits(bmpData);
return bmp;
}
catch
{
return null;
}
}
///
/// 色の取得
///
/// /// 0.0~259.99... /// private static Color GetColor(Color[] colors, double angle) { //色の初期化 int a, r, g, b, //色の数 length = colors.Length, num = 0; int d = (int)(angle / (360.0 / length)); double rest = (angle % (360.0 / length)) / (360.0 / length); if (d + 1 < length) num = d + 1; int startA = colors[d].A, endA = colors[num].A, startR = colors[d].R, endR = colors[num].R, startG = colors[d].G, endG = colors[num].G, startB = colors[d].B, endB = colors[num].B; if (startA < endA) { a = startA + (int)((endA - startA) * rest); } else { a = startA - (int)((startA - endA) * rest); } if (startR < endR) { r = startR + (int)((endR - startR) * rest); } else { r = startR - (int)((startR - endR) * rest); } if (startG < endG) { g = startG + (int)((endG - startG) * rest); } else { g = startG - (int)((startG - endG) * rest); } if (startB < endB) { b = startB + (int)((endB - startB) * rest); } else { b = startB - (int)((startB - endB) * rest); } return Color.FromArgb(a, r, g, b); } } }
テストに作ってみたコントロール クリックで中心が移動してドラッグで回転する感じ。
using System.Drawing;
using System.Windows.Forms;
using System;
using System.Drawing.Drawing2D;
using System.Diagnostics;
namespace DrawTest
{
class ConicalGradientView : Control
{
private Bitmap bmp;
private double angle = 0;
private Point center;
public Point Center
{
get { return center; }
set
{
center = value;
Refresh();
}
}
private Color[] colors = null;
public Color[] Colors
{
get { return colors; }
set
{
colors = value;
Refresh();
}
}
public ConicalGradientView()
{
SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
SetStyle(ControlStyles.SupportsTransparentBackColor, true);
SetStyle(ControlStyles.ResizeRedraw, true);
}
protected override void OnPaint(PaintEventArgs pe)
{
base.OnPaint(pe);
Stopwatch sw = new Stopwatch();
sw.Start();
bmp = ConicalGradient.GetBitmap(colors, angle, this.ClientSize.Width, this.ClientSize.Height, Center.X, Center.Y);
Console.WriteLine(sw.Elapsed);
if (bmp != null)
{
pe.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
pe.Graphics.FillEllipse(new TextureBrush(bmp), 0, 0, this.ClientSize.Width - 1, this.ClientSize.Height - 1);
pe.Graphics.DrawEllipse(Pens.Black, 0, 0, this.ClientSize.Width - 1, this.ClientSize.Height - 1);
pe.Graphics.DrawEllipse(Pens.Black, Center.X - 5, Center.Y - 5, 10, 10);
}
}
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
Center = e.Location;
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
if (e.Button == MouseButtons.Left)
{
angle = (Math.Atan2(Center.X - e.X, Center.Y - e.Y) * (180 / Math.PI));
Refresh();
}
}
}
}
Conical Gradient


0 件のコメント:
コメントを投稿