728x90
반응형
728x170
▶ MainForm.cs
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Windows.Forms;
namespace TestProject
{
/// <summary>
/// 메인 폼
/// </summary>
public partial class MainForm : Form
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 오프셋
/// </summary>
private const int OFFSET = 10;
/// <summary>
/// 소스 비트맵
/// </summary>
private Bitmap sourceBitmap = null;
/// <summary>
/// 일반 투명 비트맵
/// </summary>
private Bitmap normalTransparentBitmap = null;
/// <summary>
/// 자연스러운 투명 비트맵
/// </summary>
private Bitmap naturalTransparentBitmap = null;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - MainForm()
/// <summary>
/// 생성자
/// </summary>
public MainForm()
{
InitializeComponent();
this.openMenuItem.Click += openMenuItem_Click;
this.saveMenuItem.Click += saveMenuItem_Click;
this.resetMenuItem.Click += resetMenuItem_Click;
this.expandButton.Click += expandButton_Click;
this.sourcePictureBox.MouseClick += sourcePictureBox_MouseClick;
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Private
//////////////////////////////////////////////////////////////////////////////// Function
#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);
this.normalTransparentBitmap = new Bitmap(this.sourceBitmap);
this.naturalTransparentBitmap = new Bitmap(this.sourceBitmap);
ShowSampleBitmap();
this.expandButton.Enabled = true;
}
}
#endregion
#region 저장 메뉴 항목 클릭시 처리하기 - saveMenuItem_Click(sender, e)
/// <summary>
/// 저장 메뉴 항목 클릭시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void saveMenuItem_Click(object sender, EventArgs e)
{
if(this.saveFileDialog.ShowDialog() == DialogResult.OK)
{
this.naturalTransparentBitmap.Save(this.saveFileDialog.FileName, ImageFormat.Png);
}
}
#endregion
#region 재설정 메뉴 항목 클릭시 처리하기 - resetMenuItem_Click(sender, e)
/// <summary>
/// 재설정 메뉴 항목 클릭시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void resetMenuItem_Click(object sender, EventArgs e)
{
if(MessageBox.Show("Discard changes?", "Discard changes?", MessageBoxButtons.YesNo) == DialogResult.Yes)
{
this.normalTransparentBitmap = new Bitmap(this.sourceBitmap);
this.naturalTransparentBitmap = new Bitmap(this.sourceBitmap);
ShowSampleBitmap();
}
}
#endregion
#region 투명성 확장하기 버튼 클릭시 처리하기 - applyButton_Click(sender, e)
/// <summary>
/// 투명성 확장하기 버튼 클릭시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void expandButton_Click(object sender, EventArgs e)
{
Cursor = Cursors.WaitCursor;
float maximumDistance = float.Parse(this.maximumDistanceTextBox.Text);
this.naturalTransparentBitmap = ExpandTransparency(this.naturalTransparentBitmap, maximumDistance);
ShowSampleBitmap();
Cursor = Cursors.Default;
}
#endregion
#region 소스 픽처 박스 마우스 클릭시 처리하기 - sourcePictureBox_MouseClick(sender, e)
/// <summary>
/// 소스 픽처 박스 마우스 클릭시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void sourcePictureBox_MouseClick(object sender, MouseEventArgs e)
{
int x = e.X - OFFSET;
int y = e.Y - OFFSET;
Color color = this.sourceBitmap.GetPixel(x, y);
this.normalTransparentBitmap.MakeTransparent(color);
int deltaRed = int.Parse(this.deltaRedTextBox.Text );
int deltaGreen = int.Parse(this.deltaGreenTextBox.Text);
int deltaBlue = int.Parse(this.deltaBlueTextBox.Text );
this.naturalTransparentBitmap = Transparentify(this.naturalTransparentBitmap, x, y, deltaRed, deltaGreen, deltaBlue);
ShowSampleBitmap();
}
#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 배경 설정하기 - SetBackground()
/// <summary>
/// 배경 설정하기
/// </summary>
/// <returns>비트맵</returns>
private Bitmap SetBackground()
{
int width = this.sourceBitmap.Width + 2 * OFFSET;
int height = this.sourceBitmap.Height + 2 * OFFSET;
Bitmap bitmap = new Bitmap(width, height);
using(Graphics graphics = Graphics.FromImage(bitmap))
{
using
(
LinearGradientBrush brush = new LinearGradientBrush
(
new Point(0, 0),
new Point(64, 64),
Color.Blue,
Color.Yellow
)
)
{
graphics.FillRectangle(brush, 0, 0, width, height);
}
}
return bitmap;
}
#endregion
#region 샘플 비트맵 표시하기 - ShowSampleBitmap()
/// <summary>
/// 샘플 비트맵 표시하기
/// </summary>
private void ShowSampleBitmap()
{
Bitmap bitmap;
bitmap = SetBackground();
using(Graphics graphics = Graphics.FromImage(bitmap))
{
graphics.DrawImage(this.sourceBitmap, OFFSET, OFFSET);
}
this.sourcePictureBox.Image = bitmap;
bitmap = SetBackground();
using(Graphics graphics = Graphics.FromImage(bitmap))
{
graphics.DrawImage(this.normalTransparentBitmap, OFFSET, OFFSET);
}
this.normalPictureBox.Image = bitmap;
bitmap = SetBackground();
using(Graphics graphics = Graphics.FromImage(bitmap))
{
graphics.DrawImage(this.naturalTransparentBitmap, OFFSET, OFFSET);
}
this.naturalPictureBox.Image = bitmap;
this.sourcePictureBox.Visible = true;
this.normalPictureBox.Visible = true;
this.naturalPictureBox.Visible = true;
}
#endregion
#region 투명하게 만들기 - Transparentify(sourceBitmap, x, y, deltaRed, deltaGreen, deltaBlue)
/// <summary>
/// 투명하게 만들기
/// </summary>
/// <param name="sourceBitmap">소스 비트맵</param>
/// <param name="x">X</param>
/// <param name="y">Y</param>
/// <param name="deltaRed">적색 증분</param>
/// <param name="deltaGreen">녹색 증분</param>
/// <param name="deltaBlue">파란색 증분</param>
/// <returns>비트맵</returns>
private Bitmap Transparentify(Bitmap sourceBitmap, int x, int y, int deltaRed, int deltaGreen, int deltaBlue)
{
Color targetColor = sourceBitmap.GetPixel(x, y);
byte red = targetColor.R;
byte green = targetColor.G;
byte blue = targetColor.B;
Bitmap bitmap = new Bitmap(sourceBitmap);
Stack<Point> pointStack = new Stack<Point>();
int width = sourceBitmap.Width;
int height = sourceBitmap.Height;
bool[,] addedStackArray = new bool[width, height];
pointStack.Push(new Point(x, y));
addedStackArray[x, y] = true;
bitmap.SetPixel(x, y, Color.Transparent);
while(pointStack.Count > 0)
{
Point point = pointStack.Pop();
for(int i = point.X - 1; i <= point.X + 1; i++)
{
for(int j = point.Y - 1; j <= point.Y + 1; j++)
{
if((i < 0) || (i >= width) || (j < 0) || (j >= height))
{
continue;
}
if(addedStackArray[i, j])
{
continue;
}
Color color = sourceBitmap.GetPixel(i, j);
if(Math.Abs(red - color.R) > deltaRed)
{
continue;
}
if(Math.Abs(green - color.G) > deltaGreen)
{
continue;
}
if(Math.Abs(blue - color.B) > deltaBlue)
{
continue;
}
pointStack.Push(new Point(i, j));
addedStackArray[i, j] = true;
bitmap.SetPixel(i, j, Color.Transparent);
}
}
}
return bitmap;
}
#endregion
#region 거리 배열 구하기 - GetDistanceArray(sourceBitmap, maximumDistance)
/// <summary>
/// 거리 배열 구하기
/// </summary>
/// <param name="sourceBitmap">소스 비트맵</param>
/// <param name="maximumDistance">최대 거리</param>
/// <returns>거리 배열</returns>
private float[,] GetDistanceArray(Bitmap sourceBitmap, float maximumDistance)
{
int width = sourceBitmap.Width;
int height = sourceBitmap.Height;
float[,] distanceArray = new float[width, height];
for(int x = 0; x < width; x++)
{
for(int y = 0; y < height; y++)
{
distanceArray[x, y] = float.PositiveInfinity;
}
}
int maximumDistanceInteger = (int)maximumDistance;
if(maximumDistanceInteger < maximumDistance)
{
maximumDistanceInteger++;
}
for(int x = 0; x < width; x++)
{
for(int y = 0; y < height; y++)
{
if(sourceBitmap.GetPixel(x, y).A == 0)
{
for(int deltaX = -maximumDistanceInteger; deltaX <= maximumDistanceInteger; deltaX++)
{
int indexX = x + deltaX;
if((indexX < 0) || (indexX >= width))
{
continue;
}
for(int deltaY = -maximumDistanceInteger; deltaY <= maximumDistanceInteger; deltaY++)
{
int indexY = y + deltaY;
if((indexY < 0) || (indexY >= height))
{
continue;
}
float distance = (float)Math.Sqrt(deltaX * deltaX + deltaY * deltaY);
if(distanceArray[indexX, indexY] > distance)
{
distanceArray[indexX, indexY] = distance;
}
}
}
}
}
}
return distanceArray;
}
#endregion
#region 투명성 확장하기 - ExpandTransparency(sourceBitmap, maximumDistance)
/// <summary>
/// 투명성 확장하기
/// </summary>
/// <param name="sourceBitmap">소스 비트맵</param>
/// <param name="maximumDistance">최대 거리</param>
/// <returns>비트맵</returns>
private Bitmap ExpandTransparency(Bitmap sourceBitmap, float maximumDistance)
{
Bitmap targetBitmap = new Bitmap(sourceBitmap);
float[,] distanceArray = GetDistanceArray(sourceBitmap, maximumDistance);
int width = sourceBitmap.Width;
int height = sourceBitmap.Height;
for(int x = 0; x < width; x++)
{
for(int y = 0; y < height; y++)
{
if(sourceBitmap.GetPixel(x, y).A == 0)
{
continue;
}
float distance = distanceArray[x, y];
if(distance > maximumDistance)
{
continue;
}
float scale = distance / maximumDistance;
Color color = sourceBitmap.GetPixel(x, y);
int red = color.R;
int green = color.G;
int blue = color.B;
int alpha = (int)(255 * scale);
color = Color.FromArgb(alpha, red, green, blue);
targetBitmap.SetPixel(x, y, color);
}
}
return targetBitmap;
}
#endregion
}
}
728x90
반응형
그리드형(광고전용)
'C# > WinForm' 카테고리의 다른 글
[C#/WINFORM] 이미지 리스트 편집하기 (0) | 2020.07.22 |
---|---|
[C#/WINFORM] PrivateFontCollection 클래스 : 커스텀 폰트 사용하기 (0) | 2020.07.22 |
[C#/WINFORM] 싸인파를 따라 반전된 색상으로 텍스트 그리기 (0) | 2020.07.21 |
[C#/WINFORM] 대각선을 따라 반전된 색상으로 텍스트 그리기 (0) | 2020.07.21 |
[C#/WINFORM] 위쪽 및 아래쪽 절반의 색상으로 반전된 텍스트 그리기 (0) | 2020.07.20 |
[C#/WINFORM] 둥근 모서리 이미지 구하기 (0) | 2020.07.20 |
[C#/WINFORM] 워터마크 추가하기 (0) | 2020.07.19 |
[C#/WINFORM] 직선 방향의 가운데 정렬 텍스트 그리기 (0) | 2020.07.19 |
[C#/WINFORM] Bitmap 클래스 : 비트맵 크기 변경하기 (0) | 2020.07.16 |
[C#/WINFORM] ColorMatrix 클래스 : 이미지 불투명도 조정하기 (0) | 2020.07.13 |
댓글을 달아 주세요