첨부 소스 코드는 나눔고딕코딩 폰트를 사용합니다.
728x90
반응형
728x170

TestProject.zip
다운로드

▶ 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
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Field

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

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

        /// <summary>
        /// 각도
        /// </summary>
        private float angle = 0;

        /// <summary>
        /// 시작 포인트
        /// </summary>
        private Point startPoint = new Point(50, 100);

        /// <summary>
        /// 종료 포인트
        /// </summary>
        private Point endPoint = new Point(210, 100);

        /// <summary>
        /// 그리기 여부
        /// </summary>
        private bool isDrawing = false;

        #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.resetAngleMenuItem.Click += resetAngleMenuItem_Click;
            this.drawGridMenuItem.Click   += drawGridMenuItem_Click;
            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 열기 메뉴 항목 클릭시 처리하기 - 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.angle = 0;

                DrawImage();
            }
        }

        #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.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 각도 리셋 메뉴 항목 클릭시 처리하기 - resetAngleMenuItem_Click(sender, e)

        /// <summary>
        /// 각도 리셋 메뉴 항목 클릭시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void resetAngleMenuItem_Click(object sender, EventArgs e)
        {
            this.angle      = 0;
            this.startPoint = new Point(50, 100);
            this.endPoint   = new Point(210, 100);

            DrawImage();
        }

        #endregion
        #region 그리드 그리기 - drawGridMenuItem_Click(sender, e)

        /// <summary>
        /// 그리드 그리기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void drawGridMenuItem_Click(object sender, EventArgs e)
        {
            this.pictureBox.Refresh();
        }

        #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.startPoint = e.Location;
            this.endPoint   = e.Location;
            this.isDrawing  = 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.isDrawing)
            {
                return;
            }

            this.endPoint = e.Location;

            this.pictureBox.Refresh();
        }

        #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.isDrawing = false;

            int deltaX = this.endPoint.X - this.startPoint.X;
            int deltaY = this.endPoint.Y - this.startPoint.Y;

            double newAngle = Math.Atan2(deltaY, deltaX) * 180.0 / Math.PI;
            
            this.angle -= (float)newAngle;

            DrawImage();
        }

        #endregion
        #region 픽처 박스 페인트시 처리하기 - pictureBox_Paint(sender, e)

        /// <summary>
        /// 픽처 박스 페인트시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void pictureBox_Paint(object sender, PaintEventArgs e)
        {
            if(this.isDrawing)
            {
                e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;

                e.Graphics.DrawLine(Pens.Yellow, this.startPoint, this.endPoint);

                using(Pen pen = new Pen(Color.Red))
                {
                    pen.DashPattern = new float[] { 5, 5 };

                    e.Graphics.DrawLine(pen, this.startPoint, this.endPoint);
                }
            }

            if(this.drawGridMenuItem.Checked)
            {
                const int deltaX = 50;

                int maximumX = this.pictureBox.ClientSize.Width;
                int maximumY = this.pictureBox.ClientSize.Height;

                for(int x = 0; x < maximumX; x += deltaX)
                {
                    e.Graphics.DrawLine(Pens.Silver, x, 0, x, maximumY);
                }

                for(int y = 0; y < maximumY; y += deltaX)
                {
                    e.Graphics.DrawLine(Pens.Silver, 0, y, maximumX, y);
                }
            }
        }

        #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 이미지 저장하기 - SaveImage(image, filePath)

        /// <summary>
        /// 이미지 저장하기
        /// </summary>
        /// <param name="image">이미지</param>
        /// <param name="filePath">파일 경로</param>
        public void SaveImage(Image image, string filePath)
        {
            string extension = Path.GetExtension(filePath);

            switch(extension.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("Unknown file extension " + extension);
            }
        }

        #endregion
        #region 이미지 그리기 - DrawImage()

        /// <summary>
        /// 이미지 그리기
        /// </summary>
        private void DrawImage()
        {
            if(this.sourceBitmap == null)
            {
                this.pictureBox.Refresh();

                return;
            }

            int width  = this.sourceBitmap.Width;
            int height = this.sourceBitmap.Height;

            Matrix matrix = new Matrix();

            matrix.Rotate(this.angle);

            PointF[] pointArray =
            {
                new PointF(0    , 0     ),
                new PointF(width, 0     ),
                new PointF(0    , height),
                new PointF(width, height)
            };

            matrix.TransformPoints(pointArray);

            float minimumX = pointArray[0].X;
            float maximumX = minimumX;
            float minimumY = pointArray[0].Y;
            float maximumY = minimumY;

            for(int i = 1; i < pointArray.Length; i++)
            {
                if(minimumX > pointArray[i].X) minimumX = pointArray[i].X;
                if(maximumX < pointArray[i].X) maximumX = pointArray[i].X;
                if(minimumY > pointArray[i].Y) minimumY = pointArray[i].Y;
                if(maximumY < pointArray[i].Y) maximumY = pointArray[i].Y;
            }

            float newWidth  = maximumX - minimumX;
            float newHeight = maximumY - minimumY;

            matrix.Translate(newWidth / 2, newHeight / 2, MatrixOrder.Append);

            this.targetBitmap = new Bitmap((int)newWidth, (int)newHeight);

            using(Graphics graphics = Graphics.FromImage(this.targetBitmap))
            {
                graphics.InterpolationMode = InterpolationMode.High;

                graphics.Clear(Color.White);

                graphics.Transform = matrix;

                PointF[] targetPointArray =
                {
                    new PointF(-width / 2, -height / 2),
                    new PointF( width / 2, -height / 2),
                    new PointF(-width / 2,  height / 2)
                };

                graphics.DrawImage(sourceBitmap, targetPointArray);
            }

            this.pictureBox.Image = this.targetBitmap;
        }

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

댓글을 달아 주세요