첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.

728x90
반응형
728x170

TestProject.zip
0.02MB

▶ GraphicsHelper.cs

using System.Drawing;

namespace TestProject
{
    /// <summary>
    /// 그래픽스 헬퍼
    /// </summary>
    public static class GraphicsHelper
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// 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(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(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);

            GraphicsHelper.DrawRectangle(graphics, pen, rectangle);
        }

        #endregion
    }
}

 

728x90

 

▶ MainForm.cs

using System;
using System.Collections.Generic;
using System.Drawing;
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>
            LeftUpperCorner,

            /// <summary>
            /// 우상단 코너
            /// </summary>
            RightUpperCorner,

            /// <summary>
            /// 좌하단 코너
            /// </summary>
            LeftBottomCorner,

            /// <summary>
            /// 우하단 코너
            /// </summary>
            RightBottomCorner,
        };

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 소스 비트맵
        /// </summary>
        private Bitmap sourceBitmap = null;

        /// <summary>
        /// 타겟 비트맵
        /// </summary>
        private Bitmap targetBitmap = null;

        /// <summary>
        /// 선택 사각형
        /// </summary>
        private RectangleF selectionRectangle;

        /// <summary>
        /// 드래그 여부
        /// </summary>
        private bool isDragging = false;

        /// <summary>
        /// 현재 히트 타입
        /// </summary>
        private HitType currentHitType = HitType.None;

        /// <summary>
        /// 마지막 포인트
        /// </summary>
        private Point lastPoint;

        /// <summary>
        /// 반대편 코너
        /// </summary>
        private PointF oppositeCorner;

        /// <summary>
        /// 이미지 스케일
        /// </summary>
        private float imageScale = 1f;

        /// <summary>
        /// 종횡비 너비
        /// </summary>
        private float aspectRatioWidth = 1f;

        /// <summary>
        /// 종횡비 높이
        /// </summary>
        private float aspectRatioHeight = 1f;

        /// <summary>
        /// 종횡비
        /// </summary>
        private float aspectRatio = 1f;

        /// <summary>
        /// 사각형 너비
        /// </summary>
        private float rectangleWidth = 1f;

        /// <summary>
        /// 사각형 높이
        /// </summary>
        private float rectangleHeight = 1f;

        /// <summary>
        /// 텍스트 변경 무시 여부
        /// </summary>
        private bool ignoreTextChanged = false;

        /// <summary>
        /// 반경 임계치
        /// </summary>
        private const int RADIUS_THRESHOLD = 4;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - MainForm()

        /// <summary>
        /// 생성자
        /// </summary>
        public MainForm()
        {
            InitializeComponent();

            this.Load                           += Form_Load;
            this.openMenuItem.Click             += openMenuItem_Click;
            this.saveAsMenuItem.Click           += saveAsMenuItem_Click;
            this.exitMenuItem.Click             += exitMenuItem_Click;
            this.scale100MenuItem.Click         += scaleMenuItem_Click;
            this.scale75MenuItem.Click          += scaleMenuItem_Click;
            this.scale66MenuItem.Click          += scaleMenuItem_Click;
            this.scale50MenuItem.Click          += scaleMenuItem_Click;
            this.scale25MenuItem.Click          += scaleMenuItem_Click;
            this.scale15MenuItem.Click          += scaleMenuItem_Click;
            this.resetMenuItem.Click            += resetMenuItem_Click;
            this.aspectRatioTextBox.TextChanged += aspectRatioTextBox_TextChanged;
            this.widthTextBox.TextChanged       += widthTextBox_TextChanged;
            this.heightTextBox.TextChanged      += heightTextBox_TextChanged;
            this.pictureBox.MouseDown           += pictureBox_MouseDown;
            this.pictureBox.MouseMove           += pictureBox_MouseMove;
            this.pictureBox.MouseUp             += pictureBox_MouseUp;
            this.pictureBox.Paint               += pictureBox_Paint;
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Private
        //////////////////////////////////////////////////////////////////////////////// Event

        #region 폼 로드시 처리하기 - Form_Load(sender, e)

        /// <summary>
        /// 폼 로드시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void Form_Load(object sender, EventArgs e)
        {
            float.TryParse(this.widthTextBox.Text , out this.rectangleWidth );
            float.TryParse(this.heightTextBox.Text, out this.rectangleHeight);

            SetAspectRatio();

            this.selectionRectangle.X = 10;
            this.selectionRectangle.Y = 10;

            MouseWheel += Form_MouseWheel;
        }

        #endregion
        #region 폼 마우스 휠 처리하기 - Form_MouseWheel(sender, e)

        /// <summary>
        /// 폼 마우스 휠 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void Form_MouseWheel(object sender, MouseEventArgs e)
        {
            if(this.sourceBitmap == null)
            {
                return;
            }

            int scale = (int)(this.imageScale * 100);

            ToolStripMenuItem[] menuItemArray =
            {
                this.scale100MenuItem,
                this.scale75MenuItem,
                this.scale66MenuItem,
                this.scale50MenuItem,
                this.scale25MenuItem,
                this.scale15MenuItem,
            };

            List<int> scaleList = new List<int>() { 100, 75, 66, 50, 25, 15 };

            int index = scaleList.IndexOf(scale);

            if(e.Delta < 0)
            {
                index++;
            }
            else
            {
                index--;
            }

            if((index >= 0) && (index < menuItemArray.Length))
            {
                SetScale(menuItemArray[index]);
            }
        }

        #endregion
        #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)
            {
                try
                {
                    this.sourceBitmap = LoadBitmap(this.openFileDialog.FileName);

                    ShowTargetBitmap();

                    this.saveAsMenuItem.Enabled = true;
                }
                catch(Exception exception)
                {
                    MessageBox.Show(exception.Message);
                }
            }
        }

        #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)
            {
                try
                {
                    Bitmap bitmap = new Bitmap
                    (
                        (int)this.selectionRectangle.Width,
                        (int)this.selectionRectangle.Height
                    );

                    using(Graphics graphics = Graphics.FromImage(bitmap))
                    {
                        graphics.DrawImage
                        (
                            this.sourceBitmap,
                            0,
                            0,
                            this.selectionRectangle,
                            GraphicsUnit.Pixel
                        );
                    }

                    SaveImage(bitmap, this.saveFileDialog.FileName);
                }
                catch(Exception exception)
                {
                    MessageBox.Show(exception.Message);
                }
            }
        }

        #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)
        {
            SetScale(sender as ToolStripMenuItem);
        }

        #endregion
        #region 재설정 메뉴 항목 클릭시 처리하기 - resetMenuItem_Click(sender, e)

        /// <summary>
        /// 재설정 메뉴 항목 클릭시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void resetMenuItem_Click(object sender, EventArgs e)
        {
            this.selectionRectangle.X = 10;
            this.selectionRectangle.Y = 10;

            this.pictureBox.Refresh();
        }

        #endregion
        #region 종횡비 텍스트 박스 텍스트 변경시 처리하기 - aspectRatioTextBox_TextChanged(sender, e)

        /// <summary>
        /// 종횡비 텍스트 박스 텍스트 변경시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void aspectRatioTextBox_TextChanged(object sender, EventArgs e)
        {
            SetAspectRatio();
        }

        #endregion
        #region 너비 텍스트 박스 텍스트 변경시 처리하기 - widthTextBox_TextChanged(sender, e)

        /// <summary>
        /// 너비 텍스트 박스 텍스트 변경시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void widthTextBox_TextChanged(object sender, EventArgs e)
        {
            if(this.ignoreTextChanged)
            {
                return;
            }

            if(!float.TryParse(this.widthTextBox.Text, out this.rectangleWidth))
            {
                return;
            }

            SetRectangleHeight(this.rectangleWidth);
        }

        #endregion
        #region 높이 텍스트 박스 텍스트 변경시 처리하기 - heightTextBox_TextChanged(sender, e)

        /// <summary>
        /// 높이 텍스트 박스 텍스트 변경시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void heightTextBox_TextChanged(object sender, EventArgs e)
        {
            if(this.ignoreTextChanged)
            {
                return;
            }

            if(!float.TryParse(this.heightTextBox.Text, out this.rectangleHeight))
            {
                return;
            }

            SetRectangleWidth(this.rectangleHeight);
        }

        #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.currentHitType = FindHitType(e.Location);

            if(this.currentHitType == HitType.None)
            {
                return;
            }

            this.lastPoint = e.Location;

            switch(this.currentHitType)
            {
                case HitType.None :

                    break;

                case HitType.LeftUpperCorner :
                case HitType.TopEdge         :
                case HitType.LeftEdge        :

                    this.oppositeCorner = new PointF
                    (
                        this.selectionRectangle.Right,
                        this.selectionRectangle.Bottom
                    );

                    break;

                case HitType.RightUpperCorner :

                    this.oppositeCorner = new PointF
                    (
                        this.selectionRectangle.Left,
                        this.selectionRectangle.Bottom
                    );

                    break;

                case HitType.RightBottomCorner :
                case HitType.BottomEdge        :
                case HitType.RightEdge         :

                    this.oppositeCorner = new PointF
                    (
                        this.selectionRectangle.Left,
                        this.selectionRectangle.Top
                    );

                    break;

                case HitType.LeftBottomCorner :

                    this.oppositeCorner = new PointF
                    (
                        this.selectionRectangle.Right,
                        this.selectionRectangle.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)
        {
            Point point = e.Location;

            if(!this.isDragging)
            {
                Cursor newCursor = Cursors.Default;

                this.currentHitType = FindHitType(point);

                switch(this.currentHitType)
                {
                    case HitType.LeftUpperCorner   :
                    case HitType.RightBottomCorner :

                        newCursor = Cursors.SizeNWSE;

                        break;

                    case HitType.RightUpperCorner :
                    case HitType.LeftBottomCorner :

                        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;
                }
            }
            else
            {
                float cornerWidth  = Math.Abs(this.oppositeCorner.X - point.X / this.imageScale);
                float cornerHeight = Math.Abs(this.oppositeCorner.Y - point.Y / this.imageScale);

                SizeF cornerSize = GetReducedSize(cornerWidth, cornerHeight);

                SizeF edgeSize = new SizeF();

                if((this.currentHitType == HitType.TopEdge) || (this.currentHitType == HitType.BottomEdge))
                {
                    edgeSize = GetEnlargedSize(0, cornerHeight);
                }
                else if((this.currentHitType == HitType.LeftEdge) || (this.currentHitType == HitType.RightEdge))
                {
                    edgeSize = GetEnlargedSize(cornerWidth, 0);
                }

                float centerX = this.selectionRectangle.X + this.selectionRectangle.Width  / 2f;
                float centerY = this.selectionRectangle.Y + this.selectionRectangle.Height / 2f;

                switch(this.currentHitType)
                {
                    case HitType.LeftUpperCorner :

                        this.selectionRectangle = new RectangleF
                        (
                            this.selectionRectangle.Right  - cornerSize.Width,
                            this.selectionRectangle.Bottom - cornerSize.Height,
                            cornerSize.Width,
                            cornerSize.Height
                        );

                        break;

                    case HitType.RightUpperCorner :

                        this.selectionRectangle = new RectangleF
                        (
                            this.selectionRectangle.Left,
                            this.selectionRectangle.Bottom - cornerSize.Height,
                            cornerSize.Width,
                            cornerSize.Height
                        );

                        break;

                    case HitType.RightBottomCorner :

                        this.selectionRectangle = new RectangleF
                        (
                            this.selectionRectangle.X,
                            this.selectionRectangle.Y,
                            cornerSize.Width,
                            cornerSize.Height
                        );

                        break;

                    case HitType.LeftBottomCorner :

                        this.selectionRectangle = new RectangleF
                        (
                            this.selectionRectangle.Right - cornerSize.Width,
                            this.selectionRectangle.Top,
                            cornerSize.Width,
                            cornerSize.Height
                        );

                        break;

                    case HitType.TopEdge :

                        this.selectionRectangle = new RectangleF
                        (
                            centerX - edgeSize.Width / 2f,
                            this.selectionRectangle.Bottom - edgeSize.Height,
                            edgeSize.Width,
                            edgeSize.Height
                        );

                        break;

                    case HitType.RightEdge :

                        this.selectionRectangle = new RectangleF
                        (
                            this.selectionRectangle.Left,
                            centerY - edgeSize.Height / 2f,
                            edgeSize.Width,
                            edgeSize.Height
                        );

                        break;

                    case HitType.BottomEdge :

                        this.selectionRectangle = new RectangleF
                        (
                            centerX - edgeSize.Width / 2f,
                            this.selectionRectangle.Top,
                            edgeSize.Width,
                            edgeSize.Height
                        );

                        break;

                    case HitType.LeftEdge :

                        this.selectionRectangle = new RectangleF
                        (
                            this.selectionRectangle.Right - edgeSize.Width,
                            centerY - edgeSize.Height / 2f,
                            edgeSize.Width,
                            edgeSize.Height
                        );

                        break;

                    case HitType.Body :

                        int deltaX = (int)((point.X - this.lastPoint.X) / this.imageScale);
                        int deltaY = (int)((point.Y - this.lastPoint.Y) / this.imageScale);

                        this.selectionRectangle.X += deltaX;
                        this.selectionRectangle.Y += deltaY;

                        break;
                }

                this.lastPoint = point;

                this.pictureBox.Refresh();

                ShowWidthAndHeight();
            }
        }

        #endregion
        #region 픽처 박스 마우스 UP 처리하기 - pictureBox_MouseUp(sender, e)

        /// <summary>
        /// 픽처 박스 마우스 UP 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void pictureBox_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)
        {
            try
            {
                RectangleF scaledSelectionRectangle = GetScaledSelectionRectangle();

                using(Pen pen = new Pen(Color.Red, 2))
                {
                    GraphicsHelper.DrawRectangle(e.Graphics, pen, scaledSelectionRectangle);

                    pen.Color       = Color.Yellow;
                    pen.DashPattern = new float[] { 5, 5 };

                    GraphicsHelper.DrawRectangle(e.Graphics, pen, scaledSelectionRectangle);
                }

                PointF[] cornerPointArray =
                {
                    new PointF(scaledSelectionRectangle.Left, scaledSelectionRectangle.Top),
                    new PointF(scaledSelectionRectangle.Right, scaledSelectionRectangle.Top),
                    new PointF(scaledSelectionRectangle.Left, scaledSelectionRectangle.Bottom),
                    new PointF(scaledSelectionRectangle.Right, scaledSelectionRectangle.Bottom),
                };

                foreach(PointF point in cornerPointArray)
                {
                    GraphicsHelper.DrawBox(e.Graphics, Brushes.White, Pens.Black, point, RADIUS_THRESHOLD);
                }
            }
            catch
            {
            }
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////// Function

        #region 선택 사각형 설정하기 - SetSelectionRectangle()

        /// <summary>
        /// 선택 사각형 설정하기
        /// </summary>
        private void SetSelectionRectangle()
        {
            float centerX = this.selectionRectangle.X + this.selectionRectangle.Width  / 2f;
            float centerY = this.selectionRectangle.Y + this.selectionRectangle.Height / 2f;

            this.selectionRectangle = new Rectangle
            (
                (int)(centerX - this.rectangleWidth  / 2f),
                (int)(centerY - this.rectangleHeight / 2f),
                (int)this.rectangleWidth,
                (int)this.rectangleHeight
            );

            this.pictureBox.Refresh();
        }

        #endregion
        #region 사각형 높이 설정하기 - SetRectangleHeight(width)

        /// <summary>
        /// 사각형 높이 설정하기
        /// </summary>
        /// <param name="width">너비</param>
        private void SetRectangleHeight(float width)
        {
            this.rectangleHeight = (float)(width / this.aspectRatio);

            this.ignoreTextChanged = true;

            this.heightTextBox.Text = this.rectangleHeight.ToString();

            this.ignoreTextChanged = false;

            SetSelectionRectangle();
        }

        #endregion
        #region 사각형 너비 설정하기 - SetRectangleWidth(height)

        /// <summary>
        /// 사각형 너비 설정하기
        /// </summary>
        /// <param name="height">높이</param>
        private void SetRectangleWidth(float height)
        {
            this.rectangleWidth = (float)(height * this.aspectRatio);

            this.ignoreTextChanged = true;

            this.widthTextBox.Text = this.rectangleWidth.ToString();

            this.ignoreTextChanged = false;

            SetSelectionRectangle();
        }

        #endregion
        #region 종횡비 설정하기 - SetAspectRatio()

        /// <summary>
        /// 종횡비 설정하기
        /// </summary>
        private void SetAspectRatio()
        {
            string[] fieldStringArray = this.aspectRatioTextBox.Text.Split(':');

            if(fieldStringArray.Length < 2)
            {
                return;
            }

            if(!float.TryParse(fieldStringArray[0], out this.aspectRatioWidth))
            {
                return;
            }

            if(!float.TryParse(fieldStringArray[1], out this.aspectRatioHeight))
            {
                return;
            }

            this.aspectRatio = (float)this.aspectRatioWidth / (float)this.aspectRatioHeight;

            SetRectangleHeight(this.rectangleWidth);
        }

        #endregion
        #region 타겟 비트맵 표시하기 - ShowTargetBitmap()

        /// <summary>
        /// 타겟 비트맵 표시하기
        /// </summary>
        private void ShowTargetBitmap()
        {
            if(this.sourceBitmap == null)
            {
                return;
            }

            int targetWidth  = (int)(this.sourceBitmap.Width  * this.imageScale);
            int targetHeight = (int)(this.sourceBitmap.Height * this.imageScale);

            this.targetBitmap = new Bitmap(targetWidth, targetHeight);

            using(Graphics graphics = Graphics.FromImage(this.targetBitmap))
            {
                Point[] targetPointArray =
                {
                    new Point(0, 0),
                    new Point(targetWidth - 1, 0),
                    new Point(0, targetHeight - 1),
                };

                Rectangle sourceRectangle = new Rectangle
                (
                    0, 0,
                    this.sourceBitmap.Width  - 1,
                    this.sourceBitmap.Height - 1
                );

                graphics.DrawImage(this.sourceBitmap, targetPointArray, sourceRectangle, GraphicsUnit.Pixel);
            }

            this.pictureBox.Image   = this.targetBitmap;
            this.pictureBox.Visible = true;

            this.pictureBox.Refresh();
        }

        #endregion
        #region 스케일 설정하기 - SetScale(menuItem)

        /// <summary>
        /// 스케일 설정하기
        /// </summary>
        /// <param name="menuItem">메뉴 항목</param>
        private void SetScale(ToolStripMenuItem menuItem)
        {
            string scaleText = menuItem.Text.Replace("&", "").Replace("%", "");

            this.imageScale = float.Parse(scaleText) / 100f;

            ShowTargetBitmap();

            this.scaleMenuItem.Text = "스케일(&S) (" + menuItem.Text.Replace("&", "") + ")";

            foreach(ToolStripMenuItem scaleChildMenuItem in scaleMenuItem.DropDownItems)
            {
                scaleChildMenuItem.Checked = (scaleChildMenuItem == menuItem);
            }
        }

        #endregion
        #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 이미지 저장하기 - 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 스케일 선택 사각형 구하기 - GetScaledSelectionRectangle()

        /// <summary>
        /// 스케일 선택 사각형 구하기
        /// </summary>
        /// <returns>스케일 선택 사각형</returns>
        private RectangleF GetScaledSelectionRectangle()
        {
            float x = this.imageScale * this.selectionRectangle.X;
            float y = this.imageScale * this.selectionRectangle.Y;

            float width  = this.imageScale * this.selectionRectangle.Width;
            float height = this.imageScale * this.selectionRectangle.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 scaledSelectionRectangle = GetScaledSelectionRectangle();

            bool hitLeft;
            bool hitRight;
            bool hitTop;
            bool hitBottom;

            hitLeft   = ((point.X >= scaledSelectionRectangle.Left   - RADIUS_THRESHOLD) && (point.X <= scaledSelectionRectangle.Left   + RADIUS_THRESHOLD));
            hitRight  = ((point.X >= scaledSelectionRectangle.Right  - RADIUS_THRESHOLD) && (point.X <= scaledSelectionRectangle.Right  + RADIUS_THRESHOLD));
            hitTop    = ((point.Y >= scaledSelectionRectangle.Top    - RADIUS_THRESHOLD) && (point.Y <= scaledSelectionRectangle.Top    + RADIUS_THRESHOLD));
            hitBottom = ((point.Y >= scaledSelectionRectangle.Bottom - RADIUS_THRESHOLD) && (point.Y <= scaledSelectionRectangle.Bottom + RADIUS_THRESHOLD));

            if(hitLeft  && hitTop   ) return HitType.LeftUpperCorner;
            if(hitRight && hitTop   ) return HitType.RightUpperCorner;
            if(hitLeft  && hitBottom) return HitType.LeftBottomCorner;
            if(hitRight && hitBottom) return HitType.RightBottomCorner;

            if(hitLeft  ) return HitType.LeftEdge;
            if(hitRight ) return HitType.RightEdge;
            if(hitTop   ) return HitType.TopEdge;
            if(hitBottom) return HitType.BottomEdge;

            if
            (
                (point.X >= scaledSelectionRectangle.Left) && (point.X <= scaledSelectionRectangle.Right ) &&
                (point.Y >= scaledSelectionRectangle.Top ) && (point.Y <= scaledSelectionRectangle.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 너비/높이 표시하기 - ShowWidthAndHeight()

        /// <summary>
        /// 너비/높이 표시하기
        /// </summary>
        private void ShowWidthAndHeight()
        {
            this.ignoreTextChanged = true;

            this.widthTextBox.Text  = this.selectionRectangle.Width.ToString();
            this.heightTextBox.Text = this.selectionRectangle.Height.ToString();

            this.ignoreTextChanged = false;
        }

        #endregion
    }
}
728x90
반응형
그리드형(광고전용)
Posted by icodebroker

댓글을 달아 주세요