이번에 설명할 주제는 바이트 배열(또는 스트림)로부터 폰트를 만드는 방법에 대해서 설명드리도록 하겠습니다.
저는 이 방법을 꽤나 많이 사용하는데요. 제가 설명드리는 방법에는 이런 장점들이 있습니다.
- 사용자 컴퓨터에 폰터가 설치되어 있지 않을 경우에도 프로그램에 설정된 폰트를 사용할 수 있습니다.
- API 선언이 필요 없습니다.
- 리소스에 포함만 시키면 끝. 필요한건 바이트 배열 또는 스트림만 있으면 됩니다.
- 추가 라이브러리가 필요 없습니다.
- .NET Framework 2.0 부터 지원되기 때문에 .NET Framework를 따로 설치하지 않은 윈도우 7 운영체제와 호환!
- 프로그램의 크기에 폰트 크기가 더해집니다.
- 폰트를 적용하려면 약간의 코드 수정이 필요합니다.
System.Runtime.InteropServices
System.Drawing.Text
두 개의 네임스페이스에서 사용할 클래스도 두 개 입니다.
바로, Marshal 클래스와 PrivateFontCollection 클래스입니다. 각 클래스의 참고 문서입니다!
Marshal 클래스 (MSDN)
PrivateFontCollection 클래스 (MSDN)
사용할 클래스들의 문서를 자세히 보셨다면 감이 잡히는 분들도 계시겠고, 알 수 없는 분들도 계실 것 같네요!
이 메서드들을 사용할 것입니다.
Marshal.AllocHGlobal
Marshal.Copy
Marshal.FreeHGlobal
PrivateFontCollection.AddMemoryFont
너무 간단하지 않나요? 네 개의 메서드를 이용하면? 바로 끝입니다 ^^
어떻게 하는지 빨리 알려달라구요?
알겠습니다! 그럼 바로 코드를 살펴보도록 하죠!
public static class CSharpTechnique {
/// <summary>
/// 바이트 배열로부터 폰트 패밀리를 만듭니다.
/// </summary>
/// <param name="byteArray">폰트 패밀리를 만드는데 사용할 바이트 배열을 입력합니다.</param>
public static FontFamily FontFamilyFromByte(Byte[] byteArray) {
// 메모리 폰트를 저장하기 위한 컬렉션입니다.
PrivateFontCollection pfCollection = new PrivateFontCollection();
// 바이트 배열을 복사하기 위한 포인터를 할당합니다.
IntPtr pFont = Marshal.AllocHGlobal(byteArray.Length);
// 메모리 할당에 실패하면 null 반환합니다.
// AllocHGlobal 메서드를 호출했을 때 할당에 실패하면 내부적으로 예외를 발생시키게 되어있지만
// 추가로 처리를 해줍니다.
if ( pFont == IntPtr.Zero )
return null;
// 포인터에 바이트 배열을 복사합니다.
Marshal.Copy(byteArray, 0, pFont, byteArray.Length);
// 폰트 컬렉션에 메모리 폰트를 추가합니다.
// 꼭! 배열의 길이를 정확하게 명시해줘야 합니다.
pfCollection.AddMemoryFont(pFont, byteArray.Length);
// 메모리 폰트를 추가하는 작업이 완료되었으면,
// 할당한 메모리 공간을 해제하여 메모리 낭비가 없도록 합니다.
Marshal.FreeHGlobal(pFont);
// 추가를 했는데도 길이가 0이면 null 을 반환합니다.
if ( pfCollection.Families.Length == 0 )
return null;
// 폰트 패밀리를 반환합니다.
return pfCollection.Families[0];
}
/// <summary>
/// 바이트 배열로부터 폰트를 만듭니다.
/// </summary>
/// <param name="byteArray">폰트를 만드는데 사용할 바이트 배열을 입력합니다.</param>
/// <param name="emSize">폰트의 크기를 입력합니다.</param>
public static Font FontFromByte(Byte[] byteArray, Single emSize) {
return FontFromByte(byteArray, emSize, FontStyle.Regular);
}
/// <summary>
/// 바이트 배열로부터 폰트를 만듭니다.
/// </summary>
/// <param name="byteArray">폰트를 만드는데 사용할 바이트 배열을 입력합니다.</param>
/// <param name="emSize">폰트의 크기를 입력합니다.</param>
/// <param name="style">폰트의 스타일을 입력합니다.</param>
public static Font FontFromByte(Byte[] byteArray, Single emSize, FontStyle style) {
FontFamily ff = FontFamilyFromByte(byteArray);
// 폰트 패밀리를 만들지 못했으면 null 반환!
if (ff == null)
return null;
// 폰트를 만들고 반환합니다.
return new Font(ff, emSize, style);
}
}
이해하기 쉽도록 주석을 달아놨습니다.
PrivateFontCollection 클래스를 이용해도 바로 폰트를 만들 수 없고, 폰트 패밀리를 만드는 것이므로 폰트 패밀리를 이용하여 폰트를 만들어 줘야 합니다.
만드는 단계는 이렇게 표현됩니다.
- 포인터를 바이트 배열의 크기만큼 할당합니다.
- 메모리가 할당된 포인터에 바이트 배열을 복사합니다.
- AddMemoryFont 메서드를 호출하여 PrivateFontCollection 클래스의 컬렉션에 폰트 패밀리를 추가합니다.
- 포인터를 메모리에서 해제합니다.
- 컬렉션에 추가된 폰트 패밀리를 이용하여 폰트를 만듭니다.
예제 프로그램의 실행 화면입니다. (대상 폰트는 나눔고딕코딩 폰트입니다)
클래스 파일 및 예제 프로젝트 파일:
긴 글 읽어주셔서 감사합니다~^^
'.NET > C#' 카테고리의 다른 글
데이터를 압축하고, 압축을 풀어보자! (1) | 2014.10.28 |
---|---|
예외 처리 (0) | 2014.10.23 |
문자열을 값으로 변환하기 (0) | 2014.10.20 |
현재 호출되고 있는 메서드의 정보를 구하는 방법 (0) | 2014.10.19 |
private, public, protected 그리고 internal?? 접근 한정자에 대해 알아보자. (3) | 2014.10.13 |