728x90
반응형
728x170
▶ 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
반응형
그리드형(광고전용)
'C# > Common' 카테고리의 다른 글
[C#/COMMON] 윈도우즈 7 데스크톱과 탐색기 갱신하기 (0) | 2017.06.14 |
---|---|
[C#/COMMON] TimeSpan 구조체 : 포맷 문자열을 사용해 문자열 구하기 (0) | 2017.06.13 |
[C#/COMMON] DOS 명령어 실행하기 (0) | 2017.06.12 |
[C#/COMMON] 다각형 무게 중심 구하기 (0) | 2017.06.11 |
[C#/COMMON] 다각형 면적 구하기 (0) | 2017.06.11 |
[C#/COMMON] 엣지 브라우저 버전 구하기 (0) | 2017.06.10 |
[C#/COMMON] 운영 체제 버전 구하기 (0) | 2017.06.10 |
[C#/COMMON] ZipArchive 클래스 : ZIP 파일 생성하기/추출하기 (0) | 2017.06.10 |
[C#/COMMON] 디렉토리 삭제하기 (0) | 2017.06.10 |
[C#/COMMON] 엣지 브라우저 실행 여부 구하기 (0) | 2017.06.10 |
댓글을 달아 주세요