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

DownloadFavicon.zip
다운로드

▶ MainForm.cs

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

namespace DownloadFavicon
{
    /// <summary>
    /// 메인 폼
    /// </summary>
    public partial class MainForm : Form
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - MainForm()

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

            this.downloadButton.Click += downloadButton_Click;
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Download 버튼 클릭시 처리하기 - downloadButton_Click(sender, e)

        /// <summary>
        /// Download 버튼 클릭시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void downloadButton_Click(object sender, EventArgs e)
        {
            #region 사이트 URL을 설정한다.

            string siteURL = this.siteURLTextBox.Text.Trim();

            if(string.IsNullOrWhiteSpace(siteURL))
            {
                MessageBox.Show("사이트 URL을 입력해 주시기 바랍니다.");

                this.siteURLTextBox.Focus();

                this.siteURLTextBox.SelectAll();

                return;
            }

            if(!siteURL.StartsWith("http://") && !siteURL.StartsWith("https://"))
            {
                MessageBox.Show("사이트 URL은 \"http://\" 또는 \"https://\" 문자열로 시작해야 합니다.");

                this.siteURLTextBox.Focus();

                this.siteURLTextBox.SelectAll();

                return;
            }

            #endregion
            #region 파비콘 URI를 설정한다.

            Uri favionUri = FaviconHelper.GetFaviconURL(siteURL);

            if(favionUri == null)
            {
                MessageBox.Show("입력한 사이트 URL로 파비콘 URL을 설정할 수 없습니다.");

                this.siteURLTextBox.Focus();

                this.siteURLTextBox.SelectAll();

                return;
            }

            #endregion
            #region 다운로드 경로를 설정한다.

            string downloadPath = this.downloadPathTextBox.Text.Trim();

            if(string.IsNullOrWhiteSpace(downloadPath))
            {
                MessageBox.Show("다운로드 경로를 입력해 주시기 바랍니다");

                this.downloadPathTextBox.Focus();

                this.downloadPathTextBox.SelectAll();

                return;
            }

            if(Directory.Exists(downloadPath))
            {
                try
                {
                    Directory.CreateDirectory(downloadPath);
                }
                catch
                {
                    MessageBox.Show("다운로드 경로 생성시 에러가 발생했습니다.");

                    this.downloadPathTextBox.Focus();

                    this.downloadPathTextBox.SelectAll();

                    return;
                }
            }

            #endregion

            string downloadFilePath = Path.Combine(downloadPath, favionUri.Host + ".ico");

            FaviconHelper.DownloadFaviconFile(siteURL, downloadFilePath);
        }

        #endregion
    }
}

 

728x90

 

▶ FaviconHelper.cs

using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Net;

using HtmlAgilityPack;

namespace DownloadFavicon
{
    /// <summary>
    /// 파비콘 헬퍼
    /// </summary
    /// <remarks>
    public class FaviconHelper
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Static
        //////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 타임 아웃
        /// </summary>
        private static int _timeOut = 5000;

        private static string _userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " +
                                           "AppleWebKit/537.36 (KHTML, like Gecko) "    +
                                           "Chrome/42.0.2311.135 Safari/537.36 Edge/12.246";

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Static
        //////////////////////////////////////////////////////////////////////////////// Public

        #region 파비콘 URL구하기 - GetFaviconURL(siteURL)

        /// <summary>
        /// 파비콘 URL구하기
        /// </summary>
        /// <param name="siteURL">사이트 URL</param>
        /// <returns>파비콘 URL</returns>
        public static Uri GetFaviconURL(string siteURL)
        {
            Uri siteUri    = null;
            Uri faviconUri = null;

            try
            {
                string leftPart = new Uri(siteURL).GetLeftPart(UriPartial.Authority);

                siteUri = new Uri(leftPart);
            }
            catch
            {
                return null;
            }

            try
            {
                HtmlWeb htmlWeb = new HtmlWeb();

                htmlWeb.UserAgent  = _userAgent;
                htmlWeb.PreRequest = delegate(HttpWebRequest httpWebRequest)
                {
                    httpWebRequest.Timeout = _timeOut;

                    return true;
                };

                HtmlDocument htmlDocument = htmlWeb.Load(siteUri.ToString());

                siteUri = htmlWeb.ResponseUri;

                HtmlNodeCollection htmlNodeCollection = htmlDocument.DocumentNode.SelectNodes("//link");

                if(htmlNodeCollection != null)
                {
                    foreach(HtmlNode htmlNode in htmlNodeCollection)
                    {
                        HtmlAttribute relHtmlAttribute = GetHtmlAttribute(htmlNode, "rel");

                        if(relHtmlAttribute == null)
                        {
                            continue;
                        }

                        if(relHtmlAttribute.Value.IndexOf("icon", StringComparison.InvariantCultureIgnoreCase) > 0)
                        {
                            HtmlAttribute hrefHtmlAttribute = GetHtmlAttribute(htmlNode, "href");

                            if(hrefHtmlAttribute == null)
                            {
                                continue;
                            }

                            if(hrefHtmlAttribute.Value.StartsWith("data:", StringComparison.InvariantCultureIgnoreCase))
                            {
                                continue;
                            }

                            if(hrefHtmlAttribute.Value.StartsWith("//", StringComparison.InvariantCultureIgnoreCase))
                            {
                                faviconUri = new Uri(siteUri.Scheme + ":" + hrefHtmlAttribute.Value);

                                break;
                            }

                            Uri        absoluteUri;
                            UriBuilder uriBuilder;

                            if(Uri.TryCreate(hrefHtmlAttribute.Value, UriKind.Absolute, out absoluteUri))
                            {
                                if(string.Compare(absoluteUri.Scheme, "file", true) == 0)
                                {
                                    uriBuilder = new UriBuilder(absoluteUri);

                                    uriBuilder.Scheme = siteUri.Scheme;

                                    absoluteUri = uriBuilder.Uri;
                                }

                                faviconUri = absoluteUri;

                                break;
                            }

                            uriBuilder = new UriBuilder();

                            uriBuilder.Scheme = siteUri.Scheme;
                            uriBuilder.Host   = siteUri.Host;
                            uriBuilder.Path   = hrefHtmlAttribute.Value;

                            Uri relativeUri = uriBuilder.Uri;

                            faviconUri = relativeUri;

                            break;
                        }
                    }
                }
            }
            catch
            {
            }

            if(faviconUri == null)
            {
                try
                {
                    Uri alternateFaviconUri = new Uri(string.Format("{0}://{1}/favicon.ico", siteUri.Scheme, siteUri.Host));

                    WebRequest webRequest = WebRequest.Create(alternateFaviconUri);

                    webRequest.Timeout = _timeOut;
                    webRequest.Method  = "HEAD";

                    using(HttpWebResponse httpWebResponse = webRequest.GetResponse() as HttpWebResponse)
                    {
                        if(httpWebResponse != null && httpWebResponse.StatusCode == HttpStatusCode.OK)
                        {
                            faviconUri = alternateFaviconUri;
                        }
                    }
                }
                catch
                {
                }
            }

            return faviconUri;
        }

        #endregion
        #region 파비콘 파일 다운로드 하기 - DownloadFaviconFile(siteURL, targetFile)

        /// <summary>
        /// 파비콘 파일 다운로드 하기
        /// </summary>
        /// <param name="siteURL">사이트 URL</param>
        /// <param name="targetFile">타겟 파일</param>
        /// <returns>처리 결과</returns>
        public static bool DownloadFaviconFile(string siteURL, string targetFile)
        {
            TimeoutWebClient webClient = new TimeoutWebClient();

            Uri faviconURL = GetFaviconURL(siteURL);

            bool result = false;

            if(faviconURL != null)
            {
                webClient.Headers[HttpRequestHeader.UserAgent] = _userAgent;

                byte[] bufferArray = new byte[0];

                try
                {
                    bufferArray = webClient.DownloadData(faviconURL);
                }
                catch
                {
                }

                if(bufferArray.Length > 0)
                {
                    ImageConverter imageConverter = new ImageConverter();

                    if(imageConverter.IsValid(bufferArray))
                    {
                        IconConverter iconConverter = new IconConverter();

                        if(iconConverter.IsValid(bufferArray))
                        {
                            Icon temporaryIcon = iconConverter.ConvertFrom(bufferArray) as Icon;

                            Icon resizedIcon = new Icon(temporaryIcon, 24, 24);

                            Bitmap temporaryBitmap = resizedIcon.ToBitmap();

                            Bitmap finalBitmap;

                            if(temporaryBitmap.Width > 24)
                            {
                                finalBitmap = ResizeImage(temporaryBitmap, 24, 24);
                            }
                            else
                            {
                                finalBitmap = temporaryBitmap;
                            }

                            Icon finalIcon = GetIcon(finalBitmap);

                            try
                            {
                                using(Stream iconStream = File.OpenWrite(targetFile))
                                {
                                    finalIcon.Save(iconStream);

                                    result = true;
                                }

                            }
                            catch
                            {
                            }
                        }
                        else
                        {
                            Bitmap finalBitmap;

                            Image temporaryImage = imageConverter.ConvertFrom(bufferArray) as Image;

                            if(temporaryImage.Width >= 8)
                            {
                                if(temporaryImage.Width > 24)
                                {
                                    finalBitmap = ResizeImage(temporaryImage, 24, 24);
                                }
                                else
                                {
                                    finalBitmap = new Bitmap(temporaryImage);
                                }

                                finalBitmap.Save(targetFile);

                                result = true;
                            }
                        }
                    }
                }
            }

            if(!result)
            {
                byte[] bufferArray = new byte[0];

                try
                {
                    string alternateURL = "http://www.google.com/s2/favicons?domain_url=" + Uri.EscapeDataString(siteURL);

                    bufferArray = webClient.DownloadData(alternateURL);

                    if(bufferArray.Length > 0)
                    {
                        long checksum = GetChecksum(bufferArray);

                        if(checksum != 87073 && checksum != 59260)
                        {
                            ImageConverter imageConverter = new ImageConverter();

                            Image temporaryImage = imageConverter.ConvertFrom(bufferArray) as Image;

                            Bitmap temporaryBitmap = new Bitmap(temporaryImage);

                            Icon finalIcon = GetIcon(temporaryBitmap);

                            try
                            {
                                using(Stream iconStream = File.OpenWrite(targetFile))
                                {
                                    finalIcon.Save(iconStream);

                                    result = true;
                                }
                            }
                            catch
                            {
                            }
                        }
                    }
                }
                catch
                {
                }
            }

            webClient.Dispose();

            return result;
        }

        #endregion
        #region 아이콘 생성하기 - CreateIcon(graphicFilePath, targetFilePath)

        /// <summary>
        /// 아이콘 생성하기
        /// </summary>
        /// <param name="graphicFilePath">그래픽 파일 경로</param>
        /// <param name="targetFilePath">타겟 파일 경로</param>
        /// <returns>처리 결과</returns>
        public static bool CreateIcon(string graphicFilePath, string targetFilePath)
        {
            byte[] bufferArray = new byte[0];
            bool   result      = false;

            try
            {
                bufferArray = File.ReadAllBytes(graphicFilePath);

                if(bufferArray.Length > 0)
                {
                    ImageConverter imageConverter = new ImageConverter();

                    if(imageConverter.IsValid(bufferArray))
                    {
                        IconConverter iconConverter = new IconConverter();

                        if(iconConverter.IsValid(bufferArray))
                        {
                            Icon temporaryIcon = iconConverter.ConvertFrom(bufferArray) as Icon;

                            Icon resizedIcon = new Icon(temporaryIcon, 24, 24);

                            Bitmap temporaryBitmap = resizedIcon.ToBitmap();

                            Bitmap finalBitmap;

                            if(temporaryBitmap.Width > 24)
                            {
                                finalBitmap = ResizeImage(temporaryBitmap, 24, 24);
                            }
                            else
                            {
                                finalBitmap = temporaryBitmap;
                            }

                            Icon finalIcon = GetIcon(finalBitmap);

                            try
                            {
                                using(Stream iconStream = File.OpenWrite(targetFilePath))
                                {
                                    finalIcon.Save(iconStream);

                                    result = true;
                                }
                            }
                            catch
                            {
                            }
                        }
                        else
                        {
                            Bitmap finalBitmap;

                            Image temporaryImage = imageConverter.ConvertFrom(bufferArray) as Image;

                            if(temporaryImage.Width >= 8)
                            {
                                if(temporaryImage.Width > 24)
                                {
                                    finalBitmap = ResizeImage(temporaryImage, 24, 24);
                                }
                                else
                                {
                                    finalBitmap = new Bitmap(temporaryImage);
                                }

                                finalBitmap.Save(targetFilePath);

                                result = true;
                            }
                        }
                    }
                }
            }
            catch
            {
            }

            return result;
        }

        #endregion

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

        #region HTML 어트리뷰트 구하기 - GetHtmlAttribute(htmlNode, attributeName)

        /// <summary>
        /// HTML 어트리뷰트 구하기
        /// </summary>
        /// <param name="htmlNode">HTML 노드</param>
        /// <param name="attributeName">어트리뷰트명</param>
        /// <returns>HtmlAttribute</returns>
        private static HtmlAttribute GetHtmlAttribute(HtmlNode htmlNode, string attributeName)
        {
            return htmlNode.Attributes.FirstOrDefault(x => x.Name.Equals(attributeName, StringComparison.InvariantCultureIgnoreCase));
        }

        #endregion
        #region 이미지 크기 변경하기 - ResizeImage(sourceImage, targetWidth, targetHeight)

        /// <summary>
        /// 이미지 크기 변경하기
        /// </summary>
        /// <param name="sourceImage">소스 이미지</param>
        /// <param name="targetWidth">타겟 너비</param>
        /// <param name="targetHeight">타겟 높이</param>
        /// <returns>비트맵</returns>
        private static Bitmap ResizeImage(Image sourceImage, int targetWidth, int targetHeight)
        {
            Rectangle targetRectangle = new Rectangle(0, 0, targetWidth, targetHeight);
            Bitmap    targetBitmap    = new Bitmap(targetWidth, targetHeight);

            targetBitmap.SetResolution(sourceImage.HorizontalResolution, sourceImage.VerticalResolution);

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

                using(ImageAttributes targetImageAttributes = new ImageAttributes())
                {
                    targetImageAttributes.SetWrapMode(WrapMode.TileFlipXY);

                    targetGraphics.DrawImage(sourceImage, targetRectangle, 0, 0, sourceImage.Width, sourceImage.Height, GraphicsUnit.Pixel, targetImageAttributes);
                }
            }

            return targetBitmap;
        }

        #endregion
        #region 아이콘 구하기 - GetIcon(sourceBitmap)

        /// <summary>
        /// 아이콘 구하기
        /// </summary>
        /// <param name="sourceBitmap">소스 비트맵</param>
        /// <returns>아이콘</returns>
        private static Icon GetIcon(Bitmap sourceBitmap)
        {
            Icon targetIcon = null;

            MemoryStream sourceMemoryStream = new MemoryStream();

            sourceBitmap.Save(sourceMemoryStream, ImageFormat.Png);

            MemoryStream targetMemoryStream = new MemoryStream();

            BinaryWriter binaryWriter = new BinaryWriter(targetMemoryStream);

            // 0-1 예약, 0 
            binaryWriter.Write((byte)0);
            binaryWriter.Write((byte)0);
            // 2-3 이미지 타입 : 1 = 아이콘, 2 = 커서
            binaryWriter.Write((short)1);
            // 4-5 이미지 수
            binaryWriter.Write((short)1);
            // 이미지 엔트리 1 
            // 0 이미지 너비 
            binaryWriter.Write((byte)sourceBitmap.Width);
            // 1 이미지 높이 
            binaryWriter.Write((byte)sourceBitmap.Height);
            // 2 컬러 수
            binaryWriter.Write((byte)0);
            // 3 예약
            binaryWriter.Write((byte)0);
            // 4-5 색상 플레인
            binaryWriter.Write((short)0);
            // 6-7 픽셀 당 비트 수
            binaryWriter.Write((short)32);
            // 8-11 이미지 데이터 크기
            binaryWriter.Write((int)sourceMemoryStream.Length);
            // 12-15 이미지 데이터 오프셋
            binaryWriter.Write((int)(6 + 16));
            // 이미지 데이터 쓰기
            // PNG 데이터는 전체 PNG 데이터 파일을 포함해야 한다.
            binaryWriter.Write(sourceMemoryStream.ToArray());

            binaryWriter.Flush();

            targetMemoryStream.Position = 0;

            targetIcon = new Icon(targetMemoryStream);

            sourceMemoryStream.Close();

            binaryWriter.Close();

            return targetIcon;
        }

        #endregion
        #region 체크썸 구하기 - GetChecksum(byteArray)

        /// <summary>
        /// 체크썸 구하기
        /// </summary>
        /// <param name="byteArray">바이트 배열</param>
        /// <returns>체크썸</returns>
        private static long GetChecksum(byte[] byteArray)
        {
            long checksum = 0;

            foreach(byte element in byteArray)
            {
                checksum += element;
            }

            return checksum;
        }

        #endregion
    }
}

 

300x250

 

▶TimeoutWebClient.cs

using System;
using System.Net;

namespace DownloadFavicon
{
    /// <summary>
    /// 타임아웃 웹 클라이언트
    /// </summary>
    public class TimeoutWebClient : WebClient
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 타임 아웃
        /// </summary>
        private int timeOut = 5000;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Protected

        #region 웹 요청 구하기 - GetWebRequest(uri)

        /// <summary>
        /// 웹 요청 구하기
        /// </summary>
        /// <param name="uri">URI</param>
        /// <returns>웹 요청</returns>
        protected override WebRequest GetWebRequest(Uri uri)
        {
            WebRequest webRequest = base.GetWebRequest(uri);

            webRequest.Timeout = this.timeOut;

            return webRequest;
        }

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

댓글을 달아 주세요