=================================
=================================
=================================
출처: http://blog.hansune.com/100
폰트 내장시키기. embed fonts in fla
+ flex builder 에서내장 폰트 사용하기.
embedFonts.as
package {
import flash.display.Sprite;
import flash.text.AntiAliasType;
import flash.text.Font;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;
public class embedFont extends Sprite
{
[Embed(source="../data/DINMed.TTF", fontName="dinMedium", embedAsCFF="false", mimeType="application/x-font-truetype")]
static public var dinMedium:Class;
public function embedFont()
{
var tm:TextFormat = new TextFormat();
tm.size = 48;
tm.font = "dinMedium";
tm.color = 0x000000;
var tf:TextField = new TextField();
tf.embedFonts = true;
tf.autoSize = TextFieldAutoSize.LEFT;
tf.antiAliasType = AntiAliasType.ADVANCED;
tf.defaultTextFormat = tm;
tf.text = "is this Din \nMedium font?";
addChild(tf);
}
}
}
http://mx.coldstorageonline.com/index.php?bid=48 http://www.marcosweskamp.com/blog/archives/000113.html
http://marcosweskamp.com/blog/2005/10/embedding-fonts-in-as3.html http://developer.yahoo.com/flash/articles/runtime-fonts-as3.html http://www.connectedpixel.com/blog/fonts/embedding http://nochump.com/blog/?p=20 http://blog.paoloiulita.it/2008/03/11/as3-embedding-font-with-code-only/ + swf 파일을 불러와서 폰트를 사용하는 방법
우선 아래처럼 라이브러리에 New font 로 원하는 폰트를 링크등록시킨후, swf 파일을 만든다.
그리고 코딩.
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onCompLoadFont);
loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onIOErr);
var context:LoaderContext = new LoaderContext();
context.applicationDomain = ApplicationDomain.currentDomain;
loader.load(new URLRequest("fonts.swf"), context);
function onCompLoadFont(e:Event):void
{
var dinFontClass:Class = (e.currentTarget as LoaderInfo).applicationDomain.getDefinition("Din") as Class;
Font.registerFont(dinFontClass);
for each (var i:Font in Font.enumerateFonts(false))
{
trace("FONT :" ,i.fontName);
}
var dinfont:Font = Font.enumerateFonts(false)[0];
var tm:TextFormat = new TextFormat();
tm.size = 48;
tm.font = dinfont.fontName;
tm.color = 0x000000;
var tf:TextField = new TextField();
tf.embedFonts = true;
tf.autoSize = TextFieldAutoSize.LEFT;
tf.antiAliasType = AntiAliasType.ADVANCED;
tf.defaultTextFormat = tm;
tf.text = "How are you, today?";
addChild(tf);
}
function onIOErr(e:IOErrorEvent):void
{
trace(this, e.toString());
}
refer to :
http://easeyourdigitallife.blogspot.com/2007/06/flash-cs3-actionscript-3-example-using.html
+ 라이브러리에 등록된 폰트 바로 사용하기
위에 그림처럼 라이브러리에 등록된 폰트를 직접 사용하기
var dinClass:embedDin = new embedDin();
trace(dinClass is Font);
var tm:TextFormat = new TextFormat();
tm.font = dinClass.fontName;
tm.size = 50;
var tf:TextField = new TextField();
tf.embedFonts = true;
tf.defaultTextFormat = tm;
tf.autoSize = TextFieldAutoSize.LEFT;
tf.text = "IS Din?";
addChild(tf);
=================================
=================================
=================================
출처: http://rinn.kr/3
폰트 동적 추가하기 fontKR.swf 에 font Class가 들어있고 linkage 네임은 font_kr로 되어있다.
package {
import flash.display.Loader;
import flash.display.Sprite;
import flash.events.Event;
import flash.net.URLRequest;
import flash.text.AntiAliasType;
import flash.text.Font;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;
public class FontLoadTest extends Sprite
{
private var fontLibrary:Class;
private var font:Font;
public function FontLoadTest()
{
init();
}
private function init():void
{
loadFont("fontKR.swf");
}
private function loadFont(url:String):void
{
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, fontLoaded);
loader.load(new URLRequest(url));
}
private function fontLoaded(e:Event):void
{
fontLibrary = e.target.applicationDomain.getDefinition("font_kr") as Class;
Font.registerFont(fontLibrary);
var fontArray:Array = Font.enumerateFonts(false);
font = fontArray[0];
trace(font.fontName);
buildText();
}
private function buildText():void
{
var tf:TextField = new TextField();
tf.defaultTextFormat = new TextFormat(font.fontName,40,0);
tf.embedFonts = true;
tf.antiAliasType = AntiAliasType.ADVANCED;
tf.autoSize = TextFieldAutoSize.LEFT;
tf.text = "나눔고딕 Light ℃";
addChild(tf);
}
}
}
fontLibrary = e.target.applicationDomain.getDefinition("font_kr") as Class; 로딩된 폰트가 들어있는 SWF를 linkage이름으로 클래스화 시키고 Font.registerFont(fontLibrary); 폰트에 등록하면 사용할수 있다.
=================================
=================================
=================================
출처: http://blog.jidolstar.com/468
폰트(Font)를 동적으로 로딩해서 시스템에 등록한다는 의미는 Embed 폰트를 적용하되 애플리케이션에 포함된 폰트가 아닌 폰트를 담은 SWF를 원하는 시점에 읽어와 애플리케이션에 사용하겠다는 의미이다.
OS에서 기본적으로 제공하는 폰트는 System Font라고 불리고 애플리케이션에 포함되어 컴파일된 폰트는 Embedded Font라고 불리운다. System Font는 사용하기 편하지만 사용자의 사용환경에 따라 폰트가 설치되어 있지 않으면 심하게는 글씨가 안보이는 일이 생길 수 있다. 대신 Embedded Font는 애플리케이션에 포함되기 때문에 어떤 사용자가 애플리케이션을 사용하든지 항상 폰트를 사용한 글자를 볼 수 있다. 예를 들어 한글에 관련된 폰트를 애플리케이션에 포함시켜버리면 시스템에 한글폰트가 전혀없는 아랍국가에 있는 사용자도 애플리케이션 실행시 문제없이 한글을 볼 수 있다. 그리고 Embedded Font는 Anti-aliasing, 회전등 다양한 효과를 줄 수 있는 반면 System Font는 이런 효과에 제약이 있다. Embeded Font는 애플리케이션에 포함하는 것이므로 애플리케이션 자체가 커진다. 무거워진 애플리케이션은 결국 사용자들의 시간과 인내를 한계점에 도달시키게 할지도 모른다. 그러므로 Embeded Font를 꼭 사용해야하는 경우, 직접 애플리케이션 내부에 포함하지 않고 따로 폰트만을 담은 SWF파일을 만들어 애플리케이션이 실행되는 중간에 필요할 때 폰트를 로드할 수 있도록 설계를 하게 된다. 이러한 작업은 생각보다 단순하다. 가령, Adobe Flex의 경우 CSS의 @font-face를 이용해 폰트를 등록하고 CSS를 SWF로 만들어 StyleManager를 이용해 사용할 수 있으며 ActionScript 3.0 기반에서도 Class를 만들어 폰트를 담은 SWF를 만들어 Loader로 읽어들여 해당 폰트를Font.registerFont()로 등록할 수 있다. 본인은 이미 폰트에 관련된 글을 수도 없이 적었다. 아래 링크에 있는 내용만 가지고도 폰트를 적용하는데 충분할 것이다.
- [Flex] 폰트를 런타임(run time)시 동적으로 불러와 적용하는 방법
- [Flex, Flash] 폰트(font) Embed의 이점과 제한점
- [Flex, AIR] 프로그램 크기를 줄여보자 2 - 폰트(font) 동적로드 또는 문자범위지정
- [Flex] 폰트를 런타임(run time)시 동적으로 불러와 적용하는 방법
- [Flex/Actionscript3]폰트 유니코드 변환기(Font unicode converter)
- [Flex]한글폰트 입력이 가능한 회전하는 Textarea 컴포넌트 만드는 방법
이렇게 많이 폰트에 관련된 글을 적고도 또 언급하는 이유는 ActionScript 3.0 프로젝트에서 Font 관리자 제작 필요성을 느꼈기 때문이다. Font 클래스가 있는데 무슨 또 관리자냐고 생각할 수 있다. 하지만 Font는 이미 등록되어 있는 폰트를 관리하는 것이다.(System Font든 Embeded Font든) 본인이 하고자 하는 것은 동적으로 폰트를 로딩해서 시스템에 적용하는데 필요한 클래스를 작성하는 것이다. 즉, 폰트를 동적으로 로드하고 등록해주는 본인이 제작한 FontManager 클래스를 소개하는 것이 이 글을 쓰는 목적이다.
1. Flex에서 Font를 어떻게 동적으로 등록하여 사용하나?
(Flash 개발자이지만 Flex는 생소하다면 그냥 가볍게 읽자. 자세하게 볼 필요는 없다.) 결과를 먼저 이야기 하자면 flash.text.Font 클래스를 사용하도록 컴파일 된다. 아래 코드를 보자.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" creationComplete="init()">
<mx:Style>
/* CSS file */
@font-face
{
src:url("../assets/DinmedRegular.ttf");
fontFamily: "DinmedRegular";
advancedAntiAliasing: true;
}
@font-face
{
src:url("../assets/MetaPluBolRom.TTF");
fontFamily: "MetaPluBolRom";
advancedAntiAliasing: true;
}
Application
{
color:#ffffff;
fontFamily : "DinmedRegular";
}
.myStyle
{
color:#ffcfff;
fontFamily : "MetaPluBolRom";
}
</mx:Style>
<mx:Label text="I'm Jidolstar"/>
<mx:Label text="http://jidolstar.com/blog" styleName="myStyle"/>
</mx:Application>
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" creationComplete="init()">
<mx:Style>
/* CSS file */
@font-face
{
src:url("../assets/DinmedRegular.ttf");
fontFamily: "DinmedRegular";
advancedAntiAliasing: true;
}
@font-face
{
src:url("../assets/MetaPluBolRom.TTF");
fontFamily: "MetaPluBolRom";
advancedAntiAliasing: true;
}
Application
{
color:#ffffff;
fontFamily : "DinmedRegular";
}
.myStyle
{
color:#ffcfff;
fontFamily : "MetaPluBolRom";
}
</mx:Style>
<mx:Label text="I'm Jidolstar"/>
<mx:Label text="http://jidolstar.com/blog" styleName="myStyle"/>
</mx:Application>
위 코드는 어렵지 않게 해석할 수 있을 것이다. 잘 알고 있겠지만 Flex의 MXML과 CSS는 컴파일시 ActionScript 3.0으로 변환되어 진다. 위 코드에서 CSS부분만 어떻게 변경되는가 보면 다음과 같다. (참고로 컴파일 옵션으로 -keep-generated-actionscript=true 을 설정하면 아래 코드 처럼 볼 수 있겠다.)
mx_internal static var _FontTest_StylesInit_done:Boolean = false;
mx_internal function _FontTest_StylesInit():void
{
// only add our style defs to the StyleManager once
if (mx_internal::_FontTest_StylesInit_done)
return;
else
mx_internal::_FontTest_StylesInit_done = true;
var style:CSSStyleDeclaration;
var effects:Array;
// myStyle
style = StyleManager.getStyleDeclaration(".myStyle");
if (!style)
{
style = new CSSStyleDeclaration();
StyleManager.setStyleDeclaration(".myStyle", style, false);
}
if (style.factory == null)
{
style.factory = function():void
{
this.color = 0xffcfff;
this.fontFamily = "MetaPluBolRom";
};
}
// Application
style = StyleManager.getStyleDeclaration("Application");
if (!style)
{
style = new CSSStyleDeclaration();
StyleManager.setStyleDeclaration("Application", style, false);
}
if (style.factory == null)
{
style.factory = function():void
{
this.color = 0xffffff;
this.fontFamily = "DinmedRegular";
};
}
StyleManager.mx_internal::initProtoChainRoots();
}
// embed carrier vars
[Embed(advancedAntiAliasing='true', mimeType='application/x-font', _pathsep='true', source='../assets/DinmedRegular.ttf', _file='D:/FontTest/src/FontTest.mxml', fontName='DinmedRegular', _line='8')]
private var _embed__font_DinmedRegular_medium_normal_444147531:Class;
[Embed(advancedAntiAliasing='true', mimeType='application/x-font', _pathsep='true', source='../assets/MetaPluBolRom.TTF', _file='D:/FontTest/src/FontTest.mxml', fontName='MetaPluBolRom', _line='15')]
private var _embed__font_MetaPluBolRom_medium_normal_1521687713:Class;
매우 신기하게 Flex 컴파일러(mxmlc)는 저렇게 바꿔준다. CSS를 적용할 때는 StyleManager 클래스를 사용하고 Font와 같은 외부 자원을 사용하는 경우에는 그냥 Embed 시켜버린다. 폰트는 @font-face가 [Embed(…)]형태로 바뀐다는 것이다. 위의 경우 애플리케이션에 CSS가 포함되는 경우이고 반대로 동적으로 CSS를 만든 경우는 어떨까? CSS를 mxmlc로 컴파일해서 사용할 수 있다는 것은 알고 있을 것이다. 다음 코드는 동적으로 CSS를 로드하는 코드이다.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" creationComplete="init()">
<mx:Script>
<![CDATA[
import mx.events.StyleEvent;
import com.starpl.net.FontEvent;
import com.starpl.net.IFontInfo;
import com.starpl.net.FontManager;
private var fontInfo:IFontInfo;
private var textField:TextField;
private var styleEventDispatcher:IEventDispatcher;
private function init():void
{
styleEventDispatcher = StyleManager.loadStyleDeclarations( "MyStyle.swf" );
styleEventDispatcher.addEventListener( StyleEvent.COMPLETE, onComplete );
styleEventDispatcher.addEventListener( StyleEvent.ERROR, onError );
}
private function onComplete( event:StyleEvent ):void
{
}
private function onError( event:StyleEvent ):void
{
}
]]>
</mx:Script>
<mx:Label text="I'm Jidolstar"/>
<mx:Label text="http://jidolstar.com/blog" styleName="myStyle"/>
</mx:Application>
그럼, 위 코드에서 StyleManager.loadStyleDeclarations()에서 로드하는 MyStyle.swf는 MyStyle.css로 만들어졌다는 이야기인데 이 코드는 어떻게 변해있을까? 다음 코드는 mxmlc로 MyStyle.css를 컴파일할때 만들어지는 ActionScript 3.0 코드이다.
package
{
import flash.system.Security;
import flash.text.Font;
import mx.core.mx_internal;
import mx.managers.SystemManager;
import mx.modules.ModuleBase;
import mx.styles.CSSStyleDeclaration;
import mx.styles.IStyleModule;
import mx.styles.StyleManager;
[ExcludeClass]
public class MyStyle extends ModuleBase implements IStyleModule
{
/**
* @private
*/
private var selectors:Array = [];
/**
* @private
*/
private var overrideMap:Object = {};
/**
* @private
*/
private var effectMap:Object = {};
/**
* @private
*/
private var unloadGlobal:Boolean;
/**
* @private
*/
private static var domainsAllowed:Boolean = allowDomains();
/**
* @private
*/
private static function allowDomains():Boolean
{
// allowDomain not allowed in AIR
if (Security.sandboxType != "application")
Security.allowDomain("*");
return true;
}
[Embed(advancedAntiAliasing='true', mimeType='application/x-font', _pathsep='true', source='../assets/DinmedRegular.ttf', _file='D:/FontTest/src/MyStyle.css', fontName='DinmedRegular', _line='4')]
private static var _embed__font_DinmedRegular_medium_normal_731457564:Class;
[Embed(advancedAntiAliasing='true', mimeType='application/x-font', _pathsep='true', source='../assets/MetaPluBolRom.TTF', _file='D:/FontTest/src/MyStyle.css', fontName='MetaPluBolRom', _line='11')]
private static var _embed__font_MetaPluBolRom_medium_normal_1234377680:Class;
public function MyStyle()
{
var style:CSSStyleDeclaration;
var keys:Array;
var selector:String;
var effects:Array;
var addedEffects:Array;
selector = ".myStyle";
style = StyleManager.getStyleDeclaration(selector);
if (!style)
{
style = new CSSStyleDeclaration();
StyleManager.setStyleDeclaration(selector, style, false);
selectors.push(selector);
}
keys = overrideMap[selector];
if (keys == null)
{
keys = [];
overrideMap[selector] = keys;
}
style.mx_internal::setStyle('color', 0xffcfff);
keys.push("color");
style.mx_internal::setStyle('fontFamily', "MetaPluBolRom");
keys.push("fontFamily");
selector = "Application";
style = StyleManager.getStyleDeclaration(selector);
if (!style)
{
style = new CSSStyleDeclaration();
StyleManager.setStyleDeclaration(selector, style, false);
selectors.push(selector);
}
keys = overrideMap[selector];
if (keys == null)
{
keys = [];
overrideMap[selector] = keys;
}
style.mx_internal::setStyle('color', 0xffffff);
keys.push("color");
style.mx_internal::setStyle('fontFamily', "DinmedRegular");
keys.push("fontFamily");
Font.registerFont(_embed__font_DinmedRegular_medium_normal_731457564);
Font.registerFont(_embed__font_MetaPluBolRom_medium_normal_1234377680);
}
public function unload():void
{
unloadOverrides();
unloadStyleDeclarations();
if (unloadGlobal)
{
StyleManager.mx_internal::stylesRoot = null;
StyleManager.mx_internal::initProtoChainRoots();
}
}
/**
* @private
*/
private function unloadOverrides():void
{
for (var selector:String in overrideMap)
{
var style:CSSStyleDeclaration = StyleManager.getStyleDeclaration(selector);
if (style != null)
{
var keys:Array = overrideMap[selector];
var numKeys:int;
var i:uint;
if (keys != null)
{
numKeys = keys.length;
for (i = 0; i < numKeys; i++)
{
style.mx_internal::clearOverride(keys[i]);
}
}
keys = effectMap[selector];
if (keys != null)
{
numKeys = keys.length;
var index:uint;
var effects:Array = style.mx_internal::effects;
for (i = 0; i < numKeys; i++)
{
index = effects.indexOf(numKeys[i]);
if (index >= 0)
{
effects.splice(index, 1);
}
}
}
}
}
overrideMap = null;
effectMap = null;
}
/**
* @private
*/
private function unloadStyleDeclarations():void
{
var numSelectors:int = selectors.length;
for (var i:int = 0; i < numSelectors; i++)
{
var selector:String = selectors[i];
StyleManager.clearStyleDeclaration(selector, false);
}
selectors = null;
}
}
}
위 코드는 CSS코드가 ActionScript 3.0으로 만들어진 것을 보여준다. 재미있게도 ModuleBase 클래스를 확장했다. 또한 IStyleModule을 구현했다. StyleManager.loadStyleDeclaration()을 호출할때 ModuleManager를 이용해 이 MyStyle.swf를 로드한다는 것을 의미한다. 실제로 StyleManager를 살펴보면 ModuleManager 활용해서 CSS를 동적으로 로드한다. 또한 CSS로 SWF로 만들면 내부적으로 StyleManager를 이용해 Style을 적용하고 폰트도 Embed를 통해서 포함하고 있다. 코드를 보면 Embed된 폰트를 Font.registerFont()함수를 이용해서 등록하고 있는 것 또한 확인할 수 있다. 살펴본 결과만 보면 Flex가 ActionScript 3.0 기반이고 Flex는 개발의 효율성을 증대시키기 위한 일종의 프레임워크이다라는 것을 쉽게 이해시켜주는 부분이 아닐가 싶다.
2. FontLoader 만들기 – 잘못 제작된 클래스
앞서 Flex SDK를 살펴본 결과 폰트를 동적으로 로드해서 등록하는 것은 생각보다 어려울 것 같지 않다. 결국 Font.registerFont()를 이용하면 되는 것이다. 그런데 본인은 Flex SDK를 이용하지 않고 순수 ActionScript 3.0 환경에서도 Font를 동적으로 로드해서 사용할 수 있도록 하는 환경을 만들고 싶다. 이런 환경을 구축하기 위한 조건은 다음과 같다.
- 조건 1 : ActionScript 3.0 환경에서도 정상적으로 동작하도록 한다.
- 조건 2 : 이미 로드된 폰트는 다시 로드하지 않는다.
조건 2는 당연하다. 이미 로드되어 Font.registerFont()를 이용해 등록된 폰트를 또 로드할 필요가 없지 않는가? 이 조건에 따르도록 FontLoader 클래스를 작성해보았다.
package com.jidolstar.fonts
{
import flash.display.Loader;
import flash.events.ErrorEvent;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IOErrorEvent;
import flash.events.SecurityErrorEvent;
import flash.net.URLRequest;
import flash.system.ApplicationDomain;
import flash.system.LoaderContext;
import flash.system.Security;
import flash.system.SecurityDomain;
import flash.text.Font;
import flash.utils.describeType;
[Event(name="loaded", type="com.starpl.net.FontLoaderEvent")]
[Event(name="error", type="com.starpl.net.FontLoaderEvent")]
/**
* 폰트를 담은 SWF를 동적으로 로딩하고 로드한 SWF로 부터 Embed 폰트의 Class를 시스템에 등록하는 역할을 한다.
*
* <p>폰트를 담은 SWF를 만드는 방법</p>
* <ul>
* <li> 아래 예제처럼 fontName(JidolstarFont)은 클래스이름, AS파일 이름과 같아야한다.
* <pre>
* package
* {
* import flash.display.Sprite;
* public class JidolstarFont extends Sprite
* {
* [Embed( mimeType='application/x-font',
* source='../../assets/MetaPluBolRom.TTF',
* fontName='JidolstarFont',
* unicodeRange='U+0041,U+0044,U+0059,U+0061,U+0064,U+0079,U+0030-U+0039,U+002B,U+002D'
* )]
* static public var FontClass:Class;
* }
* }
* </pre>
* <li> FontClass 이름은 바뀌면 안된다.
* <li> mxmlc등을 이용해 단독으로 컴파일해서 swf파일을 만든다.
* </ul>
*
* <p>클래스를 사용하는 방법 </p>
* <pre>
* var testFontName:String = "HYNamuB";
* var textField:TextField = new TextField;
* textField.text = "안녕하세요";
* addChild( textField );
*
* textField.x = 50;
* textField.y = 50;
*
* fontLoader = new FontLoader( testFontName+".swf", testFontName );
* fontLoader.addEventListener( FontLoaderEvent.LOADED, onFontLoaded );
* fontLoader.addEventListener( FontLoaderEvent.ERROR, onFontLoadError );
* fontLoader.load();
*
* private function onFontLoaded( event:FontLoaderEvent ):void
* {
* //Embed 처리된 폰트 리스팅
* var embededfonts:Array = Font.enumerateFonts( false );
* for each( var embededfont:Font in embededfonts )
* {
* trace( "fontName="+embededfont.fontName+
* ",fontType="+embededfont.fontType+
* ",fontStyle="+embededfont.fontStyle+
* ",hasGlyphs = "+embededfont.hasGlyphs( "안녕하세요" ) );
* }
*
* var textFormat:TextFormat = new TextFormat(testFontName, 14)
* textField.embedFonts = true;
* textField.setTextFormat( textFormat );
* }
*
* private function onFontLoadError( event:FontLoaderEvent ):void
* {
* trace( event.fontName, event.fontURL, event.message );
* }
* </pre>
*
* @author Yongho Ji(jidolstar[at]gmail.com)
* @since 2009.03.06
*/
public class FontLoader extends EventDispatcher
{
private var loader:Loader;
private var loaderContext:LoaderContext;
private var _fontURL:String;
private var _fontName:String;
/**
* 생성자
* @param fontURL 폰트를 로드할 경로
* @param fontName 폰트이름
*/
public function FontLoader( fontURL:String, fontName:String )
{
super();
this._fontURL = fontURL;
this._fontName = fontName;
}
/**
* 폰트를 로드할 URL
*/
public function get fontURL():String
{
return _fontURL;
}
/**
* 폰트 이름
*/
public function get fontName():String
{
return _fontName;
}
/**
* 해당폰트가 등록되어 있는지 검사후에 폰트 로드 실시
* 등록되어 있는 경우 loaded 이벤트 송출됨.
* 등록되어 있지 않은 경우 로드요청.
*/
public function load():void
{
//해당 폰트가 이미 등록되어 있는지 조사
var currentFonts:Array = Font.enumerateFonts( false );
var hasFont:Boolean = false;
for each ( var f:Font in currentFonts )
{
if( fontName == f.fontName )
{
hasFont = true;
break;
}
}
//폰트가 등록되어 있다면 Loaded이벤트를 날려준다!
if( hasFont )
{
this.dispatchEvent(new FontLoaderEvent(FontLoaderEvent.LOADED, _fontName, _fontURL, null ));
}
//폰트가 등록되어 있지 않다면 폰트 로드를 시도한다.
else
{
if( !loader )
{
loader = new Loader();
}
if( !loaderContext )
{
loaderContext = new LoaderContext();
loaderContext.checkPolicyFile = true;
loaderContext.applicationDomain = new ApplicationDomain( ApplicationDomain.currentDomain );
if ( Security.sandboxType == Security.REMOTE)
{
loaderContext.securityDomain = SecurityDomain.currentDomain;
}
else
{
loaderContext.securityDomain = null;
}
}
loader.contentLoaderInfo.addEventListener( Event.COMPLETE, onLoaded, false, 0, true);
loader.contentLoaderInfo.addEventListener( IOErrorEvent.IO_ERROR, onError, false, 0, true);
loader.contentLoaderInfo.addEventListener( SecurityErrorEvent.SECURITY_ERROR, onError, false, 0, true);
loader.load( new URLRequest( _fontURL ), loaderContext );
}
}
/**
* 로드 완료시 해당 폰트가 있는지 확인후 등록한다.
*/
private function onLoaded( event:Event ):void
{
if( loader.contentLoaderInfo.applicationDomain.hasDefinition( _fontName ) )
{
//폰트 등록
var fontClass:Class = loader.contentLoaderInfo.applicationDomain.getDefinition( _fontName ) as Class;
Font.registerFont( fontClass.FontClass );
this.dispatchEvent( new FontLoaderEvent( FontLoaderEvent.LOADED, _fontName, _fontURL ) );
}
else
{
//해당폰트를 찾을 수 없으므로 실패 이벤트 송출
this.dispatchEvent( new FontLoaderEvent( FontLoaderEvent.ERROR, _fontName, _fontURL, "Font Load fail" ) );
}
clearLoader();
}
/**
* 폰트 로드 실패시 처리
*/
private function onError( event:ErrorEvent ):void
{
this.dispatchEvent( new FontLoaderEvent( FontLoaderEvent.ERROR, _fontName, _fontURL, event.text ) );
clearLoader();
}
/**
* 로더 삭제
*/
private function clearLoader():void
{
if (loader)
{
if (loader.contentLoaderInfo)
{
loader.contentLoaderInfo.removeEventListener( Event.COMPLETE, onLoaded, false );
loader.contentLoaderInfo.removeEventListener( IOErrorEvent.IO_ERROR, onError, false );
loader.contentLoaderInfo.removeEventListener( SecurityErrorEvent.SECURITY_ERROR, onError, false );
}
try
{
loader.close();
loader.unload();
}
catch(error:Error)
{
}
loader = null;
loaderContext = null;
}
}
}
}
FontLoader 클래스를 사용한 예제는 다음과 같다.
package
{
import com.jidolstar.fonts.FontLoader;
import com.jidolstar.fonts.FontLoaderEvent;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.text.Font;
import flash.text.TextField;
import flash.text.TextFormat;
/**
* FontLoader 테스터
* @author Yongho, Ji
* @since 2009.03.17
*/
public class FontTest extends Sprite
{
private var fontLoader:FontLoader;
private var testFontName:String = "HYNamuB";
private var textField:TextField;
public function FontTest()
{
super();
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
textField = new TextField;
textField.text = "안녕하세요";
addChild( textField );
textField.x = 50;
textField.y = 50;
fontLoader = new FontLoader( testFontName+".swf", testFontName );
fontLoader.addEventListener( FontLoaderEvent.LOADED, onFontLoaded );
fontLoader.addEventListener( FontLoaderEvent.ERROR, onFontLoadError );
fontLoader.load();
}
private function onFontLoaded( event:FontLoaderEvent ):void
{
//Embed 처리된 폰트 리스팅
var embededfonts:Array = Font.enumerateFonts( false );
for each( var embededfont:Font in embededfonts )
{
trace( "fontName="+embededfont.fontName+
",fontType="+embededfont.fontType+
",fontStyle="+embededfont.fontStyle+
",hasGlyphs = "+embededfont.hasGlyphs( "안녕하세요" ) );
}
var textFormat:TextFormat = new TextFormat(testFontName, 14)
textField.embedFonts = true;
textField.setTextFormat( textFormat );
}
private function onFontLoadError( event:FontLoaderEvent ):void
{
trace( event.fontName, event.fontURL, event.message );
}
}
}
따로 분석은 하지 않겠다. 위에서 사용한 소스는 아래 링크를 통해 다운로드 받아볼 수 있다. Flex Builder 3에 import 해서 테스트 해보길 바란다.
3. FontManager 만들기 – 중복으로 폰트 로드하는 것을 완벽하게 방지
위에서 FontLoader의 문제점을 살펴보았다. 생각보다 간단히 해결될 것 같지는 않다. 결국 약간의 디자인(설계) 패턴을 응용해야한다. 본인은 이 문제를 해결하기 위해 Singleton 디자인 패턴과 Proxy 디자인 패턴을 활용하고자 한다.
Singleton 패턴은 주로 제한된 객체를 생성하기 위해 사용한다. 이름 자체만 보더라도 1개의 객체만을 허용하는 클래스를 만드는 것을 목적으로 한다.
Proxy 패턴은 말그대로 대리자 클래스를 만들어 사용하는 것을 의미한다. 기존 클래스를 그대로 사용하되 부가적인 기능을 더하는데 사용하는 설계 패턴으로 생각하면 되겠다.
참고로 이런 디자인 패턴은 GoF의 23가지 디자인 패턴에 포함하므로 필요할 때 학습해두면 클래스 설계시 매우 유용할 것이다. 2번의 조건(중복로드방지, AS3 프로젝트에서 실행가능)을 가능하게 하기 위해 FontManager를 만들었다. FontManager는 크게 3개 ActionScript 코드로 이뤄진다. IFontInfo.as, FontManager.as, FontEvent.as가 그것이다. 아래는 IFontInfo.as 이다. IFontInfo 인터페이스이며 사용자는 이 인터페이스를 이용해서 Font를 로드한다.
package com.jidolstar.fonts
{
import flash.events.IEventDispatcher;
/**
* Font 컨텐츠를 로드하는 중간 에러 발생시 송출된다.
* @eventType com.jidolstar.fonts.FontEvent.ERROR
*/
[Event(name="error", type="com.jidolstar.fonts.FontEvent")]
/**
* Font 컨텐츠를 로드하고 있는 중일때 송출
* @eventType com.jidolstar.fonts.FontEvent.PROGRESS
*/
[Event(name="progress", type="com.jidolstar.fonts.FontEvent")]
/**
* Font 컨텐츠를 로드를 완료하고 애플리케이션에 폰트 적용이 완료되었을때 송출
* @eventType com.jidolstar.fonts.FontEvent.COMPLETE
*/
[Event(name="complete", type="com.jidolstar.fonts.FontEvent")]
/**
* Font 컨텐츠가 로드 준비가 완료되었을때 송출
* @eventType com.jidolstar.fonts.FontEvent.SETUP
*/
[Event(name="setup", type="com.jidolstar.fonts.FontEvent")]
/**
* 폰트 로드를 하기 위한 인터페이스
*/
public interface IFontInfo extends IEventDispatcher
{
/**
* Font 컨텐츠 로드 실시하면 true
*/
function get start():Boolean;
/**
* 에러발생시 true
*/
function get error():Boolean;
/**
* Font 컨텐츠 로드 완료되고 적용되었을때 true
*/
function get complete():Boolean;
/**
* Font 컨텐츠 로드 준비가 완료되었을때 true
*/
function get setup():Boolean;
/**
* Font 컨텐츠를 로드할 URL
*/
function get url():String;
/**
* Font 컨텐츠 로드 시작
*/
function load():void;
}
}
아래는 FontEvent.as 파일이다.
package com.jidolstar.fonts
{
import flash.events.Event;
import flash.events.ProgressEvent;
/**
* 폰트 이벤트
* @author Yongho, Ji
* @since 2009.03.09
*/
public class FontEvent extends ProgressEvent
{
/**
* 로드 성공시
*/
public static const COMPLETE:String = "complete";
/**
* 로드 설정시
*/
public static const SETUP:String = "setup";
/**
* 로드 진행시
*/
public static const PROGRESS:String = "progress";
/**
* 로드 실패시
*/
public static const ERROR:String = "error";
/**
* 에러 메시지
*/
public var errorText:String;
/**
* 폰트 정보
*/
public var fontInfo:IFontInfo;
/**
* 폰트 로더 이벤트
* @param type 이벤트 Type
* @param bubbles
* @param cancelable
* @param bytesLoaded
* @param bytesTotal
* @param errorText
* @param fontInfo
*/
public function FontEvent(type:String, bubbles:Boolean = false, cancelable:Boolean = false,
bytesLoaded:uint = 0, bytesTotal:uint = 0,
errorText:String = null, fontInfo:IFontInfo = null )
{
super(type, bubbles, cancelable, bytesLoaded, bytesTotal)
this.errorText = errorText;
this.fontInfo = fontInfo;
}
/**
* 이벤트 클론
*/
public override function clone():Event
{
return new FontEvent( type, bubbles, cancelable, bytesLoaded, bytesTotal, errorText, fontInfo );
}
}
}
마지막으로 FontManager.as이다
package com.jidolstar.fonts
{
/**
* Font를 동적으로 로드해서 적용하기 위한 매니저이다.
* Font 컨텐츠는 SWF로 존재하며 이 SWF을 로드하기 위한 URL이 있다면 사용자는 FontManager.getInstance().getFontInfo( url )로
* IFontInfo 인스턴스를 얻을 수 있으며 폰트 로드/적용 되는 상황을 FontEvent로 받을 수 있다.
*
* @author Yongho, Ji
* @since 2009.03.09
*/
public class FontManager
{
private static var _singleton:FontManager;
private var fontInfoList:Object = {};
/**
* 싱글턴을 위한 생성자
*/
public function FontManager( singletonForce:SingletonForce )
{
}
/**
* 싱글턴 인스턴스 생성
*/
public static function getInstance():FontManager
{
if( !_singleton )
{
_singleton = new FontManager( new SingletonForce );
}
return _singleton;
}
/**
* URL에 대한 Font 정보를 얻오온다.
*/
public function getFontInfo( url:String ):IFontInfo
{
var info:FontInfo = fontInfoList[url] as FontInfo;
if( !info )
{
info = new FontInfo( url );
fontInfoList[url] = info;
}
return new FontInfoProxy( info );
}
}
}
import com.jidolstar.fonts.FontEvent;
import com.jidolstar.fonts.IFontInfo;
import flash.display.DisplayObject;
import flash.display.Loader;
import flash.events.ErrorEvent;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IOErrorEvent;
import flash.events.ProgressEvent;
import flash.events.SecurityErrorEvent;
import flash.net.URLRequest;
import flash.system.ApplicationDomain;
import flash.system.LoaderContext;
import flash.system.Security;
import flash.system.SecurityDomain;
import flash.utils.getQualifiedClassName;
/**
* @private
* FontManager 싱글톤 패턴을 위한 클래스
*/
class SingletonForce {}
/**
* @private
* 폰트를 담은 컨텐트를 로드하고 관리하는 클래스
*/
class FontInfo extends EventDispatcher
{
private var _url:String;
private var loader:Loader;
private var _error:Boolean = false;
private var _start:Boolean = false;
private var _complete:Boolean = false;
private var _setup:Boolean = false;
private var _bytesTotal:int = 0;
private var reference:DisplayObject;
private var applicationDomain:ApplicationDomain;
public function FontInfo( url:String )
{
super();
_url = url;
}
public function get start():Boolean
{
return _start;
}
public function get error():Boolean
{
return _error;
}
public function get complete():Boolean
{
return _complete;
}
public function get setup():Boolean
{
return _setup;
}
public function get url():String
{
return _url;
}
public function get size():int
{
return _bytesTotal;
}
public function load():void
{
if( _start )
return;
_start = true;
var r:URLRequest = new URLRequest( _url );
var c:LoaderContext = new LoaderContext;
c.applicationDomain = new ApplicationDomain( ApplicationDomain.currentDomain );
if( Security.sandboxType == Security.REMOTE )
{
c.securityDomain = SecurityDomain.currentDomain;
}
loader = new Loader;
loader.contentLoaderInfo.addEventListener( Event.INIT, initHandler);
loader.contentLoaderInfo.addEventListener( Event.COMPLETE, completeHandler);
loader.contentLoaderInfo.addEventListener( ProgressEvent.PROGRESS, progressHandler);
loader.contentLoaderInfo.addEventListener( IOErrorEvent.IO_ERROR, errorHandler);
loader.contentLoaderInfo.addEventListener( SecurityErrorEvent.SECURITY_ERROR, errorHandler);
loader.load(r, c);
}
/**
* @private
*/
private function clearLoader():void
{
if (loader)
{
if (loader.contentLoaderInfo)
{
loader.contentLoaderInfo.removeEventListener(
Event.INIT, initHandler);
loader.contentLoaderInfo.removeEventListener(
Event.COMPLETE, completeHandler);
loader.contentLoaderInfo.removeEventListener(
ProgressEvent.PROGRESS, progressHandler);
loader.contentLoaderInfo.removeEventListener(
IOErrorEvent.IO_ERROR, errorHandler);
loader.contentLoaderInfo.removeEventListener(
SecurityErrorEvent.SECURITY_ERROR, errorHandler);
}
if (_complete)
{
try
{
loader.close();
}
catch(error:Error)
{
}
}
try
{
loader.unload();
}
catch(error:Error)
{
}
loader = null;
}
}
/**
* @private
*/
public function initHandler(event:Event):void
{
reference = loader.content;
if( !reference )
{
var fontEvent:FontEvent = new FontEvent(
FontEvent.ERROR, event.bubbles, event.cancelable);
fontEvent.bytesLoaded = 0;
fontEvent.bytesTotal = 0;
fontEvent.errorText = "SWF is not a loadable Font";
dispatchEvent(fontEvent);
return;
}
applicationDomain = loader.contentLoaderInfo.applicationDomain;
_setup = true;
dispatchEvent(new FontEvent(FontEvent.SETUP));
}
/**
* @private
*/
public function progressHandler(event:ProgressEvent):void
{
var fontEvent:FontEvent = new FontEvent(
FontEvent.PROGRESS, event.bubbles, event.cancelable);
fontEvent.bytesLoaded = event.bytesLoaded;
fontEvent.bytesTotal = event.bytesTotal;
dispatchEvent(fontEvent);
}
/**
* @private
*/
public function completeHandler(event:Event):void
{
_complete = true;
var fontEvent:FontEvent;
try
{
var className:String = getQualifiedClassName( reference );
var mainClass:Class = applicationDomain.getDefinition( className ) as Class;
new mainClass();
fontEvent = new FontEvent( FontEvent.COMPLETE, event.bubbles, event.cancelable);
fontEvent.bytesLoaded = loader.contentLoaderInfo.bytesLoaded;
fontEvent.bytesTotal = loader.contentLoaderInfo.bytesTotal;
dispatchEvent(fontEvent);
}
catch( e:Error )
{
fontEvent = new FontEvent( FontEvent.ERROR, event.bubbles, event.cancelable);
fontEvent.errorText = e.message;
dispatchEvent(fontEvent);
}
clearLoader();
}
/**
* @private
*/
public function errorHandler(event:ErrorEvent):void
{
_error = true;
var fontEvent:FontEvent = new FontEvent(
FontEvent.ERROR, event.bubbles, event.cancelable);
fontEvent.bytesLoaded = 0;
fontEvent.bytesTotal = 0;
fontEvent.errorText = event.text;
dispatchEvent(fontEvent);
}
}
/**
* @private
* FontInfo 클래스를 한번 wraping하고 IFontInfo를 구현한 클래스이다.
*
*
* 사용자는 FontManager.getFontInfo( url ) 을 이용해 이 클래스의 인스턴스를 얻게된다.
* 한개의 url에 대해 여러개의 FontInfoProxy 인스턴스가 생성될 수 있다.
* 하지만 같은 url을 참조한 FontInfoProxy 인스턴스에 대해서는 단 한개의 FontInfo 인스턴스만 참조하도록 한다.
* 즉, URL에 대해서는 한개의 FontInfo가 된다.
*
*
* 이런 Proxy를 만든 이유는 폰트를 담은 컨텐츠를 url을 비교하여 중복 로드하는 것을 방지하기 위함이다.
* 사용자는 FontInfoProxy 존재를 알 필요없이 IFontInfo로 접근 접근만을 허용한다.
* 따로 Unload는 구현하지 않는다. 왜냐하면 Font가 등록되면 삭제되지는 않기 때문이다.
*
*/
class FontInfoProxy extends EventDispatcher implements IFontInfo
{
private var info:FontInfo;
public function FontInfoProxy( info:FontInfo )
{
this.info = info;
info.addEventListener( FontEvent.SETUP, fontEventHandler, false, 0, true );
info.addEventListener( FontEvent.PROGRESS, fontEventHandler, false, 0, true );
info.addEventListener( FontEvent.COMPLETE, fontEventHandler, false, 0, true );
info.addEventListener( FontEvent.ERROR, fontEventHandler, false, 0, true );
}
/**
* @private
*/
public function get error():Boolean
{
return info.error;
}
/**
* @private
*/
public function get start():Boolean
{
return info.start;
}
/**
* @private
*/
public function get complete():Boolean
{
return info.complete;
}
/**
* @private
*/
public function get setup():Boolean
{
return info.setup;
}
/**
* @private
*/
public function get url():String
{
return info.url;
}
/**
* Font Load 실시
* 이미 로드가 진행진행중이거나 완료한 상태라면 따로 load를 실시하지 않도록 한다.
* 즉, 실제 로드는 한번만 실시한다.
*/
public function load():void
{
if( info.error )
{
dispatchEvent( new FontEvent( FontEvent.ERROR ) );
}
else if( info.start )
{
if( info.setup )
{
dispatchEvent( new FontEvent( FontEvent.SETUP ) );
if( info.complete )
{
var fontEvent:FontEvent;
fontEvent = new FontEvent( FontEvent.PROGRESS );
fontEvent.bytesTotal = info.size;
fontEvent.bytesLoaded = info.size;
dispatchEvent( fontEvent );
fontEvent = new FontEvent( FontEvent.COMPLETE );
fontEvent.bytesTotal = info.size;
fontEvent.bytesLoaded = info.size;
dispatchEvent( fontEvent );
}
}
}
else
{
info.load();
}
}
/**
* @private
*/
private function fontEventHandler(event:FontEvent):void
{
dispatchEvent(event);
}
}
조금만 정성을 들인다면 어렵지 않게 해석할 수 있다. 앞서 설명했듯이 Proxy 패턴과 Singleton 패턴을 섞어서 제작했다. Flex SDK의 ModuleManager에서 Factory 부분이 빠진 구조로 볼 수 있다. 이렇게 만든 클래스 구조는 "조건 2. 이미 로드된 폰트는 다시 로드하지 않는다" 를 만족한다. 사용법은 매우 단순하다. FontManager.getInstance().getFontInfo( url ) 을 사용해서 IFontInfo 형태의 객체를 받아 로드 상태를 알기 위해 FontEvent에 정의된 이벤트 청취자를 등록하고 마지막으로 IFontInfo의 load()함수를 호출하면 해당 폰트가 로딩되고 애플리케이션에 적용된다. 폰트는 아래와 같은 방법으로 ActionScript 3.0으로 만든다.
package
{
import flash.display.Sprite;
import flash.text.Font;
public class MyFont extends Sprite
{
[Embed( mimeType='application/x-font', source='../assets/DinmedRegular.ttf', fontName='DinmedRegular', embedAsCFF=false)]
static public var FontClass1:Class;
[Embed( mimeType='application/x-font', source='../assets/MetaPluBolRom.TTF', fontName='MetaPluBolRom', embedAsCFF=false)]
static public var FontClass2:Class;
public function MyFont()
{
super();
Font.registerFont( FontClass1 );
Font.registerFont( FontClass2 );
}
}
}
폰트를 Embed하고 flash.text.Font의 registerFont() 함수를 이용해 Embed된 폰트를 등록해준다. 폰트는 위처럼 2개든 여러개든 상관없다. Embed한 폰트수만큼 등록하면 되겠다. 사용하기 위해 이 클래스를 mxmlc로 컴파일한다. 그런 다음 아래 예제처럼 FontManager를 이용해 로드해서 폰트를 애플리케이션에 적용할 수 있다.
package {
import com.jidolstar.fonts.FontEvent;
import com.jidolstar.fonts.FontManager;
import com.jidolstar.fonts.IFontInfo;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.text.TextField;
import flash.text.TextFormat;
public class FontManagerTest extends Sprite
{
private var fontInfo1:IFontInfo;
private var fontInfo2:IFontInfo;
private var textField1:TextField;
private var textField2:TextField;
public function FontManagerTest()
{
super();
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
fontInfo1 = FontManager.getInstance().getFontInfo( "MyFont.swf" );
fontInfo1.addEventListener( FontEvent.COMPLETE, onComplete );
fontInfo1.addEventListener( FontEvent.ERROR, onError );
fontInfo1.load();
//fontInfo1과 같은 경로의 SWF를 로드한다.
//fontInfo1.load()를 한번 시도했기 때문에 fontInfo2.load()에서는 실제로드하지 않는다.
//다만, 사용자는 이벤트를 통해 로드 되는 것처럼 사용하는 것 뿐이다. 즉, 인터페이스는 계속 유지시켜줌으로써 사용자의 오용을 방지시킨다.
fontInfo2 = FontManager.getInstance().getFontInfo( "MyFont.swf" );
fontInfo2.addEventListener( FontEvent.COMPLETE, onComplete );
fontInfo2.addEventListener( FontEvent.ERROR, onError );
fontInfo2.load();
textField1 = new TextField;
textField1.embedFonts = true;
textField1.defaultTextFormat = new TextFormat( "DinmedRegular" );
textField1.text = "I'm jidolstar";
textField1.x = 10;
textField1.y = 10;
textField1.rotation = 10;
addChild( textField1 );
textField2 = new TextField;
textField2.embedFonts = true;
textField2.defaultTextFormat = new TextFormat( "MetaPluBolRom" );
textField2.text = "http://jidolstar.com";
textField2.x = 10;
textField2.y = 30;
textField2.rotation = 10;
addChild( textField2 );
}
private function onComplete( event:FontEvent ):void
{
trace( (event.target as IFontInfo).url );
}
private function onError( event:FontEvent ):void
{
}
}
}
실행결과
이것으로 폰트를 동적으로 로딩하여 ActionScript 3.0 프로젝트에도 쉽게 적용할 수 있게 되었다. Flex에도 적용할 수 있다. 물론 CSS형태의 편의성은 제공하지 못하지만 중복으로 로드하지 않는 장점이 있기 때문에 사용할 가치는 있다.
소스코드는 아래 링크에서 다운로드 받는다. Flex Builder 3 이상에서 Import 해서 테스트 해보면 되겠다.
정리하며...
ActionScript 3.0 기반 애플리케이션에 동적로딩을 통해 폰트를 시스템에 적용시켜주는 FontManager를 제작해보았다. 하나의 URL에 따라 중복으로 로딩되지 않도록 하고 Flex가 아닌 ActionScript 3.0 프로젝트 진행에 도움이 되도록 했다. Flex의 좋은 프레임워크를 놔두고 이런 클래스를 만드는 이유는 Flex는 대형 프로젝트의 애플리케이션에 적합하기 때문이다. 제작할 애플리케이션이 간단하고 용량이 중요하다면 Flex 사용을 하지 않는 편이 좋을 수 있다. 배보다 배꼽이 더 큰 애플리케이션을 만들지 말자는 것이다. 그래서 손수 FontManager와 같은 클래스를 제작할 필요가 느꼈다. 앞으로 이러한 문제로 FontManager 말고도 다양한 클래스를 제작할 생각이다. 이러다가 프레임워크 만드는거 아닌가? ^^;
참고 : Font Embed시 Flash player 10, AIR 1.5 이상부터 embedAsCFF 속성을 사용해야합니다. 다음 글을 참고하세요. 2009.11.16
=================================
=================================
=================================
'ADOBE > ActionScript' 카테고리의 다른 글
플래시 - as3.0 플래시 안에서 swf 플래시 로드하기 (0) | 2012.01.30 |
---|---|
플레시에서 개행문자의 처리 (0) | 2012.01.16 |
플래시 액션스크립트 키코드 (0) | 2012.01.11 |
플래시 AS3.0 view 에 따로 브라우져 뛰우기 관련 (0) | 2012.01.10 |
[AS] 플래시 AS3.0 AIR 삼성TV SDK 에뮬레이터, TV 구동관련 (0) | 2012.01.09 |
댓글 영역