Flash platform2012.03.25 18:47


출처 : http://goo.gl/Je692


얼마 전에 Image Sprite 를 사용했을때의 효과에 대해서 포스팅을 한적이 있는데요. 이제서야 그 두번째 포스팅을 하게 되네요. 

테스트에 사용한 이미지들이 얼마전에 스토어에 오픈한 Pix : Pixel Mixer의 이미지들이라서 이제서야 블로그 포스팅을 할 수 있게 되었습니다. :D  생각 보다 Pix 에 대한 사용자들의 반응이 좋아서, 작업에 참여한 사람들 모두 싱글 벙글 하고 있습니다. 


이 포스팅은 이전에 작성된 Flash App Performance : Image Sprite Sheet 와 이어지는 내용입니다. 아직 이전 포스팅을 안읽으신 분들은 읽고 본 포스팅을 보시는게 좋을것 같습니다.



Image Sprite 로 만들어서 작업하는게 좋다는건 알고 있는데, 얼마나 차이가 발생할까 궁금해서 테스트를 해 봤습니다. 테스트 대상은 모바일이고 OS에 따라 차이가 나겠지만, 이정도 차이라면 확실하게 좋다고 말할 수 있겠네요. 비교는 단순히 Embed 태그를 이용해서 각각의 이미지를 따로 사용했을때와 (Image Embed) 이미지들을 Sprit 해서 하나의 이미지를 사용했을때 (Image Sprite) 경우는 비교 했습니다.


Flash Builder Profiler

Flash Builder Profiler 상에서 나타나는 메모리 점유율

왼쪽 : Image Embed (176K) , 오른쪽 : Image Sprite (68K) , 차이 108K


왼쪽 : Image Embed (5296K) , 오른쪽 : Image Sprite (5178K) , 차이 118K



Adobe AIR Simulator

AIR Simulator 에서 어플리케이션을 실행 시켰을때 나타나는 메모리 점유율

왼쪽 : Image Embed (19886080 Byte) , 오른쪽 : Image Sprite (6754304 Byte) , 차이 13131776 Byte



Device Test (iPhone 4S)

iPhone 4S 에서 어플리케이션을 실행 시켰을때 나타나는 메모리 점유율

왼쪽 : Image Embed (4890624Byte) , 오른쪽 : Image Sprite (2478080 Byte) , 차이 2412544 Byte



메모리를 줄여 준다는게 사용자가 느끼기에는 확연한 차이가 없습니다. 하지만, 모바일이나 적은 리소스만 운영을 할 수 있는 플랫폼에서는 반드시 필요한 작업이라 할 수 있습니다. 프로젝트가 대부분 마무리 되고, 더이상 디자인 수정 사항이 없다고 판단이 될때 적용해 보세요. 



댓글은 언제든지 환영 합니다. :ㅇ


Posted by Flash 동강
Flash platform2012.01.25 16:20

 Image Sprite Sheet는 게임이나 웹서비스에서 이미지를 불러올때 여러개로 나눠져 있는 이미지를 불러 오는 것 보다 하나의 이미지를 불러오는게 비교적 좋은 로딩 시간 또는 로딩 되는 파일 크기를 줄일수 있기 때문에 사용하는 방법이다. 많은 서비스에서 이미 CSS Sprite Sheet 를 이용하여 사이트에 포함 되어 있는 이미지를 하나의 이미지를 통해 불러 와서 사용함으로 로딩 타임을 줄이는 이점을 취하고 있다.


  • 이미지를 온라인에서 불러올 경우 요청 횟수를 줄일수 있다.
  • 여러 이미지를 하나의 이미지 파일로 만들기 때문에 이미지 크기를 줄일수 있다. (클수도 있다)
  • 하나의 이미지로 해당 어플리케이션의 스킨을 지정 할 수 있다. (해당 이미지만 교체 하면 스킨이 바뀐다)




Flash/Flex(이하 Flash)로 구현된 어플리케이션(이하 앱)들은 대부분의 이미지가 컴파일 타임에 임베딩 되기 때문에 로딩 시간 단축에 대한 장점은 줄어들겠지만, 메모리 관리 측면에서 보면 상당히 이득을 준다. 이 문서에서는 Flash 앱 개발시에 Image Sprite Sheet 를 만들어서 사용하는 방법에 대해 다룬다.



Image Sprite Tool


합쳐진 이미지를 사용하기에 앞서 Actionscript로 사용하기 편하게 이미지를 합쳐주는 툴이 필요 하다. 물론 수작업으로 해도 되지만, 이미 좋은 툴들이 나와 있으니 아래 나열된 툴중 무료를 사용하도록 하겠다. 툴은 어떤 것을 사용해도 상관 없지만 툴에서 만들어주는 이미지 퀄러티와 설명 파일형식을 고려 해야 한다.



Sprite Sheet Packer


Sprite Sheet Packer 는 아래 그림 처럼 이미지를 불러와서 하나의 png/jpeg/bitmap 파일로 만들어 준다. 또한 만들어진 이미지에 대한 좌표값을 가지고 있는 txt/xml 파일도 만들어 준다. 최대 단점은 윈도우에서만 된다는거;;





위와 같이 이미지를 추가한 뒤에 Image File 이름 Map File (합쳐진 이미지의 위치값에 대한 파일) 이름을 설정해 준뒤에 Build Sprite Sheet 버튼을 누르면 아래와 같이 두개의 파일이 생성 된다.



sample.png




sample.xml


sample.xml 과 sample.png 파일이 생성 되었다.




사용 방법


Sprite Sheet Packer 를 통해 이미지를 만들었다면 다음과 같은 방법으로 이미지를 사용할 수 있다.  (다른 툴을 이용했다면 해당 툴이서 출력해 주는 xml 또는 text 파일 형식에 맞게 수정해서 사용할 수 있다)


아래 Client Code 에서는 위의 툴을 이용하여 생성한 sample.png와 sample.xml 을 임베딩하여 ImageSpriteSheet.as 클래스를 사용하여 popup_bg를 불러와서 화면에 표시 하고 있다.



client code


package {
     
    import flash.display.Sprite;
    import flash.display.StageAlign;
    import flash.display.StageScaleMode;
    import flash.utils.ByteArray;
     
    public class ImageSprite_sprite extends Sprite {
         
        [Embed (source="/assets/sample.png")]
        private var IMAGE_SHEET:Class;
        [Embed (source="/assets/sample.xml", mimeType="application/octet-stream")]
        private var DATA_SHEET:Class;      
         
        public function ImageSprite_sprite()
        {
            super();
             
            // support autoOrients
            stage.align = StageAlign.TOP_LEFT;
            stage.scaleMode = StageScaleMode.NO_SCALE;
             
            init();
        }          
         
        private function init():void
        {
            // embed 한 xml과 png 파일을 로드 하여 파싱한다.
                        var xmlData:ByteArray = (new DATA_SHEET()) as ByteArray;
             
            var spriteSheet:ImageSpriteSheet;
            spriteSheet = new ImageSpriteSheet();
            spriteSheet.init(new IMAGE_SHEET(), XML(xmlData.readUTFBytes(xmlData.bytesAvailable)));
             
 
            // xml 에 정의 되어 있는 activity_indicator_160 을 불러와서 추가 한다.
            addChild(spriteSheet.getImage('popup_bg'));
             
        }
         
    }  
}




 ImageSpriteSheet Class


package {
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.geom.Point;
    import flash.geom.Rectangle;
    import flash.utils.Dictionary;
     
     
    public class ImageSpriteSheet {
         
        private var _sheetImage:Bitmap;
        private var _sheetData:Dictionary;
         
        public function ImageSpriteSheet(){
        }          
         
        public function init(spriteSheet:Bitmap, sheetXML:XML):void {
             
            _sheetImage = spriteSheet;
            _sheetData = new Dictionary();
            parseSheetXML(sheetXML);           
        }
         
        private function parseSheetXML(data:XML):void {
             
            var i:int 0;
            var list:XMLList = data.Asset.Item;
             
            for(; i < list.length(); ++i) {
                 
                var key:String = list[i].Key;
                var value:Rectangle = parseImageBound(list[i].Value);
                _sheetData[key] = value;               
            }          
        }
         
        private function parseImageBound(data:String):Rectangle {
             
            var properties:Array =  data.split(" ");
            var bound:Rectangle;
             
            try {
             
                bound = new Rectangle(properties[0], properties[1], properties[2], properties[3]);
                 
            }catch(error:Error) {
                 
                throw new Error("Invalid data. please confirm data.");
            }
             
            return bound;
        }
         
        public function hasImage(name:String):Boolean {
             
            return (_sheetData[name])? true false;
        }
         
        public function getImage(name:String):Bitmap {
             
            if(hasImage(name)) {
                 
                var bound:Rectangle = _sheetData[name];
                var image:BitmapData = new BitmapData(bound.width, bound.height, true);
                image.copyPixels(_sheetImage.bitmapData, bound, new Point(00));
                 
                return new Bitmap(image);
            }