첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.
본 블로그는 광고를 포함하고 있습니다.
광고 클릭에서 발생하는 수익금은 모두 블로그 콘텐츠 향상을 위해 쓰여집니다.

728x90
반응형
728x170

TestProject.zip
다운로드

▶ BitmapHelper.cs

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

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

        #region Field

        /// <summary>
        /// 픽셀 비트 수
        /// </summary>
        public const int PIXEL_BIT_COUNT = 32;

        /// <summary>
        /// 이미지 바이트 배열
        /// </summary>
        public byte[] ImageByteArray;

        /// <summary>
        /// 행 바이트 수
        /// </summary>
        public int RowByteCount;

        #endregion

        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Field

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

        /// <summary>
        /// 소스 비트맵 데이터
        /// </summary>
        private BitmapData sourceBitmapData;

        #endregion

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

        #region 너비 - Width

        /// <summary>
        /// 너비
        /// </summary>
        public int Width
        {
            get
            {
                return this.sourceBitmap.Width;
            }
        }

        #endregion
        #region 높이 - Height

        /// <summary>
        /// 높이
        /// </summary>
        public int Height
        {
            get
            {
                return this.sourceBitmap.Height;
            }
        }

        #endregion

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

        #region 생성자 - BitmapHelper(sourceBitmap)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="sourceBitmap">소스 비트맵</param>
        public BitmapHelper(Bitmap sourceBitmap)
        {
            this.sourceBitmap = sourceBitmap;
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 픽셀 구하기 - GetPixel(x, y, red, green, blue, alpha)

        /// <summary>
        /// 픽셀 구하기
        /// </summary>
        /// <param name="x">X</param>
        /// <param name="y">Y</param>
        /// <param name="red">적색 채널</param>
        /// <param name="green">녹색 채널</param>
        /// <param name="blue">청색 채널</param>
        /// <param name="alpha">알파 채널</param>
        public void GetPixel(int x, int y, out byte red, out byte green, out byte blue, out byte alpha)
        {
            int i = y * this.sourceBitmapData.Stride + x * 4;

            blue  = ImageByteArray[i++];
            green = ImageByteArray[i++];
            red   = ImageByteArray[i++];
            alpha = ImageByteArray[i  ];
        }

        #endregion
        #region 적색 채널 구하기 - GetRed(x, y)

        /// <summary>
        /// 적색 채널 구하기
        /// </summary>
        /// <param name="x">X</param>
        /// <param name="y">Y</param>
        /// <returns>적색 채널</returns>
        public byte GetRed(int x, int y)
        {
            int i = y * this.sourceBitmapData.Stride + x * 4;

            return ImageByteArray[i + 2];
        }

        #endregion
        #region 녹색 채널 구하기 - GetGreen(x, y)

        /// <summary>
        /// 녹색 채널 구하기
        /// </summary>
        /// <param name="x">X</param>
        /// <param name="y">Y</param>
        /// <returns>녹색 채널</returns>
        public byte GetGreen(int x, int y)
        {
            int i = y * this.sourceBitmapData.Stride + x * 4;

            return ImageByteArray[i + 1];
        }

        #endregion
        #region 청색 채널 구하기 - GetBlue(x, y)

        /// <summary>
        /// 청색 채널 구하기
        /// </summary>
        /// <param name="x">X</param>
        /// <param name="y">Y</param>
        /// <returns>청색 채널</returns>
        public byte GetBlue(int x, int y)
        {
            int i = y * this.sourceBitmapData.Stride + x * 4;

            return ImageByteArray[i];
        }

        #endregion
        #region 알파 채널 구하기 - GetAlpha(x, y)

        /// <summary>
        /// 알파 채널 구하기
        /// </summary>
        /// <param name="x">X</param>
        /// <param name="y">Y</param>
        /// <returns>알파 채널</returns>
        public byte GetAlpha(int x, int y)
        {
            int i = y * this.sourceBitmapData.Stride + x * 4;

            return ImageByteArray[i + 3];
        }

        #endregion

        #region 픽셀 설정하기 - SetPixel(x, y, red, green, blue, alpha)

        /// <summary>
        /// 픽셀 설정하기
        /// </summary>
        /// <param name="x">X</param>
        /// <param name="y">Y</param>
        /// <param name="red">적색 채널</param>
        /// <param name="green">녹색 채널</param>
        /// <param name="blue">청색 채널</param>
        /// <param name="alpha">알파 채널</param>
        public void SetPixel(int x, int y, byte red, byte green, byte blue, byte alpha)
        {
            int i = y * this.sourceBitmapData.Stride + x * 4;

            ImageByteArray[i++] = blue;
            ImageByteArray[i++] = green;
            ImageByteArray[i++] = red;
            ImageByteArray[i  ] = alpha;
        }

        #endregion
        #region 적색 채널 설정하기 - SetRed(x, y, red)

        /// <summary>
        /// 적색 채널 설정하기
        /// </summary>
        /// <param name="x">X</param>
        /// <param name="y">Y</param>
        /// <param name="red">적색 채널</param>
        public void SetRed(int x, int y, byte red)
        {
            int i = y * this.sourceBitmapData.Stride + x * 4;

            ImageByteArray[i + 2] = red;
        }

        #endregion
        #region 녹색 채널 설정하기 - SetGreen(x, y, green)

        /// <summary>
        /// 녹색 채널 설정하기
        /// </summary>
        /// <param name="x">X</param>
        /// <param name="y">Y</param>
        /// <param name="green">녹색 채널</param>
        public void SetGreen(int x, int y, byte green)
        {
            int i = y * this.sourceBitmapData.Stride + x * 4;

            ImageByteArray[i + 1] = green;
        }

        #endregion
        #region 청색 채널 설정하기 - SetBlue(x, y, blue)

        /// <summary>
        /// 청색 채널 설정하기
        /// </summary>
        /// <param name="x">X</param>
        /// <param name="y">Y</param>
        /// <param name="blue">청색 채널</param>
        public void SetBlue(int x, int y, byte blue)
        {
            int i = y * this.sourceBitmapData.Stride + x * 4;

            ImageByteArray[i] = blue;
        }

        #endregion
        #region 알파 채널 설정하기 - SetAlpha(x, y, alpha)

        /// <summary>
        /// 알파 채널 설정하기
        /// </summary>
        /// <param name="x">X</param>
        /// <param name="y">Y</param>
        /// <param name="alpha">알파 채널</param>
        public void SetAlpha(int x, int y, byte alpha)
        {
            int i = y * this.sourceBitmapData.Stride + x * 4;

            ImageByteArray[i + 3] = alpha;
        }

        #endregion

        #region 비트맵 잠금 설정하기 - LockBitmap()

        /// <summary>
        /// 비트맵 잠금 설정하기
        /// </summary>
        public void LockBitmap()
        {
            Rectangle sourceRectangle = new Rectangle
            (
                0,
                0,
                this.sourceBitmap.Width,
                this.sourceBitmap.Height
            );

            this.sourceBitmapData = this.sourceBitmap.LockBits
            (
                sourceRectangle,
                ImageLockMode.ReadWrite,
                PixelFormat.Format32bppArgb
            );

            RowByteCount = this.sourceBitmapData.Stride;

            int totalByteCount = this.sourceBitmapData.Stride * this.sourceBitmapData.Height;

            ImageByteArray = new byte[totalByteCount];

            Marshal.Copy(this.sourceBitmapData.Scan0, ImageByteArray, 0, totalByteCount);
        }

        #endregion
        #region 비트맵 잠금 해제하기 - UnlockBitmap()

        /// <summary>
        /// 비트맵 잠금 해제하기
        /// </summary>
        public void UnlockBitmap()
        {
            int totalByteCount = this.sourceBitmapData.Stride * this.sourceBitmapData.Height;

            Marshal.Copy(ImageByteArray, 0, this.sourceBitmapData.Scan0, totalByteCount);

            this.sourceBitmap.UnlockBits(this.sourceBitmapData);

            ImageByteArray = null;

            this.sourceBitmapData = null;
        }

        #endregion
    }
}

 

728x90

 

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

        #region 픽셀 타입 - PixelType

        /// <summary>
        /// 픽셀 타입
        /// </summary>
        private enum PixelType
        {
            /// <summary>
            /// 적색
            /// </summary>
            Red,

            /// <summary>
            /// 녹색
            /// </summary>
            Green,

            /// <summary>
            /// 청색
            /// </summary>
            Blue,
        }

        #endregion

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

        #region Field

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

        #endregion

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

        #region 생성자 - MainForm()

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

            this.openMenuItem.Click   += openMenuItem_Click;
            this.saveAsMenuItem.Click += saveAsMenuItem_Click;
            this.applyButton.Click    += applyButton_Click;
        }

        #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 = GetBitmap(this.openFileDialog.FileName);

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

                this.saveAsMenuItem.Enabled = true;

                this.applyButton.Enabled = true;
            }
        }

        #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.pictureBox.Image, this.saveFileDialog.FileName);
            }
        }

        #endregion
        #region 적용 버튼 클릭시 처리하기 - applyButton_Click(sender, e)

        /// <summary>
        /// 적용 버튼 클릭시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void applyButton_Click(object sender, EventArgs e)
        {
            PixelType pixelType = PixelType.Red;

            if(this.greenRadioButton.Checked)
            {
                pixelType = PixelType.Green;
            }
            else if(this.blueRadioButton.Checked)
            {
                pixelType = PixelType.Blue;
            }

            int   threshold  = int.Parse(this.thresholdTextBox.Text);
            float multiplier = float.Parse(this.multiplierTextBox.Text);

            this.pictureBox.Image = GetBitmap(this.sourceBitmap, pixelType, threshold, multiplier);
        }

        #endregion

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

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

        /// <summary>
        /// 비트맵 구하기
        /// </summary>
        /// <param name="filePath">파일 경로</param>
        /// <returns>비트맵</returns>
        private Bitmap GetBitmap(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("Unknown file extension " + fileExtension);
            }
        }

        #endregion
        #region 비트맵 구하기 - GetBitmap(sourceBitmap, pixelType, threshold, multiplier)

        /// <summary>
        /// 비트맵 구하기
        /// </summary>
        /// <param name="sourceBitmap">소스 비트맵</param>
        /// <param name="pixelType">픽셀 타입</param>
        /// <param name="threshold">임계값</param>
        /// <param name="multiplier">승수</param>
        /// <returns>비트맵</returns>
        private Bitmap GetBitmap(Bitmap sourceBitmap, PixelType pixelType, int threshold, float multiplier)
        {
            Bitmap targetBitmap = new Bitmap(sourceBitmap);

            BitmapHelper targetBitmapHelper = new BitmapHelper(targetBitmap);

            targetBitmapHelper.LockBitmap();

            int targetWidth  = targetBitmap.Width;
            int targetHeight = targetBitmap.Height;

            for(int y = 0; y < targetHeight; y++)
            {
                for(int x = 0; x < targetWidth; x++)
                {
                    byte red;
                    byte green;
                    byte blue;
                    byte alpha;

                    targetBitmapHelper.GetPixel(x, y, out red, out green, out blue, out alpha);

                    switch(pixelType)
                    {
                        case PixelType.Red :

                            if((red >= green + threshold) && (red > blue + threshold))
                            {
                                int newRed = (int)(red * multiplier);

                                if(newRed > 255)
                                {
                                    newRed = 255;
                                }
                                else if(newRed < 0)
                                {
                                    newRed = 0;
                                }

                                red = (byte)newRed;
                            }

                            break;

                        case PixelType.Green :

                            if((green >= red + threshold) && (green > blue + threshold))
                            {
                                int newGreen = (int)(green * multiplier);

                                if(newGreen > 255)
                                {
                                    newGreen = 255;
                                }
                                else if(newGreen < 0)
                                {
                                    newGreen = 0;
                                }

                                green = (byte)newGreen;
                            }

                            break;

                        case PixelType.Blue :

                            if((blue >= red + threshold) && (blue > green + threshold))
                            {
                                int newBlue = (int)(blue * multiplier);

                                if(newBlue > 255)
                                {
                                    newBlue = 255;
                                }
                                else if(newBlue < 0)
                                {
                                    newBlue = 0;
                                }

                                blue = (byte)newBlue;
                            }

                            break;
                    }

                    targetBitmapHelper.SetPixel(x, y, red, green, blue, alpha);
                }
            }

            targetBitmapHelper.UnlockBitmap();

            return targetBitmap;
        }

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

댓글을 달아 주세요