728x90
반응형
728x170
▶ MainForm.cs
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Windows.Forms;
namespace TestProject
{
/// <summary>
/// 메인 폼
/// </summary>
public partial class MainForm : Form
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 색상 배열
/// </summary>
private Color[] colorArray =
{
Color.Red,
Color.OrangeRed,
Color.Yellow,
Color.Green,
Color.Blue,
Color.Indigo,
Color.Fuchsia,
};
/// <summary>
/// 소스 비트맵
/// </summary>
private Bitmap sourceBitmap = null;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - MainForm()
/// <summary>
/// 생성자
/// </summary>
public MainForm()
{
InitializeComponent();
this.openMenuItem.Click += openMenuItem_Click;
this.saveAsMenuItem.Click += saveAsMenuItem_Click;
this.thicknessTextBox.TextChanged += parameterTextBox_TextChanged;
this.colorScaleTextBox.TextChanged += parameterTextBox_TextChanged;
this.opacityTextBox.TextChanged += parameterTextBox_TextChanged;
this.drawOutlineCheckBox.CheckedChanged += parameterCheckBox_CheckedChanged;
this.applyEllipticalMaskCheckBox.CheckedChanged += parameterCheckBox_CheckedChanged;
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Private
//////////////////////////////////////////////////////////////////////////////// Event
#region 열기 메뉴 항목 클릭시 처리하기 - openMenuItem_Click(sender, e)
/// <summary>
/// 열기 메뉴 항목 클릭시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void openMenuItem_Click(object sender, EventArgs e)
{
if(this.openFileDialog.ShowDialog() == DialogResult.OK)
{
this.sourceBitmap = LoadBitmapUnlocked(this.openFileDialog.FileName);
DrawImage();
}
}
#endregion
#region 다른 이름으로 저장 메뉴 항목 클릭시 처리하기 - saveAsMenuItem_Click(sender, e)
/// <summary>
/// 다른 이름으로 저장 메뉴 항목 클릭시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void saveAsMenuItem_Click(object sender, EventArgs e)
{
if(this.saveFileDialog.ShowDialog() == DialogResult.OK)
{
SaveImage(this.pictureBox.Image, this.saveFileDialog.FileName);
}
}
#endregion
#region 매개 변수 텍스트 박스 텍스트 변경시 처리하기 - parameterTextBox_TextChanged(sender, e)
/// <summary>
/// 매개 변수 텍스트 박스 텍스트 변경시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void parameterTextBox_TextChanged(object sender, EventArgs e)
{
DrawImage();
}
#endregion
#region 매개 변수 체크 박스 체크 변경시 처리하기 - parameterCheckBox_CheckedChanged(sender, e)
/// <summary>
/// 매개 변수 체크 박스 체크 변경시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void parameterCheckBox_CheckedChanged(object sender, EventArgs e)
{
DrawImage();
}
#endregion
//////////////////////////////////////////////////////////////////////////////// Function
#region 잠금 없이 비트맵 로드하기 - LoadBitmapUnlocked(filePath)
/// <summary>
/// 잠금 없이 비트맵 로드하기
/// </summary>
/// <param name="filePath">파일 경로</param>
/// <returns>비트맵</returns>
private Bitmap LoadBitmapUnlocked(string filePath)
{
using(Bitmap bitmap = new Bitmap(filePath))
{
return new Bitmap(bitmap);
}
}
#endregion
#region 이미지 저장하기 - SaveImage(image, filePath)
/// <summary>
/// 이미지 저장하기
/// </summary>
/// <param name="image">이미지</param>
/// <param name="filePath">파일 경로</param>
private void SaveImage(Image image, string filePath)
{
string fileExtension = Path.GetExtension(filePath);
switch(fileExtension.ToLower())
{
case ".bmp" : image.Save(filePath, ImageFormat.Bmp ); break;
case ".exif" : image.Save(filePath, ImageFormat.Exif); break;
case ".gif" : image.Save(filePath, ImageFormat.Gif ); break;
case ".jpg" :
case ".jpeg" : image.Save(filePath, ImageFormat.Jpeg); break;
case ".png" : image.Save(filePath, ImageFormat.Png ); break;
case ".tif" :
case ".tiff" : image.Save(filePath, ImageFormat.Tiff); break;
default : throw new NotSupportedException($"알 수 없는 파일 확장자 : {fileExtension}");
}
}
#endregion
#region 거리 구하기 - GetDistance(point1, point2)
/// <summary>
/// 거리 구하기
/// </summary>
/// <param name="point1">포인트 1</param>
/// <param name="point2">포인트 2</param>
/// <returns>거리</returns>
private float GetDistance(PointF point1, PointF point2)
{
float deltaX = point1.X - point2.X;
float deltaY = point1.Y - point2.Y;
return (float)Math.Sqrt(deltaX * deltaX + deltaY * deltaY);
}
#endregion
#region 거리 구하기 - GetDistance(point, rectangle)
/// <summary>
/// 거리 구하기
/// </summary>
/// <param name="point">포인트</param>
/// <param name="rectangle">사각형</param>
/// <returns>거리</returns>
private float GetDistance(PointF point, Rectangle rectangle)
{
float maximumDistance = GetDistance(point, new PointF(rectangle.Left, rectangle.Top));
float testDistance = GetDistance(point, new PointF(rectangle.Left, rectangle.Bottom));
if(maximumDistance < testDistance)
{
maximumDistance = testDistance;
}
testDistance = GetDistance(point, new PointF(rectangle.Right, rectangle.Top));
if(maximumDistance < testDistance)
{
maximumDistance = testDistance;
}
testDistance = GetDistance(point, new PointF(rectangle.Right, rectangle.Bottom));
if(maximumDistance < testDistance)
{
maximumDistance = testDistance;
}
return maximumDistance;
}
#endregion
#region 극 좌표 → 직교 좌표 변환하기 - ConvertPolarToCartesian(radius, theta, x, y)
/// <summary>
/// 극 좌표 → 직교 좌표 변환하기
/// </summary>
/// <param name="radius">반경</param>
/// <param name="theta">세타</param>
/// <param name="x">X</param>
/// <param name="y">Y</param>
private void ConvertPolarToCartesian(float radius, float theta, out float x, out float y)
{
x = (float)(radius * Math.Cos(theta));
y = (float)(radius * Math.Sin(theta));
}
#endregion
#region 나선 포인트 리스트 구하기 - GetSpiralPointList(centerPoint, thickness, angleOffset, maximumTheta)
/// <summary>
/// 나선 포인트 리스트 구하기
/// </summary>
/// <param name="centerPoint">중심 포인트</param>
/// <param name="thickness">두께</param>
/// <param name="angleOffset">각도 오프셋</param>
/// <param name="maximumTheta">최대 세타</param>
/// <returns>나선 포인트 리스트</returns>
private List<PointF> GetSpiralPointList(PointF centerPoint, float thickness, float angleOffset, float maximumTheta)
{
List<PointF> pointList = new List<PointF>();
const float deltaTheta = (float)(5 * Math.PI / 180);
for(float theta = 0; ; theta += deltaTheta)
{
float radius = thickness * theta;
float x;
float y;
ConvertPolarToCartesian(radius, theta + angleOffset, out x, out y);
x += centerPoint.X;
y += centerPoint.Y;
pointList.Add(new PointF((float)x, (float)y));
if(theta + angleOffset > maximumTheta)
{
break;
}
}
return pointList;
}
#endregion
#region 색상화 비트맵 구하기 - GetColorizeBitmap(sourceBitmap, color, colorScale)
/// <summary>
/// 색상화 비트맵 구하기
/// </summary>
/// <param name="sourceBitmap">소스 비트맵</param>
/// <param name="color">색상</param>
/// <param name="colorScale">색상 스케일</param>
/// <returns>색상화 비트맵</returns>
private Bitmap GetColorizeBitmap(Bitmap sourceBitmap, Color color, float colorScale)
{
ColorMatrix colorMatrix = new ColorMatrix
(
new float[][]
{
new float[] { color.R / 255f * colorScale, 0 , 0 , 0, 0},
new float[] { 0 , color.G / 255f * colorScale, 0 , 0, 0},
new float[] { 0 , 0 , color.B / 255f * colorScale, 0, 0},
new float[] { 0 , 0 , 0 , 1, 0},
new float[] { 0 , 0 , 0 , 0, 1}
}
);
int width = sourceBitmap.Width;
int height = sourceBitmap.Height;
Bitmap targetBitmap = new Bitmap(width, height);
using(ImageAttributes imageAttributes = new ImageAttributes())
{
imageAttributes.SetColorMatrix(colorMatrix);
using(Graphics graphics = Graphics.FromImage(targetBitmap))
{
Point[] targetPointArray =
{
new Point(0 , 0 ),
new Point(width, 0 ),
new Point(0 , height)
};
Rectangle sourceRectangle = new Rectangle(0, 0, width, height);
graphics.DrawImage
(
sourceBitmap,
targetPointArray,
sourceRectangle,
GraphicsUnit.Pixel,
imageAttributes
);
}
}
return targetBitmap;
}
#endregion
#region 타원형 비트맵 구하기 - GetEllipticalBitmap(sourceBitmap)
/// <summary>
/// 타원형 비트맵 구하기
/// </summary>
/// <param name="sourceBitmap">소스 비트맵</param>
/// <returns>타원형 비트맵</returns>
private Bitmap GetEllipticalBitmap(Bitmap sourceBitmap)
{
Bitmap targetBitmap = (Bitmap)sourceBitmap.Clone();
using(Graphics graphics = Graphics.FromImage(targetBitmap))
{
graphics.Clear(Color.Transparent);
using(TextureBrush brush = new TextureBrush(sourceBitmap))
{
Rectangle rectangle = new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height);
graphics.FillEllipse(brush, rectangle);
}
}
return targetBitmap;
}
#endregion
#region 나선 비트맵 구하기 - SpiralizeBitmap(sourceBitmap, colorArray, thickness, colorScale, opacity,
drawOutline, applyEllipticalMask)
/// <summary>
/// 나선 비트맵 구하기
/// </summary>
/// <param name="sourceBitmap">소스 비트맵</param>
/// <param name="colorArray">색상 배열</param>
/// <param name="thickness">두께</param>
/// <param name="colorScale">색상 스케일</param>
/// <param name="opacity">불투명도</param>
/// <param name="drawOutline">윤곽선 그리기 여부</param>
/// <param name="applyEllipticalMask">타원 마스크 적용 여부</param>
/// <returns>나선 비트맵</returns>
private Bitmap SpiralizeBitmap
(
Bitmap sourceBitmap,
Color[] colorArray,
float thickness,
float colorScale,
float opacity,
bool drawOutline,
bool applyEllipticalMask
)
{
int width = sourceBitmap.Width;
int height = sourceBitmap.Height;
Bitmap spiralBitmap = new Bitmap(width, height);
using(Graphics graphics = Graphics.FromImage(spiralBitmap))
{
graphics.Clear(this.pictureBox.BackColor);
graphics.SmoothingMode = SmoothingMode.AntiAlias;
int spiralCount = colorArray.Length;
float angularSpacing = (float)(2 * Math.PI / spiralCount);
float startAngle = 0;
PointF centerPoint = new PointF(width / 2, height / 2);
Rectangle rectangle = new Rectangle(0, 0, width, height);
float maximumDistance = GetDistance(centerPoint, rectangle);
float maximumTheta = maximumDistance / thickness + 2 * (float)Math.PI;
List<List<PointF>> spiralPointList = new List<List<PointF>>();
for(int i = 0; i <= spiralCount; i++)
{
spiralPointList.Add
(
GetSpiralPointList
(
centerPoint,
thickness,
startAngle,
maximumTheta
)
);
startAngle += angularSpacing;
}
for(int i = 0; i < spiralCount; i++)
{
List<PointF> pointList1 = new List<PointF>(spiralPointList[i ]);
List<PointF> pointList2 = new List<PointF>(spiralPointList[i + 1]);
pointList2.Reverse();
pointList1.AddRange(pointList2);
using(Bitmap colorizedBitmap = GetColorizeBitmap(this.sourceBitmap, this.colorArray[i], colorScale))
{
using(TextureBrush brush = new TextureBrush(colorizedBitmap))
{
graphics.FillPolygon(brush, pointList1.ToArray());
}
}
if(drawOutline)
{
graphics.DrawLines(Pens.Black, pointList1.ToArray());
}
}
}
Bitmap targetBitmap = (Bitmap)sourceBitmap.Clone();
using(Graphics graphics = Graphics.FromImage(targetBitmap))
{
ColorMatrix colorMatrix = new ColorMatrix();
colorMatrix.Matrix33 = opacity;
ImageAttributes imageAttributes = new ImageAttributes();
imageAttributes.SetColorMatrix
(
colorMatrix,
ColorMatrixFlag.Default,
ColorAdjustType.Bitmap
);
Rectangle rectangle = new Rectangle(0, 0, targetBitmap.Width, targetBitmap.Height);
graphics.DrawImage
(
spiralBitmap,
rectangle,
0,
0,
targetBitmap.Width,
targetBitmap.Height,
GraphicsUnit.Pixel,
imageAttributes
);
}
if(applyEllipticalMask)
{
targetBitmap = GetEllipticalBitmap(targetBitmap);
}
return targetBitmap;
}
#endregion
#region 이미지 그리기 - DrawImage()
/// <summary>
/// 이미지 그리기
/// </summary>
private void DrawImage()
{
if(this.sourceBitmap == null)
{
return;
}
float thickness;
float colorScale;
float opacity;
if(!float.TryParse(this.thicknessTextBox.Text, out thickness))
{
return;
}
if(!float.TryParse(this.colorScaleTextBox.Text, out colorScale))
{
return;
}
if(!float.TryParse(this.opacityTextBox.Text, out opacity))
{
return;
}
this.pictureBox.Image = SpiralizeBitmap
(
this.sourceBitmap,
this.colorArray,
thickness,
colorScale,
opacity,
this.drawOutlineCheckBox.Checked,
this.applyEllipticalMaskCheckBox.Checked
);
}
#endregion
}
}
728x90
반응형
그리드형(광고전용)
'C# > WinForm' 카테고리의 다른 글
[C#/WINFORM] Graphics 클래스 : FillPath/DrawPath 메소드를 사용해 라운드 사각형 그리기 (0) | 2020.08.10 |
---|---|
[C#/WINFORM] Graphics 클래스 : DrawRectangle 메소드를 사용해 사각형 그리기 (0) | 2020.08.10 |
[C#/WINFORM] Bitmap 클래스 : 비트맵 바이트 배열 구하기 (0) | 2020.08.10 |
[C#/WINFORM] 디지털 시계 표시하기 (0) | 2020.08.09 |
[C#/WINFORM] LED 텍스트 표시하기 (0) | 2020.08.09 |
[C#/WINFORM] Bitmap 클래스 : 이미지 나선 효과 사용하기 (0) | 2020.08.08 |
[C#/WINFORM] Bitmap 클래스 : 잠금없이 비트맵 로드하기 (0) | 2020.08.08 |
[C#/WINFORM] Image 클래스 : 이미지 저장하기 (0) | 2020.08.08 |
[C#/WINFORM] Bitmap 클래스 : 회색조/투명/네거티브/세피아 톤 필터 사용하기 (0) | 2020.08.08 |
[C#/WINFORM] Bitmap 클래스 : 세피아 톤 비트맵 구하기 (0) | 2020.08.08 |
[C#/WINFORM] Bitmap 클래스 : 네거티브 비트맵 구하기 (0) | 2020.08.08 |
댓글을 달아 주세요