728x90
반응형
728x170
▶ Cell.cs
using System.Drawing;
using System.Drawing.Drawing2D;
namespace TestProject
{
/// <summary>
/// 셀
/// </summary>
public class Cell
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region Field
/// <summary>
/// 테두리 사각형
/// </summary>
public RectangleF BoundRectangle;
/// <summary>
/// 비트맵
/// </summary>
public Bitmap Bitmap = null;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - Cell(boundRectangle)
/// <summary>
/// 생성자
/// </summary>
/// <param name="boundRectangle">테두리 사각형</param>
public Cell(RectangleF boundRectangle)
{
BoundRectangle = boundRectangle;
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 포인트 포함 여부 구하기 - ContainsPoint(point)
/// <summary>
/// 포인트 포함 여부 구하기
/// </summary>
/// <param name="point">포인트</param>
/// <returns>포인트 포함 여부</returns>
public bool ContainsPoint(PointF point)
{
return BoundRectangle.Contains(point);
}
#endregion
#region 그리기 - Draw(graphics, pen, cellWidth, cellHeight)
/// <summary>
/// 그리기
/// </summary>
/// <param name="graphics">그래픽스</param>
/// <param name="pen">펜</param>
/// <param name="cellWidth">셀 너비</param>
/// <param name="cellHeight">셀 높이</param>
public void Draw(Graphics graphics, Pen pen, float cellWidth, float cellHeight)
{
if(Bitmap != null)
{
float bitmapWidth = Bitmap.Width;
float bitmapHeight = Bitmap.Height;
float centerX = bitmapWidth / 2f;
float centerY = bitmapHeight / 2f;
if(bitmapWidth / bitmapHeight > BoundRectangle.Width / BoundRectangle.Height)
{
bitmapWidth = BoundRectangle.Width / BoundRectangle.Height * bitmapHeight;
}
else
{
bitmapHeight = bitmapWidth / (BoundRectangle.Width / BoundRectangle.Height);
}
RectangleF sourceRectangle = new RectangleF
(
centerX - bitmapWidth / 2f,
centerY - bitmapHeight / 2f,
bitmapWidth,
bitmapHeight
);
PointF[] targetPointArray =
{
new PointF(BoundRectangle.Left , BoundRectangle.Top ),
new PointF(BoundRectangle.Right, BoundRectangle.Top ),
new PointF(BoundRectangle.Left , BoundRectangle.Bottom)
};
graphics.DrawImage(Bitmap, targetPointArray, sourceRectangle, GraphicsUnit.Pixel);
}
graphics.DrawRectangle
(
pen,
BoundRectangle.X,
BoundRectangle.Y,
BoundRectangle.Width,
BoundRectangle.Height
);
GraphicsPath path = GetRoundedRectanglePath
(
BoundRectangle,
2 * pen.Width,
2 * pen.Width,
true,
true,
true,
true
);
graphics.DrawPath(pen, path);
}
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Private
#region 둥근 사각형 경로 구하기 - GetRoundedRectanglePath(rectangle, radiusX, radiusY, roundLeftUpper, roundRightUpper, roundRightLower, roundLeftLower)
/// <summary>
/// 둥근 사각형 경로 구하기
/// </summary>
/// <param name="rectangle">사각형</param>
/// <param name="radiusX">반경 X</param>
/// <param name="radiusY">반경 Y</param>
/// <param name="roundLeftUpper">좌상단 라운드 여부</param>
/// <param name="roundRightUpper">우상단 라운드 여부</param>
/// <param name="roundRightLower">우하단 라운드 여부</param>
/// <param name="roundLeftLower">좌하단 라운드 여부</param>
/// <returns>둥근 사각형 경로</returns>
private GraphicsPath GetRoundedRectanglePath
(
RectangleF rectangle,
float radiusX,
float radiusY,
bool roundLeftUpper,
bool roundRightUpper,
bool roundRightLower,
bool roundLeftLower
)
{
PointF point1;
PointF point2;
GraphicsPath graphicsPath = new GraphicsPath();
if(roundLeftUpper)
{
RectangleF cornerRectangle = new RectangleF
(
rectangle.X,
rectangle.Y,
2 * radiusX,
2 * radiusY
);
graphicsPath.AddArc(cornerRectangle, 180, 90);
point1 = new PointF(rectangle.X + radiusX, rectangle.Y);
}
else
{
point1 = new PointF(rectangle.X, rectangle.Y);
}
if(roundRightUpper)
{
point2 = new PointF(rectangle.Right - radiusX, rectangle.Y);
}
else
{
point2 = new PointF(rectangle.Right, rectangle.Y);
}
graphicsPath.AddLine(point1, point2);
if(roundRightUpper)
{
RectangleF cornerRectangle = new RectangleF
(
rectangle.Right - 2 * radiusX,
rectangle.Y,
2 * radiusX,
2 * radiusY
);
graphicsPath.AddArc(cornerRectangle, 270, 90);
point1 = new PointF(rectangle.Right, rectangle.Y + radiusY);
}
else
{
point1 = new PointF(rectangle.Right, rectangle.Y);
}
if(roundRightLower)
{
point2 = new PointF(rectangle.Right, rectangle.Bottom - radiusY);
}
else
{
point2 = new PointF(rectangle.Right, rectangle.Bottom);
}
graphicsPath.AddLine(point1, point2);
if(roundRightLower)
{
RectangleF cornerRectangle = new RectangleF
(
rectangle.Right - 2 * radiusX,
rectangle.Bottom - 2 * radiusY,
2 * radiusX,
2 * radiusY
);
graphicsPath.AddArc(cornerRectangle, 0, 90);
point1 = new PointF(rectangle.Right - radiusX, rectangle.Bottom);
}
else
{
point1 = new PointF(rectangle.Right, rectangle.Bottom);
}
if(roundLeftLower)
{
point2 = new PointF(rectangle.X + radiusX, rectangle.Bottom);
}
else
{
point2 = new PointF(rectangle.X, rectangle.Bottom);
}
graphicsPath.AddLine(point1, point2);
if(roundLeftLower)
{
RectangleF cornerRectangle = new RectangleF
(
rectangle.X,
rectangle.Bottom - 2 * radiusY,
2 * radiusX,
2 * radiusY
);
graphicsPath.AddArc(cornerRectangle, 90, 90);
point1 = new PointF(rectangle.X, rectangle.Bottom - radiusY);
}
else
{
point1 = new PointF(rectangle.X, rectangle.Bottom);
}
if(roundLeftUpper)
{
point2 = new PointF(rectangle.X, rectangle.Y + radiusY);
}
else
{
point2 = new PointF(rectangle.X, rectangle.Y);
}
graphicsPath.AddLine(point1, point2);
graphicsPath.CloseFigure();
return graphicsPath;
}
#endregion
}
}
728x90
▶ 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 int imageWidth;
/// <summary>
/// 이미지 높이
/// </summary>
private int imageHeight;
/// <summary>
/// 셀 너비
/// </summary>
private float cellWidth;
/// <summary>
/// 셀 높이
/// </summary>
private float cellHeight;
/// <summary>
/// 셀 각도
/// </summary>
private float cellAngle;
/// <summary>
/// 구분자 너비
/// </summary>
private float dividerWidth;
/// <summary>
/// 변환
/// </summary>
private Matrix transform = null;
/// <summary>
/// 역변환
/// </summary>
private Matrix inverseTransform = null;
/// <summary>
/// 셀 리스트
/// </summary>
private List<Cell> cellList = null;
/// <summary>
/// 문서 업데이트 여부
/// </summary>
private bool documentUpdated = false;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - MainForm()
/// <summary>
/// 생성자
/// </summary>
public MainForm()
{
InitializeComponent();
FormClosing += Form_FormClosing;
this.saveAsMenuItem.Click += saveAsMenuItem_Click;
this.exitMenuItem.Click += exitMenuItem_Click;
this.dividerWidthTextBox.TextChanged += dividerWidthTextBox_TextChanged;
this.dividerColorValueLabel.Click += dividerColorValueLabel_Click;
this.backgroundColorValueLabel.Click += backgroundColorValueLabel_Click;
this.createButton.Click += createButton_Click;
this.pictureBox.Paint += pictureBox_Paint;
this.pictureBox.MouseClick += pictureBox_MouseClick;
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Private
//////////////////////////////////////////////////////////////////////////////// Event
#region 폼을 닫을 경우 처리하기 - Form_FormClosing(sender, e)
/// <summary>
/// 폼을 닫을 경우 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void Form_FormClosing(object sender, FormClosingEventArgs e)
{
e.Cancel = !CheckDocumentUpdated();
}
#endregion
#region 다른 이름으로 저장 메뉴 항목 클릭시 처리하기 - saveAsMenuItem_Click(sender, e)
/// <summary>
/// 다른 이름으로 저장 메뉴 항목 클릭시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void saveAsMenuItem_Click(object sender, EventArgs e)
{
SaveBitmap();
}
#endregion
#region 종료 메뉴 항목 클릭시 처리하기 - exitMenuItem_Click(sender, e)
/// <summary>
/// 종료 메뉴 항목 클릭시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void exitMenuItem_Click(object sender, EventArgs e)
{
Close();
}
#endregion
#region 구분자 너비 텍스트 박스 텍스트 변경시 처리하기 - dividerWidthTextBox_TextChanged(sender, e)
/// <summary>
/// 구분자 너비 텍스트 박스 텍스트 변경시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void dividerWidthTextBox_TextChanged(object sender, EventArgs e)
{
float width;
if(float.TryParse(this.dividerWidthTextBox.Text, out width))
{
this.dividerWidth = width;
this.pictureBox.Refresh();
}
}
#endregion
#region 구분자 색상 값 레이블 클릭시 처리하기 - dividerColorValueLabel_Click(sender, e)
/// <summary>
/// 구분자 색상 값 레이블 클릭시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void dividerColorValueLabel_Click(object sender, EventArgs e)
{
this.colorDialog.Color = this.dividerColorValueLabel.BackColor;
if(this.colorDialog.ShowDialog() == DialogResult.OK)
{
this.dividerColorValueLabel.BackColor = this.colorDialog.Color;
this.pictureBox.Refresh();
}
}
#endregion
#region 배경 색상 값 레이블 클릭시 처리하기 - backgroundColorValueLabel_Click(sender, e)
/// <summary>
/// 배경 색상 값 레이블 클릭시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void backgroundColorValueLabel_Click(object sender, EventArgs e)
{
this.colorDialog.Color = this.backgroundColorValueLabel.BackColor;
if(this.colorDialog.ShowDialog() == DialogResult.OK)
{
this.backgroundColorValueLabel.BackColor = this.colorDialog.Color;
this.pictureBox.Refresh();
}
}
#endregion
#region 생성 버튼 클릭시 처리하기 - createButton_Click(sender, e)
/// <summary>
/// 생성 버튼 클릭시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void createButton_Click(object sender, EventArgs e)
{
if(!CheckDocumentUpdated())
{
return;
}
try
{
this.imageWidth = int.Parse (this.imageWidthTextBox.Text );
this.imageHeight = int.Parse (this.imageHeightTextBox.Text );
this.cellWidth = int.Parse (this.cellWidthTextBox.Text );
this.cellHeight = int.Parse (this.cellHeightTextBox.Text );
this.cellAngle = float.Parse(this.cellAngleTextBox.Text );
this.dividerWidth = float.Parse(this.dividerWidthTextBox.Text);
this.transform = new Matrix();
this.transform.Rotate(this.cellAngle);
this.inverseTransform = new Matrix();
this.inverseTransform.Rotate(-this.cellAngle);
MakeCells();
this.pictureBox.ClientSize = new Size(this.imageWidth, this.imageHeight);
this.pictureBox.Visible = true;
this.saveAsMenuItem.Enabled = true;
this.pictureBox.Refresh();
}
catch(Exception exception)
{
MessageBox.Show(exception.Message);
}
}
#endregion
#region 픽처 박스 페인트시 처리하기 - pictureBox_Paint(sender, e)
/// <summary>
/// 픽처 박스 페인트시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void pictureBox_Paint(object sender, PaintEventArgs e)
{
DrawCells(e.Graphics);
}
#endregion
#region 픽처 박스 마우스 클릭시 처리하기 - pictureBox_MouseClick(sender, e)
/// <summary>
/// 픽처 박스 마우스 클릭시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void pictureBox_MouseClick(object sender, MouseEventArgs e)
{
if(this.openFileDialog.ShowDialog() == DialogResult.OK)
{
try
{
PointF[] pointArray = { e.Location };
this.inverseTransform.TransformPoints(pointArray);
foreach(Cell cell in this.cellList)
{
if(cell.ContainsPoint(pointArray[0]))
{
cell.Bitmap = new Bitmap(this.openFileDialog.FileName);
this.documentUpdated = true;
break;
}
}
}
catch(Exception exception)
{
MessageBox.Show(exception.Message);
}
this.pictureBox.Refresh();
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////// Function
#region 문서 업데이트 여부 체크하기 - CheckDocumentUpdated()
/// <summary>
/// 문서 업데이트 여부 체크하기
/// </summary>
/// <returns>문서 업데이트 여부</returns>
private bool CheckDocumentUpdated()
{
if(!this.documentUpdated)
{
return true;
}
DialogResult result = MessageBox.Show
(
"변경 사항을 저장하시겠습니까?",
"CONFIRMATION",
MessageBoxButtons.YesNoCancel
);
if(result == DialogResult.No)
{
return true;
}
if(result == DialogResult.Cancel)
{
return false;
}
SaveBitmap();
return !this.documentUpdated;
}
#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 비트맵 저장하기 - SaveBitmap()
/// <summary>
/// 비트맵 저장하기
/// </summary>
private void SaveBitmap()
{
if(this.saveFileDialog.ShowDialog() == DialogResult.OK)
{
using(Bitmap bitmap = new Bitmap(this.imageWidth, this.imageHeight))
{
using(Graphics graphics = Graphics.FromImage(bitmap))
{
DrawCells(graphics);
}
SaveImage(bitmap, this.saveFileDialog.FileName);
}
this.documentUpdated = false;
}
}
#endregion
#region 셀 만들기 - MakeCells()
/// <summary>
/// 셀 만들기
/// </summary>
private void MakeCells()
{
PointF[] pointArray =
{
new PointF(0 , 0 ),
new PointF(0 , this.imageHeight),
new PointF(this.imageWidth, this.imageHeight),
new PointF(this.imageWidth, 0 ),
};
this.inverseTransform.TransformPoints(pointArray);
float minimumX = pointArray[0].X;
float minimumY = pointArray[0].Y;
float maximumX = minimumX;
float maximumY = minimumY;
for(int i = 1; i < pointArray.Length; i++)
{
if(minimumX > pointArray[i].X)
{
minimumX = pointArray[i].X;
}
if(maximumX < pointArray[i].X)
{
maximumX = pointArray[i].X;
}
if(minimumY > pointArray[i].Y)
{
minimumY = pointArray[i].Y;
}
if(maximumY < pointArray[i].Y)
{
maximumY = pointArray[i].Y;
}
}
int minimumRow = (int)(minimumY / this.cellHeight) - 1;
int maximumRow = (int)(maximumY / this.cellHeight) + 1;
int minimumColumn = (int)(minimumX / this.cellWidth ) - 1;
int maximumColumn = (int)(maximumX / this.cellWidth ) + 1;
GraphicsPath graphicsPath = new GraphicsPath();
graphicsPath.AddPolygon(pointArray);
Graphics graphics = CreateGraphics();
this.cellList = new List<Cell>();
for(int row = minimumRow; row <= maximumRow; row++)
{
for(int column = minimumColumn; column <= maximumColumn; column++)
{
Region region = new Region(graphicsPath);
float x = column * this.cellWidth;
float y = row * this.cellHeight;
if(Math.Abs(column % 2) == 1)
{
y += this.cellHeight / 2f;
}
RectangleF cellRectangle = new RectangleF
(
x,
y,
this.cellWidth,
this.cellHeight
);
region.Intersect(cellRectangle);
if(!region.IsEmpty(graphics))
{
this.cellList.Add(new Cell(cellRectangle));
}
}
}
}
#endregion
#region 셀 그리기 - DrawCells(graphics)
/// <summary>
/// 셀 그리기
/// </summary>
/// <param name="graphics">그래픽스</param>
private void DrawCells(Graphics graphics)
{
graphics.SmoothingMode = SmoothingMode.AntiAlias;
graphics.InterpolationMode = InterpolationMode.High;
graphics.Clear(this.backgroundColorValueLabel.BackColor);
graphics.Transform = this.transform;
using(Pen pen = new Pen(this.dividerColorValueLabel.BackColor, this.dividerWidth))
{
foreach(Cell cell in this.cellList)
{
cell.Draw(graphics, pen, this.cellWidth, this.cellHeight);
}
}
}
#endregion
}
}
728x90
반응형
그리드형(광고전용)
'C# > WinForm' 카테고리의 다른 글
[C#/WINFORM] 누겟 설치 : ImageProcessor.Plugins.WebP (0) | 2021.05.17 |
---|---|
[C#/WINFORM] 누겟 설치 : ImageProcessor (0) | 2021.05.17 |
[C#/WINFORM] OpenFileDialog 클래스 : AutoUpgradeEnabled 속성을 사용해 이전 스타일 대화 상자 열기 (0) | 2021.04.30 |
[C#/WINFORM] IWin32Window 인터페이스 : 메시지 박스 최상위 표시하기 (0) | 2021.04.30 |
[C#/WINFORM] Bitmap 클래스 : 스크롤 가능한 육각형 몽타주 비트맵 사용하기 (0) | 2021.04.11 |
[C#/WINFORM] Bitmap 클래스 : 스크롤 가능한 대각선 몽타주 비트맵 사용하기 (0) | 2021.04.11 |
[C#/WINFORM] 측면 및 종횡비로 정의된 사각형 찾기 (0) | 2021.04.11 |
[C#/WINFORM] B 트리 사용하기 (0) | 2021.04.10 |
[C#/WINFORM] Bitmap 클래스 : 마우스 휠을 사용해 특정 종횡비로 비트맵 잘라내기 (0) | 2021.04.10 |
[C#/WINFORM] 특정 화면에서 전경 윈도우의 전체 화면 모드 여부 구하기 (0) | 2021.04.10 |
[C#/WINFORM] 윈도우 텍스트 구하기 (0) | 2021.04.07 |
댓글을 달아 주세요