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

728x90
반응형
728x170

TestProject.zip
다운로드

▶ CalculationType.cs

namespace TestProject
{
    /// <summary>
    /// 계산 타입
    /// </summary>
    public enum CalculationType
    {
        /// <summary>
        /// Average
        /// </summary>
        Average,

        /// <summary>
        /// Add
        /// </summary>
        Add,

        /// <summary>
        /// SubtractLeft
        /// </summary>
        SubtractLeft,

        /// <summary>
        /// SubtractRight
        /// </summary>
        SubtractRight,

        /// <summary>
        /// Difference
        /// </summary>
        Difference,

        /// <summary>
        /// Multiply
        /// </summary>
        Multiply,

        /// <summary>
        /// Minmum
        /// </summary>
        Minmum,

        /// <summary>
        /// Maximum
        /// </summary>
        Maximum,

        /// <summary>
        /// Amplitude
        /// </summary>
        Amplitude
    }
}

 

728x90

 

▶ CalculationHelper.cs

using System;

namespace TestProject
{
    /// <summary>
    /// 계산 헬퍼
    /// </summary>
    public static class CalculationHelper
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Static
        //////////////////////////////////////////////////////////////////////////////// Public

        #region 계산하기 - Calculate(sourceValue1, sourceValue2, calculationType)

        /// <summary>
        /// 계산하기
        /// </summary>
        /// <param name="sourceValue1">소스 값 1</param>
        /// <param name="sourceValue2">소스 값 2</param>
        /// <param name="calculationType">계산 타입</param>
        /// <returns>계산 값</returns>
        public static byte Calculate(byte sourceValue1, byte sourceValue2, CalculationType calculationType)
        {
            int  temporaryValue = 0;
            byte targetValue    = 0;

            if(calculationType == CalculationType.Add)
            {
                temporaryValue = sourceValue1 + sourceValue2;
            }
            else if(calculationType == CalculationType.Average)
            {
                temporaryValue = (sourceValue1 + sourceValue2) / 2;
            }
            else if(calculationType == CalculationType.SubtractLeft)
            {
                temporaryValue = sourceValue1 - sourceValue2;
            }
            else if(calculationType == CalculationType.SubtractRight)
            {
                temporaryValue = sourceValue2 - sourceValue1;
            }
            else if(calculationType == CalculationType.Difference)
            {
                temporaryValue = Math.Abs(sourceValue1 - sourceValue2);
            }
            else if(calculationType == CalculationType.Multiply)
            {
                temporaryValue = (int)((sourceValue1 / 255.0 * sourceValue2 / 255.0) * 255.0);
            }
            else if(calculationType == CalculationType.Minmum)
            {
                temporaryValue = (sourceValue1 < sourceValue2 ? sourceValue1 : sourceValue2);
            }
            else if(calculationType == CalculationType.Maximum)
            {
                temporaryValue = (sourceValue1 > sourceValue2 ? sourceValue1 : sourceValue2);
            }
            else if(calculationType == CalculationType.Amplitude)
            {
                temporaryValue = (int)(Math.Sqrt(sourceValue1 * sourceValue1 + sourceValue2 * sourceValue2) / Math.Sqrt(2.0));
            }

            if(temporaryValue < 0)
            { 
                targetValue = 0; 
            }
            else if(temporaryValue > 255)
            {
                targetValue = 255; 
            }
            else
            { 
                targetValue = (byte)temporaryValue; 
            }

            return targetValue;
        }

        #endregion
    }
}

 

300x250

 

▶ 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
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 비트맵 복사하기 - CopyBitmap(sourceBitmap, targetWidth)

        /// <summary>
        /// 비트맵 복사하기
        /// </summary>
        /// <param name="sourceBitmap">소스 비트맵</param>
        /// <param name="targetWidth">타겟 너비</param>
        /// <returns>비트맵</returns>
        public static Bitmap CopyBitmap(Bitmap sourceBitmap, int targetWidth)
        {
            float ratio       = 1.0f;
            int   maximumSize = sourceBitmap.Width > sourceBitmap.Height ? sourceBitmap.Width : sourceBitmap.Height;

            ratio = (float)maximumSize / (float)targetWidth;

            Bitmap targetBitmap = (sourceBitmap.Width > sourceBitmap.Height ? new Bitmap(targetWidth, (int)(sourceBitmap.Height / ratio)) :
                                                                              new Bitmap((int)(sourceBitmap.Width / ratio), targetWidth));

            using(Graphics targetGraphics = Graphics.FromImage(targetBitmap))
            {
                targetGraphics.CompositingQuality = CompositingQuality.HighQuality;
                targetGraphics.InterpolationMode  = InterpolationMode.HighQualityBicubic;
                targetGraphics.PixelOffsetMode    = PixelOffsetMode.HighQuality;

                targetGraphics.DrawImage
                (
                    sourceBitmap,
                    new Rectangle(0, 0, targetBitmap.Width, targetBitmap.Height),
                    new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height),
                    GraphicsUnit.Pixel
                );

                targetGraphics.Flush();
            }

            return targetBitmap;
        }

        #endregion
        #region 비트맵 혼합하기 - BlendBitmap(sourceBitmap1, sourceBitmap2, calculationType)

        /// <summary>
        /// 비트맵 혼합하기
        /// </summary>
        /// <param name="sourceBitmap1">소스 비트맵 1</param>
        /// <param name="sourceBitmap2">소스 비트맵 2</param>
        /// <param name="calculationType">계산 타입</param>
        /// <returns>비트맵</returns>
        public static Bitmap BlendBitmap(Bitmap sourceBitmap1, Bitmap sourceBitmap2, CalculationType calculationType)
        {
            BitmapData sourceBitmapData1 = sourceBitmap1.LockBits
            (
                new Rectangle(0, 0, sourceBitmap1.Width, sourceBitmap1.Height),
                ImageLockMode.ReadOnly,
                PixelFormat.Format32bppArgb
            );

            byte[] sourceByteArray1 = new byte[sourceBitmapData1.Stride * sourceBitmapData1.Height];

            Marshal.Copy(sourceBitmapData1.Scan0, sourceByteArray1, 0, sourceByteArray1.Length);

            sourceBitmap1.UnlockBits(sourceBitmapData1);

            BitmapData sourceBitmapData2 = sourceBitmap2.LockBits
            (
                new Rectangle(0, 0, sourceBitmap2.Width, sourceBitmap2.Height),
                ImageLockMode.ReadOnly,
                PixelFormat.Format32bppArgb
            );

            byte[] sourceByteArray2 = new byte[sourceBitmapData2.Stride * sourceBitmapData2.Height];

            Marshal.Copy(sourceBitmapData2.Scan0, sourceByteArray2, 0, sourceByteArray2.Length);

            sourceBitmap2.UnlockBits(sourceBitmapData2);

            for(int k = 0; (k + 4 < sourceByteArray1.Length) && (k + 4 < sourceByteArray2.Length); k += 4)
            {
                sourceByteArray1[k    ] = CalculationHelper.Calculate(sourceByteArray1[k    ], sourceByteArray2[k    ], calculationType);
                sourceByteArray1[k + 1] = CalculationHelper.Calculate(sourceByteArray1[k + 1], sourceByteArray2[k + 1], calculationType);
                sourceByteArray1[k + 2] = CalculationHelper.Calculate(sourceByteArray1[k + 2], sourceByteArray2[k + 2], calculationType);
            }

            Bitmap targetBitmap = new Bitmap(sourceBitmap1.Width, sourceBitmap1.Height);

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

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

            targetBitmap.UnlockBits(targetBitmapData);

            return targetBitmap;
        }

        #endregion
    }
}

 

▶ 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>
        /// 소스 비트맵 1
        /// </summary>
        private Bitmap sourceBitmap1 = null;

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

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

        #endregion

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

        #region 생성자 - MainForm()

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

            this.blendTypeComboBox.Items.Add(CalculationType.Add          );
            this.blendTypeComboBox.Items.Add(CalculationType.Amplitude    );
            this.blendTypeComboBox.Items.Add(CalculationType.Average      );
            this.blendTypeComboBox.Items.Add(CalculationType.Difference   );
            this.blendTypeComboBox.Items.Add(CalculationType.Maximum      );
            this.blendTypeComboBox.Items.Add(CalculationType.Minmum       );
            this.blendTypeComboBox.Items.Add(CalculationType.Multiply     );
            this.blendTypeComboBox.Items.Add(CalculationType.SubtractLeft );
            this.blendTypeComboBox.Items.Add(CalculationType.SubtractRight);

            this.blendTypeComboBox.SelectedIndex = 0;

            this.loadSourceImage1Button.Click           += loadSourceImageButton_Click;
            this.loadSourceImage2Button.Click           += loadSourceImageButton_Click;
            this.blendTypeComboBox.SelectedIndexChanged += blendTypeComboBox_SelectedIndexChanged;
            this.saveImageButton.Click                  += saveImageButton_Click;
        }

        #endregion

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

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

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

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

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

                    this.sourceBitmap1 = Bitmap.FromStream(streamReader.BaseStream) as Bitmap;

                    streamReader.Close();

                    this.sourceImage1PictureBox.Image = BitmapHelper.CopyBitmap
                    (
                        this.sourceBitmap1,
                        this.targetImagePictureBox.Width
                    );
                }
                else if(sender == this.loadSourceImage2Button)
                {
                    StreamReader streamReader = new StreamReader(openFileDialog.FileName);

                    this.sourceBitmap2 = Bitmap.FromStream(streamReader.BaseStream) as Bitmap;

                    streamReader.Close();

                    this.sourceImage2PictureBox.Image = BitmapHelper.CopyBitmap
                    (
                        this.sourceBitmap2,
                        this.targetImagePictureBox.Width
                    );
                }

                ApplyFilter(true);
            }
        }

        #endregion
        #region 블렌드 타입 콤보 박스 선택 인덱스 변경시 처리하기 - blendTypeComboBox_SelectedIndexChanged(sender, e)

        /// <summary>
        /// 블렌드 타입 콤보 박스 선택 인덱스 변경시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void blendTypeComboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            ApplyFilter(true);
        }

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

        /// <summary>
        /// 이미지 저장 버튼 클릭시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void saveImageButton_Click(object sender, EventArgs e)
        {
            ApplyFilter(false);

            if(this.targetBitmap != null)
            {
                SaveFileDialog saveFileDialog = new SaveFileDialog();

                saveFileDialog.Title  = "저장 파일명 선택";
                saveFileDialog.Filter = "PNG 파일(*.png)|*.png|JPEG 파일(*.jpg)|*.jpg|비트맵 파일(*.bmp)|*.bmp";

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

                    ImageFormat imgFormat = ImageFormat.Png;

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

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

                    this.targetBitmap.Save(streamWriter.BaseStream, imgFormat);

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

                    this.targetBitmap = null;
                }
            }
        }

        #endregion

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

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

        /// <summary>
        /// 필터 적용하기
        /// </summary>
        /// <param name="preview">미리보기 여부</param>
        private void ApplyFilter(bool preview)
        {
            if(this.sourceBitmap1 == null || this.sourceBitmap2 == null ||
               this.sourceImage2PictureBox.Image == null || this.sourceImage1PictureBox.Image == null)
            {
                return;
            }

            if(preview == true)
            {
                this.targetImagePictureBox.Image = BitmapHelper.BlendBitmap
                (
                    this.sourceImage1PictureBox.Image as Bitmap,
                    this.sourceImage2PictureBox.Image as Bitmap,
                    (CalculationType)this.blendTypeComboBox.SelectedItem
                );
            }
            else
            {
                this.targetBitmap = BitmapHelper.BlendBitmap
                (
                    this.sourceBitmap1,
                    this.sourceBitmap2,
                    (CalculationType)this.blendTypeComboBox.SelectedItem
                );
            }
        }

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

댓글을 달아 주세요