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

TestProject.zip
0.02MB

▶ ColorSubstitutionFilter.cs

using System.Drawing;

namespace TestProject
{
    /// <summary>
    /// 색상 대체 필터
    /// </summary>
    public class ColorSubstitutionFilter
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 임계치 값
        /// </summary>
        private int thresholdValue = 10;

        /// <summary>
        /// 소스 색상
        /// </summary>
        private Color sourceColor = Color.White;

        /// <summary>
        /// 타겟 색상
        /// </summary>
        private Color targetColor = Color.White;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Property
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 임계치 값 - ThresholdValue

        /// <summary>
        /// 임계치 값
        /// </summary>
        public int ThresholdValue
        {
            get
            {
                return this.thresholdValue;
            }
            set
            {
                this.thresholdValue = value;
            }
        }

        #endregion
        #region 소스 색상 - SourceColor

        /// <summary>
        /// 소스 색상
        /// </summary>
        public Color SourceColor
        {
            get
            {
                return this.sourceColor;
            }
            set
            {
                this.sourceColor = value;
            }
        }

        #endregion
        #region 타겟 색상 - TargetColor

        /// <summary>
        /// 타겟 색상
        /// </summary>
        public Color TargetColor
        {
            get
            {
                return this.targetColor;
            }
            set
            {
                this.targetColor = value;
            }
        }

        #endregion
    }
}

 

728x90

 

▶ BitmapHelper.cs

using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;

namespace TestProject
{
    /// <summary>
    /// 비트맵 헬퍼
    /// </summary>
    public static class BitmapHelper
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Static
        //////////////////////////////////////////////////////////////////////////////// Public

        #region 비트맵 구하기 - GetBitmap(sourceBitmap)

        /// <summary>
        /// 비트맵 구하기
        /// </summary>
        /// <param name="sourceBitmap">소스 비트맵</param>
        /// <returns>비트맵</returns>
        public static Bitmap GetBitmap(Bitmap sourceBitmap)
        {
            Bitmap targetBitmap = new Bitmap(sourceBitmap.Width, sourceBitmap.Height, PixelFormat.Format32bppArgb);
            
            using(Graphics graphics = Graphics.FromImage(targetBitmap))
            {
                graphics.CompositingQuality = CompositingQuality.HighQuality;
                graphics.InterpolationMode  = InterpolationMode.HighQualityBicubic;
                graphics.PixelOffsetMode    = PixelOffsetMode.HighQuality;
                graphics.SmoothingMode      = SmoothingMode.HighQuality;
                
                graphics.DrawImage
                (
                    sourceBitmap,
                    new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height),
                    new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height),
                    GraphicsUnit.Pixel
                );
            }

            return targetBitmap;
        }

        #endregion
        #region 색상 대체하기 - SubstituteColor(sourceBitmap, colorSubstitutionFilter)

        /// <summary>
        /// 색상 대체하기
        /// </summary>
        /// <param name="sourceBitmap">소스 비트맵</param>
        /// <param name="colorSubstitutionFilter">색상 대체 필터</param>
        /// <returns>비트맵</returns>
        public static Bitmap SubstituteColor(Bitmap sourceBitmap, ColorSubstitutionFilter colorSubstitutionFilter)
        {
            BitmapData sourceBitmapData = sourceBitmap.LockBits
            (
                new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height),
                ImageLockMode.ReadOnly,
                PixelFormat.Format32bppArgb
            );

            Bitmap targetBitmap = new Bitmap
            (
                sourceBitmap.Width,
                sourceBitmap.Height,
                PixelFormat.Format32bppArgb
            );

            BitmapData targetBitmapData = targetBitmap.LockBits
            (
                new Rectangle(0, 0, targetBitmap.Width, targetBitmap.Height),
                ImageLockMode.WriteOnly,
                PixelFormat.Format32bppArgb
            );

            byte[] targetByteArray = new byte[targetBitmapData.Stride * targetBitmapData.Height];

            Marshal.Copy(sourceBitmapData.Scan0, targetByteArray, 0, targetByteArray.Length);

            sourceBitmap.UnlockBits(sourceBitmapData);

            byte sourceRed   = 0;
            byte sourceGreen = 0;
            byte sourceBlue  = 0;
            byte sourceAlpha = 0;

            int targetRed   = 0;
            int targetGreen = 0;
            int targetBlue  = 0;

            byte newRedValue   = colorSubstitutionFilter.TargetColor.R;
            byte newGreenValue = colorSubstitutionFilter.TargetColor.G;
            byte newBlueValue  = colorSubstitutionFilter.TargetColor.B;

            byte redFilter   = colorSubstitutionFilter.SourceColor.R;
            byte greenFilter = colorSubstitutionFilter.SourceColor.G;
            byte blueFilter  = colorSubstitutionFilter.SourceColor.B;

            byte minimumValue = 0;
            byte maximumValue = 255;

            for(int k = 0; k < targetByteArray.Length; k += 4)
            {
                sourceAlpha = targetByteArray[k + 3];

                if(sourceAlpha != 0)
                {
                    sourceBlue  = targetByteArray[k    ];
                    sourceGreen = targetByteArray[k + 1];
                    sourceRed   = targetByteArray[k + 2];

                    if
                    (
                        (sourceBlue  < blueFilter  + colorSubstitutionFilter.ThresholdValue && sourceBlue  > blueFilter  - colorSubstitutionFilter.ThresholdValue) &&
                        (sourceGreen < greenFilter + colorSubstitutionFilter.ThresholdValue && sourceGreen > greenFilter - colorSubstitutionFilter.ThresholdValue) &&
                        (sourceRed   < redFilter   + colorSubstitutionFilter.ThresholdValue && sourceRed   > redFilter   - colorSubstitutionFilter.ThresholdValue)
                    )
                    {
                        targetBlue = blueFilter - sourceBlue + newBlueValue;

                        if(targetBlue > maximumValue)
                        {
                            targetBlue = maximumValue;
                        }
                        else if(targetBlue < minimumValue)
                        {
                            targetBlue = minimumValue;
                        }

                        targetGreen = greenFilter - sourceGreen + newGreenValue;

                        if(targetGreen > maximumValue)
                        {
                            targetGreen = maximumValue;
                        }
                        else if(targetGreen < minimumValue)
                        {
                            targetGreen = minimumValue;
                        }

                        targetRed = redFilter - sourceRed + newRedValue;

                        if(targetRed > maximumValue)
                        {
                            targetRed = maximumValue;
                        }
                        else if(targetRed < minimumValue)
                        {
                            targetRed = minimumValue;
                        }

                        targetByteArray[k    ] = (byte)targetBlue;
                        targetByteArray[k + 1] = (byte)targetGreen;
                        targetByteArray[k + 2] = (byte)targetRed;
                        targetByteArray[k + 3] = sourceAlpha;
                    }
                }
            }

            Marshal.Copy(targetByteArray, 0, targetBitmapData.Scan0, targetByteArray.Length);

            targetBitmap.UnlockBits(targetBitmapData);

            return targetBitmap;
        }

        #endregion
    }
}

 

300x250

 

▶ MainForm.cs

using System;
using System.Drawing;
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 ColorSubstitutionFilter filter = new ColorSubstitutionFilter();

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Consructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - MainForm()

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

            this.sourcePictureBox.MouseUp           += pictureBox_MouseUp;
            this.targetPictureBox.MouseUp           += pictureBox_MouseUp;
            this.thresholdTrackBar.ValueChanged     += thresholdTrackBar_ValueChanged;
            this.selectSourceColorButton.Click      += selectColorButton_Click;
            this.selectReplacementColorButton.Click += selectColorButton_Click;
            this.loadImageButton.Click              += loadImageButton_Click;
            this.saveImageButton.Click              += saveImageButton_Click;
            this.setSourceButton.Click              += setSourceButton_Click;
        }

        #endregion

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

        #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)
        {
            if(sender is PictureBox)
            {
                PictureBox pictureBox = sender as PictureBox;

                using(Bitmap bitmap = new Bitmap(pictureBox.Width, pictureBox.Height))
                {
                    this.sourcePictureBox.DrawToBitmap(bitmap, new Rectangle(0, 0, pictureBox.Width, pictureBox.Height));

                    this.sourceColorPanel.BackColor = bitmap.GetPixel(e.X, e.Y);
                }

                ApplyFilter();
            }
        }

        #endregion
        #region 임계치 트랙바 값 변경시 처리하기 - thresholdTrackBar_ValueChanged(sender, e)

        /// <summary>
        /// 임계치 트랙바 값 변경시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void thresholdTrackBar_ValueChanged(object sender, EventArgs e)
        {
            this.thresholdValueLabel.Text = this.thresholdTrackBar.Value.ToString() + "%";
            
            ApplyFilter();
        }

        #endregion
        #region 색상 선택 버튼 클릭시 처리하기 - selectColorButton_Click(sender, e)

        /// <summary>
        /// 색상 선택 버튼 클릭시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void selectColorButton_Click(object sender, EventArgs e)
        {
            using(ColorDialog colorDialog = new ColorDialog())
            {
                colorDialog.AllowFullOpen = true;
                colorDialog.AnyColor      = true;
                colorDialog.FullOpen      = true;

                if(sender == this.selectSourceColorButton)
                {
                    colorDialog.Color = this.sourceColorPanel.BackColor;
                }
                else if(sender == this.selectReplacementColorButton)
                {
                    colorDialog.Color = this.replacementColorPanel.BackColor;
                }

                if(colorDialog.ShowDialog() == DialogResult.OK)
                {
                    if(sender == this.selectSourceColorButton)
                    {
                        this.sourceColorPanel.BackColor = colorDialog.Color;
                    }
                    else if(sender == this.selectReplacementColorButton)
                    {
                        this.replacementColorPanel.BackColor = colorDialog.Color;
                    }
                    
                    ApplyFilter();
                }
            }
        }

        #endregion
        #region 이미지 로드 버튼 클릭시 처리하기 - loadImageButton_Click(sender, e)

        /// <summary>
        /// 이미지 로드 버튼 클릭시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void loadImageButton_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();

            openFileDialog.Title  = "이미지 파일 선택";
            openFileDialog.Filter = "JPEG 이미지(*.jpg)|*.jpg|PNG 이미지(*.png)|*.png|비트맵 이미지(*.bmp)|*.bmp";

            if(openFileDialog.ShowDialog() == DialogResult.OK)
            {
                StreamReader streamReader = new StreamReader(openFileDialog.FileName);

                Bitmap sourceBitmap = new Bitmap(streamReader.BaseStream);

                streamReader.Close();

                this.sourcePictureBox.Image = BitmapHelper.GetBitmap(sourceBitmap);

                ApplyFilter();
            }
        }

        #endregion
        #region 이미지 저장 버튼 클릭시 처리하기 - saveImageButton_Click(sender, e)

        /// <summary>
        /// 이미지 저장 버튼 클릭시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void saveImageButton_Click(object sender, EventArgs e)
        {
            if(this.targetPictureBox.Image != null)
            {
                SaveFileDialog saveFileDialog = new SaveFileDialog();

                saveFileDialog.Title  = "이미지 파일 선택";
                saveFileDialog.Filter = "JPEG 이미지(*.jpg)|*.jpg|PNG 이미지(*.png)|*.png|비트맵 이미지(*.bmp)|*.bmp";

                if(saveFileDialog.ShowDialog() == DialogResult.OK)
                {
                    string fileExtension = Path.GetExtension(saveFileDialog.FileName).ToUpper();

                    ImageFormat imageFormat = ImageFormat.Png;

                    if(fileExtension == "BMP")
                    {
                        imageFormat = ImageFormat.Bmp;
                    }
                    else if(fileExtension == "JPG")
                    {
                        imageFormat = ImageFormat.Jpeg;
                    }

                    StreamWriter streamWriter = new StreamWriter(saveFileDialog.FileName, false);

                    this.targetPictureBox.Image.Save(streamWriter.BaseStream, imageFormat);

                    streamWriter.Flush();
                    streamWriter.Close();
                }
            }
        }

        #endregion
        #region 타겟을 소스로 설정 버튼 클릭시 처리하기 - setSourceButton_Click(sender, e)

        /// <summary>
        /// 타겟을 소스로 설정 버튼 클릭시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void setSourceButton_Click(object sender, EventArgs e)
        {
            Bitmap targetBitmap = this.targetPictureBox.Image as Bitmap;

            this.sourcePictureBox.Image = BitmapHelper.GetBitmap(targetBitmap);
        }

        #endregion

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

        #region 필터 적용하기 - ApplyFilter()

        /// <summary>
        /// 필터 적용하기
        /// </summary>
        private void ApplyFilter()
        {
            if(this.sourcePictureBox.Image != null)
            {
                this.filter.SourceColor    = this.sourceColorPanel.BackColor;
                this.filter.ThresholdValue = (byte)(255.0f / 100.0f * (float)this.thresholdTrackBar.Value);
                this.filter.TargetColor    = this.replacementColorPanel.BackColor;

                Bitmap sourceBitmap = this.sourcePictureBox.Image as Bitmap;

                this.targetPictureBox.Image = BitmapHelper.SubstituteColor(sourceBitmap, filter);

                this.colorFilterPanel.Enabled = true;
                this.saveImageButton.Enabled  = true;
                this.setSourceButton.Enabled  = true;
            }
        }

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

댓글을 달아 주세요