728x90
반응형
728x170
▶ HexagonHelper.cs
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
namespace TestProject
{
/// <summary>
/// 육각형 헬퍼
/// </summary>
public static class HexagonHelper
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Public
#region 육각형 너비 구하기 - GetHexgonWidth(height)
/// <summary>
/// 육각형 너비 구하기
/// </summary>
/// <param name="height">높이</param>
/// <returns>육각형 너비</returns>
public static float GetHexgonWidth(float height)
{
return (float)(4 * (height / 2 / Math.Sqrt(3)));
}
#endregion
#region 육각형 인덱스 설정하기 - SetHexgonIndex(x, y, height, row, column)
/// <summary>
/// 육각형 인덱스 설정하기
/// </summary>
/// <param name="x">X</param>
/// <param name="y">Y</param>
/// <param name="height">육각형 높이</param>
/// <param name="row">행</param>
/// <param name="column">열</param>
public static void SetHexgonIndex(float x, float y, float height, out int row, out int column)
{
float width = GetHexgonWidth(height);
column = (int)(x / (width * 0.75f));
if(column % 2 == 0)
{
row = (int)Math.Floor(y / height);
}
else
{
row = (int)Math.Floor((y - height / 2) / height);
}
float testX = column * width * 0.75f;
float testY = row * height;
if(column % 2 != 0)
{
testY += height / 2;
}
bool isAbove = false;
bool isBelow = false;
float deltaX = x - testX;
if(deltaX < width / 4)
{
float deltaY = y - (testY + height / 2);
if(deltaX < 0.001)
{
if(deltaY < 0)
{
isAbove = true;
}
if(deltaY > 0)
{
isBelow = true;
}
}
else if(deltaY < 0)
{
if(-deltaY / deltaX > Math.Sqrt(3))
{
isAbove = true;
}
}
else
{
if(deltaY / deltaX > Math.Sqrt(3))
{
isBelow = true;
}
}
}
if(isAbove)
{
if(column % 2 == 0)
{
row--;
}
column--;
}
else if(isBelow)
{
if(column % 2 != 0)
{
row++;
}
column--;
}
}
#endregion
#region 포인트 배열 구하기 - GetPointArray(height, row, column, minimumX, minimumY)
/// <summary>
/// 포인트 배열 구하기
/// </summary>
/// <param name="height">육각형 높이</param>
/// <param name="row">행</param>
/// <param name="column">열</param>
/// <param name="minimumX">최소 X</param>
/// <param name="minimumY">최소 Y</param>
/// <returns>포인트 배열</returns>
public static PointF[] GetPointArray(float height, float row, float column, float minimumX, float minimumY)
{
float width = GetHexgonWidth(height);
float y = height / 2;
float x = 0;
y += row * height;
if(column % 2 != 0)
{
y += height / 2;
}
x += column * (width * 0.75f);
return new PointF[]
{
new PointF(minimumX + x , minimumY + y ),
new PointF(minimumX + x + width * 0.25f, minimumY + y - height / 2),
new PointF(minimumX + x + width * 0.75f, minimumY + y - height / 2),
new PointF(minimumX + x + width , minimumY + y ),
new PointF(minimumX + x + width * 0.75f, minimumY + y + height / 2),
new PointF(minimumX + x + width * 0.25f, minimumY + y + height / 2)
};
}
#endregion
#region 육각형 그리드 그리기 - DrawHexgonGrid(graphics, pen, minimumX, maximumX, minimumY, maximumY, height)
/// <summary>
/// 육각형 그리드 그리기
/// </summary>
/// <param name="graphics">그래픽스</param>
/// <param name="pen">펜</param>
/// <param name="minimumX">최소 X</param>
/// <param name="maximumX">최대 X</param>
/// <param name="minimumY">최소 Y</param>
/// <param name="maximumY">최대 Y</param>
/// <param name="height">육각형 높이</param>
public static void DrawHexgonGrid(Graphics graphics, Pen pen, float minimumX, float maximumX, float minimumY, float maximumY, float height)
{
for(int row = 0; ; row++)
{
PointF[] pointArray = HexagonHelper.GetPointArray(height, row, 0, minimumX, minimumY);
if(pointArray[4].Y > maximumY)
{
break;
}
for(int column = 0; ; column++)
{
pointArray = HexagonHelper.GetPointArray(height, row, column, minimumX, minimumX);
if(pointArray[3].X > maximumX)
{
break;
}
if(pointArray[4].Y <= maximumY)
{
graphics.DrawPolygon(pen, pointArray);
}
}
}
}
#endregion
#region 다각형 내에서 이미지 그리기 - DrawImageInPolygon(graphcis, pointArray, image)
/// <summary>
/// 다각형 내에서 이미지 그리기
/// </summary>
/// <param name="graphcis">그래픽스</param>
/// <param name="pointArray">포인트 배열</param>
/// <param name="image">이미지</param>
public static void DrawImageInPolygon(Graphics graphcis, PointF[] pointArray, Image image)
{
float minimumX;
float maximumX;
float minimumY;
float maximumY;
SetPolygonBoundRectangle(pointArray, out minimumX, out maximumX, out minimumY, out maximumY);
float width = maximumX - minimumX;
float height = maximumY - minimumY;
float centerX = (minimumX + maximumX) / 2f;
float centerY = (minimumY + maximumY) / 2f;
float scaleX = width / image.Width;
float scaleY = height / image.Height;
float scale = Math.Max(scaleX, scaleY);
float scaledWdth = image.Width * scale;
float scaledHeight = image.Height * scale;
float radiusX = scaledWdth / 2f;
float radiusY = scaledHeight / 2f;
RectangleF sourceRectangle = new RectangleF(0, 0, image.Width, image.Height);
PointF[] targetPointArray =
{
new PointF(centerX - radiusX, centerY - radiusY),
new PointF(centerX + radiusX, centerY - radiusY),
new PointF(centerX - radiusX, centerY + radiusY)
};
GraphicsPath graphicsPath = new GraphicsPath();
graphicsPath.AddPolygon(pointArray);
GraphicsState graphicsState = graphcis.Save();
graphcis.SetClip(graphicsPath);
graphcis.DrawImage(image, targetPointArray, sourceRectangle, GraphicsUnit.Pixel);
graphcis.Restore(graphicsState);
}
#endregion
//////////////////////////////////////////////////////////////////////////////// Private
#region 다각형 테두리 사각형 설정하기 - SetPolygonBoundRectangle(pointArray, minimumX, maximumX, minimumY, maximumY)
/// <summary>
/// 다각형 테두리 사각형 설정하기
/// </summary>
/// <param name="pointArray">포인트 배열</param>
/// <param name="minimumX">최소 X</param>
/// <param name="maximumX">최대 X</param>
/// <param name="minimumY">최소 Y</param>
/// <param name="maximumY">최대 Y</param>
private static void SetPolygonBoundRectangle(PointF[] pointArray, out float minimumX, out float maximumX, out float minimumY, out float maximumY)
{
minimumX = pointArray[0].X;
maximumX = minimumX;
minimumY = pointArray[0].Y;
maximumY = minimumY;
foreach(PointF point in pointArray)
{
if(minimumX > point.X)
{
minimumX = point.X;
}
if(maximumX < point.X)
{
maximumX = point.X;
}
if(minimumY > point.Y)
{
minimumY = point.Y;
}
if(maximumY < point.Y)
{
maximumY = point.Y;
}
}
}
#endregion
}
}
728x90
▶ Hexagon.cs
using System.Drawing;
using System.IO;
namespace TestProject
{
/// <summary>
/// 육각형
/// </summary>
public class Hexagon
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Public
#region Field
/// <summary>
/// 행
/// </summary>
public int Row;
/// <summary>
/// 열
/// </summary>
public int Column;
/// <summary>
/// 비트맵
/// </summary>
public Bitmap Bitmap;
/// <summary>
/// 파일 경로
/// </summary>
public string FilePath;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - Hexagon(row, column, bitmap, filePath)
/// <summary>
/// 생성자
/// </summary>
/// <param name="row">행</param>
/// <param name="column">열</param>
/// <param name="bitmap">비트맵</param>
/// <param name="filePath">파일 경로</param>
public Hexagon(int row, int column, Bitmap bitmap, string filePath)
{
Row = row;
Column = column;
Bitmap = bitmap;
FileInfo fileInfo = new FileInfo(filePath);
FilePath = fileInfo.Name;
}
#endregion
}
}
300x250
▶ 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 float hexgonHeight = 200;
/// <summary>
/// 테두리 두께
/// </summary>
private float borderThickness = 5;
/// <summary>
/// 육각형 리스트
/// </summary>
private List<Hexagon> hexagonList = new List<Hexagon>();
/// <summary>
/// 행 수
/// </summary>
private int rowCount = 1;
/// <summary>
/// 열 수
/// </summary>
private int columnCount = 1;
/// <summary>
/// 비트맵
/// </summary>
private Bitmap bitmap = null;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - MainForm()
/// <summary>
/// 생성자
/// </summary>
public MainForm()
{
InitializeComponent();
this.openMenuItem.Click += openMenuItem_Click;
this.saveAsMenuItem.Click += saveAsMenuItem_Click;
this.exitMenuItem.Click += exitMenuItem_Click;
this.hexagonHeightTextBox.TextChanged += hexagonHeightTextBox_TextChanged;
this.borderThicknessTextBox.TextChanged += hexagonHeightTextBox_TextChanged;
this.borderColorPictureBox.Click += borderColorPictureBox_Click;
this.backgroundColorPictureBox.Click += backgroundColorPictureBox_Click;
this.createButton.Click += createButton_Click;
this.pictureBox.MouseMove += pictureBox_MouseMove;
this.pictureBox.MouseClick += pictureBox_MouseClick;
}
#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.openFileDialog1.ShowDialog() == DialogResult.OK)
{
FileInfo fileInfo1 = new FileInfo(this.openFileDialog1.FileName);
DirectoryInfo directoryInfo = fileInfo1.Directory;
List<FileInfo> fileInfoList = new List<FileInfo>();
foreach(FileInfo fileInfo2 in directoryInfo.GetFiles())
{
string fileExtension = fileInfo2.Extension.ToLower().Replace(".", "");
if
(
(fileExtension == "bmp" ) ||
(fileExtension == "png" ) ||
(fileExtension == "jpg" ) ||
(fileExtension == "jpeg") ||
(fileExtension == "gif" ) ||
(fileExtension == "tiff")
)
{
fileInfoList.Add(fileInfo2);
}
}
int rowCount = (int)Math.Sqrt(fileInfoList.Count);
int columnCount = rowCount;
if(rowCount * columnCount < fileInfoList.Count)
{
columnCount++;
}
if(rowCount * columnCount < fileInfoList.Count)
{
rowCount++;
}
this.hexagonList = new List<Hexagon>();
int index = 0;
for(int row = 0; row < rowCount; row++)
{
for(int column = 0; column < columnCount; column++)
{
string name = fileInfoList[index].Name;
string filePath = fileInfoList[index].FullName;
Bitmap bitmap = LoadBitmap(filePath);
this.hexagonList.Add(new Hexagon(row, column, bitmap, name));
index++;
if(index >= fileInfoList.Count)
{
break;
}
}
if(index >= fileInfoList.Count)
{
break;
}
}
MakeGrid();
}
}
#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.bitmap, this.saveFileDialog.FileName);
}
}
#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 육각형 높이 텍스트 박스 텍스트 변경시 처리하기 - hexagonHeightTextBox_TextChanged(sender, e)
/// <summary>
/// 육각형 높이 텍스트 박스 텍스트 변경시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void hexagonHeightTextBox_TextChanged(object sender, EventArgs e)
{
float height;
float thickness;
if(!float.TryParse(this.hexagonHeightTextBox.Text, out height) || height < 10)
{
return;
}
if(!float.TryParse(this.borderThicknessTextBox.Text, out thickness))
{
return;
}
this.hexgonHeight = height;
this.borderThickness = thickness;
this.pictureBox.Refresh();
}
#endregion
#region 테두리 색상 픽처 박스 클릭시 처리하기 - borderColorPictureBox_Click(sender, e)
/// <summary>
/// 테두리 색상 픽처 박스 클릭시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void borderColorPictureBox_Click(object sender, EventArgs e)
{
this.colorDialog.Color = this.borderColorPictureBox.BackColor;
if(this.colorDialog.ShowDialog() == DialogResult.OK)
{
this.borderColorPictureBox.BackColor = this.colorDialog.Color;
this.pictureBox.Refresh();
}
}
#endregion
#region 배경 색상 픽처 박스 클릭시 처리하기 - backgroundColorPictureBox_Click(sender, e)
/// <summary>
/// 배경 색상 픽처 박스 클릭시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void backgroundColorPictureBox_Click(object sender, EventArgs e)
{
this.colorDialog.Color = this.backgroundColorPictureBox.BackColor;
if(this.colorDialog.ShowDialog() == DialogResult.OK)
{
this.backgroundColorPictureBox.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)
{
MakeGrid();
this.pictureBox.Visible = true;
}
#endregion
#region 픽처 박스 마우스 이동시 처리하기 - pictureBox_MouseMove(sender, e)
/// <summary>
/// 픽처 박스 마우스 이동시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void pictureBox_MouseMove(object sender, MouseEventArgs e)
{
int row;
int column;
HexagonHelper.SetHexgonIndex(e.X, e.Y, this.hexgonHeight, out row, out column);
int index = FindHexagon(row, column);
string indexString = "(" + row.ToString() + ", " + column.ToString() + ")";
if(index < 0)
{
Text = $"Bitmap 클래스 : 스크롤 가능한 육각형 몽타주 비트맵 사용하기 : {indexString}";
}
else
{
string name = this.hexagonList[index].FilePath;
int position = name.IndexOf('.');
Text = $"{indexString} {name.Substring(0, position)}";
}
}
#endregion
#region 픽처 박스 마우스 클릭시 처리하기 - pictureBox_MouseClick(sender, e)
/// <summary>
/// 픽처 박스 마우스 클릭시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void pictureBox_MouseClick(object sender, MouseEventArgs e)
{
int row;
int column;
HexagonHelper.SetHexgonIndex(e.X, e.Y, this.hexgonHeight, out row, out column);
RemoveHexagon(row, column);
if(this.openFileDialog2.ShowDialog() == DialogResult.OK)
{
Bitmap bitmap = LoadBitmap(openFileDialog2.FileName);
this.hexagonList.Add(new Hexagon(row, column, bitmap, openFileDialog2.FileName));
}
MakeGrid();
}
#endregion
//////////////////////////////////////////////////////////////////////////////// Function
#region 비트맵 로드하기 - LoadBitmap(filePath)
/// <summary>
/// 비트맵 로드하기
/// </summary>
/// <param name="filePath">파일 경로</param>
/// <returns>비트맵</returns>
private Bitmap LoadBitmap(string filePath)
{
using(Bitmap bitmap = new Bitmap(filePath))
{
return new Bitmap(bitmap);
}
}
#endregion
#region 그리드 테두리 사각형 찾기 - FindGridBoundRectangle(maximumX, maximumY)
/// <summary>
/// 그리드 테두리 사각형 찾기
/// </summary>
/// <param name="maximumX">최대 X</param>
/// <param name="maximumY">최대 Y</param>
private void FindGridBoundRectangle(out float maximumX, out float maximumY)
{
maximumX = 0;
maximumY = 0;
float minimumX = this.borderThickness / 2f;
PointF[] pointArray;
pointArray = HexagonHelper.GetPointArray
(
this.hexgonHeight,
this.rowCount - 1,
this.columnCount - 1,
minimumX,
minimumX
);
if(maximumX < pointArray[3].X)
{
maximumX = pointArray[3].X;
}
if(maximumY < pointArray[4].Y)
{
maximumY = pointArray[4].Y;
}
pointArray = HexagonHelper.GetPointArray
(
this.hexgonHeight,
this.rowCount - 1,
this.columnCount - 1,
minimumX,
minimumX
);
if(maximumX < pointArray[3].X)
{
maximumX = pointArray[3].X;
}
if(maximumY < pointArray[4].Y)
{
maximumY = pointArray[4].Y;
}
maximumX += minimumX;
maximumY += minimumX;
}
#endregion
#region 그리드 그리기 - DrawGrid(graphics, maximumX, maximumY)
/// <summary>
/// 그리드 그리기
/// </summary>
/// <param name="graphics">그래픽스</param>
/// <param name="maximumX">최대 X</param>
/// <param name="maximumY">최대 Y</param>
private void DrawGrid(Graphics graphics, int maximumX, int maximumY)
{
graphics.Clear(this.backgroundColorPictureBox.BackColor);
graphics.SmoothingMode = SmoothingMode.AntiAlias;
float minimumX = this.borderThickness / 2f;
foreach(Hexagon hexagon in this.hexagonList)
{
PointF[] pointArray = HexagonHelper.GetPointArray
(
this.hexgonHeight,
hexagon.Row,
hexagon.Column,
minimumX,
minimumX
);
if(pointArray[3].X > maximumX)
{
continue;
}
if(pointArray[4].Y > maximumY)
{
continue;
}
HexagonHelper.DrawImageInPolygon
(
graphics,
HexagonHelper.GetPointArray
(
this.hexgonHeight,
hexagon.Row,
hexagon.Column,
minimumX,
minimumX
),
hexagon.Bitmap
);
}
using(Pen pen = new Pen(this.borderColorPictureBox.BackColor, this.borderThickness))
{
HexagonHelper.DrawHexgonGrid
(
graphics,
pen,
minimumX,
maximumX,
minimumX,
maximumY,
this.hexgonHeight
);
}
}
#endregion
#region 그리드 만들기 - MakeGrid()
/// <summary>
/// 그리드 만들기
/// </summary>
private void MakeGrid()
{
if(!int.TryParse(this.rowCountTextBox.Text, out this.rowCount))
{
return;
}
if(!int.TryParse(this.columnCountTextBox.Text, out this.columnCount))
{
return;
}
float maximumX;
float maximumY;
FindGridBoundRectangle(out maximumX, out maximumY);
int width = (int)maximumX + 1;
int height = (int)maximumY + 1;
this.bitmap = new Bitmap(width, height);
using(Graphics graphics = Graphics.FromImage(this.bitmap))
{
DrawGrid(graphics, width, height);
}
this.pictureBox.Image = this.bitmap;
this.saveAsMenuItem.Enabled = true;
}
#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 육각형 찾기 - FindHexagon(row, column)
/// <summary>
/// 육각형 찾기
/// </summary>
/// <param name="row">행</param>
/// <param name="column">열</param>
/// <returns>인덱스</returns>
private int FindHexagon(int row, int column)
{
for (int i = this.hexagonList.Count - 1; i >= 0; i--)
{
if((this.hexagonList[i].Row == row) && (this.hexagonList[i].Column == column))
{
return i;
}
}
return -1;
}
#endregion
#region 육각형 제거하기 - RemoveHexagon(row, column)
/// <summary>
/// 육각형 제거하기
/// </summary>
/// <param name="row">행</param>
/// <param name="column">열</param>
private void RemoveHexagon(int row, int column)
{
int index = FindHexagon(row,column);
if(index >= 0)
{
this.hexagonList.RemoveAt(index);
}
}
#endregion
}
}
728x90
반응형
그리드형(광고전용)
'C# > WinForm' 카테고리의 다른 글
[C#/WINFORM] IProgress<T> 인터페이스 : Report 메소드를 사용해 비동기 작업시 진행 상태 보고하기 (0) | 2021.06.27 |
---|---|
[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 |
댓글을 달아 주세요