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

TestProject.zip
다운로드

▶ MainForm.cs

using System;
using System.Drawing;
using System.IO;
using System.Windows.Forms;

using TestProject.Properties;

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

        #region Field

        /// <summary>
        /// GIF 래퍼
        /// </summary>
        private GIFWrapper wrapper = null;

        /// <summary>
        /// 파일 경로
        /// </summary>
        private string filePath = null;

        /// <summary>
        /// 현재 컨트롤
        /// </summary>
        private Control currentControl = null;

        /// <summary>
        /// GIF 파트 헤더 컨트롤
        /// </summary>
        private GIFPartHeaderControl headerControl;

        /// <summary>
        /// GIF 파트 16진수 문자열 뷰 컨트롤
        /// </summary>
        private GIFPartHexadecimalControl hexadecimalControl;

        /// <summary>
        /// GIF 파트 LWZ 이미지 컨트롤
        /// </summary>
        private GIFPartLWZImageControl lwzImageControl;

        /// <summary>
        /// GIF 파트 메타 어플리케이션 컨트롤
        /// </summary>
        private GIFPartMetaApplicationControl metaApplicationControl;

        /// <summary>
        /// GIF 파트 메타 그래픽스 컨트롤
        /// </summary>
        private GIFPartMetaGraphicsControl metaGraphicsControl;

        /// <summary>
        /// GIF 파트 메타 루프 컨트롤
        /// </summary>
        private GIFPartMetaLoopControl metaLoopControl;

        /// <summary>
        /// GIF 파트 메타 텍스트 컨트롤
        /// </summary>
        private GIFPartMetaTextControl metaTextControl;

        #endregion

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

        #region 래퍼 - Wrapper

        /// <summary>
        /// 래퍼
        /// </summary>
        public GIFWrapper Wrapper
        {
            get
            {
                return this.wrapper;
            }
            set
            {
                this.wrapper = value;

                UpdatePartList();

                UpdatePreviewPanel();
            }
        }

        #endregion

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

        #region 생성자 - MainForm()

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

            #region GIF 컨트롤을 설정한다.

            this.headerControl          = new GIFPartHeaderControl();
            this.hexadecimalControl     = new GIFPartHexadecimalControl();
            this.lwzImageControl        = new GIFPartLWZImageControl();
            this.metaApplicationControl = new GIFPartMetaApplicationControl();
            this.metaGraphicsControl    = new GIFPartMetaGraphicsControl();
            this.metaLoopControl        = new GIFPartMetaLoopControl();
            this.metaTextControl        = new GIFPartMetaTextControl();

            #endregion
            #region 파트 리스트 뷰를 설정한다.

            ImageList imageList = new ImageList();

            imageList.Images.Add(Resources.header );
            imageList.Images.Add(Resources.lwzimg );
            imageList.Images.Add(Resources.app    );
            imageList.Images.Add(Resources.comment);
            imageList.Images.Add(Resources.ctrl   );
            imageList.Images.Add(Resources.text   );
            imageList.Images.Add(Resources.unknown);
            imageList.Images.Add(Resources.eof    );
            imageList.Images.Add(Resources.garbage);

            this.partListView.SmallImageList = imageList;

            #endregion
            #region 이벤트를 설정한다.

            DragEnter                                += Form_DragEnter;
            DragDrop                                 += Form_DragDrop;
            this.openMenuItem.Click                  += openMenuItem_Click;
            this.saveMenuItem.Click                  += saveMenuItem_Click;
            this.saveAsMenuItem.Click                += saveAsMenuItem_Click;
            this.partListView.SelectedIndexChanged   += partListView_SelectedIndexChanged;
            this.headerControl.ValueChanged          += gifControl_ValueChanged;
            this.hexadecimalControl.ValueChanged     += gifControl_ValueChanged;
            this.lwzImageControl.ValueChanged        += gifControl_ValueChanged;
            this.metaApplicationControl.ValueChanged += gifControl_ValueChanged;
            this.metaGraphicsControl.ValueChanged    += gifControl_ValueChanged;
            this.metaLoopControl.ValueChanged        += gifControl_ValueChanged;
            this.metaTextControl.ValueChanged        += gifControl_ValueChanged;

            #endregion
        }

        #endregion

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

        #region 폼 드래그 ENTER 처리하기 - Form_DragEnter(sender, e)

        /// <summary>
        /// 폼 드래그 ENTER 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void Form_DragEnter(object sender, DragEventArgs e)
        {
            if(e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                e.Effect = DragDropEffects.Move;
            }
            else
            {
                e.Effect = DragDropEffects.None;
            }
        }

        #endregion
        #region 폼 드래그 DROP 처리하기 - Form_DragDrop(sender, e)

        /// <summary>
        /// 폼 드래그 DROP 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void Form_DragDrop(object sender, DragEventArgs e)
        {
            if(e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                try
                {
                    string[] fileArray = (string[])e.Data.GetData(DataFormats.FileDrop);

                    if(fileArray != null && fileArray.Length > 0)
                    {
                        GIFWrapper wrapper = new GIFWrapper(fileArray[0]);

                        Wrapper = wrapper;

                        this.filePath = fileArray[0];
                    }
                }
                catch(Exception exception)
                {
                    MessageBox.Show
                    (
                        "GIF 이미지 로딩시 에러가 발생했습니다.\r\n\r\n" + exception.Message,
                        "ERROR",
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Error
                    );
                }
            }
        }

        #endregion
        #region 파일 열기 메뉴 항목 클릭시 처리하기 - openMenuItem_Click(sender, e)

        /// <summary>
        /// 파일 열기 메뉴 항목 클릭시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void openMenuItem_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();

            openFileDialog.AutoUpgradeEnabled = true;
            openFileDialog.Filter             = "GIF 이미지|*.gif|모든 파일|*.*";
            openFileDialog.FilterIndex        = 0;
            openFileDialog.Multiselect        = false;
            openFileDialog.RestoreDirectory   = true;

            if(openFileDialog.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    GIFWrapper wrapper = new GIFWrapper(openFileDialog.FileName);

                    Wrapper = wrapper;

                    this.filePath = openFileDialog.FileName;
                }
                catch(Exception exception)
                {
                    MessageBox.Show
                    (
                        "GIF 이미지 로딩시 에러가 발생했습니다.\r\n\r\n" + exception.Message,
                        "ERROR",
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Error
                    );
                }
            }
        }

        #endregion
        #region 저장하기 메뉴 항목 클릭시 처리하기 - saveMenuItem_Click(sender, e)

        /// <summary>
        /// 저장하기 메뉴 항목 클릭시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void saveMenuItem_Click(object sender, EventArgs e)
        {
            if(this.wrapper == null)
            {
                return;
            }

            if(string.IsNullOrEmpty(this.filePath))
            {
                return;
            }

            try
            {
                byte[] dataByteArray = this.wrapper.GetDataByteArray();

                File.WriteAllBytes(this.filePath, dataByteArray);
            }
            catch(Exception exception)
            {
                MessageBox.Show
                (
                    "GIF 이미지 저장시 에러가 발생했습니다.\r\n\r\n" + exception.Message,
                    "ERROR",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Error
                );
            }
        }

        #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.wrapper == null)
            {
                return;
            }

            try
            {
                byte[] dataByteArray = this.wrapper.GetDataByteArray();

                SaveFileDialog saveFileDialog = new SaveFileDialog();

                saveFileDialog.AutoUpgradeEnabled = true;
                saveFileDialog.CheckFileExists    = false;
                saveFileDialog.CheckPathExists    = true;
                saveFileDialog.DefaultExt         = ".gif";
                saveFileDialog.FileName           = string.IsNullOrEmpty(this.filePath) ? "image.gif" : Path.GetFileName(this.filePath);
                saveFileDialog.Filter             = "GIF 이미지|*.gif|모든 파일|*.*";
                saveFileDialog.FilterIndex        = 0;
                saveFileDialog.RestoreDirectory   = true;

                if(saveFileDialog.ShowDialog() == DialogResult.OK)
                {
                    File.WriteAllBytes(saveFileDialog.FileName, dataByteArray);
                }
            }
            catch(Exception exception)
            {
                MessageBox.Show
                (
                    "GIF 이미지 저장시 에러가 발생했습니다.\r\n\r\n" + exception.Message,
                    "ERROR",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Error
                );
            }
        }

        #endregion
        #region 모든 지연 시간 설정하기 메뉴 항목 클릭시 처리하기 - setAllDelayTimeMenuItem_Click(sender, e)

        /// <summary>
        /// 모든 지연 시간 설정하기 메뉴 항목 클릭시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void setAllDelayTimeMenuItem_Click(object sender, EventArgs e)
        {
            if(this.wrapper == null)
            {
                return;
            }

            decimal initial = 0m;
            decimal count   = 0m;

            foreach(GIFPart part in this.wrapper)
            {
                if(part is GIFPartMetaData.GraphicsControl)
                {
                    initial += (part as GIFPartMetaData.GraphicsControl).DelayTime;

                    count++;
                }
            }

            if(count > 0)
            {
                initial = Math.Floor(initial / count);
            }

            SelectNumberForm form = new SelectNumberForm("지연 시간 선택하기", "지연 시간", 65535, initial);

            if(form.ShowDialog() == DialogResult.OK)
            {
                ushort value = Convert.ToUInt16(form.Value);

                foreach(GIFPart part in this.wrapper)
                {
                    if(part is GIFPartMetaData.GraphicsControl)
                    {
                        (part as GIFPartMetaData.GraphicsControl).DelayTime = value;
                    }
                }

                UpdateExistingList();

                UpdatePreviewPanel();
            }
        }

        #endregion
        #region 파트 리스트 뷰 선택 인덱스 변경시 처리하기 - partListView_SelectedIndexChanged(sender, e)

        /// <summary>
        /// 파트 리스트 뷰 선택 인덱스 변경시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void partListView_SelectedIndexChanged(object sender, EventArgs e)
        {
            this.partPanel.Controls.Clear();

            Control nextControl = null;

            object partObject = this.partListView.SelectedItems.Count == 0 ? null : this.partListView.SelectedItems[0].Tag;

            if(partObject is GIFPartHeader)
            {
                GIFPartHeader header = partObject as GIFPartHeader;

                this.headerControl.Part = header;

                nextControl = this.headerControl;
            }
            else if(partObject is GIFPartLWZImage)
            {
                GIFPartLWZImage lwzImage = partObject as GIFPartLWZImage;

                this.lwzImageControl.Part = lwzImage;

                nextControl = this.lwzImageControl;
            }
            else if(partObject is GIFPartMetaData.ApplicationData)
            {
                GIFPartMetaData.ApplicationData applicationData = partObject as GIFPartMetaData.ApplicationData;

                this.metaApplicationControl.Part = applicationData;

                nextControl = this.metaApplicationControl;
            }
            else if(partObject is GIFPartMetaData.Comment)
            {
                GIFPartMetaData.Comment comment = partObject as GIFPartMetaData.Comment;

                this.hexadecimalControl.Part = comment;

                nextControl = this.hexadecimalControl;
            }
            else if(partObject is GIFPartMetaData.GraphicsControl)
            {
                GIFPartMetaData.GraphicsControl graphicsControl = partObject as GIFPartMetaData.GraphicsControl;

                this.metaGraphicsControl.Part = graphicsControl;

                nextControl = this.metaGraphicsControl;
            }
            else if(partObject is GIFPartMetaData.Loop)
            {
                GIFPartMetaData.Loop metaLoop = partObject as GIFPartMetaData.Loop;

                this.metaLoopControl.Part = metaLoop;

                nextControl = this.metaLoopControl;
            }
            else if(partObject is GIFPartMetaData.TextDraw)
            {
                GIFPartMetaData.TextDraw metaText = partObject as GIFPartMetaData.TextDraw;

                this.metaTextControl.Part = metaText;

                nextControl = this.metaTextControl;
            }
            else if(partObject is GIFPartMetaData)
            {
                GIFPartMetaData metaData = partObject as GIFPartMetaData;

                this.hexadecimalControl.Part = metaData;

                nextControl = this.hexadecimalControl;
            }
            else if(partObject is GIFPartGarbageData)
            {
                GIFPartGarbageData grabaseData = partObject as GIFPartGarbageData;

                this.hexadecimalControl.Part = grabaseData;

                nextControl = this.hexadecimalControl;
            }

            if(this.currentControl != nextControl)
            {
                SuspendLayout();

                this.partPanel.Controls.Clear();

                if(nextControl != null)
                {
                    this.partPanel.Controls.Add(nextControl);

                    nextControl.Dock = DockStyle.Fill;
                }

                ResumeLayout();

                this.currentControl = nextControl;
            }
        }

        #endregion
        #region GIF 컨트롤 값 변경시 처리하기 - gifControl_ValueChanged(sender, e)

        /// <summary>
        /// GIF 컨트롤 값 변경시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void gifControl_ValueChanged(object sender, EventArgs e)
        {
            UpdatePreviewPanel();

            GIFPart part = (sender as IGIFControl).GIFPart;

            ListViewItem updateItem = null;

            foreach(ListViewItem item in this.partListView.Items)
            {
                if(item.Tag == part)
                {
                    updateItem = item;

                    break;
                }
            }

            if(updateItem != null)
            {
                UpdateListViewItem(updateItem, part);
            }
        }

        #endregion

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

        #region 리스트 뷰 항목 업데이트하기 - UpdateListViewItem(item, part)

        /// <summary>
        /// 리스트 뷰 항목 업데이트하기
        /// </summary>
        /// <param name="item">리스트 뷰 항목</param>
        /// <param name="part">GIF 파트</param>
        private void UpdateListViewItem(ListViewItem item, GIFPart part)
        {
            if(part is GIFPartHeader)
            {
                item.Text       = "헤더";
                item.ImageIndex = 0;
            }
            else if(part is GIFPartLWZImage)
            {
                GIFPartLWZImage lwzImage = part as GIFPartLWZImage;

                item.Text = string.Format
                (
                    "이미지 [{0}x{1} @{2}x{3}]",
                    lwzImage.Width,
                    lwzImage.Height,
                    lwzImage.Left,
                    lwzImage.Top
                );

                item.ImageIndex = 1;
            }
            else if(part is GIFPartMetaData.ApplicationData)
            {
                GIFPartMetaData.ApplicationData applicationData = part as GIFPartMetaData.ApplicationData;

                item.Text = string.Format("앱 데이터 [{0}]", applicationData.AppIdentifier);

                item.ImageIndex = 2;
            }
            else if (part is GIFPartMetaData.Loop)
            {
                GIFPartMetaData.Loop loop = part as GIFPartMetaData.Loop;

                item.Text = string.Format("앱 데이터 [반복 : {0}]", loop.IterationCount);

                item.ImageIndex = 2;
            }
            else if(part is GIFPartMetaData.Comment)
            {
                GIFPartMetaData.Comment comment = part as GIFPartMetaData.Comment;

                item.Text = string.Format("주석 [{0} 바이트]", comment.ContentByteArray.Length);

                item.ImageIndex = 3;
            }
            else if(part is GIFPartMetaData.GraphicsControl)
            {
                GIFPartMetaData.GraphicsControl control = part as GIFPartMetaData.GraphicsControl;

                item.Text = string.Format
                (
                    "제어 [변환 : {0}, 지연 : {1}]",
                    control.UseTransparency ? "1" : "0",
                    control.UseUserInput ? "사용자" : ((control.DelayTime).ToString() + "밀리초")
                );

                item.ImageIndex = 4;
            }
            else if(part is GIFPartMetaData.TextDraw)
            {
                GIFPartMetaData.TextDraw textDraw = part as GIFPartMetaData.TextDraw;

                string text = textDraw.Text;

                item.Text = string.Format
                (
                    "텍스트 [{2}, @{0}x{1}]",
                    textDraw.Left,
                    textDraw.Width,
                    text.Length > 10 ? (text.Substring(0, 8) + "...") : text
                );

                item.ImageIndex = 5;
            }
            else if(part is GIFPartMetaData)
            {
                GIFPartMetaData metaData = part as GIFPartMetaData;

                item.Text = string.Format("미정 [{0}]", metaData.MetaType);

                item.ImageIndex = 6;
            }
            else if(part is GIFPartTerminator)
            {
                item.Text = "파일 끝";

                item.ImageIndex = 7;
            }
            else if(part is GIFPartGarbageData)
            {
                GIFPartGarbageData garbageData = part as GIFPartGarbageData;

                item.Text = "가비지 데이터";

                item.ImageIndex = 8;
            }
        }

        #endregion
        #region 파트 리스트 업데이트하기 - UpdatePartList()

        /// <summary>
        /// 파트 리스트 업데이트하기
        /// </summary>
        private void UpdatePartList()
        {
            if(InvokeRequired)
            {
                Invoke(new Action(UpdatePartList));

                return;
            }

            SuspendLayout();

            this.partListView.Items.Clear();

            if(this.wrapper != null)
            {
                foreach(GIFPart part in this.wrapper)
                {
                    ListViewItem item = new ListViewItem();

                    UpdateListViewItem(item, part);

                    item.SubItems.Add(part.Length.ToString());

                    item.Tag = part;

                    this.partListView.Items.Add(item);
                }
            }

            ResumeLayout();
        }

        #endregion
        #region 기존 리스트 업데이트하기 - UpdateExistingList()

        /// <summary>
        /// 기존 리스트 업데이트하기
        /// </summary>
        private void UpdateExistingList()
        {
            if(InvokeRequired)
            {
                Invoke(new Action(UpdatePartList));

                return;
            }

            SuspendLayout();

            ListViewItem item;

            for(int i = 0; i < this.wrapper.Count; i++)
            {
                GIFPart part = this.wrapper[i];

                if(this.partListView.Items.Count <= i)
                { 
                    item = new ListViewItem();

                    UpdateListViewItem(item, this.wrapper[i]);

                    item.SubItems.Add(this.wrapper[i].Length.ToString());

                    item.Tag = this.wrapper[i];

                    this.partListView.Items.Add(item);
                }
                else if(this.partListView.Items[i].Tag != this.wrapper[i])
                {
                    int index = -1;

                    for(int j = 0; j < this.partListView.Items.Count; j++)
                    {
                        if(this.partListView.Items[j].Tag == part)
                        {
                            index = j;

                            break;
                        }
                    }

                    if(index == -1)
                    { 
                        item = new ListViewItem();

                        UpdateListViewItem(item, this.wrapper[i]);

                        item.SubItems.Add(this.wrapper[i].Length.ToString());

                        item.Tag = this.wrapper[i];

                        this.partListView.Items.Insert(i, item);
                    }
                    else
                    { 
                        item = this.partListView.Items[index];

                        UpdateListViewItem(item, part);

                        this.partListView.Items.RemoveAt(index);

                        this.partListView.Items.Insert(i, item);
                    }
                }
                else
                {
                    item = partListView.Items[i];

                    UpdateListViewItem(item, part);
                }
            }

            ResumeLayout();
        }

        #endregion
        #region 미리보기 패널 업데이트하기 - UpdatePreviewPanel()

        /// <summary>
        /// 미리보기 패널 업데이트하기
        /// </summary>
        private void UpdatePreviewPanel()
        {
            if(InvokeRequired)
            {
                Invoke(new Action(UpdatePreviewPanel));

                return;
            }

            Image image = null;

            if(this.wrapper != null)
            {
                try
                {
                    image = this.wrapper.ToImage();
                }
                catch(Exception exception)
                {
                    image = new Bitmap(256, 256);

                    using(Graphics graphics = Graphics.FromImage(image))
                    {
                        using(Pen pen = new Pen(Color.Red, 4f))
                        {
                            using(Font font = new Font(FontFamily.GenericSansSerif, 8f, FontStyle.Regular))
                            {
                                graphics.Clear(Color.Transparent);

                                graphics.DrawRectangle(pen, 0, 0, 256, 256);

                                graphics.DrawLine(pen, 0, 0, 256, 256);
                                graphics.DrawLine(pen, 256, 0, 0, 256);

                                graphics.DrawString(exception.Message, font, Brushes.Black, new RectangleF(8, 8, 248, 248));
                            }
                        }
                    }
                }
            }

            if(this.previewPictureBox.Image != null)
            {
                this.previewPictureBox.Image.Dispose();
            }

            this.previewPictureBox.Image = image;
        }

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