728x90
반응형
728x170
▶ GraphicsExtension.cs
using System.Drawing;
namespace TestProject
{
/// <summary>
/// 그래픽스 확장
/// </summary>
public static class GraphicsExtension
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Public
#region 사각형 그리기 - DrawRectangle(graphics, pen, rectangle)
/// <summary>
/// 사각형 그리기
/// </summary>
/// <param name="graphics">그래픽스</param>
/// <param name="pen">펜</param>
/// <param name="rectangle">사각형</param>
public static void DrawRectangle(this Graphics graphics, Pen pen, RectangleF rectangle)
{
graphics.DrawRectangle(pen, rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height);
}
#endregion
#region 상자 그리기 - DrawBox(graphics, brush, pen, centerPoint, radius)
/// <summary>
/// 상자 그리기
/// </summary>
/// <param name="graphics">그래픽스</param>
/// <param name="brush">브러시</param>
/// <param name="pen">펜</param>
/// <param name="centerPoint">중심 포인트</param>
/// <param name="radius">반경</param>
public static void DrawBox(this Graphics graphics, Brush brush, Pen pen, PointF centerPoint, float radius)
{
RectangleF rectangle = new RectangleF
(
centerPoint.X - radius,
centerPoint.Y - radius,
2 * radius,
2 * radius
);
graphics.FillRectangle(brush, rectangle);
graphics.DrawRectangle(pen, rectangle);
}
#endregion
#region 이미지 확대/축소하기 - ScaleImage(sourceBitmap, scale)
/// <summary>
/// 이미지 확대/축소하기
/// </summary>
/// <param name="sourceBitmap">소스 비트맵</param>
/// <param name="scale">스케일</param>
/// <returns>비트맵</returns>
public static Bitmap ScaleImage(this Bitmap sourceBitmap, float scale)
{
if(sourceBitmap == null)
{
return null;
}
int widthScaled = (int)(sourceBitmap.Width * scale);
int heightScaled = (int)(sourceBitmap.Height * scale);
Bitmap targetBitmap = new Bitmap(widthScaled, heightScaled);
using(Graphics graphics = Graphics.FromImage(targetBitmap))
{
Point[] targetPointArray =
{
new Point(0 , 0 ),
new Point(widthScaled - 1, 0 ),
new Point(0 , heightScaled - 1)
};
Rectangle targetRectangle = new Rectangle
(
0,
0,
sourceBitmap.Width - 1,
sourceBitmap.Height - 1
);
graphics.DrawImage(sourceBitmap, targetPointArray, targetRectangle, GraphicsUnit.Pixel);
}
return targetBitmap;
}
#endregion
}
}
728x90
▶ BitmapHelper.cs
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
namespace TestProject
{
/// <summary>
/// 비트맵 헬퍼
/// </summary>
public class BitmapHelper
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Public
#region Field
/// <summary>
/// 픽셀 비트 수
/// </summary>
public const int PIXEL_BIT_COUNT = 32;
/// <summary>
/// 이미지 바이트 배열
/// </summary>
public byte[] ImageByteArray;
/// <summary>
/// 행 바이트 수
/// </summary>
public int RowByteCount;
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 소스 비트맵
/// </summary>
private Bitmap sourceBitmap;
/// <summary>
/// 소스 비트맵 데이터
/// </summary>
private BitmapData sourceBitmapData;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 너비 - Width
/// <summary>
/// 너비
/// </summary>
public int Width
{
get
{
return this.sourceBitmap.Width;
}
}
#endregion
#region 높이 - Height
/// <summary>
/// 높이
/// </summary>
public int Height
{
get
{
return this.sourceBitmap.Height;
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - BitmapHelper(sourceBitmap)
/// <summary>
/// 생성자
/// </summary>
/// <param name="sourceBitmap">소스 비트맵</param>
public BitmapHelper(Bitmap sourceBitmap)
{
this.sourceBitmap = sourceBitmap;
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 픽셀 구하기 - GetPixel(x, y, red, green, blue, alpha)
/// <summary>
/// 픽셀 구하기
/// </summary>
/// <param name="x">X</param>
/// <param name="y">Y</param>
/// <param name="red">적색 채널</param>
/// <param name="green">녹색 채널</param>
/// <param name="blue">청색 채널</param>
/// <param name="alpha">알파 채널</param>
public void GetPixel(int x, int y, out byte red, out byte green, out byte blue, out byte alpha)
{
int i = y * this.sourceBitmapData.Stride + x * 4;
blue = ImageByteArray[i++];
green = ImageByteArray[i++];
red = ImageByteArray[i++];
alpha = ImageByteArray[i ];
}
#endregion
#region 적색 채널 구하기 - GetRed(x, y)
/// <summary>
/// 적색 채널 구하기
/// </summary>
/// <param name="x">X</param>
/// <param name="y">Y</param>
/// <returns>적색 채널</returns>
public byte GetRed(int x, int y)
{
int i = y * this.sourceBitmapData.Stride + x * 4;
return ImageByteArray[i + 2];
}
#endregion
#region 녹색 채널 구하기 - GetGreen(x, y)
/// <summary>
/// 녹색 채널 구하기
/// </summary>
/// <param name="x">X</param>
/// <param name="y">Y</param>
/// <returns>녹색 채널</returns>
public byte GetGreen(int x, int y)
{
int i = y * this.sourceBitmapData.Stride + x * 4;
return ImageByteArray[i + 1];
}
#endregion
#region 청색 채널 구하기 - GetBlue(x, y)
/// <summary>
/// 청색 채널 구하기
/// </summary>
/// <param name="x">X</param>
/// <param name="y">Y</param>
/// <returns>청색 채널</returns>
public byte GetBlue(int x, int y)
{
int i = y * this.sourceBitmapData.Stride + x * 4;
return ImageByteArray[i];
}
#endregion
#region 알파 채널 구하기 - GetAlpha(x, y)
/// <summary>
/// 알파 채널 구하기
/// </summary>
/// <param name="x">X</param>
/// <param name="y">Y</param>
/// <returns>알파 채널</returns>
public byte GetAlpha(int x, int y)
{
int i = y * this.sourceBitmapData.Stride + x * 4;
return ImageByteArray[i + 3];
}
#endregion
#region 픽셀 설정하기 - SetPixel(x, y, red, green, blue, alpha)
/// <summary>
/// 픽셀 설정하기
/// </summary>
/// <param name="x">X</param>
/// <param name="y">Y</param>
/// <param name="red">적색 채널</param>
/// <param name="green">녹색 채널</param>
/// <param name="blue">청색 채널</param>
/// <param name="alpha">알파 채널</param>
public void SetPixel(int x, int y, byte red, byte green, byte blue, byte alpha)
{
int i = y * this.sourceBitmapData.Stride + x * 4;
ImageByteArray[i++] = blue;
ImageByteArray[i++] = green;
ImageByteArray[i++] = red;
ImageByteArray[i ] = alpha;
}
#endregion
#region 적색 채널 설정하기 - SetRed(x, y, red)
/// <summary>
/// 적색 채널 설정하기
/// </summary>
/// <param name="x">X</param>
/// <param name="y">Y</param>
/// <param name="red">적색 채널</param>
public void SetRed(int x, int y, byte red)
{
int i = y * this.sourceBitmapData.Stride + x * 4;
ImageByteArray[i + 2] = red;
}
#endregion
#region 녹색 채널 설정하기 - SetGreen(x, y, green)
/// <summary>
/// 녹색 채널 설정하기
/// </summary>
/// <param name="x">X</param>
/// <param name="y">Y</param>
/// <param name="green">녹색 채널</param>
public void SetGreen(int x, int y, byte green)
{
int i = y * this.sourceBitmapData.Stride + x * 4;
ImageByteArray[i + 1] = green;
}
#endregion
#region 청색 채널 설정하기 - SetBlue(x, y, blue)
/// <summary>
/// 청색 채널 설정하기
/// </summary>
/// <param name="x">X</param>
/// <param name="y">Y</param>
/// <param name="blue">청색 채널</param>
public void SetBlue(int x, int y, byte blue)
{
int i = y * this.sourceBitmapData.Stride + x * 4;
ImageByteArray[i] = blue;
}
#endregion
#region 알파 채널 설정하기 - SetAlpha(x, y, alpha)
/// <summary>
/// 알파 채널 설정하기
/// </summary>
/// <param name="x">X</param>
/// <param name="y">Y</param>
/// <param name="alpha">알파 채널</param>
public void SetAlpha(int x, int y, byte alpha)
{
int i = y * this.sourceBitmapData.Stride + x * 4;
ImageByteArray[i + 3] = alpha;
}
#endregion
#region 비트맵 잠금 설정하기 - LockBitmap()
/// <summary>
/// 비트맵 잠금 설정하기
/// </summary>
public void LockBitmap()
{
Rectangle sourceRectangle = new Rectangle
(
0,
0,
this.sourceBitmap.Width,
this.sourceBitmap.Height
);
this.sourceBitmapData = this.sourceBitmap.LockBits
(
sourceRectangle,
ImageLockMode.ReadWrite,
PixelFormat.Format32bppArgb
);
RowByteCount = this.sourceBitmapData.Stride;
int totalByteCount = this.sourceBitmapData.Stride * this.sourceBitmapData.Height;
ImageByteArray = new byte[totalByteCount];
Marshal.Copy(this.sourceBitmapData.Scan0, ImageByteArray, 0, totalByteCount);
}
#endregion
#region 비트맵 잠금 해제하기 - UnlockBitmap()
/// <summary>
/// 비트맵 잠금 해제하기
/// </summary>
public void UnlockBitmap()
{
int totalByteCount = this.sourceBitmapData.Stride * this.sourceBitmapData.Height;
Marshal.Copy(ImageByteArray, 0, this.sourceBitmapData.Scan0, totalByteCount);
this.sourceBitmap.UnlockBits(this.sourceBitmapData);
ImageByteArray = null;
this.sourceBitmapData = null;
}
#endregion
}
}
300x250
▶ MainForm.cs
using System;
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
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Enumeration
////////////////////////////////////////////////////////////////////////////////////////// Private
#region 히트 타입 - HitType
/// <summary>
/// 히트 타입
/// </summary>
private enum HitType
{
/// <summary>
/// 해당 무
/// </summary>
None,
/// <summary>
/// 몸체
/// </summary>
Body,
/// <summary>
/// 왼쪽 가장자리
/// </summary>
LeftEdge,
/// <summary>
/// 오른쪽 가장자리
/// </summary>
RightEdge,
/// <summary>
/// 위쪽 가장자리
/// </summary>
TopEdge,
/// <summary>
/// 아래쪽 가장자리
/// </summary>
BottomEdge,
/// <summary>
/// 상단 왼쪽 모서리
/// </summary>
TopLeftCorner,
/// <summary>
/// 상단 오른쪽 모서리
/// </summary>
TopRightCorner,
/// <summary>
/// 하단 왼쪽 모서리
/// </summary>
BottomLeftCorner,
/// <summary>
/// 하단 오른쪽 모서리
/// </summary>
BottomRightCorner,
};
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 상자 반경
/// </summary>
private const int BOX_RADIUS = 4;
/// <summary>
/// 배경 비트맵
/// </summary>
private Bitmap backgroundBitmap = null;
/// <summary>
/// 전경 비트맵
/// </summary>
private Bitmap foregroundBitmap = null;
/// <summary>
/// 전경 사각형
/// </summary>
private RectangleF foregroundRectangle = new RectangleF(-10, -10, 1, 1);
/// <summary>
/// 드래그 여부
/// </summary>
private bool isDragging = false;
/// <summary>
/// 히트 타입
/// </summary>
private HitType hitType = HitType.None;
/// <summary>
/// 마지막 마우스 포인트
/// </summary>
private Point lastMousePoint;
/// <summary>
/// 반대 모서리
/// </summary>
private PointF oppositeCorner;
/// <summary>
/// 이미지 확대/축소
/// </summary>
private float imageScale = 1f;
/// <summary>
/// 종횡비
/// </summary>
private float aspectRatio = 1f;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - MainForm()
/// <summary>
/// 생성자
/// </summary>
public MainForm()
{
InitializeComponent();
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Private
//////////////////////////////////////////////////////////////////////////////// Event
#region 배경 이미지 메뉴 항목 클릭시 처리하기 - backgroundImageMenuItem_Click(sender, e)
/// <summary>
/// 배경 이미지 메뉴 항목 클릭시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void backgroundImageMenuItem_Click(object sender, EventArgs e)
{
if(this.openFileDialog.ShowDialog() == DialogResult.OK)
{
this.backgroundBitmap = GetBitmap(this.openFileDialog.FileName);
this.pictureBox.Image = this.backgroundBitmap.ScaleImage(this.imageScale);
this.pictureBox.Refresh();
}
}
#endregion
#region 전경 이미지 메뉴 항목 클릭시 처리하기 - foregroundImageMenuItem_Click(sender, e)
/// <summary>
/// 전경 이미지 메뉴 항목 클릭시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void foregroundImageMenuItem_Click(object sender, EventArgs e)
{
if(this.openFileDialog.ShowDialog() == DialogResult.OK)
{
this.foregroundBitmap = GetBitmap(this.openFileDialog.FileName);
this.foregroundRectangle = new RectangleF
(
0,
0,
this.foregroundBitmap.Width,
this.foregroundBitmap.Height
);
this.aspectRatio = (float)this.foregroundBitmap.Width / (float)this.foregroundBitmap.Height;
Bitmap ellipseBitmap = new Bitmap(this.foregroundBitmap.Width, this.foregroundBitmap.Height);
using(Graphics ellipseGraphics = Graphics.FromImage(ellipseBitmap))
{
ellipseGraphics.Clear(Color.Transparent);
using(GraphicsPath path = new GraphicsPath())
{
path.AddEllipse(this.foregroundRectangle);
using(PathGradientBrush brush = new PathGradientBrush(path))
{
Blend blend = new Blend();
blend.Positions = new float[] { 0.0f, 0.05f, 1.0f };
blend.Factors = new float[] { 0.0f, 1.0f , 1.0f };
brush.CenterPoint = new PointF
(
this.foregroundBitmap.Width / 2f,
this.foregroundBitmap.Height / 2f
);
brush.CenterColor = Color.White;
brush.SurroundColors = new Color[] { Color.FromArgb(0, 0, 0, 0) };
brush.Blend = blend;
ellipseGraphics.FillPath(brush, path);
}
}
}
CopyAlpha(this.foregroundBitmap, ellipseBitmap);
this.pictureBox.Refresh();
}
}
#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)
{
Bitmap targetBitmap = new Bitmap(this.backgroundBitmap);
if(this.foregroundBitmap != null)
{
using(Graphics targetGraphics = Graphics.FromImage(targetBitmap))
{
targetGraphics.DrawImage(this.foregroundBitmap, this.foregroundRectangle);
}
}
SaveImage(targetBitmap, 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 확대/축소 메뉴 항목 클릭시 처리하기 - scaleMenuItem_Click(sender, e)
/// <summary>
/// 확대/축소 메뉴 항목 클릭시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void scaleMenuItem_Click(object sender, EventArgs e)
{
ToolStripMenuItem menuItem = sender as ToolStripMenuItem;
string scaleText = menuItem.Text.Replace("&", "").Replace("%", "");
this.imageScale = float.Parse(scaleText) / 100f;
this.pictureBox.Image = this.backgroundBitmap.ScaleImage(this.imageScale);
this.pictureBox.Refresh();
this.scaleMenuItem.Text = "확대/축소 (" + menuItem.Text.Replace("&", "") + ")";
foreach(ToolStripMenuItem childMenuItem in scaleMenuItem.DropDownItems)
{
childMenuItem.Checked = (childMenuItem == menuItem);
}
}
#endregion
#region 픽처 박스 마우스 DOWN 처리하기 - pictureBox_MouseDown(sender, e)
/// <summary>
/// 픽처 박스 마우스 DOWN 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void pictureBox_MouseDown(object sender, MouseEventArgs e)
{
this.hitType = FindHitType(e.Location);
if(this.hitType == HitType.None)
{
return;
}
this.lastMousePoint = e.Location;
switch(this.hitType)
{
case HitType.None :
break;
case HitType.TopLeftCorner :
case HitType.TopEdge :
case HitType.LeftEdge :
this.oppositeCorner = new PointF
(
this.foregroundRectangle.Right,
this.foregroundRectangle.Bottom
);
break;
case HitType.TopRightCorner :
this.oppositeCorner = new PointF
(
this.foregroundRectangle.Left,
this.foregroundRectangle.Bottom
);
break;
case HitType.BottomRightCorner :
case HitType.BottomEdge :
case HitType.RightEdge :
this.oppositeCorner = new PointF
(
this.foregroundRectangle.Left,
this.foregroundRectangle.Top
);
break;
case HitType.BottomLeftCorner :
this.oppositeCorner = new PointF
(
this.foregroundRectangle.Right,
this.foregroundRectangle.Top
);
break;
}
this.isDragging = 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)
{
if(this.isDragging)
{
ProcessDraggingMouseMove(e.Location);
}
else
{
ProcessNotDraggingMouseMove(e.Location);
}
}
#endregion
#region 픽처 박스 마우스 UP 처리하기 - pictrueBox_MouseUp(sender, e)
/// <summary>
/// 픽처 박스 마우스 UP 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void pictrueBox_MouseUp(object sender, MouseEventArgs e)
{
this.isDragging = false;
}
#endregion
#region 픽처 박스 페인트시 처리하기 - pictureBox_Paint(sender, e)
/// <summary>
/// 픽처 박스 페인트시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void pictureBox_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.InterpolationMode = InterpolationMode.High;
try
{
RectangleF foregoundRectangleScaled = ScaleForegroundRectangle();
if(this.foregroundBitmap != null)
{
e.Graphics.DrawImage(this.foregroundBitmap, foregoundRectangleScaled);
}
using(Pen pen = new Pen(Color.Red, 2))
{
e.Graphics.DrawRectangle(pen, foregoundRectangleScaled);
pen.Color = Color.Yellow;
pen.DashPattern = new float[] { 5, 5 };
e.Graphics.DrawRectangle(pen, foregoundRectangleScaled);
}
PointF[] cornerPointArray =
{
new PointF(foregoundRectangleScaled.Left , foregoundRectangleScaled.Top ),
new PointF(foregoundRectangleScaled.Right, foregoundRectangleScaled.Top ),
new PointF(foregoundRectangleScaled.Left , foregoundRectangleScaled.Bottom),
new PointF(foregoundRectangleScaled.Right, foregoundRectangleScaled.Bottom),
};
foreach(PointF point in cornerPointArray)
{
e.Graphics.DrawBox(Brushes.White, Pens.Black, point, BOX_RADIUS);
}
}
catch
{
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////// Function
#region 비트맵 구하기 - GetBitmap(filePath)
/// <summary>
/// 비트맵 구하기
/// </summary>
/// <param name="filePath">파일 경로</param>
/// <returns>비트맵</returns>
private Bitmap GetBitmap(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 알파 채널 복사하기 - CopyAlpha(targetBitmap, sourceMaskBitmap)
/// <summary>
/// 알파 채널 복사하기
/// </summary>
/// <param name="targetBitmap">타겟 비트맵</param>
/// <param name="sourceMaskBitmap">소스 마스크 비트맵</param>
private void CopyAlpha(Bitmap targetBitmap, Bitmap sourceMaskBitmap)
{
BitmapHelper targetBitmapHelper = new BitmapHelper(targetBitmap );
BitmapHelper sourceMaskBitmapHelper = new BitmapHelper(sourceMaskBitmap);
targetBitmapHelper.LockBitmap();
sourceMaskBitmapHelper.LockBitmap();
for(int x = 0; x < targetBitmap.Width; x++)
{
for(int y = 0; y < targetBitmap.Height; y++)
{
targetBitmapHelper.SetAlpha(x, y, sourceMaskBitmapHelper.GetAlpha(x, y));
}
}
sourceMaskBitmapHelper.UnlockBitmap();
targetBitmapHelper.UnlockBitmap();
}
#endregion
#region 전경 이미지 사각형 확대/축소하기 - ScaleForegroundRectangle()
/// <summary>
/// 전경 이미지 사각형 확대/축소하기
/// </summary>
/// <returns>전경 이미지 사각형 확대/축소하기</returns>
private RectangleF ScaleForegroundRectangle()
{
float x = this.imageScale * this.foregroundRectangle.X;
float y = this.imageScale * this.foregroundRectangle.Y;
float width = this.imageScale * this.foregroundRectangle.Width;
float height = this.imageScale * this.foregroundRectangle.Height;
return new RectangleF(x, y, width, height);
}
#endregion
#region 히트 타입 찾기 - FindHitType(point)
/// <summary>
/// 히트 타입 찾기
/// </summary>
/// <param name="point">포인트</param>
/// <returns>히트 타입</returns>
private HitType FindHitType(Point point)
{
RectangleF rectangle = ScaleForegroundRectangle();
bool hitLeft;
bool hitRight;
bool hitTop;
bool hitBottom;
hitLeft = ((point.X >= rectangle.Left - BOX_RADIUS) && (point.X <= rectangle.Left + BOX_RADIUS));
hitRight = ((point.X >= rectangle.Right - BOX_RADIUS) && (point.X <= rectangle.Right + BOX_RADIUS));
hitTop = ((point.Y >= rectangle.Top - BOX_RADIUS) && (point.Y <= rectangle.Top + BOX_RADIUS));
hitBottom = ((point.Y >= rectangle.Bottom - BOX_RADIUS) && (point.Y <= rectangle.Bottom + BOX_RADIUS));
if(hitLeft && hitTop)
{
return HitType.TopLeftCorner;
}
if(hitRight && hitTop)
{
return HitType.TopRightCorner;
}
if(hitLeft && hitBottom)
{
return HitType.BottomLeftCorner;
}
if(hitRight && hitBottom)
{
return HitType.BottomRightCorner;
}
if(hitLeft)
{
return HitType.LeftEdge;
}
if(hitRight)
{
return HitType.RightEdge;
}
if(hitTop)
{
return HitType.TopEdge;
}
if(hitBottom)
{
return HitType.BottomEdge;
}
if((point.X >= rectangle.Left) && (point.X <= rectangle.Right ) &&
(point.Y >= rectangle.Top ) && (point.Y <= rectangle.Bottom))
{
return HitType.Body;
}
return HitType.None;
}
#endregion
#region 감소된 크기 구하기 - GetReducedSize(newWidth, newHeight)
/// <summary>
/// 감소된 크기 구하기
/// </summary>
/// <param name="newWidth">신규 너비</param>
/// <param name="newHeight">신규 높이</param>
/// <returns>감소된 크기</returns>
private SizeF GetReducedSize(float newWidth, float newHeight)
{
if(newWidth < 10)
{
newWidth = 10;
}
if(newHeight < 10)
{
newHeight = 10;
}
if(newWidth / newHeight > this.aspectRatio)
{
newWidth = newHeight * this.aspectRatio;
}
else
{
newHeight = newWidth / this.aspectRatio;
}
return new SizeF(newWidth, newHeight);
}
#endregion
#region 확장된 크기 구하기 - GetEnlargedSize(newWidth, newHeight)
/// <summary>
/// 확장된 크기 구하기
/// </summary>
/// <param name="newWidth">신규 너비</param>
/// <param name="newHeight">신규 높이</param>
/// <returns>확장된 크기</returns>
private SizeF GetEnlargedSize(float newWidth, float newHeight)
{
if(newWidth < 10)
{
newWidth = 10;
}
if(newHeight < 10)
{
newHeight = 10;
}
if(newWidth / newHeight > this.aspectRatio)
{
newHeight = newWidth / this.aspectRatio;
}
else
{
newWidth = newHeight * this.aspectRatio;
}
return new SizeF(newWidth, newHeight);
}
#endregion
#region 드래그하는 경우 마우스 이동시 처리하기 - ProcessDraggingMouseMove(mousePoint)
/// <summary>
/// 드래그하는 경우 마우스 이동시 처리하기
/// </summary>
/// <param name="mousePoint">마우스 포인트</param>
private void ProcessDraggingMouseMove(Point mousePoint)
{
float cornerWidth = Math.Abs(this.oppositeCorner.X - mousePoint.X / this.imageScale);
float cornerHeight = Math.Abs(this.oppositeCorner.Y - mousePoint.Y / this.imageScale);
SizeF cornerSize = GetReducedSize(cornerWidth, cornerHeight);
SizeF edgeSize = new SizeF();
if((this.hitType == HitType.TopEdge) || (this.hitType == HitType.BottomEdge))
{
edgeSize = GetEnlargedSize(0, cornerHeight);
}
else if((this.hitType == HitType.LeftEdge) || (this.hitType == HitType.RightEdge))
{
edgeSize = GetEnlargedSize(cornerWidth, 0);
}
float centerX = this.foregroundRectangle.X + this.foregroundRectangle.Width / 2f;
float centerY = this.foregroundRectangle.Y + this.foregroundRectangle.Height / 2f;
switch(this.hitType)
{
case HitType.TopLeftCorner :
this.foregroundRectangle = new RectangleF
(
this.foregroundRectangle.Right - cornerSize.Width,
this.foregroundRectangle.Bottom - cornerSize.Height,
cornerSize.Width,
cornerSize.Height
);
break;
case HitType.TopRightCorner :
this.foregroundRectangle = new RectangleF
(
this.foregroundRectangle.Left,
this.foregroundRectangle.Bottom - cornerSize.Height,
cornerSize.Width,
cornerSize.Height
);
break;
case HitType.BottomRightCorner :
this.foregroundRectangle = new RectangleF
(
this.foregroundRectangle.X,
this.foregroundRectangle.Y,
cornerSize.Width,
cornerSize.Height
);
break;
case HitType.BottomLeftCorner :
this.foregroundRectangle = new RectangleF
(
this.foregroundRectangle.Right - cornerSize.Width,
this.foregroundRectangle.Top,
cornerSize.Width,
cornerSize.Height
);
break;
case HitType.TopEdge :
this.foregroundRectangle = new RectangleF
(
centerX - edgeSize.Width / 2f,
this.foregroundRectangle.Bottom - edgeSize.Height,
edgeSize.Width,
edgeSize.Height
);
break;
case HitType.RightEdge :
this.foregroundRectangle = new RectangleF
(
this.foregroundRectangle.Left,
centerY - edgeSize.Height / 2f,
edgeSize.Width,
edgeSize.Height
);
break;
case HitType.BottomEdge :
this.foregroundRectangle = new RectangleF
(
centerX - edgeSize.Width / 2f,
this.foregroundRectangle.Top,
edgeSize.Width,
edgeSize.Height
);
break;
case HitType.LeftEdge :
this.foregroundRectangle = new RectangleF
(
this.foregroundRectangle.Right - edgeSize.Width,
centerY - edgeSize.Height / 2f,
edgeSize.Width,
edgeSize.Height
);
break;
case HitType.Body :
int deltaX = (int)((mousePoint.X - this.lastMousePoint.X) / this.imageScale);
int deltaY = (int)((mousePoint.Y - this.lastMousePoint.Y) / this.imageScale);
this.foregroundRectangle.X += deltaX;
this.foregroundRectangle.Y += deltaY;
break;
}
this.lastMousePoint = mousePoint;
this.pictureBox.Refresh();
}
#endregion
#region 드래그하지 않는 경우 마우스 이동시 처리하기 - ProcessNotDraggingMouseMove(mousePoint)
/// <summary>
/// 드래그하지 않는 경우 마우스 이동시 처리하기
/// </summary>
/// <param name="mousePoint">마우스 포인트</param>
private void ProcessNotDraggingMouseMove(Point mousePoint)
{
Cursor newCursor = Cursors.Default;
this.hitType = FindHitType(mousePoint);
switch(this.hitType)
{
case HitType.TopLeftCorner :
case HitType.BottomRightCorner :
newCursor = Cursors.SizeNWSE;
break;
case HitType.TopRightCorner :
case HitType.BottomLeftCorner :
newCursor = Cursors.SizeNESW;
break;
case HitType.LeftEdge :
case HitType.RightEdge :
newCursor = Cursors.SizeWE;
break;
case HitType.TopEdge :
case HitType.BottomEdge :
newCursor = Cursors.SizeNS;
break;
case HitType.Body :
newCursor = Cursors.SizeAll;
break;
}
if(this.pictureBox.Cursor != newCursor)
{
this.pictureBox.Cursor = newCursor;
}
}
#endregion
}
}
728x90
반응형
그리드형(광고전용)
'C# > WinForm' 카테고리의 다른 글
[C#/WINFORM] 레이더 차트 그리기 (0) | 2020.12.26 |
---|---|
[C#/WINFORM] Graphics 클래스 : DrawString 메소드를 사용해 회전 텍스트 그리기 (0) | 2020.12.26 |
[C#/WINFORM] PointF 구조체 : 포인트 밀접 여부 구하기 (0) | 2020.12.26 |
[C#/WINFORM] RichTextBox 클래스 : 테이블 추가하기 (0) | 2020.12.26 |
[C#/WINFORM] RichTextBox 클래스 : 이미지 캡처하기 (0) | 2020.12.25 |
[C#/WINFORM] 화면 보호기/절전 모드 방지하기/허용하기 (0) | 2020.12.21 |
[C#/WINFORM] Form 클래스 : CreateParams 속성을 사용해 작업 전환기(Tab Switcher)에서 애플리케이션 숨기기 (0) | 2020.12.19 |
[C#/WINFORM] SVG 이미지 사용하기 (0) | 2020.12.19 |
[C#/WINFORM] 관리자 권한으로 실행하기 (0) | 2020.12.18 |
[C#/WINFORM] 화면 캡처 방지하기 (0) | 2020.12.17 |
댓글을 달아 주세요