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

TestProject.zip
다운로드

▶ MainForm.cs

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
using System.IO;
using System.Windows.Forms;

namespace TestProject
{
    /// <summary>
    /// 메인 폼
    /// </summary>
    public partial class MainForm : Form
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 오버레이 비트맵
        /// </summary>
        private Bitmap overlayBitmap = null;

        /// <summary>
        /// 오버레이 스케일 비트맵
        /// </summary>
        private Bitmap overlayScaledBitmap = null;

        /// <summary>
        /// 메인 비트맵
        /// </summary>
        private Bitmap mainBitmap = null;

        /// <summary>
        /// 메인 작업 비트맵
        /// </summary>
        private Bitmap mainWorkingBitmap = null;

        /// <summary>
        /// 메인 작업 스케일 비트맵
        /// </summary>
        private Bitmap mainWorkingScaledBitmap = null;

        /// <summary>
        /// 비트맵 스케일
        /// </summary>
        private float bitmapScale = 1;

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

        /// <summary>
        /// 선택 영역 포인트 리스트
        /// </summary>
        private List<PointF> selectedAreaPointList = new List<PointF>();

        /// <summary>
        /// 선택 영역 스케일 포인트 리스트
        /// </summary>
        private List<PointF> selectedAreaScaledPointList = new List<PointF>();

        #endregion

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

        #region 생성자 - MainForm()

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

            this.openOverlayImageMenuItem.Click   += openOverlayImageMenuItem_Click;
            this.openMainImageMenuItem.Click      += openMainImageMenuItem_Click;
            this.resetMenuItem.Click              += resetMenuItem_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.scale5MenuItem.Click             += scaleMenuItem_Click;
            this.overlayImagePictureBox.MouseDown += overlayImagePictureBox_MouseDown;
            this.overlayImagePictureBox.MouseMove += overlayImagePictureBox_MouseMove;
            this.overlayImagePictureBox.MouseUp   += overlayImagePictureBox_MouseUp;
            this.overlayImagePictureBox.Paint     += overlayImagePictureBox_Paint;
            this.copyButton.Click                 += copyButton_Click;
        }

        #endregion

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

        #region 오버레이 이미지 열기 메뉴 항목 클릭시 처리하기 - openOverlayImageMenuItem_Click(sender, e)

        /// <summary>
        /// 오버레이 이미지 열기 메뉴 항목 클릭시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void openOverlayImageMenuItem_Click(object sender, EventArgs e)
        {
            if(this.openFileDialog.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    this.overlayBitmap = LoadBitmapFile(this.openFileDialog.FileName);

                    this.resetMenuItem.Enabled = false;

                    ShowScaledBitmap();
                }
                catch(Exception exception)
                {
                    MessageBox.Show(exception.Message);
                }
            }
        }

        #endregion
        #region 메인 이미지 열기 메뉴 항목 클릭시 처리하기 - openMainImageMenuItem_Click(sender, e)

        /// <summary>
        /// 메인 이미지 열기 메뉴 항목 클릭시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void openMainImageMenuItem_Click(object sender, EventArgs e)
        {
            if(this.openFileDialog.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    this.mainBitmap = LoadBitmapFile(this.openFileDialog.FileName);

                    this.mainWorkingBitmap = new Bitmap(this.mainBitmap);

                    this.resetMenuItem.Enabled = false;

                    ShowScaledBitmap();
                }
                catch(Exception exception)
                {
                    MessageBox.Show(exception.Message);
                }
            }
        }

        #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.mainWorkingBitmap = new Bitmap(this.mainBitmap);

            this.resetMenuItem.Enabled = false;

            ShowScaledBitmap();
        }

        #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.mainWorkingBitmap, 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.bitmapScale = float.Parse(scaleText) / 100f;

            ShowScaledBitmap();

            this.scaleMenuItem.Text = "확대/축소(&S) (" + menuItem.Text.Replace("&", "") + ")";

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

            ScaleSelectionArea();
        }

        #endregion
        #region 오버레이 이미지 픽처 박스 마우스 DOWN 처리하기 - overlayImagePictureBox_MouseDown(sender, e)

        /// <summary>
        /// 오버레이 이미지 픽처 박스 마우스 DOWN 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void overlayImagePictureBox_MouseDown(object sender, MouseEventArgs e)
        {
            if(this.overlayImagePictureBox.Image == null)
            {
                return;
            }

            this.isDrawing = true;

            this.selectedAreaScaledPointList = new List<PointF>();

            this.selectedAreaScaledPointList.Add(e.Location);

            this.selectedAreaPointList = new List<PointF>();

            this.selectedAreaPointList.Add(new PointF(e.X / this.bitmapScale, e.Y / this.bitmapScale));

            this.overlayImagePictureBox.Refresh();
        }

        #endregion
        #region 오버레이 이미지 픽처 박스 마우스 이동시 처리하기 - overlayImagePictureBox_MouseMove(sender, e)

        /// <summary>
        /// 오버레이 이미지 픽처 박스 마우스 이동시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void overlayImagePictureBox_MouseMove(object sender, MouseEventArgs e)
        {
            if(!this.isDrawing)
            {
                return;
            }

            this.selectedAreaScaledPointList.Add(e.Location);

            this.selectedAreaPointList.Add
            (
                new PointF
                (
                    e.X / this.bitmapScale,
                    e.Y / this.bitmapScale
                )
            );

            this.overlayImagePictureBox.Refresh();
        }

        #endregion
        #region 오버레이 이미지 픽처 박스 마우스 UP 처리하기 - overlayImagePictureBox_MouseUp(sender, e)

        /// <summary>
        /// 오버레이 이미지 픽처 박스 마우스 UP 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void overlayImagePictureBox_MouseUp(object sender, MouseEventArgs e)
        {
            this.isDrawing = false;

            this.overlayImagePictureBox.Refresh();
            
            this.copyButton.Enabled = (this.selectedAreaPointList.Count > 2);
        }

        #endregion
        #region 오버레이 이미지 픽처 박스 페인트시 처리하기 - overlayImagePictureBox_Paint(sender, e)

        /// <summary>
        /// 오버레이 이미지 픽처 박스 페인트시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void overlayImagePictureBox_Paint(object sender, PaintEventArgs e)
        {
            if(this.selectedAreaPointList.Count < 3)
            {
                return;
            }

            e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;

            PointF[] pointArray = this.selectedAreaScaledPointList.ToArray();

            using(Pen pen = new Pen(Color.Red, 2))
            {
                if(this.isDrawing)
                {
                    e.Graphics.DrawLines(pen, pointArray);
                }
                else
                {
                    e.Graphics.DrawPolygon(pen, pointArray);
                }

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

                if(this.isDrawing)
                {
                    e.Graphics.DrawLines(pen, pointArray);
                }
                else
                {
                    e.Graphics.DrawPolygon(pen, pointArray);
                }
            }
        }

        #endregion
        #region 복사 버튼 클릭시 처리하기 - copyButton_Click(sender, e)

        /// <summary>
        /// 복사 버튼 클릭시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void copyButton_Click(object sender, EventArgs e)
        {
            if(this.selectedAreaPointList.Count < 3)
            {
                return;
            }

            this.copyButton.Enabled = false;

            this.resetMenuItem.Enabled = true;

            using(Graphics graphics = Graphics.FromImage(this.mainWorkingBitmap))
            {
                using(TextureBrush brush = new TextureBrush(this.overlayBitmap))
                {
                    graphics.FillPolygon(brush, this.selectedAreaPointList.ToArray());
                }
            }

            ShowScaledBitmap();
        }

        #endregion

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

        #region 비트맵 파일 로드하기 - LoadBitmapFile(filePath)

        /// <summary>
        /// 비트맵 파일 로드하기
        /// </summary>
        /// <param name="filePath">파일 경로</param>
        /// <returns>비트맵</returns>
        private Bitmap LoadBitmapFile(string filePath)
        {
            using(Bitmap bitmap = new Bitmap(filePath))
            {
                return new Bitmap(bitmap);
            }
        }

        #endregion
        #region 크기 변경 비트맵 구하기 - GetScaledBitmap(sourceBitmap, scale)

        /// <summary>
        /// 크기 변경 비트맵 구하기
        /// </summary>
        /// <param name="sourceBitmap">소스 비트맵</param>
        /// <param name="scale">척도</param>
        /// <returns>크기 조정 비트맵</returns>
        private Bitmap GetScaledBitmap(Bitmap sourceBitmap, float scale)
        {
            int scaledWidth  = (int)(sourceBitmap.Width  * scale);
            int scaledHeight = (int)(sourceBitmap.Height * scale);

            Bitmap targetBitmap = new Bitmap(scaledWidth, scaledHeight);

            using(Graphics graphics = Graphics.FromImage(targetBitmap))
            {
                Rectangle targetRectangle = new Rectangle(0, 0, scaledWidth       , scaledHeight       );
                Rectangle sourceRectangle = new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height);

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

            return targetBitmap;
        }

        #endregion
        #region 크기 변경 비트맵 표시하기 - ShowScaledBitmap()

        /// <summary>
        /// 크기 변경 비트맵 표시하기
        /// </summary>
        private void ShowScaledBitmap()
        {
            if(this.overlayBitmap != null)
            {
                this.overlayScaledBitmap = GetScaledBitmap(this.overlayBitmap, this.bitmapScale);

                this.overlayImagePictureBox.Image   = this.overlayScaledBitmap;
                this.overlayImagePictureBox.Visible = true;
            }

            if(this.mainWorkingBitmap != null)
            {
                this.mainWorkingScaledBitmap = GetScaledBitmap(this.mainWorkingBitmap, this.bitmapScale);

                this.mainImagePictureBox.Image   = this.mainWorkingScaledBitmap;
                this.mainImagePictureBox.Visible = true;
            }

            this.saveAsMenuItem.Enabled = ((this.overlayBitmap != null) && (this.mainWorkingBitmap != null));
        }

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

        #endregion
        #region 선택 영역 크기 변경하기 - ScaleSelectionArea()

        /// <summary>
        /// 선택 영역 크기 변경하기
        /// </summary>
        private void ScaleSelectionArea()
        {
            this.selectedAreaScaledPointList = new List<PointF>();

            foreach(PointF point in this.selectedAreaPointList)
            {
                this.selectedAreaScaledPointList.Add
                (
                    new PointF
                    (
                        point.X * this.bitmapScale,
                        point.Y * this.bitmapScale
                    )
                );
            }
        }

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

댓글을 달아 주세요