円錐形のグラデーションの描画方法が分からなかったので、
書いてみた。
本当はもっと簡単な方法があるのかもしれない。
// // 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 件のコメント:
コメントを投稿