직장을 옮기면서 Flash에 관심을 가진지도 3년이 넘었다. 당시만해도 PHP정도만 경험이 있었고 수년동안 웹과는 단절된 상태였기 때문에 Ajax로 만들어진 구글맵을 보고 "이런걸 만들 수 있구나..."라는 말을 중얼거리며 꽤 놀랐던 적이 있었다. Web 2.0, RIA라는 단어가 당시 트렌드였고 이 모든 것이 나에게는 매우 신선했고 가능성을 느끼게 하는데 충분했다. 

하지만 3년전 RIA 대표주자인 Flex 2를 처음 접했을때 국내 관련서적은 거의 없었다. Flash IDE를 기반으로 하는 책은 수도 없이 많았지만 개발요구사항을 만족시키기에는 매우 역부족이였고 Flex도 옥상훈님이 쓴 서적 딱 한권 뿐이였다. 사실 모두 기초서적들이라 초반학습에는 도움되었지만 실무에 적용하기에는 너무 부족했다. 또한 기술적으로 도움을 받을 수 있는 인맥도 전혀 없었다.

결국 내가 선택한 방법은 이 블로그이다. 말이 되던 안되던 Flex 하나를 중구장창 파고 들면서 얻은 귀중한 지식을 블로그에 하나씩 써내려갔다. 초반에는 livedocs가 어디 있는지도 몰랐고 구글 검색도 처음 해봤던 시절이라 너무 힘들었다. 블로그의 내용은 관련 카페에 소개하면서 계속 점접을 만들어갔다. 이러한 노력은 몇개월이 지나지 않아 바로 사람들에게 좋은 반응으로 이어졌고 지식공유가 일어났다. 또한 이쯤에 flexdocs.kr 사이트도 운영하게 되었다. 그때 생각하면 너무 어렵게 공부했던 기억뿐이다.

3년이 지난 지금... 사정은 너무도 많이 달라졌다. 3년전 한창 붐을 일으키던 RIA라는 단어는 이미 일상이 되버렸고 모바일이 이슈가 되면서 관련 서적도 쏟아지기 시작했다. Flash Platform에 관련된 서적도 엄청 많이 쏟아졌고 오프라인 서점만 찾아가면 듣도보지도 못한 관련서적을 꽤 많이 발견할 수 있었다.

아무튼 이젠 Flash 공부하는데 천국이 된 것임에 틀림없다.

나는 최근에 국내에 출판된 좋은 서적 4권을 소개하고자 한다.


okgosu의 액션스크립트 정석



okgosu의 액션스크립트 정석은 Flex 서적 2편으로 유명하신 옥상훈님의 책이다. 이 책은 ActionScript 3.0의 전반적인 내용을 다루고 있다. 기초문법부터 시작해 개발환경 및 디스플에이 객체를 다루는 방법을 꽤 상세하게 다루고 있다. 또한 Flash Player 10에 추가된 3D API의 기초를 다루고 있기 때문에 그동안 3D에 대해서 잘 몰랐던 사람이 공부하기에 딱 좋은 서적인 것 같다. 책의 내용이 방대하고 수많은 예시가 있어 ActionScript 3.0을 처음하는 사람에게 꽤 도움이 될 것이다.


플래시 ON 디바이스



이철규님이 번역하신 플래시 ON 디바이스는 Flash Platform을 이용해 모바일 애플리케이션을 개발하고자 하는 사람들을 위한 책이다. 사실 모바일 분야는 Flash Lite에 한정되어 있어서 필자처럼 Flex/ActionScript 3.0 기반으로만 했던 사람들에게는 넘어가기 힘든 장벽이였다. 하지만 이책은 Flash 모바일의 역사를 자세하게 소개하고 꽤 고급주제 심도있게 다루고 있어서 Flash를 이용한 모바일 개발에 관심을 가지는 사람에게 추천해줄 수 있는 책이다.  


비주얼 플렉스 UX 디자인

열이아빠님으로 활동중인 이준하님이 번역하신 비주얼 플렉스 UX 디자인은 Flex 3의 시각 컴포넌트를 사용하면서 생길 수 있는 다양한 어려움을 극복하는데 큰 도움을 준다. 레이아웃, 효과, 스타일, 스킨등을 전반적으로 다루면서 좀더 심도있게 컴포넌트를 적용할 수 있는 방법을 잘 설명해주고 있다. Flex를 이용해 풍부한 UX를 사용자들에게 경험시키고자 할때 이책은 큰 도움이 될 것이다.


ActionScript 3.0 Animation


윤도선님이 번역하신 시작하세요! 액션스크립트 3.0 애니메이션은 내가 베타 리더로도 참여했던 책이다. Flash IDE 타임라인을 이용해 애니메이션을 적용하던 수준을 넘어서 코드 기반으로 수학,물리를 이용한 다양한 에니메이션을 주는 기법에 대해서 아주 쉽게 설명하고 있다. 삼각함수, 속도, 가속도, 마찰, 바운드, 모션공식 일반적으로 수학/물리에 어려움을 느끼는 개발자들에게 꽤 유용하다. 또한 3D API를 이용하는 예도 담겨 있어 더욱 다양한 경험을 준다.


정리하며
최근에 발간된 총 4권의 책을 소개했다. 앞서 설명했듯이 3년전에 이런 고귀한 책들이 있었다면 아마도 지금까지 공부했던 시간의 절반이상은 절약할 수 있었을 것이다. 아무튼 좋은 책은 돈에 구애받지 말고 구입해서 자신의 것으로 만들어 가려는 노력이 빠른 배움의 지름길이다.

글쓴이 : 지돌스타(http://blog.jidolstar.com/690)


flexdocs.kr은 2007년 이래로 지금까지 벌써 4년째 운영되고 있습니다. 조광제님 및 많은 분들의 도움으로 지금까지 명맥을 이어가고 있습니다. 비록 Flex 2.0 문서이지만 아마도 한글문서가 절실하셨던 분들은 이 사이트가 상당히 유용했으리라 생각합니다.

서비스는 현재 무료호스팅을 받아 운영되기 때문에 별도의 자본이 필요하지 않으나 도메인은 항상 비용이 들어갑니다. 지금까지는 호스팅, 도메인 모두 제 자비를 들여서 운영해 왔습니다. 이런 중에 몇일전 아래와 같은 메일을 받았습니다.

사실 도메인 하나만 볼때 비싼 것은 아니지만 제가 관리하고 있는 도메인만 해도 수십개 됩니다. 이런 도메인들을 전부 제 개인비용으로 부담하는 것은 문제가 있다고 봅니다. 게다가... 전 가정이 있어서~ ^^;

그래서 제안하는 바, 오늘 부로 flexdocs.kr에 들어가는 모든 비용은 기부 형태로 운영되었으면 합니다. 다음 조건에서 제안하는 바입니다.

1. 기부액은 자유롭게 합니다. (하지만 너무 많이 기부하면 부담됩니다. ^^)
2. 모든 기부자는 flexdocs.kr에 날짜, 이름, 액수를 공개합니다.(필요하다면 가칭을 사용해드립니다.)
3. 기부금 사용한 내역은 flexdocs.kr에 투명하게 공개합니다.
4. 사이트는 개인적 이득 및 상업적으로 운영되지 않습니다.
5. 사이트 운영 및 사이트 발전을 위한 활동외에 다른 목적으로 기부금을 사용하지 않습니다.
6. 운영은 지돌스타(http://blog.jidolstar.com)가 맡으나 다른 분에게 양도 될 수 있습니다.
7. 만약 피치 못한 사정으로 사이트를 닫는 경우, 기부금이 남는다면 여타 다른 좋은 활동 단체에 기부금이 전달될 수 있습니다. 이때 제 블로그를 통해 공지합니다.

기부는 다음 계좌로 하시면 됩니다.

신한은행 753-02-426937 지용호

입금자는 본인으로 하시고 입금하신후 확인을 위해 아래 번호로 문자를 주시거나 메일을 보내주세요.
010-2018-영삼이일
jidolstar@gmail.com


flexdocs.kr가 정상적으로 운영될 수 있도록 노력하겠습니다. 감사합니다.

지돌스타(http://blog.jidolstar.com)




파워플 프로젝트 공식 카페를 오픈했습니다.

http://cafe.naver.com/powerfl

프로젝트 진행에 적절한 커뮤니케이션의 필요로 오픈하게 되었습니다.

현재 http://powerfl.net, http://powerfl.com, http://powerfl.co.kr 로도 접속이 가능합니다. 이 도메인은 공식페이 주소이지만 아직 없는 관계로 카페로 포워딩 처리 했습니다.

가입은 자유이며 일정수준의 활동률을 보이면 자동으로 등업처리 됩니다. 단, 참여멤버, 개발멤버는 실제 프로젝트에 참여하는 사람에 한해 운영자가 지정하며, 솔루션 제공자에게는 감사멤버로 지정할 계획입니다.

공지 : 파워플 킥오프 모임을 참고해 주세요. http://blog.jidolstar.com/680


이전부터 많은 지면을 할당하여 원더플(wonderfl.net)에 관련된 글을 많이 적었습니다. 제 블로그에 꽤 많은 Flash 개발자들이 다녀가시기 때문에 이제 원더플을 모르시는 분은 거의 없을 듯 합니다.

아시다시피 원더플은 웹에서 직접 코딩하고 컴파일되어 결과를 사이트에서 바로 확인할 수 있다는 장점이 있습니다. 여기에 SNS기능도 곁들여서 세계적으로 많이 애용되고 있는 사이트입니다. 저는 이 때문에 칭찬을 아끼지 않았죠.

하지만 원더플은 중요한 한계점이 있습니다. Flex든 ActionScript든 딱 한개의 문서만 만들 수 있습니다.  현업에서 실제로 더 중요시 되는 것은 아키텍쳐와 설계 부분에 대한 부분입니다. 그러므로 원더플의 이런 구조로는 이런 요구를 수용하기에는 부족할 수 밖에 없지요. 가령, 제 경우만 하더라도 이전에 Flex로 제작해 놓은 3D 게시판이나 상용에서 사용할 만한 이미지 에디터, 천문프로그램 정도의 코드를 원더플에 개시하기에는 너무 역부족이였습니다.

파워플(Powderfl)이란?!


지금 소개해드리고자 하는 것은 원더플의 한계를 극복하면서도 더욱 파워풀하게 Flex, ActionScript 3.0 코드를 공유할 수 있는 파워플(powderfl) 프로젝트입니다.

파워플은 ActionScript 코드를 웹에 개시하고 보여주며 소스를 공유하는 것까지는 원더플과 비슷한 컨셉입니다. 하지만 파워플은 원더플처럼 웹에서 직접 코딩할 수 있는 조악한(?) 에디터를 대신 Flash Builder를 에디터로 삼고 그 결과를 SVN으로 전송해주면 원더플과 똑같이 SWF 애플리케이션을 웹에서 볼 수 있도록 합니다.

이 아이디어는 애초부터 hika님으부터 나온 것이고, 저는 프로젝트 명만 정했습니다. ^^
Powerfl(Power + Flash) 프로젝트 명은 제가 생각해도 너무 잘지은듯.... ^^ 마침 도메인도 다 비어 있었다는 ㅋㅋ


파워플 개요
앞서 말씀드렸듯이 파워플은 원더플의 한계점을 극복하기 위해 Flash Builder를 에디터 삼는데서 시작합니다. 이에 대한 대략적인 개요는 다음과 같습니다.

  1. 서버에 계정을 만들면 svn레포지토리를 할당받는다.
  2. 로컬에서 레포지토리 싱크를 하면 서버측 swc를 전부 내려받고 기본적인 폴더 구조를 내려받는다.
  3. 로컬에서 개발한 후 커밋하면 훅스크립트( http://www.javajigi.net/pages/viewpage.action?pageId=110395394 )를 이용하여 자동으로 서버측에서 컴파일을 일으킨 후
  4. 원더플과 마찬가지로 swf를 웹에 게시한다.
  5. 커밋로그를 작성할 때 다양한 매크로를 지원하여 swf에 대한 기술을 손쉽게 하고 서버가 swf를 컴파일한 후 swf에 대한 자세한 분석레포트를 같이 올린다.
  6. svn에 커밋된 내용은 웹에서 완전히 보고, 수정하고, 삭제할 수 있으며 기존 원더플 방식을 웹에서 파일을 새로 만들어 편집하는 것도 가능하게 한다.
  7. 상대방의 svn 중 원하는 패키지를 import할 수 있게 되어 유저가 작성한 라이브러리를 캡슐화한 상태에서 공유할 수 있다.
  8. 유저는 자신의 swf를 구동하는 도중에 몇개라고 썸네일을 생성해낼 수 있다.
  9. 서버에서 생성된 swf 및 썸네일은 전부 로컬로 다운로드 받을 수 있으며, 특정 유저의 레포지토리를 zip파일로 내려받을 수 있다.

대략적으로 보면 에디터를 Flash Builder 뿐 아니라 웹에도 에디팅이 되게 하고 SVN이 되기 때문에 어떤 에디터를 써도 무방하다는 것을 알 수 있습니다. 그만큼 파워플! 한거죠 ㅋ


파워플은 왜 필요한가?
일단 한국에서 뭔가 설계, 아키텍쳐, 기술을 공유하는 것은 너무 어렵습니다. 딱히 그 이유에 대해서 말씀드릴 필요는 없고, 이런 개발 환경에서 개발자들이 힘을 합해 파워플과 같은 사이트를 만들어 운영하기 시작하고 활성화 되면 어도비에서도 한국에 대한 관심을 가지기 시작할 겁니다. 뭔가 시장이 활발한 것을 보여줘야 어도비도 반응할 것이고 '어도비는 일본만 좋아해'라며 부러운 시선을 가지지 않아도 될겁니다. 

파워플은 아마도 개발자들이 참여하는 만큼 초반부터 영어로된 사이트가 되지 않을까 생각합니다. 정상적으로 만들어져서 운영이 된다면 한국개발자뿐 아니라 일본, 미국 개발자들도 유용하게 쓸 수 있는 사이트가 되지 않을까요? 만약 그렇게 정말루~ 된다고 생각해보세요.

그리고... 파워플이 활성화 되서 어도비 공식 기술 사이트로 선정되었다고 생각해보세요. 정말 뿌듯할 겁니다.

카페나 블로그에서 정보 공유하는 것을 뛰어 넘어서 우리도 뭔가 이런 일을 누군가는 해야만 한국 Flash 발전이 있을 것이고 이러한 활동이 Flash에만 국한되는 것이 아니라 관련 업종에도 영향을 주어 여러 벤치마킹한 사이트들이 많아진다면 그 또한 즐거운 일입니다.

파워플의 특성상 유용한 공개 프레임워크들이 많이 올라올 수도 있을 겁니다. 특이하고 멋진 아키텍쳐로 이루어진 애플리케이션도 경험할 수 있을 겁니다. 다른 개발자들과 함께 협업을 통해 함께 쓸 수 있는 결과물을 도출할 수 있을 겁니다. 그리고 우리도 Flex 5 만들 수 있지 않을까요?


파워플 개발 팀원 모집

파워플 서비스가 오픈되려면 다음과 같은 분야의 다양한 노가다를 필요로 합니다.
  • 리눅스 서버 셋팅 (아마도 데비안이 후보)
  • 아파치를 다양한 mod와 합체하여 최적화 컴파일설치
  • 서비스는 php로 작성
  • db는 mySQL..오라클 꼴보기 싫으면 pSQL이나 mSQL 쓸지도..
  • svn설치 및 아파치 연동
  • svn 훅스크립트 작성을 위한 리눅스 스크립트…냐 아니면 펄이나 파이썬이냐..아니면 php냐..
  • mxmlc와 mod연동
  • 웹사이트 제작
  • 위의 모든 서비스를 웹사이트에 인테그레이션
  • rss 및 다양한 웹배포수단 연동모듈작성
  • 예상컨데 자바나 c계열 소켓서버의 브릿지를 통해 as3 socket에서 인증을 처리해주고 아파치웹서버에 접근할 수 있게 해줄 예정(귀찮은데 펄데몬으로?)
  • 기타 워드프레스 인테그레이션도 하고 싶은…ㅋㅋㅋ

어떤 분야든 좋습니다. 함께 하실 분을 찾습니다.


현재 맴버


제작일정
  • 모집마감 : 없음(언제라도 들어와만 주신다면 감사할 따름 ^^;)
  • 프로젝트 런칭 및 킥오프미팅 : 아직은 미정이지만 4월 20일정도
  • 오픈 예정 : 6월? ㅎㅎ 과연

관련글
신규 프로젝트 팀원 모집


어쨌거나~~ 한번 정도 만나서 이와 관련된 이야기를 해보고 진행하는 것은 꽤 생산적인 일이 될겁니다.
우리도 원더플과 같이 멋진 국제 기술 사이트를 만들어 보자구요!
참여하실 분은 주저말고 신청해주세요. 단, 어느 부분에 있어서 하고 싶다는 것을 적어주시면 더욱 좋습니다.
여러분의 참여가 한국 개발 현실을 바꿀 수도 있습니다. ^^

이미 사비 들여서 도메인도 구입해 두었습니다.
powerfl.com, powerfl.net, powerfl.co.kr

도메인도 샀으니 해야만 합니다. ^^

많은 참여 부탁합니다.

글쓴이 : 지돌스타(http://blog.jidolstar.com/673)
인터넷 상에 멋진 Flash 애플리케이션을 보면서 Flash 개발자라면 한번쯤은 어떻게 구현했을까 의문을 품어봤을 것이다. 필자 또한 그러했다. 하지만 남이 만든 소스를 보기 위해 SWF 파일을 디코드 하더라도 분석하기가 여간 까다로운게 아니다. 차라리 그럴바에 관련 내용을 담은 해외 서적을 하나 구입해서 공부하는게 더 빠를지도 모른다. 

이 문서는 자신의 Flash 제작 실력을 더욱 한층 높이기 위한 시도를 하고자 하는 분들을 위한 것이다. 중,고급 flash 개발 도약을 위해 도움이 되었으면 한다.

목차 
  • Wonderfl 소개 
  • Wonderfl의 주요기능 
  • Wonderfl 최고의 코드들 집합 Beautifl
  • Flash Builder 4에서 Wonderfl 코드 테스트 환경 만들기
  • Wonderfl 테스트 환경을 한번에 구축하기!
  • 정리하며
  • 참고사이트


Wonderfl 소개


Wonderfl(http://wonderfl.net)은 일본의 Kayac회사에서 제작하고 운영하고 있는 웹사이트로 ActionScript 3.0을 직접 인터넷 상에서 제작하고 컴파일할 수 있는 환경을 제공한다. Wonderfl은 Wonderful + flash가 합쳐진 단어로 생각된다. 매우 재미있고 기억하기 쉬운 단어 조합이다.

이 사이트는 단순히 컴파일하고 결과만 볼 수 있는 단계를 넘어 각종 공개된 라이브러리와 연동이 가능하며, 개발자들간에 코드 공유를 통해 더 좋은 코드로 개선할 수 있는 환경을 제공한다. 이로써 Flash 개발자간에 코드레벨 SNS를 실현했다고 생각한다.
 
개인적으로 Flash 개발자라면 이 사이트와 매우 가깝게 지내야한다고 생각한다. 실제로 일본의 매우 유명한 Flash 개발자들의 귀중한 노하우가 많이 공개되어 있기도 하다.

공개된 라이브러리를 활용하기 위한 환경을 구축하는 일을 매우 귀찮고 방법 또한 난해한 경우가 다분하다. 이런 경우 Wonderfl의 검색기능을 통해 필요한 기술을 쉽게 습득해서 그런 문제를 해결할 수도 있다.


Wonderfl 주요 기능

필자는 Wonderfl은 Flash 개발자간 코드공유 SNS라고 정의하고 싶다. Wonderfl의 몇가지 기능을 소개하면서 그 이유를 알아보도록 하자.

1. 코드 작성
Wonderfl의 가장 기본적인 기능 중에 하나로 코드 작성후 실시간으로 컴파일하고 결과를 볼 수 있는 기능이다. 이 기능은 Flex 컴파일러인 mxmlc을 활용해서 만든 것으로 파악한다. 그렇기 때문에 일반 ActionScript 3.0 코드외에도 MXML 태그로 작성해도 컴파일이 가능하다. 코드에 대한 라이센스도 함께 지정할 수 있고 작성이 완료된 코드는 블로그나 다른 커뮤니티에 퍼갈 수 있도록 되어 있다.


2. "Fork"기능을 이용한 다른 사람의 코드 수정
Fork기능은 이미 만들어진 코드를 퍼가서 자기 입맛대로 수정하는 것을 의미한다. wonderfl에 올라온 모든 코드는 이 작업이 가능하다. Fork의 강력함은 아래 소개하는 필자의 2개의 글을 참고하면 좋겠다.

10만개 입자를 이용한 유체 시뮬레이션 실험
Flash 속도 개선을 위한 실험 - 10만개 입자 유체 시뮬레이션 연장전!




3. 좋아하는 코드 찜하기
Fork 기능은 매우 강력하지만 또한 부담스러울 수 있다. 수정하지도 않을 코드를 Fork하는 것은 왠지 끌리지 않는다. 이럴때 사용할 수 있는 기능이 favorite 기능이다. 멋진 코드를 발견하면 "add to favorites"를 클릭하자. 그러면 다음에 설명할 "나의 페이지"에서 지금까지 favorite로 지정한 코드 리스트를 언제든지 참고할 수 있게 된다.


4. Following, Follower 기능
트위터와 같이 Following, Follower 기능이 존재한다. 코드 공유를 넘어 유용한 코드를 생산하는 사람을 Follow로 등록하면 나의 페이지에서 Following 리스트로 확인할 수 있고, 또 그 사람이 만들어내는 코드를 언제든지 쉽게 확인할 수 있게 된다. 그야말로 개발자 코드레벨 SNS 사이트인 것이다.

5. 나의 페이지
나의 페이지는 자신이 만든 코드, Fork나 favorite로 지정된 코드, Follow로 지정한 사람들의 동향을 확인할 수 있는 기능을 가지고 있다. 이 페이지는 "wonderfl.net/user/아이디"로 접근할 수 있다. 필자는 http://wonderfl.net/user/jidolstar 이다.



6. 질문&답변 기능
코드중에 이해하기 힘든 코드나 설명이 필요한 코드가 있다면 질문할 수 있다. 방법은 Fork를 하고 tag에 question을 달면 된다. 일본어, 영어로 해야하기 때문에 왠지 부담이 되겠지만 활용하면 분명 좋은 기능이다.





Wonderfl 최고의 코드들 집합 Beautifl
Beautifl(http://beautifl.net)은 Wonderfl에 올라온 멋진 코드들만 선별해서 종류별로 소개해준 사이트이다. 이 사이트는 Wonderfl에 올라온 코드중에 추천받은 코드만 엄선하여 보기 좋게 카테고리를 만들어 분류해주고 있다. 잘 이용하면 큰 도움이 되는 사이트이다.

Beautifl.net의 메인화면



Flash Builder 4에서 Wonderfl 코드 테스트 환경 만들기
Wonderfl에서 매우 좋은 코드 툴을 제공하고 있지만 약간의 수정외에는 Flash Builder 만큼 자유롭게 개발하기는 힘들다. Wonderfl에서 조금 놀다보면 이제 그곳에 있는 코드를 가져와 내것으로 만들어보고 싶게 된다.  

Wonderfl에는 Flash Player에서 제공하는 Native 클래스들(flash.* 패키지로 구성된 것들)뿐 아니라 외부 다른 유용한 라이브러리를 함께 활용할 수 있는 환경이기 때문에 그와 비슷한 환경을 만들어주는 것이 필요하게 된다. 필자처럼 Wonderfl에 공개된 코드를 매번 가져다가 테스트 해보는 사람은 필요할때 마다 라이브러리를 가져다 쓰는 것은 매우 귀찮은 작업이다. 그러므로 필요한 라이브러리를 한번에 가져와 언제든지 테스트 해볼 수 있는 환경을 구축할 필요성이 생긴다.

여기서는 라이브러리를 자신의 워크스페이스에 포함하는 방법과 그 라이브러리를 이용해 테스트를 하는 방법을 간단히 소개한다.

1. 라이브러리 가져오기
Wonderfl에서 사용하는 라이브러리 목록은 사이트 우측상단에 Wonderfl > libraries 메뉴로 들어가면 아래와 같은 화면을 통해 사용한 라이브러리의 종류와 버전을 확인할 수 있다.


각 라이브러리의 좌측에 download.swc를 직접 다운로드 받아 자신의 프로젝트에 포함시킬 수도 있다. 하지만 여러분은 단순히 라이브러리를 이용하는 차원이 아니라 직접 디버깅하며 코드를 분석할 필요가 있을 수 있다. 이러한 경우에는 직접 라이브러리 프로젝트를 만들어 소스를 항상 참조하는 환경을 만들어야 한다. 이러한 환경을 만들때 참고해야할 사항은 다음과 같다.

첫째. Wonderfl에 공개된 라이브러리는 다양한 배포 경로를 가진다.
공개된 라이브러리는 다양한 배포 경로를 가진다. 가령, Google Code에 최종 버전을 압축해서 배포하는 사람도 있지만 그냥 SVN에만 올려놓는 사람도 있다. 또 자신의 웹사이트(TweenMax의 경우)에서 직접 배포하는 경우도 있고 Google이 아닌 다른 커뮤니티(betweenAS3, thread의 경우 libspark.org)에서 배포하는 경우도 있다. 어떤 경우는 소스를 공개하지 않고 SWC만 공개하는 경우도 있다.(Alternative3D의 경우) 우리는 다양한 배포 경로에 맞게 알아서 참고해 사용해야한다.

둘째. Wonderfl에 사용된 라이브러리의 버전을 확인한다.
공개된 라이브러리는 왠만하면 Wonderfl에서 사용하고 있는 버전을 이용하는 것이 좋다. 그렇지 않으면 Wonderfl 코드를 사용할 때 버전차이로 컴파일 에러가 발생할 수 있다.  


셋째. 라이브러리간 의존성을 확인한다.
가령, jiglibflash 라이브러리의 경우 기본적으로 Papervision3D, Sandy3D, Alternative3D, away3d, five3d 라이브러리가 있는 경우에만 컴파일을 할 수 있다. 만약 jiglibflash에서 away3d, five3d를 제외한 다른 라이브러리만 사용하는 경우에는 해당코드를 찾아 컴파일 대상에서 제외해야한다. 아래 화면은 jiglibflash의 속성에서 필요없다고 판단한 클래스를 제외시키는 방법을 보여준다.



위와 같은 3가지 참고사항에 따라 Flash Builder의 워크스페이스에 라이브러리 프로젝트를 만들면 다음과 같은 Package Explorer의 모습을 기대할 수 있다.



2. Wonderfl 애플리케이션 제작 
위 과정을 통해 라이브러리를 자신의 워크스페이스에 받아왔으면 이제 테스트를 위한 애플리케이션 제작 프로젝트를 만들 차례이다. 

첫째. Flash Builder의 File>New를 통해 ActionScript 3.0 프로젝트를 만든다. 필자는 프로젝트 이름을 wonderfl로 했다.
둘째. 만들어진 프로젝트에 libs 폴더를 만들고 소스가 공개되지 않은 SWC 파일을 복사해둔다.

셋째. 라이브러리 경로를 잡아준다. 지금까지 만들어놓은 라이브러리를 전부 사용하기 위해 먼저 "Add Project..."버튼을 눌러 라이브러리를 모두 등록한다. 또 "Add SWC Folder..." 버튼을 눌러 libs를 입력해 libs 폴더에 SWC를 사용하는 라이브러리로 등록한다.

넷째, .actionScriptProperites의 <excludedEntries>부분을 모두 삭제한다.
<excludedEntries>는 FlexSDK를 이용해 mxmlc가 컴파일하는 과정에서 필요없는 라이브러리를 빼는 역할을 한다. 하지만 Wonderfl에 공개된 코드들은 FlexSDK의 모든 라이브러리를 거의 100% 사용하므로 이 부분을 제거할 필요가 있는 것이다. 하지만 .actionScriptProperites 파일은 숨김파일이므로 Package Explorer 창에 바로 보이지 않는다. 이 부분에 대해서는 http://blog.jidolstar.com/665 를 참고하고 <excludedEntries>를 제거하길 바란다.

다섯째, HTML wrapper 파일은 삭제해준다.
HTML wrapper 파일을 웹브라우저에서 실행하는 것을 가정하에 Flash 애플리케이션이 자동으로 HTML에 Embed처리 되도록 생성해주는 일종의 템플릿 코드이다. wonderfl의 코드들이 단독 Flash Player 에서 제대로 동작하는 경우가 있다. HTML wrapper 설정을 해지함으로써 제대로 동작하지 않는 것을 방지할 수 있는데, 굳이 이 설정을 한 상태로 하고 테스트 하다가 stageWidth, stageHeight관련 문제가 발생하면 http://blog.jidolstar.com/656를 참고하길 바란다.

 
여섯째, Wonderfl에서 마음에 드는 소스 코드를 복사한다.
일곱째, default package에 ActionScript 파일을 만들고 복사한 Wonderfl 코드를 붙인다. 이 때 주의할 것은 파일명과 클래스 명은 동일해야한다. 이때 이름규칙을 정해주면 좋다. bitmap실험은 bitmap_로, 게임은 game_으로, papervision3d면 pv3d_로 시작하도록 만들어놓으면 관리하기 용이해진다.

여덟째, 만들어진 ActionScript 코드를 실행하기 위해 Default Application으로 설정한다. (아래화면 참고)
이것은 .actionScriptProperties 파일의 <applications>에 등록하는 과정중 하나이다. 직접 .actionScriptProperties를 편집해도 되겠다.

아홉째. 실행하고자 하는 ActionScript 파일을 열고 Shift+Alt+X,W를 눌러 실행한다.
열째. 실행코드에 Wonderfl의 출처를 남겨두는 것이 좋다!
아래처럼 Wonderfl에서 가져온 코드의 출처를 남겨두면 나중에 다시 참고할 수 있게 된다.

마지막으로, 일본어 주석은 일본어 번역기를 이용한다.
필자의 경험상 네이버 일본어 번역기가 원본코드를 깨뜨리지 않고 알맞게 번역해주었다. 활용하면 도움이 된다.


Wonderfl 테스트 환경을 한번에 구축하기!
지금까지 라이브러리와 개발환경을 구축하는 방법을 소개했다. 하지만 이러한 개발환경을 만든다는 것은 너무 버겁고 귀찮은 작업이다. 필자는 이러한 문제를 한방에 해결할 수 있는 솔루션을 여러분께 선물하고자 한다.



필자는 Wonderfl 코드의 테스트 환경을 쉽게 만들어주기 위해 Naver 개발자 센터의 오픈프로젝트로 "원더플 개발환경구축 프로젝트"를 만들었다. 이 페이지는 Google Code와 유사한 오픈 프로젝트이다. SVN을 지원해주기 때문에 이 기능을 이용해서 위에서 설명한 라이브러리들을 단 한번의 Checkout으로 개발 환경을 만들 수 있다.

이것을 수행하기 위해 먼저 다음과 같은 툴이 필요하다.



위 과정을 다했으면 기본 개발 환경이 구축된 것이다. 다음으로 SVN에서 라이브러리를 다음과정을 통해 모두 checkout 한다. 

 
  • Flash Builder 4를 실행한후 새로운 워크스페이스를 만든다.
  • 메뉴에서 File>Import를 통해 창이 열리면 SVN>Checkout Projects from SVN을 선택한다.
  • Create a new repository location을 선택후 Next 버튼 누른다.
  • https://dev.naver.com/svn/wonderfl/trunk를 입력한다. 아이디는 네이버 아이디, 비밀번호는 anonsvn이다. 아이디, 비밀번호 모두 anonsvn 이다.
  • 열려있는 모든 프로젝트를 전부 선택한 뒤 Finish 버튼을 누른다. 자동으로 SVN에서 프로젝트에 필요한 라이브러리와 자료를 워크스페이스에 포함시키게 된다. 5~10분 소요됨
위 과정을 모두 완료했다면 Package Explorer에 다음과 같이 라이브러리 프로젝트들이 생성될 것이다.


또한 init_template도 있을 것이다. 이것은 테스트 프로젝트를 자동으로 만들기 위한 파일을 모아둔 것이다. 이중에 init.xml은 ANT구동 파일로서 그 역할을 담당하게 된다.(참고로 이런 방법론은 찬익님과 Hika님의 글에서 아이디어를 얻었다. 두분께 감사한다.)

테스트 프로젝트는 다음과 같은 과정으로 만든다. (복잡해 보일지 모르겠지만 한번 해보면 이보다 쉬운 방법은 없다고 생각할 것이다. ^^)


  • 워크스페이스에 ActionScript 3.0 프로젝트 생성한다.
  • init_template내에 init.xml을 생성한 프로젝트의 root에 복사한다.
  • init.xml을 열어 "프로젝트 이름을 넣는다" 안에 프로젝트 명을 넣는다.
  • Ant View에 init.xml을 드래그 해서 붙인다. 3번 항목에 붙인 프로젝트 이름이 ANT View에 표시될 것이다. 
    만약 Ant View가 없다면 Windows>Show View>Other를 선택해 ANT를 찾아 선택하여 열어준다.
    만약 ANT가 없다면 Flash Builder에 ANT 플러그인이 설치되지 않은 것이므로 먼저 플러그인부터 설치해야한다. 참고 : http://blog.flashplatform.kr/213
  • Ant View에 붙은 해당 프로젝트 이름 옆에 (+) 버튼을 눌러 init가 나오면 두번 클릭해 실행한다. 
    이때 Console창에 마지막에 BUILD SUCCESSFUL이 나오면 ANT 실행을 성공한 것이다.
  • 생성한 프로젝트를 선택한 다음 F5를 눌러 새로고침한다.  
    다음과 같은 변화가 일어난다. 
    - Main.as가 만들어지고 기본 Application으로 등록된다.
    - libs 폴더에 SWC 파일들이 복사된다.
    - remote 폴더가 생긴다. 이 폴더는 외부자원를 로드하는 예제를 작성할때 외부자원을 이곳에 놓고 쓰면 되겠다.
    - HTML Wrapper 폴더가 삭제된다. 
    - Wonderfl에서 사용하는 기본 라이브러리가 자동으로 등록된다. 


아래 화면은 위 과정을 통해 구축된 애플리케이션의 Package Explorer 화면이다. 이제부터 default package에 필요한 수만큼 Wonderfl에서 가져온 actionscript 코드를 테스트 할 수 있게 되었다.


더불어, 위 과정을 통해 개인적으로 만든 테스트 프로젝트들 모음을 아래 링크를 통해 볼 수 있다.
http://dev.naver.com/scm/viewvc.php/branches/jidolstar/?root=wonderfl

SVN의 https://dev.naver.com/svn/wonderfl/branches/jidolstar 경로로 부터 직접 받아볼 수 있으니 참고 바란다.




정리하며
개인적으로 Wonderfl은 필자에게 매우 도움이 되는 사이트이다. 한국의 Flash 개발자들도 Wonderfl을 적극적으로 활용했으면 하는 바램을 가지는 마음에서 이 문서를 작성했다. 아무쪼록 도움이 되었길 바란다. 


참고사이트



글쓴이 : 지돌스타(http://blog.jidolstar.com/669)

나는 Flex나 기타 무거운 프레임워크를 사용하지 않고 ActionScript 3.0 API 수준으로 개발을 한지 이제 겨우 1년이 넘은 것 같다. Flex로 개발할 것과 ActionScript로 개발해야할 것에 대한 구분은 항상 명확하다. 자주 새로 빠르게 로드되어야 하는 애플리케이션 제작은 무조건 ActionScript 기반으로 제작한다. 하지만 가끔 사용하며 Flex 컴포넌트를 잘 활용해야하는 애플리케이션이라면 Flex로 개발한다.

ActionScript 3.0기반으로 개발하고 완성하고 나서는 뭔가 꼬여있는듯한 느낌, 유지보수가 안될 것 같은 느낌을 항상 받아왔다. 또한 깨끗하지 못한 객체관리가 항상 걸렸고 너무 길어져서 지저분해지는 코드 또한 마음에 들지 않았다. 그리고 클래스간 역할 분담이 분명하지 않는다는 느낌을 받았다. 동작은 뭔가 석연치 않은 느낌을 계속 받았다. 어떤 개발의 스킬이나 전문적인 지식에 대해서 학습을 해보지 못해봤던 나로써는 설계때부터 항상 고민거리가 생긴다.

나는 근 한달동안 블로그 활동 및 외부 활동을 거의 안하면서 개발에만 매진하면서 지냈다. 바로 스타플의 타임라인 개발때문이였다. 타임라인이 궁금하시다면 아래 링크로 접속해보면 된다.

스타플 타임라인 업그레이드 및 앨범 기능 추가 소식


개발하면서 위에서 제시한 문제점을 어느정도 해소시킬 수 있는 몇가지 개념들이 있었다. 여기에 간단하게 적어두도록 하겠다.


1. 객체의 재사용 Object Pool
Flash 개발하면서 항상 걸리는 문제중에 하나가 메모리이다. Flash Player가 정확한 가비지 컬렉터(GC)를 가진다고 하지만 지금도 그다지 명확한 신뢰를 받지 못하고 있다. 하지만 분명 GC는 동작한다. 중요한 것은 Flash Player의 GC를 너무 맹신하지는 말자는 것이다.

new를 통한 객체 생성은 항상 지양하는 것이 가장 중요한 메모리 관리의 첫걸음이다. MyClass.Factory()와 같은 static 클래스를 통해 내부적으로 new를 사용하고 각종 처리는 factory가 담당하는 것이 각종 초기화 및 객체관리에 도움이 된다.

더불어 매우 자주 사용하다가 없어지는 객체를 계속 new를 통해 생성하고 GC객체화 시키는 것은 메모리 관리에 도움이 안될뿐 더러 퍼포먼스에도 문제가 있다. 실제로 비교적 큰 디스플레이 객체인 Sprite를 new를 자주하면 전체적인 퍼포먼스에 좋지 않은 영향을 줄 수 있다. 이런 경우에 퍼포먼스와 메모리를 동시에 해결할 수 있는 방법은 바로 Object Pool을 이용하는 것이다.

Using object pools : http://lab.polygonal.de/2008/06/18/using-object-pools/ 

위의 글은 Object Pool의 강력함을 시각적으로 말해주고 있다. 특히나 Object나 Point와 같은 작은 클래스가 아닌 Sprite와 같은 큰 클래스의 경우 new 연산자 사용보다 Object Pool의 사용은 큰 이점을 주고 있다는 것을 알 수 있다.

사용한 객체를 그냥 버리지 말자. 잘 보관했다가 다시 사용할 수 있게 만들고 사용하자... 특히나 시각객체(Sprite기반)이 자주 생성,소멸해야하는 경우라면 강력히 Object Pool을 사용하라고 주장한다.


2. Linked List 와 Dictionary
컴퓨터를 전공한 사람이라면(본인은 아님) 자료구조를 배우면서 Linked List는 반드시 이해해야할 필수 항목이다. 나는 이번 타임라인을 제작하면서 Linked List를 활용해 중간중간에 얻어진 시간순서 데이터를 엮어주는데 요긴하게 사용했다. 일반적인 Array형태의 데이터는 중간에 데이터 삽입하는 것은 효율적이지 못하지만 Linked List는 연결하고자 하는 지점의 연결부의를 끊고 그 중간에 삽입하여 앞뒤로 연결만 하면 되기 때문에 훨씬 효율적이다.

Data Structures example : linked lists http://lab.polygonal.de/2007/08/13/data-structures-example-linked-lists/

또한 특정 key의 자료검색에 Dictionary를 사용했다. Dictionary를 직접 사용하는 것보다는 한번 감싸서 클래스를 만들어 추가/삭제/편집/데이터접근등을 처리하기 쉽게 하면 정말 요긴해진다. 나는 Linked List와 더불어 Dictionary를 통해 key값을 통한 데이터 검색에 사용했다. 이것을 이용하면 아무래도 index 순으로 찾는 것보다 훨씬 빠른 검색을 할 수 있다.


3. MVC
개발자라면 Model-View-Controller에 대한 개념을 잘 알고 있을 것이다. 이러한 개념은 Flex 수준의 개발이라면 Flex가 어느정도 지원해주는 편이기 때문에 그나마 괜찮지만 ActionScript 수준에서 개발하려면 이 점을 고려하는 것이 좋다. 기본적으로 Model의 데이터 변화는 View에 영향을 미치고 View의 변화는 Controller에 영향을 준다. Controller는 View와 Model을 통제하며 서로의 상호작용에 조절한다. 그리고 View가 Model을 절대 변경하지 않는다. 이런 약속으로 MVC 구조를 설계하면 View와 View관계도 명확해지고 아직 로드되지 않는 View(모듈)에게도 도움이 된다.

타임라인의 경우 최초 구동될때 달력과 보기설정은 아에 모듈로 만들어 버린다. 그리고 보여달라고 요청할때만 모듈을 로드해 시각화시킨다. 이때 모듈은 부모 애플리케이션에 Model에 있는 데이터를 사용한다. 이 데이터는 View(모듈)의 존재를 모르기 때문에 어떤 상황이 되든 사용할 수 있다. 또 달력과 보기설정은 같이 보여질 수 없다. 각각 show()와 hide()함수가 있는데 달력이 show하면 보기설정은 hide가 호출되어야하는 식이다. 그런데 View에서 이런것을 컨트롤해버리면 View간에 상호 간섭이 생긴다. 이런 경우 Controller가 중재하도록 하면 훨씬 쉽게 이런 문제를 해결할 수 있다.


4. 인자객체를 이용하자.
TextField를 이용해서 객체를 생성해본적이 있을 것이다. 1개 Text를 출력하기 위해서 얼마나 많은 설정을 해야하고 또한 수십줄이 넘는 코딩을 해야하는가? 타임라인의 달력 기능에는 한개 한개가 다 TextField 객체들이다. 물론 반복적으로 생성해주면 되지만 이 마저도 마우스오버,클릭,선택등과 같은 동작에 대응해야하기 때문에 단 몇줄 코드로는 이런 기능을 구현하기가 어렵다.

나는 이러한 문제를 인자객체를 이용해 해결했다.
이에 대해서는 더이상 말이 필요없다. 다음 글을 보자.
인자객체 : http://diebuster.com/flash/?s=인자객체


5. Helper 수준의 프레임워크
이번 타임라인을 제작하면서 가장 도움이 되었다고 생각하는 사람은 hika님이다. 물론 같은 회사도 아니고 자주 만나본 것도 아니지만 hika님의 블로그에 정리해놓은 내용은 나에게 큰 자극제가 되었다. 그중에 hika님이 만들어놓은 ActionScript 3.0 프레임워크는 나에게 큰 도움이 되었다. 이는 흔히 말하는 무거운 프레임워크 아니다. 정확히 말하자면 Helper 수준이다. Helper 수준이라는 것은 Flex처럼 Button, Label, DataGrid와 같은 컴포넌트를 가지는 것이 아니라 Sprite, Shape, TextField, Loader등의 기본 ActionScript 3.0 기반의 클래스를 더욱 효율적으로 사용하게 하기 위한 것이라는 것이다.

나는 이 프레임워크를 이용해서 시각객체관리, 레이어관리, Embed자원관리, 원격자원관리, 이벤트관리, 데이터관리등 전반적으로 큰 도움이 되었다. 나는 hika님이 만들어놓은 프레임워크를 분석하면서 큰 구조의 변경없이 나만의 프레임워크로 변경하고 이번 타임라인 개발에 적극적으로 사용했다. 만약 프레임워크의 도움이 아니였다면 역시나 어려운 코딩을 감당해야할지도 모르겠다.


6. EnterFrame 수준의 동작 관리
MouseMove 이벤트를 시각객체를 이동하는데 사용하지 말자. 대신 EnterFrame 이벤트시에 stage.mouseX, stage.mouseY등을 사용해서 시각객체를 이동시키자. 실제로 MouseMove 이벤트는 그 동작이 매우 느리다. 그러나 EnterFrame 이벤트는 최소한 stage.frameRate에 지정된 수준에서 발생하기 때문에 느린 마우스 동작에 걱정하지 않아도 된다.

나는 타임라인을 마우스로 움직일 때 이 방법을 사용했다.

마우스 이벤트 최적화 : http://diebuster.com/flash/category/algorithm/io


7. Event 사용의 최소화
나는 Event 사용을 최소화 하려고 많이 노력했다. 정말 필요한 곳에만 사용해도 개발에 무리가 없었다. 시각객체를 통한 이벤트 전파는 생각보다 매우 느린 편이기 때문에 되도록이면 사용을 지양해야한다. 이것도 정말 필요하고 요긴하다고 판단할때만 사용하는 것이 옳다. 사용한 이벤트는 반드시 remove시키는 것이 현명하다. useWeakReference는 정말 필요할때만 사용하는 것이 좋다. 되도록이면 명시적으로 remove 시키는 것이 메모리 관리에 도움이 된다.


8. arguments.callee 활용
arguments.callee는 함수 자신을 말한다. 이는 꽤 유용한데 특히나 이벤트 리스너 함수에서 자신을 호출한 이벤트를 삭제할때 사용될 수 있다.

스스로 삭제되는 이벤트 리스너 : http://diebuster.com/flash/110


9. BitmapData.clone() 사용 지양
BitmapData 클래스는 비트맵 데이터를 저장하는 클래스이다. 이 데이터를 시각화 하기 위해 사용하는 클래스는 Bitmap이다. new Bitmap( bitmapData ) 시에 첫번째 인자가 BitmapData 객체이다.  같은 bitmapData가 자주 사용되어져야 하는 경우에 bitmapData.clone() 을 통해 계속 생성하지 말고 그냥 원본 bitmapData를 이용해 Bitmap객체를 생성해서 시각화 처리하자.

나는 타임라인에 들어가는 각종 비트맵 객체에서 bitmapData를 뽑아내어 static으로 참조해 계속 사용하도록 했고 Bitmap 또한 Object Pool 관리를 통해 최소한의 객체 생성을 유도시켜 메모리 관리를 하도록 했다.


10. mouseChildren, mouseEnabled, tabChildren과 같은 속성은 왠만하면 false로 지정하자.
이러한 속성들이 필요없는 곳에 사용되면 오히려 퍼포먼스에 악영향을 준다. 정말 필요한곳에만 사용하는 것이 좋다. 이들 속성의 의미를 파악해두는 것이 중요하다.


11. cacheAsBitmap은 이동에만 사용하자.
cacheAsBitmap은 확대,축소,회전,Alpha값 변경되는 곳에는 사용하지 않는 편이 좋다.
다음 글을 참고하자.

왜 cacheAsBitmap은 나쁜가? http://www.bytearray.org/?p=290


12. 동적언어의 장점을 충분히 살리자.
동적언어와 정적언어의 차이점은 메모리를 사용하는 차이점에서 비롯된다. 실행하는 시점에 초기에 메모리를 확보해서 사용하는 언어는 정적이다라고 하며 거대한 메모리를 먼저 잡아놓고 실행하는 시점에 메모리를 자유롭게 사용하는 것은 동적언어이다. ActionScript 는 동적언어이기 때문에 중간중간에 실행도중 클래스 정의, 함수를 추가/수정/삭제가 가능하다. 이에서 나온 개념이 클로저라는 것인데 이 개념을 잘 이용하면 코딩이 훨씬 간편하고 편리해질 경우가 많다. Flex의 대부분 코딩 방법은 정적언어처럼 되어 있는데 사실 ActionScript는 동적언어이므로 이를 더 잘 사용해서 만들어져야 한다고 생각한다. 

Closure에 대해 : http://diebuster.com/flash/82


추가사항

13. package 격리원칙
클래스 격리에 대해서는 들어봤을 것이다. 클래스내 함수에 public, private를 적절하게 잘 사용해서 외부에 노출되는 메소드는 3~4개정도로 하고 내부 동작방식을 몰라도 클래스를 쉽게 이해할 수 있도록 하는데 필요한 개념이다. 이는 사용하는 관점도 그렇고 상속받는 관점에서도 마찬가지로 적용되도록 한다.

패키지 격리라는 것은 internal을 적극활용한다는 의미이다. 아마도 많은 개발자들이 internal의 강력함을 잘 인지하지 못할것이다. 이에 대해서는 내가 굳이 설명할 필요 없다. 다음글을 보자.

플래시 애플리케이션 개발하기 : http://diebuster.com/flash/86


14. 적절한 코딩규칙
개발하는데 코딩규칙은 무엇보다 중요하다. 가령 클래스 private 변수에는 _을 붙힌다던지 const값은 대문자로 표시한다던지 그런것 말이다. ActionScript 3.0에서 코딩규칙은 더욱 상세화 되면 좋다. 왜냐하면 워낙 동적인데다가 다른 언어에 비해서 명확한 컴파일 단계의 문법체크가 약하기 때문이다.

hika님의 2009년도 코딩 규칙을 잠깐 보자. http://diebuster.com/flash/3 

나는 처음에 클래스에 C, 정적클래스에 CS를 붙이는 의도에 대해서 잘 이해할 수 없었다. 하지만 이에 대한 강력함은 개발해보면 안다. 나는 클래스에 C, 정적클래스에 S, 인자객체는 A, internal 클래스는 앞에 _, 어떤 클래스의 Part라면 클래스명뒤에 _파트명 이런식으로 클래스 이름 규칙을 정했다. 실제로 이렇게 관리하면 클래스가 정확히 어떤 역할을 하는지 눈에 팍 들어온다. 함수를 인자로 받아야하는 경우 FN_intNumberString_Boolean:Function 과 같이 쓰면 이 인자로 들어올 함수는 반드시 function( a:int, b:Number, c:String):Boolean 형태로 만들어야 된다. 이런 규칙은 코딩시 코드힌트기능에도 표시되기 때문에 사용하면 정말 편리하다.

반복구문에 대해 : http://diebuster.com/flash/?s=%EB%B0%98%EB%B3%B5%EA%B5%AC%EB%AC%B8&submit=

결국 코딩규칙을 사용하는 명확한 의미는 한눈에 코드를 파악하고자 하는 의도에서 찾아야 한다.


정리하며
앞서 말했지만 타임라인 개발하는데 많은 도움을 주신 분을 꼽자면 hika님이다. 부족하지만 이 분의 도움으로 나는 스킬업을 할 수 있었다. 사실 hika님 입장에서는 이런 외부활동과 저술활동이 없어도 부족함이 없어보인다. 하지만 그의 공유정신 때문에 개발에 입문하는 많은 사람들에게 큰 도움이 되는 것은 사실이다. 이 글을 통해 감사하다고 전하고 싶다.

글쓴이 : 지돌스타(http://blog.jidolstar.com/661)



제가 ACP(Adobe Community Professional)가 되었습니다.
이로써 Adobe 공인 전문가 그룹에 등록 되었습니다.

http://lizfrederick.blogspot.com/2010/01/new-acps-for-2010.html

국적과 상관없이 약 300명 정도가 등록되었습니다. 분류로는 Acrobat, AfterEffect, AIR, Authorware, Captivate, ColdFusion, Creative Suite, Dreamweaver, Fireworks, Flash Media Server, Flash Mobile, Flash Platform, Flash Platform(RIA), Flash Professional, Flex, FrameMaker, Illustrator, InDesign, InDesign Server, Lightroom, LiveCycle ES, Photoshop, PhotoShop Elements, Premiere Pro, Production Premium, RoboHelp, Spry, Visual Communicator등이 있고 저는 Flash Platform(RIA) 분야로 등록되었네요.

저는 모르고 있었는데 우야꼬가 전화로 축하해주더군요. ^^;
메일을 보니까 한국 어도비로부터 축하 메일이 왔더군요.
저 외에 한국에서 ACP로 선정된 분들입니다.

강성규(땡굴이)
이정웅(블루메탈)
이준하(열이아빠)
배준균

ACP 후보 추천시 저에 대해서 작성된 내용입니다. (물론 영어로 번역되었겠죠...)

Flash Platform 기술에 대해 큰 관심을 가지고 있으며 그 기술에 대해 한국어 블로그(http://blog.jidolstar.com)를 운영하고 있다. 한국 어도비 RIA 홈페이지에 분기별로 기술문서를 기고하고 있다. 또한 ACC로써 Flash Platform 기술 전도사로 활동하고 있다(http://adoberia.co.kr/acc/acc.html). 한국어 Flex문서가 없다. 그래서 그는 flexdocs.kr 이라는 사이트를 구축했다. 그는 회사에서 Flash 개발팀장으로 근무하고 있으며 한국 SNS인 Starpl에 Flash 기술을 적용하는데 일조했다(http://starpl.com).

여러가지로 부족한데 선정해준 Adobe사에 감사하며 이름에 걸맞게 열심히 활동하고 실력도 쌓아가도록 노력하겠습니다.

글쓴이 : 지돌스타(http://blog.jidolstar.com)


"Flash로 못할 것이 없다."라는 말을 들어보셨나요? 이번에 소개하는 것은 beautifl.net에 올라온 Flash 코드중 개인적으로 자극을 받은 것만 선정해본 것들입니다. wonderfl.net에 올라온 것들이기 때문에 코드도 공개되어 있어 언제든지 분석도 할 수 있습니다. Flash의 세계를 만끽해보세요.

보러가기 : http://opencast.naver.com/FL188/16

글쓴이 : 지돌스타(http://blog.jidolstar.com/646)


Flash 애플리케이션을 만들때  통합개발환경(IDE)인 Flash CS3, CS4 나 Flex Builder, Flash Builder, FDT와 같은 툴을 주로 사용할 것이다. 실무에서는 당연히 이런 툴을 선택할 수 밖에 없다. 그러나 이들은 사실 유료이고 무겁다.

Flash MiniBuilder라는 프로그램은 간단하게 ActionScript 3.0 기반으로 개발할 수 있도록 Adobe AIR로 만들어진 가벼운 개발툴이다. 이것은 Victor Drâmbă라는 사람이 만들었으며 그의 블로그(http://www.victordramba.com)를 가보면 MiniBuilder에 대한 소식을 볼 수 있다.

MiniBuilder는 Flex SDK 3와 Java JRE 설치를 먼저 해야 정상적으로 사용할 수 있으며 사용하는 방법은 다음 동영상에서 잘 나와있다. 약간 복잡해 보이지만 중간에 start.bat를 실행해야하는 번거로움은 AIR 2.0에서는 없어질 것이라 생각한다.
http://www.youtube.com/watch?v=bjEc2eT_rCE&feature=player_embedded


이 프로그램은 Flex SDK에서 제공하는 컴파일러를 이용해서 만들어진 ActionScript 3.0코드를 컴파일하게 된다. 워낙 가볍기 때문에 Flash Builder에서 느껴지는 묵직함은 찾아볼 수 없다. 일반적인 코딩도 별 어려움이 없고 또한 코드힌트기능 및 에러메시지 출력 기능도 있기 때문에 이 또한 유용하다. 아쉬운 점은 디버깅을 할 수 없고 한글 주석도 못단다는 점.

MiniBuilder는 공개소스이다. GPL 라이센스를 가지며 Google Code(http://code.google.com/p/minibuilder/)에서 전반적인 설명과 소스코드를 볼 수 있다. 원한다면 Flex Builder 3나 Flash Builder 4에서 SVN으로 다운로드 받아 직접 소스를 테스트해볼 수도 있다. (본인도 SVN으로 다운받아 해봤다. 자바소스까지 포함되어 있으므로 Eclipse+Flex Builder 3 Plug-in 환경에서 작업할 것을 권한다. MXML 사용 안하고 전부 ActionScript 3.0으로 만들었다.)



MiniBuilder는 AIR뿐 아니라 Flash버전으로도 제작되어 유명한 ActionScript 3.0 코드 공유사이트인 Wonderfl의 에디터로도 활용되었다. 다음 제작자의 글을 보면 그에 대한 소개가 나와있다.
http://www.victordramba.com/?p=71



벌써 이것이 만들어져 소개된지 몇개월 되었는데 이렇게 멋진 공개 프로그램이 한국에 소개된게 딱 하나밖에 못본 것 같아 간단하게 소개해본다.

참고 링크
Victor Drâmbă의 블로그 : http://www.victordramba.com
Flash MiniBuilder Google Code : http://code.google.com/p/minibuilder
설치 및 사용방법 : http://www.youtube.com/watch?v=bjEc2eT_rCE&feature=player_embedded


글쓴이 : 지돌스타(http://blog.jidolstar.com/642)

로컬자원을 서버에 전송하기 위해 우리는 FileReference Class를 사용하면 된다.
FileReference로 파일을 서버에 전송하는 방법은 많이 공개가 되어 있다.
알다시피 FileReference의 browse()함수를 호출한 뒤, select 이벤트가 발생시 upload() 함수를 이용하여 선택한 로컬자원을 서버로 보낸다.

서버에서는 아주 단순하게 서버 임시 저장소에 저장된 파일을 원하는 곳에 복사하기만 하면 된다.
php의 경우 move_uploaded_file() 메소드를 사용하면 되겠다.

그럼 Flex 시행도중 캡쳐한 화면을 저장하는 경우에도 위와 같은 방법으로 저장이 가능할까?

답은 "된다"


나는 예전에 ImageSnapshot 클래스를 이용해 base64로 변환해서 서버로 전송한 뒤에 base64를 decode하여 저장하는 방법에 대해서 언급한적이 있다. (http://blog.jidolstar.com/301 참고)
이 방법의 단점은 이미지가 큰 경우 base64로 encode, decode 하는 과정에서 서버성능 및 클라이언트 성능에 따라 속도 및 부하에 영향을 준다. 그러므로 이 방법으로는 PNGEncoder 및 JPGEncoder로 PNG, JPG 파일 형식에 맞는 데이타를 만들었다고 해도, FileReference와 같이 데이타를 전송을 할 수 없었다.

하지만 Google을 열심히 돌아다녔다니 이 문제점에 대한 해결의 실마리를 찾을 수 있었다.
(역시 Google!!!)

간단히 방법을 요약하자면
화면을 BitmapData로 만들어 PNGEncoder나 JPGEncoder를 이용하여 encode한 다음, 그 결과값인 byteArray값을 서버에 전송한다. 전송된 데이타는 FileReference에서 upload()을 이용해 보낸 파일을 저장할때와 동일하게 저장하면 되겠다.

1. BitmapData로 캡쳐해라.

아래 target은 캡쳐할 UIComponent와 같은 DisplayObject 객체이다.

BitmapData로 캡쳐
var bitmapData:BitmapData = new BitmapData(target.width, target.height, true, 0xFFFFFF);
var drawingRectangle:Rectanglenew Rectangle(0, 0, target.width, target.height);
bitmapData.draw(target, new Matrix(), null, null, drawingRectangle, false);

단, BitmapData를 이용해서 화면을 캡쳐할 대상이 외부 동영상이나 사진같은 거라면 crossdomain.xml 에 대한 check가 있어야 한다. 컨텐츠 로드시 checkPolicyFile 속성을  true로 설정할 필요가 있겠다.
그리고 2880px 이상의 크기는 BitmapData로 만들 수 없다.



2. JPG나 PNG로 Encode 하여 ByteArray를 얻는다.


Flex 3 SDK에는 mx.graphics.codec 패키지에 JPGEncoder와 PNGEncoder가 있다. 인터넷을 뒤져보면 GIFEncoder등도 있을것이다. Flex 2 환경에서 작업한다면 Google code에 Adobe AS3 Corelib에 이들이 제공된다. 만약 JPGEncoder를 사용한다면 다음과 같이 하면 되겠다.

JPGEncoder를 이용하여  JPG  ByteArray값 만들기
import mx.graphics.codec.JPGEncoder;

var byteArray:ByteArray = new JPGEncoder().encode(bitmapData);


Flex 3 SDK는 이러한 Encoder가 IImageEncoder로 구현되었다. 필요하다면 언제 어디서나 Encoder를 바꿔야 하는 경우 IImageEncoder를 사용하는 것이 좋을 수 있겠다.
가령 아래 예제처럼 말이다.

다양한 Image Encoder 사용하기
import mx.graphics.codec.*;

var imageType:String = "jpg";
var imageEncoder:IImageEncoder;
if( imageType.toUpperCase() == "JPG" ) imageEncoder= new JPEGEncoder();
else if( imageType.toUpperCase() == "PNG" ) imageEncoder= new PNGEncoder();
var byteArray:ByteArray = imageEncoder.encode(bitmapData);



 

3. 서버에 ByteArray를 전송한다.

데이타를 전송할때는 FileReference를 사용하지 않는다.
바로 URLLoader와 URLRequest만 이용해서 전송이 가능하다. 참고 데이타는 POST방식으로 URLVariable을 이용해서 보낼 수 있다.

Flex/AIR 데이터 전송 방법
//assumed variable declarations
//var byteArray:ByteArray = 2번째 단계에서 JPG 데이타를 얻었다.
//var fileName:String = "desiredfilename.jpg" //저장할 파일 이름이다. 아무거나 적자!
//var uploadPath:String = "저장할 때 사용되는 서버측 script 경로"
//var parameters:URLVariables = 이미지 이외에 다른 보낼 다른 데이타가 있다면 이것을 이용한다.
//function onComplete(eventObj:Event):void {  성공적으로 데이타를 전송했을때 핸들러 함수 정의
//function onError(eventObj:ErrorEvent):void {  이미지 전송을 실패했을때 핸들러 함수 정의

var urlRequest:URLRequest = new URLRequest();
urlRequest.url = uploadPath;
//urlRequest.contentType = 'multipart/form-data; boundary=' + UploadPostHelper.getBoundary();
urlRequest.method = URLRequestMethod.POST;
urlRequest.data = UploadPostHelper.getPostData(file, byteArray, parameters);
urlRequest.requestHeaders.push( new URLRequestHeader( 'Cache-Control', 'no-cache' ) );
urlRequest.requestHeaders.push( new URLRequestHeader( 'Content-Type', 'multipart/form-data; boundary=' +UploadPostHelper.getBoundary()) );

var urlLoader:URLLoader = new URLLoader();
urlLoader.dataFormat = URLLoaderDataFormat.BINARY;
urlLoader.addEventListener(Event.COMPLETE, onComplete);
urlLoader.addEventListener(IOErrorEvent.IO_ERROR, onError);
urlLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onError);
urlLoader.load(urlRequest);


위에 진한 부분에 대한 클래스는 아래에 정의되어 있다. 당신은 이 클래스가 어떻게 구성되었는가 열심히 공부할 필요가 없다.(원한다면 해도 된다. 말리지 않음 ^^)

UploadPostHelper Class (Language : java)
package {

    import flash.events.*;
    import flash.net.*;
    import flash.utils.ByteArray;
    import flash.utils.Endian;

    /**
     * Take a fileName, byteArray, and parameters object as input and return ByteArray post data suitable for a UrlRequest as output
     *
     * @see http://marstonstudio.com/?p=36
     * @see http://www.w3.org/TR/html4/interact/forms.html
     * @see http://www.jooce.com/blog/?p=143
     * @see http://www.jooce.com/blog/wp%2Dcontent/uploads/2007/06/uploadFile.txt
     * @see http://blog.je2050.de/2006/05/01/save-bytearray-to-file-with-php/
     *
     * @author Jonathan Marston
     * @version 2007.08.19
     *
     * This work is licensed under a Creative Commons Attribution NonCommercial ShareAlike 3.0 License.
     * @see http://creativecommons.org/licenses/by-nc-sa/3.0/
     *
     */

    public class UploadPostHelper {

        /**
         * Boundary used to break up different parts of the http POST body
         */

        private static var _boundary:String = "";

        /**
         * Get the boundary for the post.
         * Must be passed as part of the contentType of the UrlRequest
         */

        public static function getBoundary():String {

            if(_boundary.length == 0) {
                for (var i:int = 0; i < 0x20; i++ ) {
                    _boundary += String.fromCharCode( int( 97 + Math.random() * 25 ) );
                }
            }

            return _boundary;
        }

        /**
         * Create post data to send in a UrlRequest
         */

        public static function getPostData(fileName:String, byteArray:ByteArray, parameters:Object = null):ByteArray {

            var i: int;
            var bytes:String;

            var postData:ByteArray = new ByteArray();
            postData.endian = Endian.BIG_ENDIAN;

            //add Filename to parameters
            if(parameters == null) {
                parameters = new Object();
            }
            parameters.Filename = fileName;

            //add parameters to postData
            for(var name:String in parameters) {
                postData = BOUNDARY(postData);
                postData = LINEBREAK(postData);
                bytes = 'Content-Disposition: form-data; name="' + name + '"';
                for ( i = 0; i < bytes.length; i++ ) {
                    postData.writeByte( bytes.charCodeAt(i) );
                }
                postData = LINEBREAK(postData);
                postData = LINEBREAK(postData);
                postData.writeUTFBytes(parameters[name]);
                postData = LINEBREAK(postData);
            }

            //add Filedata to postData
            postData = BOUNDARY(postData);
            postData = LINEBREAK(postData);
            bytes = 'Content-Disposition: form-data; name="Filedata"; filename="';
            for ( i = 0; i < bytes.length; i++ ) {
                postData.writeByte( bytes.charCodeAt(i) );
            }
            postData.writeUTFBytes(fileName);
            postData = QUOTATIONMARK(postData);
            postData = LINEBREAK(postData);
            bytes = 'Content-Type: application/octet-stream';
            for ( i = 0; i < bytes.length; i++ ) {
                postData.writeByte( bytes.charCodeAt(i) );
            }
            postData = LINEBREAK(postData);
            postData = LINEBREAK(postData);
            postData.writeBytes(byteArray, 0, byteArray.length);
            postData = LINEBREAK(postData);

            //add upload filed to postData
            postData = LINEBREAK(postData);
            postData = BOUNDARY(postData);
            postData = LINEBREAK(postData);
            bytes = 'Content-Disposition: form-data; name="Upload"';
            for ( i = 0; i < bytes.length; i++ ) {
                postData.writeByte( bytes.charCodeAt(i) );
            }
            postData = LINEBREAK(postData);
            postData = LINEBREAK(postData);
            bytes = 'Submit Query';
            for ( i = 0; i < bytes.length; i++ ) {
                postData.writeByte( bytes.charCodeAt(i) );
            }
            postData = LINEBREAK(postData);

            //closing boundary
            postData = BOUNDARY(postData);
            postData = DOUBLEDASH(postData);

            return postData;
        }

        /**
         * Add a boundary to the PostData with leading doubledash
         */

        private static function BOUNDARY(p:ByteArray):ByteArray {
            var l:int = UploadPostHelper.getBoundary().length;

            p = DOUBLEDASH(p);
            for (var i:int = 0; i < l; i++ ) {
                p.writeByte( _boundary.charCodeAt( i ) );
            }
            return p;
        }

        /**
         * Add one linebreak
         */

        private static function LINEBREAK(p:ByteArray):ByteArray {
            p.writeShort(0x0d0a);
            return p;
        }

        /**
         * Add quotation mark
         */

        private static function QUOTATIONMARK(p:ByteArray):ByteArray {
            p.writeByte(0x22);
            return p;
        }

        /**
         * Add Double Dash
         */

        private static function DOUBLEDASH(p:ByteArray):ByteArray {
            p.writeShort(0x2d2d);
            return p;
        }

    }
}



한가지 중요한 정보를 언급하겠다.
URLLoader를 이용해 서버에 전송할때, 프로그램이 같은 도메인상에 있는 경우에는 보안문제가 없다. 하지만 다른 도메인에 위치한 서버로 이미지를 전송할때는 반드시 crossdomain.xml을 check해야한다.

1. Security.loadPolicyFile(http://다른도메인/crossdomain.xml); 를 URLLoader의 load()함수를 호출하기 전에 호출한다.

2. Flash Player 9.0.124.0 버전부터는 HTTP Header 보안취약점을 해결하기 위해서 cross domain 정책이 변경되었는데.... 서버측에 있는 crossdomain.xml에 allow-http-request-headers-from가 추가되어져야 한다. 이것은 HTTP 헤더 전송을 허용할지 결정해준다.

crossdomain.xml (Language : xml)
<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "http://www.adobe.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
      <allow-access-from domain="*.jidolstar.com" />
      <allow-http-request-headers-from domain="*.jidolstar.com" headers="*"/>
</cross-domain-policy>

위 처럼 서버측 crossdomain.xml에 allow-http-request-headers-from을 추가함으로 다른 도메인간에 HTTP 헤더 전송을 허용할 수 있다.

서로 다른 도메인에 SWF와 서버측 코드가 배치되어 있다면 반드시 이 사실을 숙지하길 바란다.


3. Flash Player 10에서는 사용자 인터렉션이 반드시 필요하다.

다음글을 참고하세요.

http://blog.jidolstar.com/411 


 

4. 서버측 코드 작성

만약 위 3번 코드에서 var parameters:URLVariables를 아래와 같이 작성했다고 하자.

URLVariables 설정 (Language : java)
var parameters:URLVariables = new URLVariables();
parameters.method = "id";
parameters.userId = "2000321";


그럼 PHP 코드로 아래와 같은 방법처럼 만들면 되겠다.(테스트는 안해봤음)

PHP 코드 예제 (Language : php)
<?php
$method = $_POST['method'];
$userId = $_POST['userId'];
$file_temp = $_FILES['Filedata']['tmp_name'];
$file_name = $_FILES['Filedata']['name'];
$file_size = $_FILES['Filedata']['size'];

if( $method == "id" )
{
  $movePath = "/home/myPath/images/$userId_$file_name";
}
else
{
  $movePath = "/home/myPath/images/time_".time()."_".$file_name;
}

move_uploaded_file($file_temp,$movePath);

echo "save Complete";
?>


마지막 save Comple 메시지를 받기 위해서는 Flex의 Complete 이벤트 발생시 아래와 같은 방법으로 받으면 되겠다. 이것을 알아내는데도 많이 힘들었다. 일종의 팁이다. ^^;

데이타 받기 (Language : java)
var loader:URLLoader = URLLoader(event.target);
var bytedata:ByteArray = loader.data;
var strData:String = bytedata.toString();
trace( strData)


실제 업무에도 잘 이용하고 있다.
이미지 에디터 등을 만들때 아주아주 유용한 자료가 될 것이다.

누가 예제 프로그램 만들어서 트랙백 걸어 주시면 고맙겠다.


자료 출처 
http://marstonstudio.com/2007/08/19/how-to-take-a-snapshot-of-a-flash-movie-and-automatically-upload-the-jpg-to-a-server-in-three-easy-steps/


지돌스타 블로그내 참고자료
 - ImageSnapshot 클래스에 대해 : http://blog.jidolstar.com/301
 - FileReference의 UploadCompleteData 이벤트 : http://blog.jidolstar.com/324
 - 동영상 캡쳐 방법 : http://blog.jidolstar.com/215


글쓴이 : 지돌스타(http://blog.jidolstar.com/352)

Adobe AIR는 다양한 OS(Windows, Mac, Linux)에 구동될 수 있는 애플리케이션을 만드는데 사용하는 일종의 Flash Platfom기술이다. Flash ActionScript 3.0이나 Ajax만으로도 AIR 애플리케이션을 만들 수 있기 때문에 기존에 웹개발자들이 다른 언어를 배우지 않고 일반 데스크탑용 애플리케이션을 만드는데 있어서 접근성이 좋다. 앞으로 AIR는 데스크탑뿐 아니라 모바일등과 같은 다양한 기기에도 적용될 예정이다.

하지만 AIR외에 다른 데스크탑용 애플리케이션과 비교해 그 적용범위가 아직까지 많은 부분 부족하고 복잡한 UI를 다루는데 있어서 성능문제가 걸릴 수 있다. 하지만 AIR 2.0 Beta 버전이 오픈된 것을 볼 수 있었듯이 계속 발전해나갈 것이다. 물론 성능면에서도 마찬가지 일 것이다. 그래도 약간은 부족하다. 기능은 그렇다 쳐도 지금의 성능을  개발자가 조금만 신경을 쓴다면  획기적으로 향상시킬 수 있다.

일전에 Reducing CPU usage in Adobe AIR라는 글을 보았다. 여기서는 매우 단순하고 쉬운 방법으로 framerate를 줄임으로서 CPU 사용율을 현격히 줄이는 방법을 소개하고 있다.

이 방법이 퍼포먼스를 올리기 위한 방법의 하나의 예시는 될 수 있지만 그 전부는 아니라는 점은 밝혀둔다.

(이 글을 완벽히 이해하기 위해서는 ActionScript 3.0과 AIR에 대한 전반적 이해가 요구됩니다.)

FrameRate를 줄임
Framerate를 줄임(Framerate throttling)은 애플리케이션의 휴면(idle)이 있을때 자원 사용을 줄여 퍼포먼스를 증가시키는 기술을 의미한다. 이를 구현하기 위해 ActionScript 3.0에서 매우 유용한 속성으로 Stage.frameRate가 있다. 이것을 이용하면 런타임시에 애플리케이션의 framerate를 변경시킬 수 있다. 

여기서 보여지는 예제는 Reducing CPU usage in Adobe AIR에서 소개한 글에 나온 예제를 조금더 실용적으로 만들었다.(실제로 실행해 볼 수 있도록) Flash Builder 4와 AIR 2.0 SDK를 설치한 사람들이라면 이 예제를 실제로 테스트 해볼 수 있다. 아래 순서대로 개발/테스트 환경을 구축하면 된다.

  • 만약 Flash Builder를 설치 안했다면 다음 링크를 통해 받으세요.
  • SDK와 Runtime을 다운로드 받습니다.
  • 다운받은 Runtime을 실행해 설치합니다.
  • (MS Windows의 경우)SDK는 압축을 풀고 그안에 있는 내용을 Flash builder가 설치된 sdks/4.0.0과 sdks/3.4.1 폴더에 각각 덮어씌웁니다. 제 경우는 C:\Program Files\Adobe\Adobe Flash Builder Plug-in Beta 2\sdks\4.0.0
  • Flash Builder를 실행합니다.
  • 메뉴에서 File > New > Flex Project를 선택합니다.
  • 프로젝트 이름을 적고 Application Type은 AIR를 선택합니다.
  • Next버튼을 두번 클릭후 Main Application file이름이 프로젝트명.mxml로 되어 있다면 Novice.as로 바꾸세요. 그리고 Finish 버튼을 누릅니다.
  • 아래 첫번째 초급 코드를 복사해서 Novice클래스를 열어 붙힙니다.
  • 디버그 모드로 테스트합니다.
  • 두번째, 세번째의 경우 만들어진 프로젝트의 소스폴더에 해당 클래스 이름으로 Class를 만듭니다. File > New > ActionScript Class를 선택한뒤 아래 소스를 복사해 붙여넣으면 되겠죠?
  • Package Explorer에 프로젝트명을 선택후 마우스 우클릭해서 컨텍스트 메뉴에서 Properties를 선택합니다.
  • 창이 뜨면 좌측 Flex Applications를 선택하고 오른쪽에 Add를 눌러 추가한 클래스(Intermediate.as, Expert.as)를 추가한뒤 OK를 합니다. Intermediate-app.xml과 Expert-app.xml이 자동 생성됩니다.
  • 이제 디버그 모드로 실행하면서 동작하는 형태를 학습하세요.
  • 아래 소스는 다음 링크에서 다운로드 받으셔도 됩니다.



  • 초급
    Framerate를 줄일때의 시점을 선택하는데 가장 쉽고 유용한 방법은 NativeApplication에서 Event.ACTIVATE 와 Event.DEACTIVATE 이벤트를 사용하는 것이다. AIR로 만들어진 빈윈도우를 선택해서 사용할때 CPU사용율이 1.8%라면 다른 윈도우를 선택해 그 윈도우의 CPU 사용율이 0.4%까지 떨여졌다고 한다. 또한 framerate를 0.01로 지정하면 0.2%까지 떨어진다고 한다. 이에 대한 예제는 다음과 같다. 예제가 이해하기 쉬우므로 따로 설명하지 않겠다.


    package {
    	import flash.desktop.NativeApplication;
    	import flash.display.NativeWindow;
    	import flash.display.NativeWindowInitOptions;
    	import flash.display.NativeWindowType;
    	import flash.display.Sprite;
    	import flash.display.StageAlign;
    	import flash.display.StageScaleMode;
    	import flash.events.Event;
    	import flash.text.TextField;
    	import flash.text.TextFieldAutoSize;
    	import flash.utils.getTimer;
    	
    	/**
    	 * CPU 사용 줄이기 예제 1 
    	 * @author Yongho, Ji
    	 * @since 2009.12.1
    	 * @see http://blog.jidolstar.com/622
    	 */ 
    	public class Novice extends Sprite {
    		private var __isActive:Boolean = false;
    		private var __window:NativeWindow;
    		private var __textField:TextField;
    		public function Novice() {
    			__init();
    			var options:NativeWindowInitOptions = new NativeWindowInitOptions();
    			options.type = NativeWindowType.UTILITY;
    			
    			__window = new NativeWindow(options);
    			__window.width = 200;
    			__window.height = 200;
    			__window.title = "Novice";
    			
    			__textField = new TextField();
    			__textField.autoSize = TextFieldAutoSize.LEFT;
    			__textField.text = "";
    			
    			__window.stage.scaleMode = StageScaleMode.NO_SCALE;
    			__window.stage.align = StageAlign.TOP_LEFT;
    			
    			__window.stage.addChild(__textField);
    			__window.activate();
    			__window.addEventListener(Event.CLOSING,__onClosing);
    		}
    		private function __init():void {
    			NativeApplication.nativeApplication.addEventListener(Event.ACTIVATE, __onActive );
    			NativeApplication.nativeApplication.addEventListener(Event.DEACTIVATE, __onDeactive );
    			stage.addEventListener(Event.ENTER_FRAME,__onEnterFrame);
    		}
    		private function __onActive($event:Event):void {
    			stage.frameRate = 50;
    			__isActive = true;
    		}
    		private function __onDeactive($event:Event):void {
    			stage.frameRate = 1;
    			__isActive = false;
    		}
    		private function __onEnterFrame($event:Event):void {
    			__textField.text =  "active:" + __isActive + " " + getTimer();
    		}
    		private function __onClosing($event:Event):void {
    			NativeApplication.nativeApplication.exit();
    		}
    	}
    }
    


    중급

    위의 예제보다 조금더 고급적으로 framerate를 조절할 필요가 있다. 가령, 마우스 휠 이벤트에 따라 스크롤이 되는 컨텐츠가 있는 경우가 그것인데 평소에는 작은 framerate를 유지하다가 스크롤시에 빠른 렌더링이 필요하므로 framerate를 올려주는 것이다. 구체적으로 MouseEvent.MOUSE_WHEEL이 발생시 framerate를 올려주고 Event.ENTER_FRAME 이벤트에서 스크롤링후 500ms이 지난 다음 다시 framerate를 줄이는 것이다. 이도 휴면(idle)상태에서 쓸데없이 렌더링되는 것을 방지하고 필요한 동작할 때만 빠른 렌더링을 요구하도록 함으로써 CPU 사용율을 줄여주는 것이다.

    package {
    	import flash.desktop.NativeApplication;
    	import flash.display.NativeWindow;
    	import flash.display.NativeWindowInitOptions;
    	import flash.display.NativeWindowType;
    	import flash.display.Sprite;
    	import flash.display.StageAlign;
    	import flash.display.StageScaleMode;
    	import flash.events.Event;
    	import flash.events.MouseEvent;
    	import flash.text.TextField;
    	import flash.text.TextFieldAutoSize;
    	import flash.utils.getTimer;
    	/**
    	 * CPU 사용 줄이기 예제 2 
    	 * @author Yongho, Ji
    	 * @since 2009.12.1
    	 * @see http://blog.jidolstar.com/622
    	 */ 
    	public class Intermediate extends Sprite {
    		private static const ACTIVE:int = 50;
    		private static const INACTIVE:int = 1;
    		private var __isActive:Boolean = false;
    		private var __isScrolling:Boolean = false;
    		private var __buffer:int;
    
    		private var __window:NativeWindow;
    		public function Intermediate() {
    			__init();
    			var options:NativeWindowInitOptions = new NativeWindowInitOptions();
    			options.type = NativeWindowType.UTILITY;
    			
    			__window = new NativeWindow(options);
    			__window.width = 200;
    			__window.height = 200;
    			__window.title = "Intermediate";
    			
    			var textField:TextField = new TextField();
    			textField.y = 20;
    			textField.width = 195;
    			textField.height = 175;
    			textField.multiline = true;
    			textField.wordWrap = true;
    			textField.border = true;
    			textField.borderColor = 0xff0000;
    			textField.text = "Adobe AIR는 다양한 OS(Windows, Mac, Linux)에 구동될 수 있는 애플리케이션을 만드는데 사용하는 일종의 Flash Platfom기술이다. Flash ActionScript 3.0이나 Ajax만으로도 AIR 애플리케이션을 만들 수 있기 때문에 기존에 웹개발자들이 다른 언어를 배우지 않고 일반 데스크탑용 애플리케이션을 만드는데 있어서 접근성이 좋다. 앞으로 AIR는 데스크탑뿐 아니라 모바일등과 같은 다양한 기기에도 적용될 예정이다.하지만 원천적으로 데스크탑용 애플리케이션과 비교해 그 적용범위가 아직까지 많은 부분 부족하고 복잡한 UI를 다루는데 있어서 성능문제가 걸릴 수 있다. 적용되는 범위는 AIR 2.0 Beta 버전이 오픈된 것을 볼 수 있었듯이 계속 발전해나갈 것이다. 또한 성능면에서도 마찬가지 일 것이다. 그래도 성능면에 있어서 개발자가 조금만 신경을 쓴다면 어떤 부분에 있어서 획기적으로 AIR 애플리케이션의 성능을 향상시킬 수 있다. 일전에 Reducing CPU usage in Adobe AIR라는 글을 보았다. 여기서는 매우 단순하고 쉬운 방법으로 framerate를 줄임으로서 CPU 사용율을 현격히 줄이는 방법을 소개하고 있다. ";
    
    			__window.stage.scaleMode = StageScaleMode.NO_SCALE;
    			__window.stage.align = StageAlign.TOP_LEFT;
    			
    			__window.stage.addChild(textField);
    			__window.activate();
    			__window.addEventListener(Event.CLOSING,__onClosing);
    		}
    		private function __init():void {
    			NativeApplication.nativeApplication.addEventListener(Event.ACTIVATE, __onActive );
    			NativeApplication.nativeApplication.addEventListener(Event.DEACTIVATE, __onDeactive );
    			stage.addEventListener(MouseEvent.MOUSE_WHEEL, __onMouseWheel, true);
    		}
    		private function __onActive($event:Event):void {
    			stage.frameRate = ACTIVE;
    			__isActive = true;
    			trace( "active" );
    		}
    		private function __onDeactive($event:Event):void {
    			stage.frameRate = INACTIVE;
    			__isActive = false;
    			trace( "deactive" );
    		}
    		private function __onMouseWheel($event:MouseEvent):void {
    			if( !__isActive ) {
    				if ( !__isScrolling ) {
    					stage.addEventListener(Event.ENTER_FRAME, __onEnterFrame, true);
    				}
    				stage.frameRate = ACTIVE;
    				__isScrolling = true;
    				__buffer = getTimer()+500;
    			}
    		}
    		private function __onEnterFrame($event:Event):void {
    			if( __buffer < getTimer() ) {
    				stage.frameRate = INACTIVE;
    				__isScrolling = false;
    			}
    		}
    		private function __onClosing($event:Event):void {
    			NativeApplication.nativeApplication.exit();
    		}
    	}
    }
    


    고급

    위에서 소개한 경우보다 약간더 어려운 주제로 넘어가보자. 먼저 창이 보이지 않을때와 보일때에 어떻게 처리할 것인가이다. 보이는 경우라면 일단 최소한의 framerate를 5로 주고 안보인다면 1로 준다. 이 경우는 MS Windows에서는 Tray Icon으로 바뀌며 창이 안보여질 때나 Mac에서 Dock으로만 표시될 필요가 있을때 사용될 수 있을 것이다. 굳이 보여지지 않는데 지나친 framerate를 줄 필요가 없기 때문이다. 평상시 Active한 상태에서는 24 framerate를 유지하지면 때에 따라서 부드럽게 운동하는 모습을 렌더링할 필요가 있을 때가 있다. 상태변화에 따라 Tweener 기능을 사용하는 경우가 그것인데 이때는 평소보다 framerate를 올려줄 필요가 있을 수 있다.

    아래 AIR 애플리케이션 소스코드는 두개의 버튼이 있다. 한개는 창의 visible을 false로 지정했다가 1초후 다시 true로 해주는 것이고 또 하나는 가상의 애니메이션이 있다고 가정하고 1초정도 여분을 둔다. 각 상태가 변할때마다 framerate를 Dubugging 시에 콘솔창에서 상태변화를 확인할 수 있도록 짜여있다.

    package {
    	import flash.desktop.NativeApplication;
    	import flash.display.NativeWindow;
    	import flash.display.NativeWindowInitOptions;
    	import flash.display.NativeWindowType;
    	import flash.display.Shape;
    	import flash.display.SimpleButton;
    	import flash.display.Sprite;
    	import flash.display.StageAlign;
    	import flash.display.StageScaleMode;
    	import flash.events.Event;
    	import flash.events.MouseEvent;
    	import flash.filters.BevelFilter;
    	import flash.text.TextField;
    	import flash.text.TextFormat;
    	import flash.utils.getTimer;
    	import flash.utils.setTimeout;
    	/**
    	 * CPU 사용 줄이기 예제 3 
    	 * @author Yongho, Ji
    	 * @since 2009.12.1
    	 * @see http://blog.jidolstar.com/622
    	 */ 
    	public class Expert extends Sprite {
    		public static const ANIMATING:int = 50;
    		public static const ACTIVE:int = 24;
    		public static const INACTIVE_VISIBLE:int = 5;
    		public static const INACTIVE_INVISIBLE:int = 1;
    		
    		private var __isActive:Boolean = false;
    		private var __isAnimating:Boolean = false;
    		private var __window:NativeWindow;
    		private var __buffer:int;
    		
    		public function Expert() {
    			__init();
    			var options:NativeWindowInitOptions = new NativeWindowInitOptions();
    			options.type = NativeWindowType.UTILITY;
    			
    			__window = new NativeWindow(options);
    			__window.width = 200;
    			__window.height = 200;
    			__window.title = "Expert";
    			
    			__window.stage.scaleMode = StageScaleMode.NO_SCALE;
    			__window.stage.align = StageAlign.TOP_LEFT;
    			
    			//창을 감추기 버튼 
    			var buttonSkin:Sprite = new Sprite;
    			buttonSkin.graphics.beginFill( 0xff0000, 1.0 );
    			buttonSkin.graphics.drawRect(0,0,100,50);
    			buttonSkin.graphics.endFill();
    			buttonSkin.filters = [new BevelFilter()];
    			var textFormat:TextFormat = new TextFormat();
    			textFormat.color = 0xffffff;
    			textFormat.align = "center";
    			var textField:TextField = new TextField();
    			textField.defaultTextFormat = textFormat;
    			textField.text = "창을 감추기(1초후에 나타남)";
    			textField.width = 100;
    			textField.multiline = true;
    			textField.wordWrap = true;
    			textField.y = buttonSkin.height/2 - textField.textHeight/2; 
    			buttonSkin.addChild( textField );
    			var button:SimpleButton = new SimpleButton(buttonSkin,buttonSkin,buttonSkin,buttonSkin);
    			button.addEventListener(MouseEvent.CLICK, __onHide );
    			__window.stage.addChild( button );
    			
    			//Animation 동작 시키기 버튼 
    			buttonSkin = new Sprite;
    			buttonSkin.graphics.beginFill( 0x0000ff, 1.0 );
    			buttonSkin.graphics.drawRect(0,0,100,50);
    			buttonSkin.graphics.endFill();
    			buttonSkin.filters = [new BevelFilter()];
    			textFormat = new TextFormat();
    			textFormat.color = 0xffffff;
    			textFormat.align = "center";
    			textField = new TextField();
    			textField.defaultTextFormat = textFormat;
    			textField.text = "동작시키기(1 second)";
    			textField.width = 100;
    			textField.multiline = true;
    			textField.wordWrap = true;
    			textField.y = buttonSkin.height/2 - textField.textHeight/2; 
    			buttonSkin.addChild( textField );
    			button= new SimpleButton(buttonSkin,buttonSkin,buttonSkin,buttonSkin);
    			button.y = 52;
    			button.addEventListener(MouseEvent.CLICK, __onAnimate );
    			__window.stage.addChild( button );			
    						
    			__window.activate();
    			__window.addEventListener(Event.CLOSING,__onClosing);
    		}
    		private function __init():void {
    			NativeApplication.nativeApplication.addEventListener(Event.ACTIVATE, __onActive );
    			NativeApplication.nativeApplication.addEventListener(Event.DEACTIVATE, __onDeactive );
    		}
    		private function setFrameRate( frameRate:Number ):void {
    			stage.frameRate = frameRate;
    			trace( frameRate );
    		}
    		private function animate($duration:int = 1000):void {
    			trace( "동작시작");
    			setFrameRate( 50 );
    			__buffer = getTimer() + $duration;
    			if(!__isAnimating) {
    				stage.addEventListener(Event.ENTER_FRAME,__onEnterFrame);
    			}
    		}
    		private function active():void {
    			if(!__isAnimating) {
    				setFrameRate( ACTIVE );	
    			} 
    			trace( "active " );
    		}
    		private function deactive():void {
    			if (!__isAnimating) {
    				setFrameRate( (__window.visible) ? INACTIVE_VISIBLE : INACTIVE_INVISIBLE );
    			}
    			trace( "deactive " );
    		}
    		private function show():void {
    			__window.visible = true;
    			active();
    		}
    		private function hide():void {
    			__window.visible = false;	
    			deactive();
    		}
    		private function __onActive($event:Event):void {
    			__isActive = true;
    			active();
    		}
    		private function __onDeactive($event:Event):void {
    			__isActive = false;
    			deactive();
    		}
    		private function __onEnterFrame($event:Event):void {
    			if( __buffer < getTimer() ) {
    				trace( "동작끝");
    				stage.removeEventListener(Event.ENTER_FRAME,__onEnterFrame);
    				__isAnimating = false;
    				if( __isActive ) {
    					active();
    				} else {
    					deactive();
    				}
    			}
    		}
    		private function __onHide($event:MouseEvent):void {
    			hide();
    			setTimeout(show,1000);
    		}
    		private function __onAnimate($event:MouseEvent):void {
    			animate( 1000 );
    		}
    		private function __onClosing($event:Event):void {
    			NativeApplication.nativeApplication.exit();
    		}
    	}
    }
    


    참고글
    Reducing CPU usage in Adobe AIR 
    [머드초보]시스템트레이아이콘(system tray icon) 예제


    글쓴이 : 지돌스타(http://blog.jidolstar.com/622)

    안녕하세요. 1개월간 http://flexdocs.kr개인적인 이유로 운영하지 못하다가 좋은 무료웹호스팅을 통해 다시 정상적으로 열었습니다. 무료 웹호스팅 계정은 http://000webhost.com으로 외국 서비스이고 몇몇 한국분들이 잘 사용하신다고 들어서 부랴부랴 다시 복구하게 되었습니다. 약간 단점이 있다면 외국 서비스인 만큼 밤시간대에 느릴 수 있다는 겁니다.

    단, 기존에 SVN으로 Flex 2문서를 수정하는 작업이 진행되었는데 이제 그 시스템을 사용할 수 없게 되었습니다. 사실 이제 더이상 필요성을 못느끼고 있는터라 이제 안정적으로 서비스를 운영하는데만 초점을 맞출 예정입니다. 호스팅서비스 회사에서 강제로 계정을 지우거나 망하지 않는 이상 flexdocs.kr은 살아있을 겁니다.

    이제 flexdocs로 공개적인 모임이나 문서 업데이트는 하지 않을 것이며 Flex한글문서에 목마름을 조금이나마 달래주는 그런 사이트로서의 명맥을 유지할 것이라 생각합니다.

    Flex 4도 나온 마당에 버젓한 Flex 4 한글문서가 나오길 간절히 바라는 마음입니다.

    관심가져주신 분들께 깊은 감사드립니다.

    글쓴이 : 지돌스타(http://blog.jidolstar.com)


    Flash, Flex, AIR 개발자들이 한권정도는 꼭 가지고 있을 만한 책이다. 이 책은 콜린 무크의 유명한 책인 Essential ActionScript 3.0을 지금도 업계에서 활발히 일하고 계신 유윤선, 송호철님이 번역한 책이다. ActionScript 3.0에 관한한 거의 바이블 수준이다. 시간될 때마다 쭉 훑어보며 느낀 거지만 ActionScript 3.0에 대한 전반적인 개념을 습득하는데 이만한 책이 없다고 생각된다. 

    Flash, Flex, AIR를 개발할 때 가장 기초가 되는 개념은 ActionScript 3.0이다. ActionScript 3.0에 대한 전반적인 개념 및 지식없이 Flex에 접근하다 보면 결국 한계를 느끼게 될 것이다. 왜냐하면 Flex 프레임워크가 모든 기능을 수행해 줄 수 있도록 만들어진 것은 아니기 때문이다. Flex는 프레임워크로서 가치가 있는 것이지 모든 기능을 Flex에서 찾으면 안된다. 또한 Flash로 개발할 때도 마찬가지 인데 타임라인만 의지하다가 뭔가 고급기술을 다뤄야할 필요가 있을때 ActionScript 3.0을 알아야 가능해진다. Flash든 Flex든 AIR든... Flash Platform 개발자가 접근할 수 있는 가장 기초가 되는 것은 결국 ActionScript 3.0이다. (예외적으로 AIR의 경우 Javascript로 만들 수 있는데 이는 컴파일러를 지원하는 차원이지 근간은 ActionScript 이다.)  

    이 책의 한가지 단점이라면 Flash Player 10 API에 해당하는 내용까지 다루지는 않고 있다. 이와 관련된 내용은 여전히 온라인의 ActionScript 3.0 라이브 독을 참고해야한다.

    글쓴이 : 지돌스타(http://blog.jidolstar.com/615

    프로그램상에 폰트를 포함할 때 다음과 같은 문장을 사용할 것이다.

    [Embed(source='C:/WINDOWS/Fonts/ARIAL.TTF', fontName = "MyFont", mimeType = "application/x-font-truetype")]
    private var font:Class;
    

    그런데 Flash Builder 4에서 작업할 때부터 위처럼 Embed한 폰트가 적용이 되지 않았다. 사용한 True Type 폰트는 언제나 테스트할때 문제없이 동작한 것이기 때문에 왜 안되는지 의문이 들었다. Flash Builder 4의 컴파일러인 mxmlc가 버그가 있거나 다른 설정이 추가되었나 싶었지만 그렇지 않았다. 그래서 열심히 구글링해봤더니 폰트를 Embed 처리할때 embedAsCFF 속성이 추가되었다는 것을 발견하고 아래처럼 테스트 코드를 작성해봤다.

    package {
    	import flash.display.Sprite;
    	import flash.text.TextField;
    	import flash.text.TextFormat;
    	import flash.text.TextFieldAutoSize;
    	import flash.text.AntiAliasType;
    	[SWF(width = "500", height = "240", backgroundColor = "#FFFFFF", framerate = "24")]
    	public class FontTest extends Sprite {
    		[Embed(source='C:/WINDOWS/Fonts/ARIAL.TTF', embedAsCFF="false", fontName = "MyFont", mimeType = "application/x-font-truetype")]
    		private var font:Class;
    		public function FontTest() {
    			var format:TextFormat = new TextFormat();
    			format.font = "MyFont";
    			format.size = 30;
    			format.color = 0x000000;
    			var label:TextField = new TextField();
    			label.embedFonts = true;
    			label.autoSize = TextFieldAutoSize.LEFT;
    			label.antiAliasType = AntiAliasType.ADVANCED;
    			label.defaultTextFormat = format;
    			label.text = "blog.jidolstar.com";
    			addChild(label);
    			label.rotation = 5;
    		}
    	}
    }
    


    여기서 embedAsCFF 속성은 도데체 뭔가? 이 전에 CFF(Compact Font Format)가 뭔지 알아야만 했다.

    폰트형태는 여러가지 종류가 있다. OTF(Open Type Font)와 TTF(True Type Font)등이 있다. OpenType은 MS와 Adobe가 TrueType의 후속작으로 Cross Platform을 지원하도록 만들 파일 포멧이라고 한다. 이 OpenType에는 Glyph Outline형식에 대한 정의는 없고 TrueType, CFF, Adobe Type 1(PostScript)를 사용한다고 한다. 이 말은 OTF중에는 TrueType으로 글자모양을 정의한 폰트도 있고 CFF 또는 PostScript Font로 정의한 폰트도 있음을 의미한다.
     
    OpenType과 TrueType에 대한 더욱 자세한 내용은 아래 링크를 참고하자.
    http://en.wikipedia.org/wiki/OpenType
    http://en.wikipedia.org/wiki/TrueType

    CFF는 OpenType의 하나로서 다음 링크에 더 세세하게 설명하고 있다.
    http://en.wikipedia.org/wiki/Compact_Font_Format#Compact_Font_Format

    CFF에 대한 스펙은 다음 파일을 참고한다.


    Flash Player 10과 Adobe AIR 1.5이상부터 TTF뿐 아니라 CFF도 지원하게 되었다. 이는 PDF와 직접적인 관계가 있는 것 같다.  그래서 폰트를 포함할때 TTF인지 CFF인지 명시할 필요에 의해 생긴 것이 embededAsCFF인듯하다. 만약 TTF를 사용한다면 위 예제처럼 embededAsCFF를 false로 지정해야한다.

    필자도 Font Type에 대한 지식은 거의 없어서 난감했다. CFF를 포함하면 글꼴 렌더링시에 텍스트를 보다 쉽게 읽을 수 있으며 작은 크기에서 글꼴의 표시 품질이 향상된다고 Adobe ActionScript 3.0 가이드 문서에는 나와 있을뿐 정확히 TTF와 CFF에 대한 명확한 해석을 찾지는 못했다.

    Adobe ActionScript 3.0 가이드 : 글꼴을 이용한 작업


    갑자기 대두된 Font 포함문제 때문에 매우 당혹스러웠지만 그나마 해결방법이라도 찾아 다행이다. 이에 대해 정확히 기술된 한글문서를 아직 찾지 못했다. 더욱 다양한 글들이 많이 올라왔으면 한다.

    이 실험은 Flash Builder 4 Beta 2에서 테스트 했으며 아래 링크로부터 Flash Builder 4를 다운받을 수 있다.
    http://www.adoberia.co.kr/pds/down.html?src=text&kw=000026



    글쓴이 : 지돌스타(http://blog.jidolstar.com/614)

    단지 25줄의 ActionScript 코드로 얼마나 멋진 애플리케이션을 만드는가 가리는 대회이다. 웹서핑하다가 우연치 않게 본 페이지에서 25줄이라고는 믿기지 않을 정도의 결과물들을 보고 이 세상에는 정말 천재들이 많구나라는 생각이 들었다.

     

    대회 규정 및 이전 대회 결과물들은 아래 홈페이지를 통해 볼 수 있다.

     

    http://www.25lines.com

     

    아래에서 소개하고 있는 ActionScript 결과물들은 2009년 1월 결승전에 올라온 작품들이다. 작품 하나하나마다 25줄의 코드라고는 믿기지 않는 작품들임을 볼 수 있을 것이다. 만든것도 대단하지만 창의적인 면에 있어서도 높은 점수를 주고 싶다.

     

    올라온 소스 코드를 분석해보려고 읽기 쉽게 정리하면서 봐도 이해못하는... ㅜㅜ

    언젠간.. 나도 저 대열에....

     

    Entry 001
    Code
    SWF

    Entry 002
    Code
    SWF

    Entry 007
    Code
    SWF

    Entry 008
    Code
    SWF

    Entry 009
    Code
    SWF

    Entry 014
    Code
    SWF

    Entry 021
    Code
    SWF

    Entry 023
    Code
    SWF

    Entry 027
    Code
    SWF

    Entry 029
    Code
    SWF

    Entry 030
    Code
    SWF

    Entry 032
    Code
    SWF

     

    글쓴이 : 지돌스타(http://blog.jidolstar.com)

    Flex 3에서 DataGrid의 Header부분의 Separator는 headerSeparatorSkin 스타일로 정의되어 있다. 화면은 Flex DataGrid에 Separator가 붙은 보통의 모습이다.

     

     

    위 프로그램은 아래와 같이 프로그래밍 한다.

    <?xml version="1.0" encoding="utf-8"?>
    <!-- http://blog.flexexamples.com/2009/03/20/removing-the-header-separator-on-the-datagrid-control-in-flex/ -->
    <mx:Application
    	name="DataGrid_headerSeparatorSkin_test"
    	xmlns:mx="http://www.adobe.com/2006/mxml"
    	backgroundColor="white" 
    	layout="vertical">
    	<mx:DataGrid id="dataGrid">
    		<mx:dataProvider>
    			<mx:ArrayCollection>
    				<mx:Object c1="1. One" c2="1. Two" c3="1. Three"/>
    				<mx:Object c1="1. One" c2="1. Two" c3="1. Three"/>
    				<mx:Object c1="1. One" c2="1. Two" c3="1. Three"/>
    				<mx:Object c1="1. One" c2="1. Two" c3="1. Three"/>
    				<mx:Object c1="1. One" c2="1. Two" c3="1. Three"/>
    				<mx:Object c1="1. One" c2="1. Two" c3="1. Three"/>
    			</mx:ArrayCollection>
    		</mx:dataProvider>
    	</mx:DataGrid>
    </mx:Application>
    
    

    만약 Separator를 지우고 싶다면 단순히 headerSeparatorSkin 에 mx.skins.ProgrammaticSkin으로 정의하면 된다. 아래는 실행화면과 소스코드이다. mx.skins.ProgrammaticSkin는 프로그램적으로 스킨을 만들 필요가 있을때 사용하는 클래스로 이 클래스 내부에서는 어떤 렌더링도 하지 않기 때문에 headerSeparatorSkin 을 이 클래스로 대체하는 것만으로도 Header의 separator를 삭제할 수 있는 것이다.

     

     

     

    <?xml version="1.0" encoding="utf-8"?>
    <!-- http://blog.flexexamples.com/2009/03/20/removing-the-header-separator-on-the-datagrid-control-in-flex/ -->
    <mx:Application
    	name="DataGrid_headerSeparatorSkin_test"
    	xmlns:mx="http://www.adobe.com/2006/mxml"
    	backgroundColor="white" 
    	layout="vertical">
    	<mx:DataGrid id="dataGrid" 
    		headerSeparatorSkin="mx.skins.ProgrammaticSkin">
    		<mx:dataProvider>
    			<mx:ArrayCollection>
    				<mx:Object c1="1. One" c2="1. Two" c3="1. Three"/>
    				<mx:Object c1="1. One" c2="1. Two" c3="1. Three"/>
    				<mx:Object c1="1. One" c2="1. Two" c3="1. Three"/>
    				<mx:Object c1="1. One" c2="1. Two" c3="1. Three"/>
    				<mx:Object c1="1. One" c2="1. Two" c3="1. Three"/>
    				<mx:Object c1="1. One" c2="1. Two" c3="1. Three"/>
    			</mx:ArrayCollection>
    		</mx:dataProvider>
    	</mx:DataGrid>
    </mx:Application>
    
    

     

    위 코드 대신 아래 코드처럼 <Style/> 블록이나 외부 .CSS 파일을 이용해서 headerSeparatorSkin의 스타일을 바꿀 수 있다.

     

     

    <?xml version="1.0" encoding="utf-8"?>
    <!-- http://blog.flexexamples.com/2009/03/20/removing-the-header-separator-on-the-datagrid-control-in-flex/ -->
    <mx:Application
    	name="DataGrid_headerSeparatorSkin_test"
    	xmlns:mx="http://www.adobe.com/2006/mxml"
    	backgroundColor="white" 
    	layout="vertical">
        <mx:Style>
            DataGrid {
                headerSeparatorSkin: ClassReference("mx.skins.ProgrammaticSkin");
            }
        </mx:Style>	
    	<mx:DataGrid id="dataGrid">
    		<mx:dataProvider>
    			<mx:ArrayCollection>
    				<mx:Object c1="1. One" c2="1. Two" c3="1. Three"/>
    				<mx:Object c1="1. One" c2="1. Two" c3="1. Three"/>
    				<mx:Object c1="1. One" c2="1. Two" c3="1. Three"/>
    				<mx:Object c1="1. One" c2="1. Two" c3="1. Three"/>
    				<mx:Object c1="1. One" c2="1. Two" c3="1. Three"/>
    				<mx:Object c1="1. One" c2="1. Two" c3="1. Three"/>
    			</mx:ArrayCollection>
    		</mx:dataProvider>
    	</mx:DataGrid>
    </mx:Application>
    

     

    또는 ActionScript 를 사용해 버튼을 누를때 동적으로 headerSeparatorSkin 스타일을 변경할 수 있도록 다음 코드처럼 만들 수 있다.

    <?xml version="1.0" encoding="utf-8"?>
    <!-- http://blog.flexexamples.com/2009/03/20/removing-the-header-separator-on-the-datagrid-control-in-flex/ -->
    <mx:Application
    	name="DataGrid_headerSeparatorSkin_test"
    	xmlns:mx="http://www.adobe.com/2006/mxml"
    	backgroundColor="white" 
    	layout="vertical">
        <mx:Script>
            <![CDATA[
                import mx.skins.ProgrammaticSkin;
    
                private function btn_click(evt:MouseEvent):void {
                    dataGrid.setStyle("headerSeparatorSkin", ProgrammaticSkin);
                }
            ]]>
        </mx:Script>
    
        <mx:Button id="btn"
                label="Set header separator skin"
                click="btn_click(event);" />
                
    	<mx:DataGrid id="dataGrid">
    		<mx:dataProvider>
    			<mx:ArrayCollection>
    				<mx:Object c1="1. One" c2="1. Two" c3="1. Three"/>
    				<mx:Object c1="1. One" c2="1. Two" c3="1. Three"/>
    				<mx:Object c1="1. One" c2="1. Two" c3="1. Three"/>
    				<mx:Object c1="1. One" c2="1. Two" c3="1. Three"/>
    				<mx:Object c1="1. One" c2="1. Two" c3="1. Three"/>
    				<mx:Object c1="1. One" c2="1. Two" c3="1. Three"/>
    			</mx:ArrayCollection>
    		</mx:dataProvider>
    	</mx:DataGrid>
    </mx:Application>
    
    

     

    좀더 파헤쳐보자.

     

    DataGrid에는 drawSeparators() 메소드가 protected로 지정되어 있다. 만약 DataGrid를 커스터마이징해서 Separator 그리는 방식을 바꾸고 싶다면 drawSeparators() 부터 찾아가면 된다. 아래 코드는 DataGrid의 drawSeparators() 메소드 정의이다

    /**
     *  Creates and displays the column header separators that the user 
     *  normally uses to resize columns.  This implementation uses
     *  the same Sprite as the lines and column backgrounds and adds
     *  instances of the headerSeparatorSkin and attaches mouse
     *  listeners to them in order to know when the user wants
     *  to resize a column.
     */
    protected function drawSeparators():void
    {
        DataGridHeader(header)._drawSeparators();
        if (lockedColumnHeader)
            DataGridHeader(lockedColumnHeader)._drawSeparators();
    }
    

     

    위 코드에서 볼 수 있듯이 결국 DataGridHeader에 정의된 _drawSeparators()쪽을 살펴봐야한다. 아래는 DataGridHeader의 _drawSeparators()와 drawSeparators() 부분이다.

    mx_internal function _drawSeparators():void
    {
        drawSeparators();
    }
    
    /**
     *  Creates and displays the column header separators that the user 
     *  normally uses to resize columns.  This implementation uses
     *  the same Sprite as the lines and column backgrounds and adds
     *  instances of the headerSeparatorSkin and attaches mouse
     *  listeners to them in order to know when the user wants
     *  to resize a column.
     */
    protected function drawSeparators():void
    {
        if (!separators)
            separators = [];
    
        var lines:UIComponent = UIComponent(getChildByName("lines"));
        
        if (!lines)
        {
            lines = new UIComponent();
            lines.name = "lines";
            addChild(lines); 
        }
        else
            setChildIndex(lines, numChildren - 1);
    
        // required to deal with some 2.x clipping behavior
        lines.scrollRect = new Rectangle(0, 0, unscaledWidth, unscaledHeight + 1);
    
        if (headerSepSkinChanged)
        {
            headerSepSkinChanged = false;
            clearSeparators();
        }
    
        var n:int = visibleColumns ? visibleColumns.length : 0;
        
        if (!needRightSeparator && n > 0)
        	n--;
        
        for (var i:int = 0; i < n; i++)
        {
            var sep:UIComponent;
            var sepSkin:IFlexDisplayObject;
            
            if (i < lines.numChildren)
            {
                sep = UIComponent(lines.getChildAt(i));
                sepSkin = IFlexDisplayObject(sep.getChildAt(0));
            }
            else
            {
                var headerSeparatorClass:Class =
                    getStyle("headerSeparatorSkin");
                sepSkin = new headerSeparatorClass();
                if (sepSkin is ISimpleStyleClient)
                    ISimpleStyleClient(sepSkin).styleName = this;
                sep = new UIComponent();
                sep.addChild(DisplayObject(sepSkin));
                lines.addChild(sep);
                
                separators.push(sep);
            }
            // if not separator
            if ( !(i == visibleColumns.length-1 && !needRightSeparatorEvents) )
            {
                DisplayObject(sep).addEventListener(
                    MouseEvent.MOUSE_OVER, columnResizeMouseOverHandler);
                DisplayObject(sep).addEventListener(
                    MouseEvent.MOUSE_OUT, columnResizeMouseOutHandler);
                DisplayObject(sep).addEventListener(
                    MouseEvent.MOUSE_DOWN, columnResizeMouseDownHandler);
            }
    		else
    		{
                // if not separator
                if ( (i == visibleColumns.length-1 && !needRightSeparatorEvents) )
                {
                    DisplayObject(sep).removeEventListener(
                        MouseEvent.MOUSE_OVER, columnResizeMouseOverHandler);
                    DisplayObject(sep).removeEventListener(
                        MouseEvent.MOUSE_OUT, columnResizeMouseOutHandler);
                    DisplayObject(sep).removeEventListener(
                        MouseEvent.MOUSE_DOWN, columnResizeMouseDownHandler);
                }
    		}
    
            var cols:Array = visibleColumns;
            if (!(cols && cols.length > 0 || dataGrid.headerVisible))
            {
                sep.visible = false;
                continue;
            }
    
            sep.visible = true;
            sep.x = headerItems[i].x +
                    visibleColumns[i].width - Math.round(sepSkin.measuredWidth / 2);
            if (i > 0)
            {
                sep.x = Math.max(sep.x,
                                 separators[i - 1].x + Math.round(sepSkin.measuredWidth / 2));
            }
            sep.y = 0;
            sepSkin.setActualSize(sepSkin.measuredWidth, Math.ceil(cachedHeaderHeight));
            
            // Draw invisible background for separator affordance
            sep.graphics.clear();
            sep.graphics.beginFill(0xFFFFFF, 0);
            sep.graphics.drawRect(-separatorAffordance, 0,
    							  sepSkin.measuredWidth + separatorAffordance,
    							  cachedHeaderHeight);
            sep.graphics.endFill();
    		sep.mouseEnabled = true;
        }
    
        while (lines.numChildren > n)
        {
            lines.removeChildAt(lines.numChildren - 1);
            separators.pop();
        }
    }
    

     

    DataGridHeader의 drawSeparators()에서 headerSeparatorSkin 스타일을 사용하는 것을 찾아볼 수 있다. 개발자는 이 부분을 커스터마이징할 수 있는 것이다.

     

    DataGrid나 DataGridHeader를 커스터마이징할 필요없이 스킨만 변경하고 싶다면 headerBackgroundSkin의 기본 스킨인 mx.skins.halo.DataGridHeaderSeparator를 커스터 마이징하거나 mx.skins.Programmatics를 확장해서 사용하면 되겠다. 아래코드는 DataGrid에서 headerBackgroundSkin이 Style로 정의된 것을 보여주고 있다.

    /**
     *  The class to use as the skin that defines the appearance of the  
     *  background of the column headers in a DataGrid control.
     *  @default mx.skins.halo.DataGridHeaderSeparator
     */
    [Style(name="headerBackgroundSkin", type="Class", inherit="no")]
    

     

     

    아래 코드는 mx.skins.halo.DataGridHeaderSeparator를 보여준다.

    ////////////////////////////////////////////////////////////////////////////////
    //
    //  ADOBE SYSTEMS INCORPORATED
    //  Copyright 2005-2007 Adobe Systems Incorporated
    //  All Rights Reserved.
    //
    //  NOTICE: Adobe permits you to use, modify, and distribute this file
    //  in accordance with the terms of the license agreement accompanying it.
    //
    ////////////////////////////////////////////////////////////////////////////////
    
    package mx.skins.halo
    {
    
    import flash.display.Graphics;
    import mx.skins.ProgrammaticSkin;
    
    /**
     *  The skin for the separator between column headers in a DataGrid.
     */
    public class DataGridHeaderSeparator extends ProgrammaticSkin
    {
    	include "../../core/Version.as";
    
    	//--------------------------------------------------------------------------
    	//
    	//  Constructor
    	//
    	//--------------------------------------------------------------------------
    
    	/**
    	 *  Constructor.
    	 */
    	public function DataGridHeaderSeparator()
    	{
    		super();
    	}
    	
    	//--------------------------------------------------------------------------
    	//
    	//  Overridden properties
    	//
    	//--------------------------------------------------------------------------
    
    	//----------------------------------
    	//  measuredWidth
    	//----------------------------------
    	
    	/**
    	 *  @private
    	 */
    	override public function get measuredWidth():Number
    	{
    		return 2;
    	}
    	
    	//----------------------------------
    	//  measuredHeight
    	//----------------------------------
    
    	/**
    	 *  @private
    	 */
    	override public function get measuredHeight():Number
    	{
    		return 10;
    	}
    	
    	//--------------------------------------------------------------------------
    	//
    	//  Overridden methods
    	//
    	//--------------------------------------------------------------------------
    
    	/**
    	 *  @private
    	 */
    	override protected function updateDisplayList(w:Number, h:Number):void
    	{
    		super.updateDisplayList(w, h);
    		var g:Graphics = graphics;
    		
    		g.clear();
    		
    		// Highlight
    		g.lineStyle(1, 0xFFFFFF, 0.5);
    		g.moveTo(0, 0);
    		g.lineTo(0, h);
    		g.lineStyle(1, getStyle("borderColor")); 
    		g.moveTo(1, 0);
    		g.lineTo(1, h);
    	}
    
    }
    
    }
    

     

    이외로 단순해서 놀랬는가? 결국 이 스킨은 borderColor 스타일로 지정된 색으로 구분자 선만 그어준다. 나는 이것을 바꿔서 실선을 점선을 그리도록 해보겠다. 아래 코드는 이를 구현한 DataGridHeaderDotSeparator 클래스이다.

     

    package
    {
    import flash.display.Graphics;
    
    import mx.skins.halo.DataGridHeaderSeparator;
    
    /**
     * DataGrid Header에 점선을 그린다.
     */ 
    public class DataGridHeaderDotSeparator extends DataGridHeaderSeparator
    {
    	/**
    	 *  Constructor.
    	 */		
    	public function DataGridHeaderDotSeparator()
    	{
    		super();
    	}
    	
    	/**
    	 *  @private
    	 */		
    	override protected function updateDisplayList(w:Number, h:Number):void
    	{
    		var g:Graphics = graphics;
    		
    		g.clear();
    		
    		
    		g.lineStyle(1, getStyle("borderColor"), 1); 
    		var i:int;
    		for( i = 0; i < h; i+=4 )
    		{
    			g.drawCircle( 1.5, i, 0.5 );
    		}
    	}		
    }
    }
    

     

     

    아래 코드는 DataGridHeaderDotSeparator 스킨을 사용하는 예제이다.

    <?xml version="1.0" encoding="utf-8"?>
    <!-- http://blog.flexexamples.com/2009/03/20/removing-the-header-separator-on-the-datagrid-control-in-flex/ -->
    <mx:Application
    	name="DataGrid_headerSeparatorSkin_test"
    	xmlns:mx="http://www.adobe.com/2006/mxml"
    	backgroundColor="white" 
    	layout="vertical">
    	<mx:DataGrid id="dataGrid"
    		headerSeparatorSkin="DataGridHeaderDotSeparator">
    		<mx:dataProvider>
    			<mx:ArrayCollection>
    				<mx:Object c1="1. One" c2="1. Two" c3="1. Three"/>
    				<mx:Object c1="1. One" c2="1. Two" c3="1. Three"/>
    				<mx:Object c1="1. One" c2="1. Two" c3="1. Three"/>
    				<mx:Object c1="1. One" c2="1. Two" c3="1. Three"/>
    				<mx:Object c1="1. One" c2="1. Two" c3="1. Three"/>
    				<mx:Object c1="1. One" c2="1. Two" c3="1. Three"/>
    			</mx:ArrayCollection>
    		</mx:dataProvider>
    	</mx:DataGrid>
    </mx:Application>
    
    

     

    아래는 위 코드를 실행한 화면이다. Header부분에 구분자(Separator)가 점선으로 되었다. 좀 뭉뚝하지만 그냥 예제일 뿐이니깐 넘어가자. ^^;

     

     

    Flex는 이처럼 프로그램적으로 스킨을 변경할 수 있다. 물론 이미지를 이용하는 방법도 있다. 이와 같은 방법으로 스킨을 변경하는 것은 Flex의 모든 컴포넌트에서 지원하므로 이런 스킬에 익숙해질 필요가 있겠다.

     

    원본 예제 : Removing the header separator on the DataGrid control in Flex

     

    주절주절 : 그냥 이렇게 가볍게 포스팅하는 것이 좋을 것 같다는 생각이 든다.

     

    글쓴이 : 지돌스타(http://blog.jidolstar.com/546)

     

    저번주 2009년 5월 23일 서울 서초동 비트컴퓨터 멀티미디어관 지하 2층에서 OKGosu.net 세미나가 있었습니다. 저는 "스타플(starpl.com) 서비스에 이용된 Flex 기술" 이라는 제목으로 발표를 했습니다.

     

    스타플 홍보도 하고 싶고 함께 기술도 공유하고 싶어서 그랬는지 주제 자체가 너무 커져서 많은 것을 전달하지 못해 약간 아쉬움이 남는 시간이였던 것 같습니다.

     

    이번 세미나로 제가 말씀드리고 싶었던 것은 아래 내용이였습니다.

     

    1. 스타플 소개

    2. Flex를 도입할 때 고려해야할 사항

    3. 개발 방법 소개

    4. 모듈 개발시 최적화 방법

    5. Flex 학습방법

     

    한가지만 해도 30분 이상씩 잡아야 제대로 설명이 가능한 건데 너무 많은 주제를 놓고 이 모든 것은 40분 내에 말할려고 했네요. ^^;;

     

    약간 보충해서 설명드릴께요.

     

    1. 스타플 소개

    스타플 구경을 못드렸네요. http://starpl.com 에 가시면 구경하실 수 있답니다.

    홍보 동영상을 다시한번 보고 싶으시다면 "홍보영상보기"를 눌러주세요.

    스타플에 대해서 더 알고 싶다면 제 블로그에서 스타플로 검색해보세요.

     

    2. Flex를 도입할 때 고려해야할 사항

    발표시 말씀드렸던 것은 Flex/Flash 중 도입 선택에 대한 문제였습니다. 어떤 경우에는 Flex를 도입하는 것이 맞는 반면 경우에 따라서는 Flex를 쓰는 것이 오히려 문제가 될 수 있습니다. 가령, Flex Framework에서 제공하는 컴포넌트를 거의 사용하지 않는데 Flex를 도입하는 것은 무리입니다. 또한 Flex를 도입하면 쉽게 해결될 것을 Flash로 만들면 그것 또한 문제지요. 이 점을 잘 생각하시고 선택하시길 바래요.

     

    3. 개발 방법 소개

    제 개인적인 개발 방법을 소개했습니다.

    분석-설계-제작-테스트-배포 형태로 된다는 것을 설명드렸죠.

    말씀 드리고 싶었던 것은 "기획자, 디자이너간에 커뮤니케이션 중요하다. 서로 존중하면서 대화에 임하라."라는 것과 제작환경 구성시 "ANT, SVN은 꼭 잘 활용해라"라는 것이였습니다. 더불어 통신관련 도식화와 애플리케이션 도식화, 그리고 UML 제작을 개발하기 전에 꼭 해보라는 것이였습니다. 이러한 작업은 앞으로 문서화에도 도움이 되며 다른 사람에게 인수인계할때도 좋고요. 나중에 그 프로그램을 다시 보더라도 내가 짠 것 내가 이해 못하는 꼴이 발생하지 않습니다. ^^

     

    4. 모듈 개발시 최적화 방법

    SWF가 다른 SWF를 로드하고 Class를 서로 참조하는 일이 발생하는 개발을 하게 되면 모듈 프로그래밍을 한다고 할 수 있습니다. 중요한 것은 다른 SWF간에 정의된 Class중복을 어떻게 해결할 것인가였습니다. 중복 자체가 크게 문제를 일으키는 것은 아니지만 필요없는 Class를 가지고 있기 때문에 프로그램 용량이 그만큼 커집니다. 그래서 중복된 Class를 없애기 위해 RSL도 이용해보고 mxmlc 컴파일러 옵션에 -include-libraries, -load-externs, -link-report 등의 옵션을 사용하는 예도 보여드렸습니다.

     

    Main애플리케이션과 모듈이 서로 같은 Class를 담고 있는 경우 그대로 로드하면 어느 한쪽의 클래스를 사용하게 되겠지요. 이때 중요한 개념이 ApplicationDomain인데 제가 이 설명을 빠뜨렸습니다.

     

    이 이야기는 다음 링크를 참고하세요.

    Flex 모듈 프로그래밍의 기초 - Application domain의 이해 1부

    Flex 모듈 프로그래밍의 기초 - Application domain의 이해 2부

     

     

    5. Flex 학습법

    이 부분은 시간관계상 설명 못드렸네요.

    어떻게 보면 매우 중요한 부분인데 ㅎㅎ

    제가 말씀 드리고 싶었던 것은 Flex 낚는 어부가 되시라는 거였습니다. Flex라는 물고기만 계속 받아먹기만 하면 발전이 없잖아요. 그래서 Flex 낚는 어부가 되기 위해 이것만은 했으면 좋겠다는 내용이였죠. 설명 못드려 아쉽네요. 시간조정을 못한 제 불찰입니다. ㅜㅜ

     

     

    아무튼 짧았지만 좋은 시간이였던 것 같습니다. 제가 발표했던 자료는 아래 링크를 통해 받아가세요.

     

     

    다른 분의 자료는 [여기]에서 받아가세요.

     

    이번 세미나를 개최하시느라 고생하신 옥상훈(http://okgosu.tistory.com)님 수고 많으셨고요.

    주최에 도움을 줬던 데브멘토(http://devmento.co.kr) 관계자 분들도 수고 많으셨습니다.

     

    발표자였던 오창훈(http://lovedev.tistory.com/), 이정웅(http://bluemetal.tistory.com/)님도 수고했어요.

     

    저는 항상 열려있습니다.

    저처럼 바보같은 질문도 괜찮습니다. 반대로 제가 답변 못하더라도 전 부끄럽지 않습니다.

    오히려 몰랐던 것을 알게 되니 좋은 것이지요. ^^

    대한민국 개발자들이 서로 소통하는데 힘써주셨으면 합니다.

     

     

     

     

    Flex나 Flash로 개발 결과물안에 폰트를 포함시켜야하는 경우를 많이 경험해봤으리라 생각한다.

    폰트를 포함(Embed)한다는 것은 시스템 폰트를 사용하지 않고 프로그램안에 폰트를 내장해서 좀더 세밀하게 폰트를 제어할 수 있게 하기 위함이다. 가령, 폰트의 안티알리어싱, 회전, 투명도 조정 등을 위해서는 반드시 프로그램안에 해당 폰트를 내장해야한다.

    폰트를 포함할때 가장 큰 문제점은 프로그램 용량이 너무 커진다는 것이다.
    이럴때 보통 동적으로 로딩하는 방법을 통해 프로그램 자체 크기 용량을 줄일 수 있다.

    그럼, 쓰여질 폰트가 제한적일때는 어떻게 할까?
    가령, 폰트안에 숫자만 사용할 것이라면 그것만 뽑아내서 사용할 수 있을 것이다.
    사용할 폰트가 제한적이라면 프로그램 크기를 줄이기 위해서라도 반드시 수행해야할 것이다.

    Flash에서는 이것을 아주 쉽게 할 수 있다.
    하지만 Flex에서 이런 작업을 하기에 여간 불편한것이 아니다.
    왜 그런지 살펴보자.

    Flex에서 폰트를 포함하기 위해서 CSS의 @font-face 또는 ActionScript3에서 Embed 메타데이타 태그를 이용하면 된다.

    즉,

    @font-face
    {
    src:systemFont("돋움");
    fontFamily: myFontFamily;
    advancedAntiAliasing: true;
    unicodeRange : U+c0ac,U+c790,U+cc98; /*변환후 사용하면 됩니다.*/
    }

    또는


    [Embed(source="../assets/돋움.ttf",fontName='MyFont',
    mimeType='application/x-font', unicodeRange='U+c0ac,U+c790,U+cc98')]
    private var font1:Class;

    이다.

    상단은 시스템 폰트를 포함 방법, 아래는 지정된 폰트를 포함하는 방법을 사용하고 있지만 어쨌든 둘다 어렵지 않게 사용할 수 있다.

    둘다 unicodeRange 속성을 가지고 있다. 여기에 입력된 값은  특정문자에 대한 유니코드(unicode)값이다.
    숫자면 숫자, 문자면 문자에 대한 유니코드값을 이곳에 넣어주어야 지정된 폰트만 프로그램안에 포함할 수 있는 것이다.

    저 유니코드 값을 넣어주어야하는데 당신은 저걸 다 외우고 있는가?
    "안녕하세요" 만 쓴다고 하자.
    그럼 이것에 대한 유니코드값은 "U+c548,U+b155,U+d558,U+c138,U+c694,U+2e"이다.
    이 값을 모른다면 Flex에서 유니코드 넣기란 여간 어려운 것이 아닐 것이다.

    본인도 이것때문에 어떻게 할까 고민하다가 폰트 유니코드 변환기를 만들어서 사용하면 되겠다 싶어서 하나 만들었다.

    사용자 삽입 이미지



    이 프로그램의 핵심 함수는 다음과 같다. 의외로 간단하다. ^^;;;

    private function encodeUnicode( fonts:String ):String

    {

           var fontUnicodes:String = "";

           var length:int = fonts.length;

           for( var i:int = 0; i < length; i++ )

           {

                 var char:String = fonts.substr( i, 1 );

                 fontUnicodes += "U+"+char.charCodeAt(0).toString(16)+",";

           }           

           return fontUnicodes;      

    }     

    우측 스타플 "내별위젯"도 그렇게 만들었다.
    회사에 Flasher가 없어서... 전부 ActionScript3로 만들었는데... 사용할 폰트가 제한적이라 이 프로그램을 유용하게 사용했다.

    왜 Flex로 하지? 어렵게 ActionScript 3로 했는가? 라고 반문하실 수 있겠다. 사실 Flex는 쓰기 편하지만 덩치가 크다. 위젯과 같은 작은 프로그램을 만들기 위해 덩치큰 Flex를 사용하는 것은 별로 바람직하지 못할때가 많다. 왜냐하면 결과물의 용량이 커지기 때문이다. 위젯의 경우 Flash를 할 수 있다면 Flash로 제작하자. Enterprise급 프로그램이라면 Flex로 만들면 되겠다.

     



    Flex 하시는 분들도 이제 폰트 Embed 범위지정 쉽게 해요.

    관련내용

    Setting character ranges
    [Flex, AIR] 프로그램 크기를 줄여보자 2 - 폰트(font) 동적로드 또는 문자범위지정
    [Flex, Flash] 폰트(font) Embed의 이점과 제한점
    [Flex] 폰트를 런타임(run time)시 동적으로 불러와 적용하는 방법


    밤하늘에 당신의 유일한 별을 찾아가세요. 스타플 http://starpl.com


    글쓴이 : 지돌스타(http://blog.jidolstar.com/414)

    Flash Player 10에 맞게 제작된 ActionScript 3.0 한글문서 입니다.
    참조하세요. ^^

    http://help.adobe.com/ko_KR/AS3LCR/Flash_10.0/
    http://help.adobe.com/ko_KR/ActionScript/3.0_ProgrammingAS3/


    글쓴이 : 지돌스타(http://blog.jidolstar.com/410)

    + Recent posts