├── .gitignore ├── README.md ├── asset ├── embed │ ├── about.txt │ └── chess.png ├── icon │ ├── 128.png │ ├── 16.png │ ├── 32.png │ └── 48.png ├── locale │ ├── en_US │ │ └── LC_MESSAGES │ │ │ └── main.mo │ └── zh_CN │ │ └── LC_MESSAGES │ │ └── main.mo └── po │ ├── SSE_zh_CN.txt │ ├── en_US.po │ ├── main.pot │ ├── make_mo.sh │ ├── make_po.sh │ ├── make_pot.sh │ ├── zh_CN.mo │ └── zh_CN.po ├── build.xml ├── lib ├── robotlegs-framework-v1.5.2.swc └── zrongas3.swc ├── sample.build.properties └── src ├── SSEContext.as ├── SpriteSheetEditor-app.xml ├── SpriteSheetEditor.mxml ├── ctrl ├── BrowseFileCmd.as ├── DragFileCmd.as ├── PreviewSSChangeCmd.as └── SaveCmd.as ├── events └── SSEvent.as ├── interf └── IPreview.as ├── main.css ├── mediator ├── AppMediator.as ├── comps │ ├── FramesAndLabelMediator.as │ └── SSPreviewMediator.as └── panel │ ├── PicPanelMediator.as │ ├── SSPanelMediator.as │ ├── StartPanelMediator.as │ ├── SwfPanelMediator.as │ └── TopPanelMediator.as ├── model ├── FileOpenerModel.as ├── FileProcessor.as ├── FileSaverModel.as ├── SpriteSheetModel.as └── StateModel.as ├── type ├── ExtendedNameType.as └── StateType.as ├── utils ├── Funs.as └── Global.as ├── view ├── About.mxml ├── comps │ ├── Alert.mxml │ ├── BMPPreview.mxml │ ├── BuildSetting.mxml │ ├── FileManager.mxml │ ├── FrameDataGrid.mxml │ ├── FramesAndLabels.mxml │ ├── ImagePreview.mxml │ ├── ImageTypeSetting.mxml │ ├── Preview.mxml │ ├── SSPreview.mxml │ ├── SaveSeqSetting.mxml │ ├── SaveSheetSetting.mxml │ ├── TransformTool.as │ ├── TransformToolControlBar.mxml │ ├── TransformToolControlBarForSS.as │ └── VDividedButton.mxml └── panel │ ├── PicPanel.mxml │ ├── SSPanel.mxml │ ├── StartPanel.mxml │ ├── SwfPanel.mxml │ └── TopPanel.mxml └── vo ├── BrowseFileDoneVO.as ├── FrameVO.as ├── LabelListVO.as ├── LabelVO.as ├── NamesVO.as ├── RectsAndBmdsVO.as └── SaveVO.as /.gitignore: -------------------------------------------------------------------------------- 1 | .actionScriptProperties 2 | .flexProperties 3 | .project 4 | .settings 5 | *.as3proj 6 | *.bat 7 | bin 8 | obj 9 | bat 10 | dist 11 | build.properties 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Sprite Sheet Editor 2 | 3 | [Sprite Sheet Editor](http://zengrong.net/sprite_sheet_editor) 是一个生成Sprite Sheet(也叫Tile Sheet)的免费小工具。 4 | 5 | ## 开发平台 6 | 7 | * Apache Flex 4.9.1 8 | * Adobe AIR 3.7 9 | 10 | ## 特点 11 | 12 | * 将swf转换成序列图或者Sprite Sheet格式; 13 | * 将多张图像拼合成一张大的Sprite Sheet以降低文件尺寸和减少网络请求; 14 | * 让Sprite Sheet也支持Label,实现类似于MovieClip中Label的功能; 15 | * 自动修剪Sheet中每帧四周的空白像素; 16 | * 使用Mask技术让JPEG格式也支持透明,大幅降低需要透明的文件的尺寸; 17 | * 支持JPEG-XR格式,该格式支持Alpha通道,图像质量优于JPEG格式; 18 | * 还有更多…… 19 | 20 | ## 更新历史 21 | 22 | 这个工具原来的名字叫做[Sprite Sheet Packer](http://zengrong.net/spritesheetpacker),从v0.5.0改名为Sprite Sheet Editor。 23 | 24 | * [2013-08-21:v0.8.2版发布](http://zengrong.net/post/1901.htm) 25 | * [2013-06-14:v0.8.1版发布](http://zengrong.net/post/1880.htm) 26 | * [2013-02-19:v0.8.0版发布](http://zengrong.net/post/1815.htm) 27 | * [2012-10-15:v0.7.3版发布](http://zengrong.net/post/1706.htm) 28 | * [2012-08-20:v0.7.2版发布](http://zengrong.net/post/1672.htm) 29 | * [2012-08-18:v0.7.1版发布](http://zengrong.net/post/1668.htm) 30 | * [2012-07-26:v0.7.0版发布](http://zengrong.net/post/1660.htm) 31 | * [2011-12-21:v0.6.2版发布](http://zengrong.net/post/1482.htm) 32 | * [2011-11-04:v0.5.9版发布](http://zengrong.net/post/1468.htm) 33 | * [2011-09-02:v0.5.7版发布](http://zengrong.net/post/1436.htm) 34 | * [2011-08-23:v0.5.6版发布](http://zengrong.net/post/1414.htm) 35 | * [2011-08-18:v0.5.0版发布,同时更名为Sprite Sheet Editor](http://zengrong.net/post/1402.htm) 36 | * [2011-06-30:v0.4版发布](http://zengrong.net/post/1357.htm) 37 | * [2011-04-26:v0.3版发布](http://zengrong.net/post/1313.htm) 38 | * [2011-04-22:v0.2版发布](http://zengrong.net/post/1311.htm) 39 | * [2011-04-19:v0.1版发布](http://zengrong.net/post/1306.htm) 40 | 41 | ## 网站 42 | 43 | * 官方网站: 44 | * WIKI: 45 | -------------------------------------------------------------------------------- /asset/embed/about.txt: -------------------------------------------------------------------------------- 1 | 2013-08-21:v0.8.2版发布 2 | 15 | 2013-06-14:v0.8.1版发布 16 | 22 | 2013-02-19:v0.8.0版发布 23 | 31 | 2012-10-15:v0.7.3版发布 32 | 36 | 2012-08-20:v0.7.2版发布 37 | 42 | 2012-08-18:v0.7.1版发布 43 | 49 | 2012-07-26:v0.7.0版发布 50 | 57 | 2011-12-21:v0.6.2版发布 58 | 61 | 2011-12-01:v0.6.1版发布 62 |
    63 |
  1. 加入在打开的SpriteSheet中增加帧的功能。帧只能增加到已有帧的末尾。
  2. 64 |
  3. 加入在打开SpriteSheet中增加SpriteSheet的功能。这样就可以实现多个SpriteSheet的合并。规则如下: 65 |
      66 |
    • 所有帧会增加到当前Sheet的末尾;
    • 67 |
    • 若label重名,则被导入Sheet中的label不导入,但依然会导入该lable的所有帧;
    • 68 |
    • 若name重名,则被导入的Sheet中该name对应的重名帧不会被导入;
    • 69 |
    • 若原始Sheet中包含name,但被导入Sheet中不含name,则会自动为被导入的Sheet中的所有帧命名。
    • 70 |
    71 |
  4. 72 |
73 | 2011-11-04:v0.5.9版发布 74 |
    75 |
  1. 导入图像文件后,支持多选排序,支持“移到顶部/底部”。
    善用此功能,可对最终生成SpriteSheet进行排版,以降低最终文件的尺寸。
  2. 76 |
  3. 预览的背景可以在方格/白色/黑色之间切换,方便查看半透明的动画。
  4. 77 |
78 | 2011-09-02:v0.5.7版发布 79 |
    80 |
  1. 解决metadata中frame的的ow和oh与w和h相等的重大BUG
  2. 81 |
  3. 现在可以把帧还原到“修剪空白”前的状态;
  4. 82 |
  5. 使用SharedObject保存设置。目前仅实现了帧率的保存。
  6. 83 |
84 | 2011-08-23:v0.5.6版发布 85 |
    86 |
  1. 加入缩小帧原始尺寸的功能;
  2. 87 |
  3. 删除帧后,会立即更新Sheet预览;
  4. 88 |
  5. 解决一些bug。
  6. 89 |
90 | 2011-08-18:v0.5.0版发布,同时更名为Sprite Sheet Editor 91 |
    92 |
  1. 采用Flex重写了界面;
  2. 93 |
  3. 修改了生成Sheet的流程;
  4. 94 |
  5. 自动计算生成的Sheet的尺寸,自动计算支持“正方形”和“2的幂”;
  6. 95 |
  7. 可更改已生成的Sheet的尺寸和排列方式;
  8. 96 |
  9. 增加对Sheet中的帧周围空白区域的自动修剪;
  10. 97 |
  11. 可以采用可视化的方式修改截取区域;
  12. 98 |
  13. 可以对待拼合的图像文件进行排序;
  14. 99 |
  15. SpriteSheetMetadata格式小幅修改。
  16. 100 |
101 | 2011-06-30:v0.4版发布 102 |
    103 |
  1. 将菜单改为按钮,避免Mac等不支持菜单的操作系统无法显示菜单;
  2. 104 |
  3. 可以打开SpriteSheet格式的图片,然后保存成其他格式。即可以在SS、JPG、PNG之间互转格式;
  4. 105 |
  5. 可以打开已有的SpriteSheet,修改Metadata后保存成新的文件;
  6. 106 |
  7. 解决0.3版手动提供的元数据无效的问题;
  8. 107 |
  9. 播放位图动画的时候,在Sheet预览中显示当前帧的范围;
  10. 108 |
  11. 解决打开的SpriteSheet格式的Label起始帧显示不正常的问题;
  12. 109 |
  13. 采用SDK2.7编译。因此需要卸载原来的软件,再升级AIR Runtime,才能正常安装。(AIR的版本兼容性很糟糕,经常无法安装,而且给出错误的提示)
  14. 110 |
111 | 2011-04-26:v0.3版发布 112 |
    113 |
  1. 加入了XML格式的元数据导出功能。
  2. 114 |
  3. 可以打开由SpriteSheetPacker保存的SS格式文件。
  4. 115 |
  5. 如果以SheetSprite方式打开jpg或png文件,可以提供一个SpriteSheetPacker生成的元数据xml文件,SpriteSheetPacker会根据元数据进行解析;若没有提供元数据,会自动在图像文件所在路径寻找同名xml文件。包含mask信息的jpg文件,会自动应用Alpha通道。
  6. 116 |
  7. 一些界面上的修改,就不说了。
  8. 117 |
118 | 2011-04-22:v0.2版发布 119 |
    120 |
  1. 修正了图像排列的BUG;
  2. 121 |
  3. 将保存图像和元数据信息合并到一个菜单,便于对照;
  4. 122 |
  5. 保存元数据的时候可以“包含附加信息”。附加信息包含:是否mask、有没有label、有没有包含名称、总帧数等等。
    附加信息选项只会影响元数据,SS格式嵌入的数据总是包含附加信息的。
  6. 123 |
  7. 保存SS格式图像和元数据的时候,可以“包含名称”。有时候我们希望用名称来查找一个Sheet中的Sprite。包含名称功能是独立的,不受“包含附加信息”影响。
    SWF视图中不能使用“包含名称”功能。名称自动使用图片的主文件名;
  8. 124 |
  9. 将文件名列表截断,只显示文件名,不显示路径。
  10. 125 |
126 | 2011-04-19:v0.1版发布 -------------------------------------------------------------------------------- /asset/embed/chess.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zrong/sprite_sheet_editor/32764c96fd14d26967c675bcde21083a045c0255/asset/embed/chess.png -------------------------------------------------------------------------------- /asset/icon/128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zrong/sprite_sheet_editor/32764c96fd14d26967c675bcde21083a045c0255/asset/icon/128.png -------------------------------------------------------------------------------- /asset/icon/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zrong/sprite_sheet_editor/32764c96fd14d26967c675bcde21083a045c0255/asset/icon/16.png -------------------------------------------------------------------------------- /asset/icon/32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zrong/sprite_sheet_editor/32764c96fd14d26967c675bcde21083a045c0255/asset/icon/32.png -------------------------------------------------------------------------------- /asset/icon/48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zrong/sprite_sheet_editor/32764c96fd14d26967c675bcde21083a045c0255/asset/icon/48.png -------------------------------------------------------------------------------- /asset/locale/en_US/LC_MESSAGES/main.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zrong/sprite_sheet_editor/32764c96fd14d26967c675bcde21083a045c0255/asset/locale/en_US/LC_MESSAGES/main.mo -------------------------------------------------------------------------------- /asset/locale/zh_CN/LC_MESSAGES/main.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zrong/sprite_sheet_editor/32764c96fd14d26967c675bcde21083a045c0255/asset/locale/zh_CN/LC_MESSAGES/main.mo -------------------------------------------------------------------------------- /asset/po/make_mo.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | find . -type f -name "*.po" > po 4 | 5 | sed -i -e 's/\.po//g' po 6 | locales=`cat po` 7 | rm po 8 | 9 | out=../locale 10 | mkdir -p $out 11 | 12 | for locale in $locales; do 13 | echo "Processing "$locale".po ..." 14 | mkdir -p $out/$locale/LC_MESSAGES 15 | msgfmt --check --verbose --output-file $out/$locale/LC_MESSAGES/main.mo $locale.po 16 | done 17 | -------------------------------------------------------------------------------- /asset/po/make_po.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | pot=`find . | grep -i \.pot$` 4 | msginit --no-translator --locale $1 --output-file $1.po --input $pot 5 | 6 | #echo "Missing locale: usage ./make_po.sh " 7 | -------------------------------------------------------------------------------- /asset/po/make_pot.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | find ../../src -type f \( -name "*.as" -o -name "*.mxml" \) > files 4 | xgettext --package-name main --package-version 0.1 --default-domain main --output main.pot --from-code=UTF-8 -L C -f files 5 | rm files 6 | -------------------------------------------------------------------------------- /asset/po/zh_CN.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zrong/sprite_sheet_editor/32764c96fd14d26967c675bcde21083a045c0255/asset/po/zh_CN.mo -------------------------------------------------------------------------------- /build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | Found the Flash Develop project: ${FD_PROJECT}. 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | main.file:${main.file} 41 | main.name:${main.name} 42 | swf.file:${swf.file} 43 | swf.name:${swf.name} 44 | FLEX_HOME:${FLEX_HOME} 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | Building swf file ${swf.file}... 62 | The main file is ${main.file}. 63 | debug:${var.debug} optimize:${var.optimize} swfversion:${var.swfversion} 64 | 65 | 66 | 67 | 68 | 69 | 70 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | Delete old certificate file. 82 | 83 | Create a new certificate file ${AND_CERT_FILE}. 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | Replace the appid from ${id} to ${APP_ID} in ${APP_XML}. 98 | 99 | 100 | 101 | 102 | 103 | Replace the content from ${initialWindow.content} to ${swf.name} in ${APP_XML}. 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | Copy ${ASSET_DIR} to ${BIN_DIR} 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | Copy ${TEMP_DIR} to ${BIN_DIR} 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | Packager a ${var.type}${var.target} 143 | The signing is ${var.signing} 144 | The output file is ${var.output} 145 | The options are ${var.options} 146 | ${FLEX_HOME}/lib/adt.jar -package ${var.signing} ${var.options} -target ${var.type}${var.target} ${var.output} ${APP_XML} ${var.fileordir} ${ANE_DIR_ARGS} 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | OS family is ${os.name}. The adl is ${var.adl}. 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | runSimulatorDebug ${APP_XML} ${BIN_DIR} 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | packair ${APP_XML} ${BIN_DIR} 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | -------------------------------------------------------------------------------- /lib/robotlegs-framework-v1.5.2.swc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zrong/sprite_sheet_editor/32764c96fd14d26967c675bcde21083a045c0255/lib/robotlegs-framework-v1.5.2.swc -------------------------------------------------------------------------------- /lib/zrongas3.swc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zrong/sprite_sheet_editor/32764c96fd14d26967c675bcde21083a045c0255/lib/zrongas3.swc -------------------------------------------------------------------------------- /sample.build.properties: -------------------------------------------------------------------------------- 1 | PROJECT_NAME=SpriteSheetEditor 2 | 3 | # The project can have multiple main class file. 4 | MAIN_NAME=SpriteSheetEditor 5 | MAIN_PATH= 6 | 7 | FLEX_HOME=D:/flashsdks/flex4.6.0 8 | FLEX_FRAMEWORKS=${FLEX_HOME}/frameworks 9 | 10 | # SRC - mxml and as files 11 | # CERT - p12 and mobileprovision files 12 | # BIN - output files 13 | # ANE - AIR Native Extension files 14 | # LIB - swc files 15 | # ASSET - assets file dir 16 | # ICON - icon files 17 | # TEMP - package temporary files 18 | # DIST - AIR release files 19 | SRC_DIR=${basedir}/src 20 | CERT_DIR=${basedir}/cert 21 | BIN_DIR=${basedir}/bin 22 | ANE_DIR=${basedir}/ane 23 | LIB_DIR=${basedir}/lib 24 | ASSET_DIR=${basedir}/asset 25 | ICON_DIR=${basedir}/asset/icon 26 | TEMP_DIR=${basedir}/temp 27 | DIST_DIR=${basedir}/dist 28 | 29 | # About AIR application packaging 30 | # http://livedocs.adobe.com/flex/3/html/help.html?content=CommandLineTools_5.html#1035959 31 | # http://livedocs.adobe.com/flex/3/html/distributing_apps_4.html#1037515 32 | 33 | # NOTICE: all paths are relative to project root 34 | 35 | # certification options 36 | AIR_CERT_NAME=SpriteSheetEditor 37 | AIR_CERT_PASS=fd 38 | AIR_CERT_FILE=${CERT_DIR}/${AIR_CERT_NAME}.p12 39 | AIR_ICONS=${ICON_DIR} 40 | AIR_DEV_SIGN=-storetype pkcs12 -keystore ${AIR_CERT_FILE} -storepass ${AIR_CERT_PASS} 41 | AIR_DIST_SIGN=-storetype pkcs12 -keystore ${AIR_CERT_FILE} -storepass ${AIR_CERT_PASS} 42 | 43 | # Application descriptor 44 | APP_XML=${basedir}/src/SpriteSheetEditor-app.xml 45 | 46 | # Flash Develop project file 47 | FD_PROJECT=${PROJECT_NAME}.as3proj 48 | 49 | # AIR Native Extensions(ANE) 50 | ANE_DIR_ARGS= 51 | #ANE_DIR_ARGS=-extdir ${ANE_DIR} 52 | 53 | # Your application ID (must match of Application descriptor) 54 | APP_ID=org.zengrong.SpriteSheetEditor 55 | 56 | # Output packages 57 | DIST_NAME=${MAIN_NAME} 58 | 59 | # Default variable value 60 | var.type=air 61 | var.target= 62 | #var.target=-captive-runtime 63 | var.output=${DIST_DIR}/${DIST_NAME}${var.target}.air 64 | var.options= 65 | #var.options=-tsa none 66 | var.signing=${AIR_DIST_SIGN} 67 | var.fileordir=-C ${TEMP_DIR} . 68 | -------------------------------------------------------------------------------- /src/SSEContext.as: -------------------------------------------------------------------------------- 1 | package 2 | { 3 | import ctrl.BrowseFileCmd; 4 | import ctrl.DragFileCmd; 5 | import ctrl.PreviewSSChangeCmd; 6 | import ctrl.SaveCmd; 7 | 8 | import events.SSEvent; 9 | 10 | import flash.display.DisplayObjectContainer; 11 | 12 | import mediator.*; 13 | import mediator.comps.*; 14 | import mediator.panel.*; 15 | 16 | import model.*; 17 | 18 | import org.robotlegs.mvcs.Context; 19 | 20 | import utils.Global; 21 | 22 | import view.comps.FramesAndLabels; 23 | import view.comps.SSPreview; 24 | import view.panel.*; 25 | 26 | /** 27 | * 28 | * @author zrong(zengrong.net) 29 | * 创建日期:2012-07-18 30 | */ 31 | public class SSEContext extends Context 32 | { 33 | public function SSEContext(contextView:DisplayObjectContainer=null, autoStartup:Boolean=true) 34 | { 35 | super(contextView, autoStartup); 36 | } 37 | 38 | private function init():void 39 | { 40 | Global.init(contextView as SpriteSheetEditor); 41 | } 42 | 43 | override public function startup():void 44 | { 45 | init(); 46 | injector.mapSingleton(FileOpenerModel); 47 | injector.mapSingleton(FileSaverModel); 48 | injector.mapSingleton(StateModel); 49 | injector.mapSingleton(SpriteSheetModel); 50 | 51 | mediatorMap.mapView(SpriteSheetEditor, AppMediator); 52 | mediatorMap.mapView(TopPanel, TopPanelMediator); 53 | mediatorMap.mapView(SwfPanel, SwfPanelMediator); 54 | mediatorMap.mapView(SSPanel, SSPanelMediator); 55 | mediatorMap.mapView(StartPanel, StartPanelMediator); 56 | mediatorMap.mapView(PicPanel, PicPanelMediator); 57 | 58 | mediatorMap.mapView(SSPreview, SSPreviewMediator,null, false, false); 59 | mediatorMap.mapView(FramesAndLabels,FramesAndLabelMediator, null, false, false); 60 | 61 | commandMap.mapEvent(SSEvent.PREVIEW_SS_CHANGE, PreviewSSChangeCmd); 62 | commandMap.mapEvent(SSEvent.SAVE, SaveCmd); 63 | commandMap.mapEvent(SSEvent.BROWSE_FILE, BrowseFileCmd); 64 | commandMap.mapEvent(SSEvent.DRAG_FILE, DragFileCmd); 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /src/SpriteSheetEditor-app.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | org.zengrong.SpriteSheetEditor 4 | SpriteSheetEditor 5 | Sprite Sheet Editor 6 | 0.8.2 7 | 8 | 9 | 11 | 12 | 13 | zengrong.net 14 | 15 | 16 | 17 | 18 | 19 | 20 | SpriteSheetEditor.swf 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 800 35 | 36 | 600 37 | 38 | 39 | 40 | 41 | 42 | 800 600 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | true 56 | false 57 | false 58 | none 59 | standard 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 73 | 74 | icon/16.png 75 | icon/32.png 76 | icon/48.png 77 | icon/128.png 78 | 79 | 82 | 83 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /src/SpriteSheetEditor.mxml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /src/ctrl/BrowseFileCmd.as: -------------------------------------------------------------------------------- 1 | package ctrl 2 | { 3 | import air.update.utils.StringUtils; 4 | import events.SSEvent; 5 | import model.FileOpenerModel; 6 | import org.robotlegs.mvcs.Command; 7 | 8 | /** 9 | * 选择一个或者一组文件 10 | * @author zrong 11 | */ 12 | public class BrowseFileCmd extends Command 13 | { 14 | [Inject] 15 | public var fileOpener:FileOpenerModel; 16 | 17 | [Inject] 18 | public var evt:SSEvent; 19 | 20 | override public function execute():void 21 | { 22 | fileOpener.open(evt.info as String); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /src/ctrl/DragFileCmd.as: -------------------------------------------------------------------------------- 1 | package ctrl 2 | { 3 | import events.SSEvent; 4 | import gnu.as3.gettext.FxGettext; 5 | import model.FileOpenerModel; 6 | import model.StateModel; 7 | import org.robotlegs.mvcs.Command; 8 | import type.StateType; 9 | import utils.Funs; 10 | 11 | /** 12 | * 处理一个拖放文件 13 | * @author zrong 14 | * Creation: 2013-08-19 15 | */ 16 | public class DragFileCmd extends Command 17 | { 18 | [Inject] public var evt:SSEvent; 19 | [Inject] public var fileOpener:FileOpenerModel; 20 | [Inject] public var stateModel:StateModel; 21 | 22 | public override function execute():void 23 | { 24 | var __files:Array = evt.info as Array; 25 | var __state:String = Funs.getStateByFile(__files[0]); 26 | if(!__state) 27 | { 28 | Funs.alert(FxGettext.gettext("These files are not supported!")); 29 | return; 30 | } 31 | if(__state == StateType.PIC) 32 | { 33 | //若当前位于PicPanel中,则将状态改为增加图像到列表 34 | if(stateModel.state == StateType.PIC) __state = StateType.ADD_TO_PIC_List; 35 | //若位于SSPanel中,则将状态改为增加到ss 36 | else if(stateModel.state == StateType.SS) __state = StateType.ADD_TO_SS; 37 | fileOpener.openFilesByDrag(__files, __state); 38 | } 39 | else if(__state == StateType.SS) 40 | { 41 | //若位于SSPanel中,则将状态改为增加到SS 42 | if(stateModel.state == StateType.SS) 43 | { 44 | __state = StateType.ADD_TO_SS; 45 | fileOpener.openFilesByDrag(__files, __state); 46 | } 47 | //否则直接切换到SS列表 48 | else fileOpener.openFilesByDrag([__files[0]], __state); 49 | } 50 | else if(__state == StateType.SWF) 51 | { 52 | fileOpener.openFilesByDrag([__files[0]], __state); 53 | } 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /src/ctrl/PreviewSSChangeCmd.as: -------------------------------------------------------------------------------- 1 | package ctrl 2 | { 3 | import events.SSEvent; 4 | 5 | import flash.display.BitmapData; 6 | import flash.geom.Rectangle; 7 | 8 | import model.SpriteSheetModel; 9 | 10 | import org.robotlegs.mvcs.Command; 11 | 12 | /** 13 | * 显示帧改变 14 | * @author zrong 15 | * 创建日期:2012-07-26 16 | */ 17 | public class PreviewSSChangeCmd extends Command 18 | { 19 | [Inject] public var ssModel:SpriteSheetModel; 20 | 21 | override public function execute():void 22 | { 23 | updateFrameDisplay(); 24 | } 25 | 26 | /** 27 | * 更新帧显示 28 | */ 29 | private function updateFrameDisplay():void 30 | { 31 | if(ssModel.selectedFrameIndex<0) return; 32 | var __frameBmd:BitmapData = null; 33 | //根据选择显示原始的或者修剪过的Frame 34 | if(ssModel.displayCrop) 35 | { 36 | __frameBmd = ssModel.adjustedSheet.getTrimBMDByIndex(ssModel.selectedFrameIndex); 37 | } 38 | else 39 | { 40 | __frameBmd = ssModel.adjustedSheet.getBMDByIndex(ssModel.selectedFrameIndex); 41 | } 42 | //rect永远使用剪切过的值 43 | var __rect:Rectangle = ssModel.adjustedSheet.metadata.frameRects[ssModel.selectedFrameIndex]; 44 | trace('更新帧:', __frameBmd.rect, ssModel.displayCrop); 45 | dispatch(new SSEvent(SSEvent.PREVIEW_SS_SHOW, {bmd:__frameBmd, rect:__rect})); 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /src/ctrl/SaveCmd.as: -------------------------------------------------------------------------------- 1 | package ctrl 2 | { 3 | import events.SSEvent; 4 | import model.FileSaverModel; 5 | import org.robotlegs.mvcs.Command; 6 | import vo.SaveVO; 7 | 8 | /** 9 | * 用于保存文件的Cmd 10 | * @author zrong 11 | * Creation: 2013-06-13 12 | */ 13 | public class SaveCmd extends Command 14 | { 15 | [Inject] 16 | public var evt:SSEvent; 17 | 18 | [Inject] 19 | public var fileSaver:FileSaverModel; 20 | 21 | override public function execute():void 22 | { 23 | var __vo:SaveVO = evt.info as SaveVO; 24 | fileSaver.save(__vo); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/events/SSEvent.as: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // zengrong.net 3 | // 创建者: zrong(zrongzrong@gmail.com) 4 | // 创建时间:2011-8-9 5 | //////////////////////////////////////////////////////////////////////////////// 6 | 7 | package events 8 | { 9 | import flash.events.Event; 10 | 11 | public class SSEvent extends Event 12 | { 13 | public static const ENTER_STATE:String = 'enterState'; 14 | public static const EXIT_STATE:String = 'exitState'; 15 | 16 | public static const FRAME_AND_LABEL_CHANGE:String = 'frameAndLabelChange'; 17 | 18 | /** 19 | * 拖动一个文件到SSE中 20 | */ 21 | public static const DRAG_FILE:String = "dragFile"; 22 | /** 23 | * 要求File对象选择一个或者一组文件 24 | */ 25 | public static const BROWSE_FILE:String = "browseFile"; 26 | 27 | /** 28 | * 选择一个或者一组文件成功 29 | */ 30 | public static const BROWSE_FILE_DONE:String = "browseFileDone"; 31 | /** 32 | * 选择的帧变化了 33 | */ 34 | public static const SELECTED_FRAMEINDICES_CHANGE:String = 'selectedFrameIndicesChange'; 35 | public static const ADD_FRAME:String = 'addFrame'; 36 | 37 | 38 | public static const CAPTURE_DONE:String = 'captureDone'; 39 | 40 | public static const SAVE_PIC:String = 'savePic'; 41 | public static const SAVE_META:String = 'saveMeta'; 42 | public static const SAVE_ALL:String = 'saveAll'; 43 | public static const SAVE_SEQ:String = 'saveSeq'; 44 | 45 | /** 46 | * 所有类型的保存事件 47 | */ 48 | public static const SAVE:String = "sssave"; 49 | 50 | /** 51 | * 收到此事件的时候开始优化Sheet,一般在删除或者增加帧内容的时候执行 52 | */ 53 | public static const OPTIMIZE_SHEET:String = 'optimizeSheet'; 54 | /** 55 | * 优化完成之后发布此事件 56 | */ 57 | public static const OPTIMIZE_SHEET_DONE:String = 'optimizeSheetDone'; 58 | 59 | public static const FILE_MANAGER_SELECTION_CHANGE:String = 'selectionChange'; 60 | public static const FILE_MANAGER_SELECTION_CHANGING:String = 'selectionChanging'; 61 | 62 | public static const PREVIEW_LOAD_COMPLETE:String = 'previewLoadComplete'; 63 | public static const PREVIEW_CLICK:String = 'previewClick'; 64 | 65 | /** 66 | * 变形工具的大小和位置改变了 67 | */ 68 | public static const TRANSFORM_CHANGE:String = "transformChange"; 69 | 70 | /** 71 | * 变形工具的帧设置大小改变了 72 | */ 73 | public static const TRANSFORM_FRAME_CHANGE:String = "transformFrameChange"; 74 | /** 75 | * 变形工具中选择是否使用变形值的事件 76 | */ 77 | public static const TRANSFORM_USE_CUSTOM_CHANGE:String = "transformUseCustomChange"; 78 | 79 | /** 80 | * 控制SS的播放 81 | */ 82 | public static const PREVIEW_SS_PLAY:String = 'previewSSPlay'; 83 | 84 | /** 85 | * 改变SS中每一帧的大小 86 | */ 87 | public static const PREVIEW_SS_RESIZE_SAVE:String = 'previewSSResizeSize'; 88 | 89 | /** 90 | * 发送要预览的帧信息 91 | */ 92 | public static const PREVIEW_SS_SHOW:String = 'previewSSShow'; 93 | 94 | /** 95 | * 要预览的帧的显示范围变化变化,剪切/原始切换 96 | * 要预览的帧的显示形式变化,帧/Label切换 97 | */ 98 | public static const PREVIEW_SS_CHANGE:String = 'previewSSChange'; 99 | 100 | /** 101 | * 建立或优化SpriteSheet 102 | */ 103 | public static const BUILD:String = 'build'; 104 | 105 | public var info:*; 106 | 107 | public function SSEvent($type:String, $info:*=null, $bubbles:Boolean=false, $cancelable:Boolean=false) 108 | { 109 | super($type, $bubbles, $cancelable); 110 | info = $info; 111 | } 112 | 113 | override public function clone():Event 114 | { 115 | return new SSEvent(type, info, bubbles, cancelable); 116 | } 117 | } 118 | } -------------------------------------------------------------------------------- /src/interf/IPreview.as: -------------------------------------------------------------------------------- 1 | package interf 2 | { 3 | import flash.display.IBitmapDrawable; 4 | import flash.events.IEventDispatcher; 5 | 6 | public interface IPreview extends IEventDispatcher 7 | { 8 | function destroy():void; 9 | function set source($so:*):void; 10 | function get content():IBitmapDrawable; 11 | } 12 | } -------------------------------------------------------------------------------- /src/main.css: -------------------------------------------------------------------------------- 1 | /* CSS file */ 2 | @namespace s "library://ns.adobe.com/flex/spark"; 3 | @namespace mx "library://ns.adobe.com/flex/mx"; 4 | 5 | 6 | global 7 | { 8 | font-size: 12; 9 | fontFamily: "Microsoft YaHei,simsun"; 10 | chrome-color: #333333; 11 | color: #CCCCCC; 12 | content-background-color: #777777; 13 | symbol-color: #000000; 14 | roll-over-color: #555555; 15 | selection-color: #333333; 16 | focus-color: #999999; 17 | accent-color: #8C8C8C 18 | } 19 | 20 | s|Application,s|Panel,mx|Panel,mx|TitleWindow,mx|TabNavigator,mx|SwatchPanel 21 | { 22 | background-color: #666666; 23 | } 24 | 25 | s|RichEditableText 26 | { 27 | focusedTextSelectionColor: #333333; 28 | unfocusedTextSelectionColor: #333333; 29 | } 30 | 31 | mx|DataGrid 32 | { 33 | alternating-item-colors: #777777, #777777; 34 | } 35 | 36 | mx|ToolTip 37 | { 38 | font-size: 12; 39 | color: #000000; 40 | } 41 | -------------------------------------------------------------------------------- /src/mediator/AppMediator.as: -------------------------------------------------------------------------------- 1 | package mediator 2 | { 3 | import events.SSEvent; 4 | import flash.desktop.ClipboardFormats; 5 | import flash.desktop.NativeDragManager; 6 | import flash.events.NativeDragEvent; 7 | import mx.events.FlexEvent; 8 | import org.robotlegs.mvcs.Mediator; 9 | 10 | public class AppMediator extends Mediator 11 | { 12 | [Inject] public var v:SpriteSheetEditor; 13 | 14 | override public function onRegister():void 15 | { 16 | // v.startState.addEventListener(FlexEvent.EXIT_STATE, handler_exitState); 17 | // v.picState.addEventListener(FlexEvent.EXIT_STATE, handler_exitState); 18 | // v.ssState.addEventListener(FlexEvent.EXIT_STATE, handler_exitState); 19 | // v.swfState.addEventListener(FlexEvent.EXIT_STATE, handler_exitState); 20 | eventMap.mapListener(eventDispatcher, SSEvent.ENTER_STATE, handler_enterState); 21 | v.addEventListener(NativeDragEvent.NATIVE_DRAG_ENTER, handler_nativeDragEnter); 22 | v.addEventListener(NativeDragEvent.NATIVE_DRAG_DROP, handler_nativeDragDrop); 23 | } 24 | 25 | private function handler_nativeDragDrop($evt:NativeDragEvent):void 26 | { 27 | dispatch(new SSEvent(SSEvent.DRAG_FILE, $evt.clipboard.getData(ClipboardFormats.FILE_LIST_FORMAT) as Array)); 28 | } 29 | 30 | private function handler_nativeDragEnter($evt:NativeDragEvent):void 31 | { 32 | if($evt.clipboard.hasFormat(ClipboardFormats.FILE_LIST_FORMAT)) 33 | { 34 | NativeDragManager.acceptDragDrop(v); 35 | } 36 | } 37 | 38 | private function handler_enterState($evt:SSEvent):void 39 | { 40 | v.currentState = $evt.info.newState; 41 | } 42 | 43 | protected function handler_exitState($event:FlexEvent):void 44 | { 45 | trace('退出状态', v.currentState); 46 | dispatch(new SSEvent(SSEvent.EXIT_STATE)); 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /src/mediator/comps/SSPreviewMediator.as: -------------------------------------------------------------------------------- 1 | package mediator.comps 2 | { 3 | import flash.events.Event; 4 | import flash.events.MouseEvent; 5 | 6 | import mx.events.FlexEvent; 7 | 8 | import events.SSEvent; 9 | 10 | import gnu.as3.gettext.FxGettext; 11 | 12 | import model.SpriteSheetModel; 13 | 14 | import org.robotlegs.mvcs.Mediator; 15 | 16 | import view.comps.SSPreview; 17 | 18 | public class SSPreviewMediator extends Mediator 19 | { 20 | [Inject] public var v:SSPreview; 21 | 22 | [Inject] public var ssModel:SpriteSheetModel; 23 | 24 | override public function onRegister():void 25 | { 26 | eventMap.mapListener(v.playBTN, MouseEvent.CLICK, handler_playBTNclick); 27 | eventMap.mapListener(v.transControlBar.saveResizeBTN, MouseEvent.CLICK, handler_saveResizeBTNclick); 28 | eventMap.mapListener(v.transControlBar.useCustomSizeCB, FlexEvent.VALUE_COMMIT, handler_resizeOriginCBChange); 29 | eventMap.mapListener(v, FlexEvent.VALUE_COMMIT, handler_resizeOriginCBChange); 30 | addViewListener(SSEvent.TRANSFORM_CHANGE, handler_transformSizeChange); 31 | 32 | addContextListener(SSEvent.PREVIEW_SS_SHOW, handler_previewShow); 33 | addContextListener(SSEvent.FRAME_AND_LABEL_CHANGE, handler_framesAndLabelsChange); 34 | addContextListener(SSEvent.SELECTED_FRAMEINDICES_CHANGE, handler_framesAndLabelsChange); 35 | addContextListener(SSEvent.OPTIMIZE_SHEET, handler_optimizeSheet); 36 | addContextListener(SSEvent.PREVIEW_SS_CHANGE, handler_previewSSChange); 37 | 38 | v.init(); 39 | setPlayEnable(); 40 | } 41 | 42 | override public function onRemove():void 43 | { 44 | eventMap.unmapListener(v.playBTN, MouseEvent.CLICK, handler_playBTNclick); 45 | eventMap.unmapListener(v.transControlBar.saveResizeBTN, MouseEvent.CLICK, handler_saveResizeBTNclick); 46 | eventMap.unmapListener(v.transControlBar.useCustomSizeCB, FlexEvent.VALUE_COMMIT, handler_resizeOriginCBChange); 47 | removeViewListener(SSEvent.TRANSFORM_CHANGE, handler_transformSizeChange); 48 | 49 | removeContextListener(SSEvent.PREVIEW_SS_SHOW, handler_previewShow); 50 | removeContextListener(SSEvent.FRAME_AND_LABEL_CHANGE, handler_framesAndLabelsChange); 51 | removeContextListener(SSEvent.SELECTED_FRAMEINDICES_CHANGE, handler_framesAndLabelsChange); 52 | removeContextListener(SSEvent.OPTIMIZE_SHEET, handler_optimizeSheet); 53 | removeContextListener(SSEvent.PREVIEW_SS_CHANGE, handler_previewSSChange); 54 | 55 | v.destroy(); 56 | handler_playBTNclick(null); 57 | } 58 | 59 | protected function handler_optimizeSheet($evt:SSEvent):void 60 | { 61 | v.destroyAni(); 62 | } 63 | 64 | protected function handler_playBTNclick($event:MouseEvent):void 65 | { 66 | ssModel.playing = v.playBTN.selected; 67 | dispatch(new SSEvent(SSEvent.PREVIEW_SS_PLAY, v.playBTN.selected)); 68 | } 69 | 70 | private function handler_saveResizeBTNclick($evt:MouseEvent):void 71 | { 72 | dispatch(new SSEvent(SSEvent.PREVIEW_SS_RESIZE_SAVE)); 73 | } 74 | 75 | private function handler_previewShow($evt:SSEvent):void 76 | { 77 | v.showBmd($evt.info.bmd); 78 | } 79 | 80 | private function handler_previewSSChange($evt:SSEvent):void 81 | { 82 | updateFrame(); 83 | v.title = ssModel.displayFrame ? FxGettext.gettext("Frame animation preview") : ("Label("+ssModel.displayLabel+")" + FxGettext.gettext("animation preview")); 84 | } 85 | 86 | private function handler_resizeOriginCBChange($evt:FlexEvent):void 87 | { 88 | updateFrame(); 89 | } 90 | 91 | private function handler_framesAndLabelsChange($evt:SSEvent):void 92 | { 93 | updateFrame(); 94 | } 95 | 96 | private function handler_transformSizeChange($evt:Event):void 97 | { 98 | updateFrame(); 99 | } 100 | 101 | private function updateFrame():void 102 | { 103 | v.frameLabel.text = ssModel.selectedFrmaeNum.toString(); 104 | setPlayEnable(); 105 | setSaveEnable(); 106 | ssModel.resizeRect = v.getResizeRect(); 107 | } 108 | 109 | private function setSaveEnable():void 110 | { 111 | v.transControlBar.setResizeBtnEnable(!ssModel.playing && ssModel.selectedFrameIndices); 112 | } 113 | 114 | private function setPlayEnable():void 115 | { 116 | if(ssModel.displayFrame) 117 | { 118 | v.playBTN.enabled = ssModel.selectedFrameIndices && ssModel.selectedFrameIndices.length>1; 119 | } 120 | else 121 | { 122 | v.playBTN.enabled = true; 123 | } 124 | } 125 | } 126 | } -------------------------------------------------------------------------------- /src/mediator/panel/PicPanelMediator.as: -------------------------------------------------------------------------------- 1 | package mediator.panel 2 | { 3 | import events.SSEvent; 4 | import flash.events.Event; 5 | import model.FileOpenerModel; 6 | import model.SpriteSheetModel; 7 | import model.StateModel; 8 | import org.robotlegs.mvcs.Mediator; 9 | import org.zengrong.display.spritesheet.SpriteSheetMetadata; 10 | import type.StateType; 11 | import view.panel.PicPanel; 12 | import vo.BrowseFileDoneVO; 13 | import vo.NamesVO; 14 | 15 | public class PicPanelMediator extends Mediator 16 | { 17 | [Inject] public var v:PicPanel; 18 | 19 | [Inject] public var stateModel:StateModel; 20 | 21 | [Inject] public var fileOpener:FileOpenerModel; 22 | 23 | [Inject] public var ssModel:SpriteSheetModel; 24 | 25 | override public function onRegister():void 26 | { 27 | addViewListener(SSEvent.CAPTURE_DONE, handler_captureDone); 28 | addViewListener(SSEvent.ADD_FRAME, handler_addFrame); 29 | eventMap.mapListener(v.fileM, Event.SELECT, handler_select); 30 | eventMap.mapListener(v.buildSetting, SSEvent.BUILD, handler_build); 31 | eventMap.mapListener(eventDispatcher, SSEvent.BROWSE_FILE_DONE, handler_browseFileDone); 32 | 33 | enterState(stateModel.oldState, stateModel.state); 34 | } 35 | 36 | 37 | override public function onRemove():void 38 | { 39 | removeViewListener(SSEvent.CAPTURE_DONE, handler_captureDone); 40 | removeViewListener(SSEvent.ADD_FRAME, handler_addFrame); 41 | eventMap.unmapListener(v.fileM, Event.SELECT, handler_select); 42 | eventMap.unmapListener(v.buildSetting, SSEvent.BUILD, handler_build); 43 | eventMap.unmapListener(eventDispatcher, SSEvent.BROWSE_FILE_DONE, handler_browseFileDone); 44 | 45 | v.fileM.init(); 46 | v.pic.viewer.source = null; 47 | } 48 | 49 | /** 50 | * 在PicPanel界面中新增Pic 51 | * @param $evt 52 | */ 53 | private function handler_select($evt:Event):void 54 | { 55 | this.dispatch(new SSEvent(SSEvent.BROWSE_FILE, StateType.ADD_TO_PIC_List)); 56 | } 57 | 58 | private function handler_captureDone($evt:SSEvent):void 59 | { 60 | ssModel.drawOriginalSheet($evt.info.bmd); 61 | var __namesVO:NamesVO = $evt.info.updateNames as NamesVO; 62 | if(__namesVO) 63 | { 64 | ssModel.originalSheet.metadata.hasName = __namesVO.hasName; 65 | ssModel.originalSheet.metadata.names = __namesVO.names; 66 | ssModel.originalSheet.metadata.namesIndex = __namesVO.namesIndex; 67 | } 68 | stateModel.state = StateType.SS; 69 | } 70 | 71 | private function enterState($oldState:String, $newState:String):void 72 | { 73 | trace('picPanel.updateOnStateChanged:', $oldState, $newState); 74 | if($newState== StateType.PIC && 75 | $oldState != $newState) 76 | { 77 | v.fileM.init(); 78 | //如果是从START状态跳转过来的,就更新一次fileList的值 79 | if($oldState == StateType.START) 80 | { 81 | v.fileM.setFileList(fileOpener.selectedFiles); 82 | //trace("从start进入pic"); 83 | //trace("file:", file.selectedFiles.length); 84 | //trace("enterState.fileList:", v.fileM.fileList.length); 85 | } 86 | } 87 | } 88 | 89 | protected function handler_build($event:SSEvent):void 90 | { 91 | ssModel.resetSheet(null, new SpriteSheetMetadata()); 92 | v.capture(); 93 | } 94 | 95 | private function handler_addFrame($evt:SSEvent):void 96 | { 97 | ssModel.addOriginalFrame($evt.info.bmd, $evt.info.rect); 98 | } 99 | 100 | private function handler_browseFileDone($evt:SSEvent):void 101 | { 102 | var __vo:BrowseFileDoneVO = $evt.info as BrowseFileDoneVO; 103 | if(__vo && __vo.openState == StateType.ADD_TO_PIC_List) 104 | { 105 | v.fileM.addFile2Manager(__vo.selectedFiles); 106 | } 107 | } 108 | } 109 | } -------------------------------------------------------------------------------- /src/mediator/panel/SSPanelMediator.as: -------------------------------------------------------------------------------- 1 | package mediator.panel 2 | { 3 | import flash.display.BitmapData; 4 | import flash.events.Event; 5 | import flash.geom.Point; 6 | import flash.geom.Rectangle; 7 | import flash.text.ReturnKeyLabel; 8 | import vo.RectsAndBmdsVO; 9 | 10 | import events.SSEvent; 11 | 12 | import gnu.as3.gettext.FxGettext; 13 | 14 | import mediator.comps.FramesAndLabelMediator; 15 | 16 | import model.FileProcessor; 17 | import model.SpriteSheetModel; 18 | import model.StateModel; 19 | 20 | import org.robotlegs.mvcs.Mediator; 21 | import org.zengrong.display.spritesheet.ISpriteSheetMetadata; 22 | import org.zengrong.display.spritesheet.MaskType; 23 | import org.zengrong.display.spritesheet.SpriteSheetMetadata; 24 | import org.zengrong.display.spritesheet.SpriteSheetMetadataJSON; 25 | import org.zengrong.display.spritesheet.SpriteSheetMetadataStarling; 26 | import org.zengrong.display.spritesheet.SpriteSheetMetadataTXT; 27 | import org.zengrong.display.spritesheet.SpriteSheetMetadataXML; 28 | import org.zengrong.file.FileEnding; 29 | import org.zengrong.utils.BitmapUtil; 30 | 31 | import type.StateType; 32 | 33 | import utils.Funs; 34 | 35 | import view.panel.SSPanel; 36 | 37 | import vo.FrameVO; 38 | import vo.LabelListVO; 39 | import vo.SaveVO; 40 | 41 | public class SSPanelMediator extends Mediator 42 | { 43 | [Inject] public var v:SSPanel; 44 | [Inject] public var stateModel:StateModel; 45 | [Inject] public var ssModel:SpriteSheetModel; 46 | 47 | override public function onRegister():void 48 | { 49 | addContextListener(SSEvent.ENTER_STATE, handler_enterState); 50 | addContextListener(SSEvent.OPTIMIZE_SHEET, handler_optimizeSheet); 51 | addContextListener(SSEvent.PREVIEW_SS_CHANGE, handler_displayChange); 52 | addContextListener(SSEvent.PREVIEW_SS_SHOW, handler_previewShow); 53 | addContextListener(SSEvent.SELECTED_FRAMEINDICES_CHANGE, handler_selected_frameindices_change); 54 | 55 | eventMap.mapListener(v.saveSheet, SSEvent.SAVE_ALL, handler_saveAll); 56 | eventMap.mapListener(v.saveSheet, SSEvent.SAVE_META, handler_saveMeta); 57 | eventMap.mapListener(v.saveSheet, SSEvent.SAVE_PIC, handler_savePic); 58 | eventMap.mapListener(v.saveSeq, SSEvent.SAVE_SEQ, handler_saveSeq); 59 | eventMap.mapListener(v.optPanel, SSEvent.BUILD, handler_build); 60 | eventMap.mapListener(v.saveSheet.nameCB, Event.CHANGE, handler_nameCBChange); 61 | eventMap.mapListener(v.sheetPreview, SSEvent.PREVIEW_CLICK, handler_sheetPreviewClick); 62 | 63 | enterState(); 64 | } 65 | 66 | override public function onRemove():void 67 | { 68 | trace('remove'); 69 | removeContextListener(SSEvent.ENTER_STATE, handler_enterState); 70 | removeContextListener(SSEvent.OPTIMIZE_SHEET, handler_optimizeSheet); 71 | removeContextListener(SSEvent.PREVIEW_SS_CHANGE, handler_displayChange); 72 | removeContextListener(SSEvent.PREVIEW_SS_SHOW, handler_previewShow); 73 | removeContextListener(SSEvent.SELECTED_FRAMEINDICES_CHANGE, handler_selected_frameindices_change); 74 | 75 | eventMap.unmapListener(v.saveSheet, SSEvent.SAVE_ALL, handler_saveAll); 76 | eventMap.unmapListener(v.saveSheet, SSEvent.SAVE_META, handler_saveMeta); 77 | eventMap.unmapListener(v.saveSheet, SSEvent.SAVE_PIC, handler_savePic); 78 | eventMap.unmapListener(v.saveSeq, SSEvent.SAVE_SEQ, handler_saveSeq); 79 | eventMap.unmapListener(v.optPanel, SSEvent.BUILD, handler_build); 80 | eventMap.unmapListener(v.saveSheet.nameCB, Event.CHANGE, handler_nameCBChange); 81 | eventMap.unmapListener(v.sheetPreview, SSEvent.PREVIEW_CLICK, handler_sheetPreviewClick); 82 | 83 | exitState(); 84 | } 85 | 86 | private function handler_sheetPreviewClick($evt:SSEvent):void 87 | { 88 | dispatch($evt); 89 | } 90 | 91 | protected function handler_nameCBChange($evt:Event):void 92 | { 93 | ssModel.adjustedSheet.metadata.hasName = v.saveSheet.nameCB.selected; 94 | } 95 | 96 | private function handler_displayChange($evt:SSEvent):void 97 | { 98 | v.saveSeq.titleLabel.text = ssModel.displayCrop ? 99 | FxGettext.gettext("trimmed size"): 100 | FxGettext.gettext("original size"); 101 | } 102 | 103 | private function handler_saveAll($evt:SSEvent):void 104 | { 105 | updateMetadata(); 106 | var __vo:SaveVO = v.getSheetSaveVO(); 107 | var __bmd:BitmapData = ssModel.getBitmapDataForSave(v.maskTypeValue, v.transparent, v.bgColor); 108 | __vo.bitmapData = __bmd; 109 | __vo.metadata = getMetadata(); 110 | __vo.type = StateType.SAVE_ALL; 111 | dispatch(new SSEvent(SSEvent.SAVE, __vo)); 112 | } 113 | 114 | protected function handler_saveMeta($event:SSEvent):void 115 | { 116 | updateMetadata(); 117 | var __vo:SaveVO = v.getSheetSaveVO(); 118 | __vo.metadata = getMetadata(); 119 | __vo.type = StateType.SAVE_META; 120 | dispatch(new SSEvent(SSEvent.SAVE, __vo)); 121 | } 122 | 123 | protected function handler_savePic($event:SSEvent):void 124 | { 125 | updateMetadata(); 126 | var __vo:SaveVO =v.getSheetSaveVO(); 127 | __vo.bitmapData = ssModel.getBitmapDataForSave(v.maskTypeValue, v.transparent, v.bgColor); 128 | __vo.type = StateType.SAVE_SHEET_PIC; 129 | dispatch(new SSEvent(SSEvent.SAVE, __vo)); 130 | } 131 | 132 | private function handler_saveSeq($evt:SSEvent):void 133 | { 134 | var __vo:SaveVO = v.getSeqSaveVO(); 135 | __vo.fileNameList = v.getSeqFileNames(ssModel.adjustedSheet.metadata.totalFrame); 136 | __vo.type = StateType.SAVE_SEQ; 137 | //根据显示的帧类型来保存序列 138 | __vo.bitmapDataList = ssModel.getBMDList(); 139 | dispatch(new SSEvent(SSEvent.SAVE, __vo)); 140 | } 141 | 142 | private function handler_enterState($evt:SSEvent):void 143 | { 144 | enterState(); 145 | } 146 | 147 | private function enterState():void 148 | { 149 | if(stateModel.state != StateType.SS) return; 150 | //更新调整后的Sheet 151 | ssModel.updateAdjustedSheet(); 152 | v.init(ssModel.adjustedSheet.bitmapData, ssModel.originalSheet.metadata.hasName); 153 | 154 | mediatorMap.createMediator(v.framesAndLabels); 155 | } 156 | 157 | private function exitState():void 158 | { 159 | ssModel.destroySheet(); 160 | v.destroy(); 161 | 162 | mediatorMap.removeMediatorByView(v.framesAndLabels); 163 | } 164 | 165 | protected function handler_build($evt:SSEvent):void 166 | { 167 | dispatch(new SSEvent(SSEvent.OPTIMIZE_SHEET)); 168 | } 169 | 170 | protected function handler_optimizeSheet($evt:SSEvent):void 171 | { 172 | optimizeSheet(); 173 | } 174 | 175 | //在预览更新的时候,绘制帧的范围 176 | private function handler_previewShow($evt:SSEvent):void 177 | { 178 | //仅在播放的时候才绘制帧的范围 179 | if(ssModel.playing) 180 | { 181 | var __rect:Rectangle = $evt.info.rect as Rectangle; 182 | v.sheetPreview.clearCanva(); 183 | v.sheetPreview.drawRect(__rect.x, __rect.y, __rect.width, __rect.height); 184 | } 185 | } 186 | 187 | //在选择帧的时候,绘制选择的帧的范围 188 | private function handler_selected_frameindices_change($evt:SSEvent):void 189 | { 190 | var __frames:Vector. = $evt.info as Vector.; 191 | if(__frames && __frames.length>0) 192 | { 193 | v.sheetPreview.clearCanva(); 194 | for (var i:int = 0; i < __frames.length; i++) 195 | { 196 | var __rect:Rectangle = __frames[i].frameRect; 197 | v.sheetPreview.drawRect(__rect.x, __rect.y, __rect.width, __rect.height); 198 | } 199 | } 200 | } 201 | 202 | /** 203 | * 根据当前的选择优化Sheet,优化的信息会被写入adjustedSheet中 204 | */ 205 | private function optimizeSheet():void 206 | { 207 | v.sheetPreview.destroy(); 208 | if(ssModel.originalSheet.metadata.totalFrame==0 || ssModel.adjustedSheet.metadata.totalFrame==0) 209 | { 210 | Funs.alert(FxGettext.gettext("No frame info, can not generate the sheet.")); 211 | v.leftPanelBG.enabled = false; 212 | return; 213 | } 214 | trace('优化帧数:', ssModel.originalSheet.metadata.totalFrame, ssModel.adjustedSheet.metadata.totalFrame); 215 | var __list:RectsAndBmdsVO = ssModel.getRectsAndBmds(v.trim, v.resetRect); 216 | trace('新生成的:', __list.bmds, __list.frameRects, __list.originRects) 217 | //保存新计算出的WH 218 | var __whRect:Rectangle = new Rectangle(); 219 | //保存新计算出的每个帧在大Sheet中放置的位置 220 | var __newFrameRects:Vector. = new Vector.; 221 | //重新计算出最终Sheet的宽高以及修改过的frameRect 222 | Funs.calculateSize( 223 | __list.frameRects, 224 | __newFrameRects, 225 | __whRect, 226 | v.limitWidth, 227 | v.explicitSize, 228 | v.powerOf2, 229 | v.square 230 | ); 231 | //绘制大Sheet位图 232 | var __sheetBmd:BitmapData = new BitmapData(__whRect.width, __whRect.height, v.transparent, v.bgColor); 233 | ssModel.redrawAdjustedSheet(__sheetBmd, new RectsAndBmdsVO(__list.bmds, __list.originRects, __newFrameRects)); 234 | v.sheetPreview.source = ssModel.adjustedSheet.bitmapData; 235 | //优化完毕,FramesAndLabel需要更新 236 | dispatch(new SSEvent(SSEvent.OPTIMIZE_SHEET_DONE)); 237 | } 238 | 239 | /** 240 | * 更新spriteSheet的metadata。在生成新的SpriteSheet前调用。 241 | */ 242 | private function updateMetadata():void 243 | { 244 | //hasName, names, namesIndex, totalFrame, frameRects, originalFrameRects 这几个变量 245 | //是在生成Sheet的时候填充的,因此这里不需要更新 246 | var __meta:ISpriteSheetMetadata = ssModel.adjustedSheet.metadata; 247 | __meta.type = v.sheetType; 248 | __meta.maskType = v.saveSheet.maskDDL.selectedIndex; 249 | var __mediator:FramesAndLabelMediator = mediatorMap.retrieveMediator(v.framesAndLabels) as FramesAndLabelMediator; 250 | var __labelMeta:LabelListVO = __mediator.getLabels(); 251 | __meta.hasLabel = __labelMeta.hasLabel; 252 | __meta.labels = __labelMeta.labels; 253 | __meta.labelsFrame = __labelMeta.labelsFrame; 254 | } 255 | 256 | private function getMetadata():ISpriteSheetMetadata 257 | { 258 | var __meta:ISpriteSheetMetadata = null; 259 | if(v.saveSheet.jsonRB.selected) 260 | { 261 | __meta = new SpriteSheetMetadataJSON(ssModel.adjustedSheet.metadata); 262 | } 263 | else if(v.saveSheet.xmlRB.selected) 264 | { 265 | __meta = new SpriteSheetMetadataXML(ssModel.adjustedSheet.metadata); 266 | SpriteSheetMetadataXML(__meta).header = Funs.getXMLHeader(FileEnding.UNIX); 267 | } 268 | else if(v.saveSheet.starlingRB.selected) 269 | { 270 | __meta = new SpriteSheetMetadataStarling(ssModel.adjustedSheet.metadata); 271 | SpriteSheetMetadataStarling(__meta).header = Funs.getXMLHeader(FileEnding.UNIX); 272 | } 273 | else 274 | { 275 | __meta = new SpriteSheetMetadataTXT(ssModel.adjustedSheet.metadata); 276 | } 277 | return __meta; 278 | } 279 | } 280 | } -------------------------------------------------------------------------------- /src/mediator/panel/StartPanelMediator.as: -------------------------------------------------------------------------------- 1 | package mediator.panel 2 | { 3 | import events.SSEvent; 4 | import flash.events.MouseEvent; 5 | import model.FileProcessor; 6 | import org.robotlegs.mvcs.Mediator; 7 | import type.StateType; 8 | import view.panel.StartPanel; 9 | 10 | public class StartPanelMediator extends Mediator 11 | { 12 | [Inject] public var v:StartPanel; 13 | 14 | override public function onRegister():void 15 | { 16 | eventMap.mapListener(v.openSWFBTN, MouseEvent.CLICK, handler_openSWFBTNClick); 17 | eventMap.mapListener(v.openPicBTN, MouseEvent.CLICK, handler_openPicBTNClick); 18 | eventMap.mapListener(v.openSSBTN, MouseEvent.CLICK, handler_openSSBTNclick); 19 | 20 | //addContextListener(SSEvent.ENTER_STATE, handler_enterState); 21 | } 22 | 23 | override public function onRemove():void 24 | { 25 | eventMap.unmapListener(v.openSWFBTN, MouseEvent.CLICK, handler_openSWFBTNClick); 26 | eventMap.unmapListener(v.openPicBTN, MouseEvent.CLICK, handler_openPicBTNClick); 27 | eventMap.unmapListener(v.openSSBTN, MouseEvent.CLICK, handler_openSSBTNclick); 28 | 29 | //removeContextListener(SSEvent.ENTER_STATE, handler_enterState); 30 | } 31 | 32 | 33 | protected function handler_openSWFBTNClick(event:MouseEvent):void 34 | { 35 | dispatch(new SSEvent(SSEvent.BROWSE_FILE,StateType.SWF)); 36 | } 37 | 38 | protected function handler_openPicBTNClick(event:MouseEvent):void 39 | { 40 | dispatch(new SSEvent(SSEvent.BROWSE_FILE,StateType.PIC)); 41 | } 42 | 43 | protected function handler_openSSBTNclick(event:MouseEvent):void 44 | { 45 | dispatch(new SSEvent(SSEvent.BROWSE_FILE,StateType.SS)); 46 | } 47 | 48 | public function handler_enterState($evt:SSEvent):void 49 | { 50 | //trace('StartPanelMediator.updateOnStateChanged:', $evt.info.oldState, $evt.info.newState); 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /src/mediator/panel/SwfPanelMediator.as: -------------------------------------------------------------------------------- 1 | package mediator.panel 2 | { 3 | import events.SSEvent; 4 | import flash.filesystem.File; 5 | import model.FileOpenerModel; 6 | import model.SpriteSheetModel; 7 | import model.StateModel; 8 | import org.robotlegs.mvcs.Mediator; 9 | import org.zengrong.display.spritesheet.SpriteSheetMetadata; 10 | import type.StateType; 11 | import view.panel.SwfPanel; 12 | 13 | /** 14 | * @author zrong 15 | * 创建日期:2012-07-18 16 | */ 17 | public class SwfPanelMediator extends Mediator 18 | { 19 | [Inject] public var v:SwfPanel; 20 | 21 | [Inject] public var stateModel:StateModel; 22 | 23 | [Inject] public var fileOpener:FileOpenerModel; 24 | 25 | [Inject] public var ssModel:SpriteSheetModel; 26 | 27 | private var _swfURL:String; 28 | 29 | private var _swfContentX:int = 0; 30 | private var _swfContentY:int = 0; 31 | 32 | override public function onRegister():void 33 | { 34 | addViewListener(SSEvent.CAPTURE_DONE, handler_captureDone); 35 | addViewListener(SSEvent.ADD_FRAME, handler_addFrame); 36 | eventMap.mapListener(v.buildSetting, SSEvent.BUILD, handler_buildClick); 37 | 38 | addContextListener(SSEvent.ENTER_STATE, handler_enterState); 39 | 40 | enterState(stateModel.oldState, stateModel.state); 41 | } 42 | 43 | override public function onRemove():void 44 | { 45 | removeViewListener(SSEvent.CAPTURE_DONE, handler_captureDone); 46 | removeViewListener(SSEvent.ADD_FRAME, handler_addFrame); 47 | eventMap.unmapListener(v.buildSetting, SSEvent.BUILD, handler_buildClick); 48 | 49 | removeContextListener(SSEvent.ENTER_STATE, handler_enterState); 50 | 51 | v.destroy(); 52 | v.swf.removeEventListener(SSEvent.PREVIEW_LOAD_COMPLETE, handler_swfLoadDone); 53 | } 54 | 55 | private function handler_captureDone($evt:SSEvent):void 56 | { 57 | v.state = StateType.LOAD_DONE; 58 | ssModel.drawOriginalSheet($evt.info); 59 | stateModel.state = StateType.SS; 60 | } 61 | 62 | private function handler_enterState($evt:SSEvent):void 63 | { 64 | enterState($evt.info.oldState, $evt.info.newState); 65 | } 66 | 67 | private function enterState($oldState:String, $newState:String):void 68 | { 69 | if($newState == StateType.SWF) 70 | { 71 | _swfURL = File(fileOpener.selectedFiles[0]).url; 72 | trace('swfPanel.load:', _swfURL); 73 | if(_swfURL) 74 | { 75 | v.swf.addEventListener(SSEvent.PREVIEW_LOAD_COMPLETE, handler_swfLoadDone); 76 | v.showSWF(_swfURL); 77 | } 78 | } 79 | } 80 | 81 | private function handler_swfLoadDone(event:SSEvent) : void 82 | { 83 | //若当前处于等待载入状态,则开始建立sheet 84 | if(v.state == StateType.WAIT_LOADED) 85 | { 86 | //如果允许调整尺寸,使用调整过的 87 | if(v.swf.enableDragContent) 88 | v.swf.moveContent(_swfContentX, _swfContentY); 89 | //开始capture 90 | v.state = StateType.PROCESSING; 91 | ssModel.resetSheet(null, new SpriteSheetMetadata()); 92 | v.capture(); 93 | } 94 | else 95 | { 96 | v.state = StateType.LOAD_DONE; 97 | } 98 | } 99 | 100 | private function handler_buildClick($evt:SSEvent):void 101 | { 102 | v.state = StateType.WAIT_LOADED; 103 | //记录当前移动的内容坐标,以便载入成功后还原 104 | _swfContentX = v.swf.contentX; 105 | _swfContentY = v.swf.contentY; 106 | v.build(_swfURL); 107 | } 108 | 109 | private function handler_addFrame($evt:SSEvent):void 110 | { 111 | ssModel.addOriginalFrame($evt.info.bmd, $evt.info.rect); 112 | } 113 | } 114 | } -------------------------------------------------------------------------------- /src/mediator/panel/TopPanelMediator.as: -------------------------------------------------------------------------------- 1 | package mediator.panel 2 | { 3 | import events.SSEvent; 4 | 5 | import flash.events.Event; 6 | import flash.events.MouseEvent; 7 | 8 | import model.StateModel; 9 | 10 | import org.robotlegs.mvcs.Mediator; 11 | import org.zengrong.utils.SOUtil; 12 | 13 | import type.StateType; 14 | 15 | import view.panel.TopPanel; 16 | 17 | public class TopPanelMediator extends Mediator 18 | { 19 | [Inject] public var v:TopPanel; 20 | 21 | [Inject] public var stateModel:StateModel; 22 | 23 | private var _prevState:String; 24 | 25 | private var _so:SOUtil; 26 | 27 | override public function onRegister():void 28 | { 29 | eventMap.mapListener(v.prevBTN, MouseEvent.CLICK, handler_prievBTNClick); 30 | eventMap.mapListener(v.fpsNS, Event.CHANGE, handler_fpsNSChange); 31 | 32 | eventMap.mapListener(eventDispatcher, SSEvent.ENTER_STATE, handler_enterState); 33 | 34 | _so = SOUtil.getSOUtil('sse'); 35 | showFPS(); 36 | } 37 | 38 | private function handler_enterState($evt:SSEvent):void 39 | { 40 | enterState($evt.info.oldState, $evt.info.newState); 41 | } 42 | 43 | private function showFPS():void 44 | { 45 | v.fpsGRP.visible = (stateModel.state != StateType.START); 46 | var __frameRate:int = int(_so.get('frameRate')); 47 | if(__frameRate > 0) 48 | { 49 | v.fpsNS.value = __frameRate; 50 | v.stage.frameRate = v.fpsNS.value; 51 | } 52 | } 53 | 54 | private function enterState($oldState:String, $newState:String):void 55 | { 56 | if(!$oldState && !$newState) return; 57 | v.stateNameLabel.text = StateType.toMainStateName($newState); 58 | if($newState == StateType.START) 59 | { 60 | _prevState = null; 61 | } 62 | else 63 | { 64 | _prevState = $oldState; 65 | //如果状态是反向跳转(从后一步跳转到前一步),那么就将返回按钮指向第一步 66 | if( ($newState == StateType.PIC || $newState == StateType.SWF) && 67 | ($oldState != StateType.START) ) 68 | _prevState = StateType.START; 69 | } 70 | trace(_prevState); 71 | v.prevBTN.enabled = (_prevState != null); 72 | showFPS(); 73 | } 74 | 75 | protected function handler_fpsNSChange(event:Event):void 76 | { 77 | v.stage.frameRate = v.fpsNS.value; 78 | _so.save(v.fpsNS.value, 'frameRate'); 79 | } 80 | 81 | protected function handler_prievBTNClick(event:MouseEvent):void 82 | { 83 | stateModel.state = _prevState; 84 | } 85 | } 86 | } -------------------------------------------------------------------------------- /src/model/FileOpenerModel.as: -------------------------------------------------------------------------------- 1 | package model 2 | { 3 | import events.SSEvent; 4 | import flash.events.IOErrorEvent; 5 | import flash.filesystem.File; 6 | import gnu.as3.gettext.FxGettext; 7 | import org.zengrong.assets.AssetsType; 8 | import org.zengrong.display.spritesheet.SpriteSheetMetadataType; 9 | import org.zengrong.net.SpriteSheetLoader; 10 | import type.ExtendedNameType; 11 | import type.StateType; 12 | import flash.events.Event; 13 | import flash.events.FileListEvent; 14 | import utils.Funs; 15 | import vo.BrowseFileDoneVO; 16 | /** 17 | * 负责打开文件 18 | * @author zrong(zengrong.net) 19 | * Creation: 2013-08-19 20 | */ 21 | public class FileOpenerModel extends FileProcessor 22 | { 23 | public function FileOpenerModel() 24 | { 25 | super(); 26 | _ssLoader = new SpriteSheetLoader(); 27 | _ssLoader.addEventListener(Event.COMPLETE, handler_ssLoadComplete); 28 | _ssLoader.addEventListener(IOErrorEvent.IO_ERROR, handler_ssLoadError); 29 | } 30 | 31 | [Inject] public var ssModel:SpriteSheetModel; 32 | 33 | private var _ssLoader:SpriteSheetLoader; //用于载入现有的SpriteSheet 34 | 35 | private var _selectedFiles:Array; //选择的文件数组 36 | 37 | public function get selectedFiles():Array 38 | { 39 | return _selectedFiles; 40 | } 41 | 42 | //---------------------------------------- 43 | // 打开文件操作 44 | //---------------------------------------- 45 | 46 | public function open($state:String):void 47 | { 48 | _openState = $state; 49 | switch(_openState) 50 | { 51 | case StateType.SWF: 52 | _file.browseForOpen(FxGettext.gettext("Select a swf file"), [ExtendedNameType.SWF_FILTER]); 53 | break; 54 | case StateType.SS: 55 | _file.browseForOpen(FxGettext.gettext("Select a Sprite Sheet file"), ExtendedNameType.ALL_PIC_FILTER_LIST); 56 | break; 57 | case StateType.PIC: 58 | _file.browseForOpenMultiple(FxGettext.gettext("Select image file"), ExtendedNameType.ALL_PIC_FILTER_LIST); 59 | break; 60 | case StateType.ADD_TO_PIC_List: 61 | _file.browseForOpenMultiple(FxGettext.gettext("Select image file"), ExtendedNameType.ALL_PIC_FILTER_LIST); 62 | break; 63 | case StateType.ADD_TO_SS: 64 | _file.browseForOpenMultiple(FxGettext.gettext("Select image file"), ExtendedNameType.ALL_PIC_FILTER_LIST); 65 | break; 66 | } 67 | } 68 | 69 | 70 | /** 71 | * 打开一个被拖入界面中的文件 72 | * @param $file 要处理的文件,可能是一个File,也可能是File数组 73 | * @param $openState 打开的状态 74 | */ 75 | public function openFilesByDrag($files:Array, $openState:String):void 76 | { 77 | _openState = $openState; 78 | checkSelectedFiles($files); 79 | } 80 | 81 | private function checkSelectedFiles($files:Array):void 82 | { 83 | _selectedFiles = $files; 84 | if(StateType.isViewState(_openState)) 85 | { 86 | //如果要切换到SS状态,需要等待SS文件载入并解析完毕后才能切换状态。 87 | //载入的工作交给SpriteSheetLaoderModel。 88 | if(_openState == StateType.SS) 89 | _ssLoader.load(File(_selectedFiles[0]).url); 90 | //如果发生选择事件的state是编辑器界面/open状态,就执行状态切换 91 | else 92 | stateModel.state = _openState; 93 | } 94 | if(_openState == StateType.ADD_TO_PIC_List || 95 | _openState == StateType.ADD_TO_SS) 96 | { 97 | var __bfd:BrowseFileDoneVO = new BrowseFileDoneVO(_openState, _selectedFiles); 98 | //向SS中加入帧的时候,要判断加入的文件是否是SS类型 99 | if(_openState == StateType.ADD_TO_SS && 100 | Funs.hasMetadataFile((_selectedFiles[0] as File).url, SpriteSheetMetadataType.XML)) 101 | { 102 | __bfd.fileType = AssetsType.SPRITE_SHEET; 103 | __bfd.metaType = SpriteSheetMetadataType.XML; 104 | } 105 | this.dispatch(new SSEvent(SSEvent.BROWSE_FILE_DONE, __bfd)); 106 | } 107 | //trace('checkSelectedFiles', _file.nativePath, $evt.files, _openState); 108 | } 109 | 110 | //---------------------------------------- 111 | // handler 112 | //---------------------------------------- 113 | override protected function handler_selectSingle($evt:Event):void 114 | { 115 | checkSelectedFiles([_file.clone()]); 116 | } 117 | 118 | override protected function handler_selectMulti($evt:FileListEvent):void 119 | { 120 | checkSelectedFiles($evt.files); 121 | } 122 | 123 | /** 124 | * 打开SS格式,载入SS完毕后调用 125 | */ 126 | private function handler_ssLoadComplete($evt:Event):void 127 | { 128 | ssModel.updateOriginalSheet(_ssLoader.getSpriteSheet()); 129 | stateModel.state = StateType.SS; 130 | } 131 | 132 | private function handler_ssLoadError($evt:IOErrorEvent):void 133 | { 134 | Funs.alert($evt.text); 135 | } 136 | } 137 | } -------------------------------------------------------------------------------- /src/model/FileProcessor.as: -------------------------------------------------------------------------------- 1 | package model 2 | { 3 | import flash.events.Event; 4 | import flash.events.FileListEvent; 5 | import flash.filesystem.File; 6 | import org.robotlegs.mvcs.Actor; 7 | 8 | /** 9 | * 专门负责对文件的处理,基类。 10 | * @author zrong(zengrong.net) 11 | * Creation: 2011-8-3 12 | * Modification: 2013-08-19 13 | */ 14 | public class FileProcessor extends Actor 15 | { 16 | [Inject] public var stateModel:StateModel; 17 | 18 | public function FileProcessor() 19 | { 20 | initFile(File.desktopDirectory); 21 | } 22 | 23 | protected var _file:File; 24 | protected var _openState:String; 25 | 26 | protected function initFile($file:File):void 27 | { 28 | if(_file) 29 | { 30 | _file.removeEventListener(FileListEvent.SELECT_MULTIPLE, handler_selectMulti); 31 | _file.removeEventListener(Event.SELECT, handler_selectSingle); 32 | _file.removeEventListener(Event.CANCEL, handler_selectCancel); 33 | } 34 | _file = $file; 35 | _file.addEventListener(FileListEvent.SELECT_MULTIPLE, handler_selectMulti); 36 | _file.addEventListener(Event.SELECT, handler_selectSingle); 37 | _file.addEventListener(Event.CANCEL, handler_selectCancel); 38 | } 39 | 40 | public function get openState():String 41 | { 42 | return _openState; 43 | } 44 | 45 | //---------------------------------------- 46 | // handler 47 | //---------------------------------------- 48 | 49 | protected function handler_selectSingle($evt:Event):void 50 | { 51 | } 52 | 53 | protected function handler_selectMulti($evt:FileListEvent):void 54 | { 55 | } 56 | 57 | protected function handler_selectCancel($evt:Event):void 58 | { 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /src/model/FileSaverModel.as: -------------------------------------------------------------------------------- 1 | package model 2 | { 3 | import flash.display.BitmapData; 4 | import flash.display.JPEGEncoderOptions; 5 | import flash.display.JPEGXREncoderOptions; 6 | import flash.display.PNGEncoderOptions; 7 | import flash.filesystem.File; 8 | import flash.filesystem.FileMode; 9 | import flash.filesystem.FileStream; 10 | import flash.utils.ByteArray; 11 | import gnu.as3.gettext.FxGettext; 12 | import type.ExtendedNameType; 13 | import type.StateType; 14 | import vo.SaveVO; 15 | import flash.events.Event; 16 | /** 17 | * 负责保存文件 18 | * @author zrong(zengrong.net) 19 | * Creation: 2013-08-19 20 | */ 21 | public class FileSaverModel extends FileProcessor 22 | { 23 | public function FileSaverModel() 24 | { 25 | super(); 26 | } 27 | 28 | private var _saveData:SaveVO; 29 | 30 | //---------------------------------------- 31 | // 保存文件操作 32 | //---------------------------------------- 33 | 34 | public function save($vo:SaveVO):void 35 | { 36 | _saveData = $vo; 37 | _openState = _saveData.type; 38 | var __title:String; 39 | switch(_saveData.type) 40 | { 41 | case StateType.SAVE_SHEET_PIC: 42 | __title = FxGettext.gettext("Select the save path of Sprite Sheet file"); 43 | //更新一次File的引用,是为了避免File指向老的已经存在的图片,导致AIR的覆盖提示错误 44 | initFile(getFile(_saveData.picType)); 45 | _file.browseForSave(__title); 46 | break; 47 | case StateType.SAVE_META: 48 | __title = FxGettext.gettext("Select the save path of metadata"); 49 | _file.browseForSave(__title); 50 | break; 51 | case StateType.SAVE_SEQ: 52 | __title = FxGettext.gettext("Select the save path of the image sequence"); 53 | _file.browseForDirectory(__title); 54 | break; 55 | case StateType.SAVE_ALL: 56 | __title = FxGettext.gettext("Select the save path of image and metedata"); 57 | //更新一次File的引用,是为了避免File指向老的已经存在的图片,导致AIR的覆盖提示错误 58 | initFile(getFile(_saveData.picType)); 59 | _file.browseForSave(__title); 60 | break; 61 | } 62 | } 63 | 64 | private function saveData():void 65 | { 66 | var __stream:FileStream = new FileStream(); 67 | var __ba:ByteArray = null; 68 | var __imgFile:File = getFile(_saveData.picType); 69 | if(_openState == StateType.SAVE_META) 70 | { 71 | __stream.open(getFile(_saveData.metaType), FileMode.WRITE); 72 | __stream.writeUTFBytes(_saveData.metadata.objectify(_saveData.isSimple, _saveData.includeName, __imgFile.name)); 73 | __stream.close(); 74 | } 75 | else if(_openState == StateType.SAVE_SHEET_PIC) 76 | { 77 | __ba = getSheet(_saveData.bitmapData, _saveData.picType, _saveData.quality); 78 | __stream.open(__imgFile, FileMode.WRITE); 79 | __stream.writeBytes(__ba); 80 | __stream.close(); 81 | } 82 | else if(_openState == StateType.SAVE_ALL) 83 | { 84 | //使用sheet的扩展名(数组元素0)新建一个File 85 | __ba = getSheet(_saveData.bitmapData, _saveData.picType, _saveData.quality); 86 | __stream.open(__imgFile, FileMode.WRITE); 87 | __stream.writeBytes(__ba); 88 | __stream.close(); 89 | 90 | //使用metadata的扩展名(数组元素1)新建一个File 91 | __stream.open(getFile(_saveData.metaType), FileMode.WRITE); 92 | __stream.writeUTFBytes(_saveData.metadata.objectify(_saveData.isSimple, _saveData.includeName,__imgFile.name)); 93 | __stream.close(); 94 | } 95 | else if(_openState == StateType.SAVE_SEQ) 96 | { 97 | var __bmds:Vector. = _saveData.bitmapDataList; 98 | var __names:Vector. = _saveData.fileNameList; 99 | //获取文件的扩展名 100 | var __ext:String = __names[0].slice(__names[0].lastIndexOf('.')); 101 | for (var i:int = 0; i < __bmds.length; i++) 102 | { 103 | __ba = getSheet(__bmds[i], __ext, _saveData.quality); 104 | __stream.open(_file.resolvePath(__names[i]), FileMode.WRITE); 105 | __stream.writeBytes(__ba); 106 | __stream.close(); 107 | } 108 | } 109 | } 110 | 111 | //---------------------------------------- 112 | // 内部方法 113 | //---------------------------------------- 114 | 115 | /** 116 | * 根据扩展名,制作一个新的File文件对象并返回 117 | */ 118 | private function getFile($ext:String):File 119 | { 120 | var __file:File = _file.parent.resolvePath(_file.name.split('.')[0]+$ext); 121 | return __file; 122 | } 123 | 124 | /** 125 | * 获取压缩之后的Sheet的Byte 126 | */ 127 | private function getSheet($bmd:BitmapData, $ext:String, $quality:int=70):ByteArray 128 | { 129 | var __ba:ByteArray = null; 130 | var __opt:*; 131 | if($ext == ExtendedNameType.PNG) 132 | { 133 | __opt = new PNGEncoderOptions(); 134 | } 135 | else if($ext == ExtendedNameType.JPEG_XR) 136 | { 137 | __opt = new JPEGXREncoderOptions($quality); 138 | } 139 | else 140 | { 141 | __opt = new JPEGEncoderOptions($quality); 142 | } 143 | return $bmd.encode($bmd.rect, __opt); 144 | } 145 | 146 | override protected function handler_selectSingle($evt:Event):void 147 | { 148 | saveData(); 149 | } 150 | } 151 | } -------------------------------------------------------------------------------- /src/model/SpriteSheetModel.as: -------------------------------------------------------------------------------- 1 | package model 2 | { 3 | import flash.display.BitmapData; 4 | import flash.geom.Rectangle; 5 | import org.zengrong.display.spritesheet.MaskType; 6 | import org.zengrong.utils.BitmapUtil; 7 | import vo.RectsAndBmdsVO; 8 | 9 | import org.robotlegs.mvcs.Actor; 10 | import org.zengrong.display.spritesheet.SpriteSheet; 11 | import org.zengrong.display.spritesheet.SpriteSheetMetadata; 12 | 13 | /** 14 | * 暂存编辑过程中的位图资源 15 | * @author zrong 16 | * 创建日期:2012-07-25 17 | */ 18 | public class SpriteSheetModel extends Actor 19 | { 20 | public function SpriteSheetModel() 21 | { 22 | } 23 | 24 | 25 | public function resetSheet($bmd:BitmapData=null, $meta:SpriteSheetMetadata=null):void 26 | { 27 | if(_originalSheet) _originalSheet.destroy(); 28 | _originalSheet = new SpriteSheet($bmd, $meta); 29 | } 30 | 31 | public function getBMDList():Vector. 32 | { 33 | if(displayCrop) return adjustedSheet.getAll(); 34 | return originalSheet.getAll(); 35 | } 36 | 37 | public function destroySheet():void 38 | { 39 | if(_originalSheet) _originalSheet.destroy(); 40 | _originalSheet = null; 41 | if(adjustedSheet) adjustedSheet.destroy(); 42 | _adjustedSheet = null; 43 | } 44 | 45 | private var _originalSheet:SpriteSheet; 46 | /** 47 | * 刚生成的sheet,或者打开的sheet文件,保存在此对象中。在此sheet的基础上进行调整后保存 48 | */ 49 | public function get originalSheet():SpriteSheet 50 | { 51 | return _originalSheet; 52 | } 53 | 54 | /** 55 | * 更新当前保存的原始Sheet 56 | */ 57 | public function updateOriginalSheet($sheet:SpriteSheet):void 58 | { 59 | if(_originalSheet) _originalSheet.destroy(); 60 | _originalSheet = $sheet; 61 | _originalSheet.parseSheet(); 62 | } 63 | 64 | private var _adjustedSheet:SpriteSheet; 65 | 66 | /** 67 | * 保存调整过的Sheet。对生成的sheet经常会做一些调整,例如剔除透明像素,加背景色等等,调整后的结果保存在此对象中 68 | */ 69 | public function get adjustedSheet():SpriteSheet 70 | { 71 | return _adjustedSheet; 72 | } 73 | 74 | /** 75 | * 基于原始的Sheet更新调整后的Sheet 76 | */ 77 | public function updateAdjustedSheet():void 78 | { 79 | //TODO 将支持多语言 80 | if(!_originalSheet) throw new TypeError("无法获取原始Sprite Sheet!"); 81 | if(_adjustedSheet) _adjustedSheet.destroy(); 82 | _adjustedSheet = _originalSheet.clone(); 83 | } 84 | 85 | public function drawOriginalSheet($bmd:BitmapData):void 86 | { 87 | _originalSheet.drawSheet($bmd); 88 | } 89 | 90 | public function addOriginalFrame($bmd:BitmapData, $sizeRect:Rectangle=null, $originalRect:Rectangle=null, $name:String=null):void 91 | { 92 | _originalSheet.addFrame($bmd, $sizeRect, $originalRect, $name); 93 | } 94 | 95 | public function addOriginalFrameAt($index:int, $bmd:BitmapData, $sizeRect:Rectangle=null, $originalRect:Rectangle=null,$name:String=null):void 96 | { 97 | _originalSheet.addFrameAt($index, $bmd, $sizeRect, $originalRect, $name); 98 | } 99 | 100 | /** 101 | * 重新设置Sheet中的帧信息,并重绘Sheet位图 102 | * @param $bmd 103 | * @param $list 104 | */ 105 | public function redrawAdjustedSheet($bmd:BitmapData, $list:RectsAndBmdsVO):void 106 | { 107 | _adjustedSheet.setFrames($list.bmds, $list.frameRects, $list.originRects, originalSheet.metadata.names); 108 | _adjustedSheet.drawSheet($bmd); 109 | } 110 | 111 | public function addAdjustedFrame($bmd:BitmapData, $sizeRect:Rectangle=null, $originalRect:Rectangle=null, $name:String=null):void 112 | { 113 | _adjustedSheet.addFrame($bmd, $sizeRect, $originalRect, $name); 114 | } 115 | 116 | public function addAdjustedFrameAt($index:int, $bmd:BitmapData, $sizeRect:Rectangle=null, $originalRect:Rectangle=null,$name:String=null):void 117 | { 118 | _adjustedSheet.addFrameAt($index, $bmd, $sizeRect, $originalRect, $name); 119 | } 120 | 121 | /** 122 | * 绘制Mask,返回带有Mask的位图(如果有mask的话) 123 | */ 124 | public function getBitmapDataForSave($maskType:int, $transparent:Boolean, $bgcolor:uint):BitmapData 125 | { 126 | if(MaskType.useMask($maskType)) 127 | { 128 | return BitmapUtil.getBitmapDataWithMask(adjustedSheet.bitmapData, $maskType == MaskType.HOR_MASK, $transparent, $bgcolor); 129 | } 130 | return adjustedSheet.bitmapData; 131 | } 132 | 133 | /** 134 | * 返回生成的原始帧rect尺寸(origin),在大sheet中的rect尺寸(frame),以及所有的BitmapData列表(bmd) 135 | * @param $trim 是否修剪 136 | * @param $reset 是否重置大小 137 | */ 138 | public function getRectsAndBmds($trim:Boolean, $reset:Boolean):RectsAndBmdsVO 139 | { 140 | //所有的BitmapData列表 141 | var __bmd:Vector. = null; 142 | //在大sheet中的rect列表 143 | var __frame:Vector. = null; 144 | //原始的(在程序中使用的)rect列表 145 | var __origin:Vector. = null; 146 | if($trim) 147 | { 148 | __bmd = new Vector.; 149 | __frame = new Vector.; 150 | __origin = new Vector.; 151 | var __sizeRect:Rectangle = null; 152 | //用于保存执行trim方法后的结果 153 | var __trim:Object = null; 154 | for (var i:int=0; i < originalSheet.metadata.totalFrame; i++) 155 | { 156 | __trim = BitmapUtil.trim(originalSheet.getBMDByIndex(i)); 157 | __sizeRect = originalSheet.metadata.originalFrameRects[i]; 158 | __frame[i] = __trim.rect; 159 | //如果重设帧的尺寸,就使用trim过后的帧的宽高建立一个新的Rect尺寸,并更新bmd 160 | if($reset) 161 | { 162 | __origin[i] = new Rectangle(0,0,__trim.rect.width,__trim.rect.height); 163 | __bmd[i] = __trim.bitmapData; 164 | } 165 | else 166 | { 167 | //如果不重设帧的尺寸,就使用原始大小的宽高。同时计算trim后的xy的偏移。 168 | //因为获得xy的偏移是基于与原始帧大小的正数,要将其转换为基于trim后的帧的偏移,用0减 169 | //不重设尺寸的情况下,不更新bmd,因为原始尺寸没变。SpriteSheet中保存的bmdList,永远都与原始尺寸相同 170 | __bmd = originalSheet.cloneFrames(); 171 | __origin[i] = new Rectangle( 172 | 0-__trim.rect.x, 173 | 0-__trim.rect.y, 174 | __sizeRect.width, 175 | __sizeRect.height); 176 | } 177 | } 178 | } 179 | else 180 | { 181 | //bmdlist永远都是原始尺寸的,因此不需要重新绘制 182 | __bmd = originalSheet.cloneFrames(); 183 | __frame = originalSheet.metadata.frameRects.concat(); 184 | __origin = originalSheet.metadata.originalFrameRects.concat(); 185 | //不trim,将以前trim过的信息还原 186 | for (var j:int = 0; j < __frame.length; j++) 187 | { 188 | __frame[j].width = __origin[j].width; 189 | __frame[j].height = __origin[j].height; 190 | __origin[j].x = 0; 191 | __origin[j].y = 0; 192 | } 193 | } 194 | return new RectsAndBmdsVO(__bmd, __origin, __frame); 195 | } 196 | 197 | /** 198 | * 是否显示修剪空白后的帧的效果 199 | */ 200 | public var displayCrop:Boolean; 201 | 202 | /** 203 | * 为true代表显示选择的Frame,false代表显示Label 204 | */ 205 | public var displayFrame:Boolean; 206 | 207 | /** 208 | * 当前选择的Label名称 209 | */ 210 | public var displayLabel:String; 211 | 212 | public var resizeRect:Rectangle; 213 | 214 | /** 215 | * 保存当前选择的帧的编号 216 | */ 217 | public var selectedFrameIndex:int=-1; 218 | 219 | public var selectedFrmaeNum:int = -1; 220 | 221 | public var selectedFrameIndices:Vector.; 222 | 223 | public var playing:Boolean; 224 | } 225 | } -------------------------------------------------------------------------------- /src/model/StateModel.as: -------------------------------------------------------------------------------- 1 | package model 2 | { 3 | import events.SSEvent; 4 | 5 | import org.robotlegs.mvcs.Actor; 6 | 7 | public class StateModel extends Actor 8 | { 9 | public function StateModel() 10 | { 11 | } 12 | 13 | private var _state:String = 'start'; 14 | 15 | private var _oldState:String; 16 | 17 | public function get oldState():String 18 | { 19 | return _oldState; 20 | } 21 | 22 | public function get state():String 23 | { 24 | return _state; 25 | } 26 | 27 | public function set state($state:String):void 28 | { 29 | _oldState = _state; 30 | _state = $state; 31 | this.dispatch(new SSEvent(SSEvent.ENTER_STATE, {oldState:_oldState, newState:$state})); 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /src/type/ExtendedNameType.as: -------------------------------------------------------------------------------- 1 | package type 2 | { 3 | import flash.net.FileFilter; 4 | import gnu.as3.gettext.FxGettext; 5 | /** 6 | * 文件扩展名 7 | * @author zrong 8 | * 创建日期:2012-07-20 9 | */ 10 | public class ExtendedNameType 11 | { 12 | public static const JPEG_XR:String = '.wdp'; 13 | public static const JPEG:String = '.jpg'; 14 | public static const PNG:String = '.png'; 15 | 16 | public static const JSON:String = '.json'; 17 | public static const XML:String = '.xml'; 18 | public static const TEXT:String = '.txt'; 19 | 20 | /** 21 | * 要打开的图像文件类型 22 | */ 23 | public static const PNG_FILTER:FileFilter = new FileFilter(FxGettext.gettext("PNG image"), '*.png'); 24 | public static const JPG_FILTER:FileFilter = new FileFilter(FxGettext.gettext("JPEG image"), '*.jpg;*.jpeg'); 25 | public static const JPEG_XR_FILTER:FileFilter = new FileFilter(FxGettext.gettext("JPEG-XR image"), '*.wdp;*.hdp'); 26 | public static const SWF_FILTER:FileFilter = new FileFilter(FxGettext.gettext("SWF animation"), '*.swf'); 27 | public static const ALL_PIC_FILTER:FileFilter = new FileFilter(FxGettext.gettext("All compatible image"), PNG_FILTER.extension + ';' + JPG_FILTER.extension + ';' + JPEG_XR_FILTER.extension); 28 | 29 | public static const ALL_PIC_FILTER_LIST:Array = [ ALL_PIC_FILTER, PNG_FILTER, JPG_FILTER, JPEG_XR_FILTER]; 30 | 31 | } 32 | } -------------------------------------------------------------------------------- /src/type/StateType.as: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // zengrong.net 3 | // 创建者: zrong zrongzrong@gmail.com 4 | // 创建时间:2011-8-3 5 | //////////////////////////////////////////////////////////////////////////////// 6 | 7 | package type 8 | { 9 | import flash.filesystem.File; 10 | import gnu.as3.gettext.FxGettext; 11 | import org.zengrong.display.spritesheet.SpriteSheetMetadata; 12 | 13 | /** 14 | * 保存State的名称 15 | * @author zrong 16 | */ 17 | public class StateType 18 | { 19 | //---------------------------------------- 20 | // 以下是编辑器的主状态 21 | //---------------------------------------- 22 | 23 | /** 24 | * 编辑器处于start状态 25 | */ 26 | public static const START:String = 'start'; 27 | 28 | /** 29 | * 编辑器处于载入SWF状态 30 | */ 31 | public static const SWF:String = 'swf'; 32 | 33 | /** 34 | * 编辑器处于载入图片状态 35 | */ 36 | public static const PIC:String = 'pic'; 37 | 38 | /** 39 | * 编辑器处于开启SS文件状态 40 | */ 41 | public static const SS:String = 'ss'; 42 | 43 | /** 44 | * 检测$state是不是主编辑器状态 45 | */ 46 | public static function isViewState($state:String):Boolean 47 | { 48 | var __mainState:Vector. = Vector.([START, SWF, PIC, SS]); 49 | for (var i:int = 0; i < __mainState.length; i++) 50 | { 51 | if(__mainState[i] == $state) 52 | return true; 53 | } 54 | return false; 55 | } 56 | 57 | public static function toMainStateName($state:String):String 58 | { 59 | switch($state) 60 | { 61 | case StateType.START: 62 | return FxGettext.gettext("Start"); 63 | case StateType.SS: 64 | return FxGettext.gettext("Edit Sprite Sheet"); 65 | case StateType.SWF: 66 | return FxGettext.gettext("Import swf file"); 67 | } 68 | return FxGettext.gettext("Process image file"); 69 | } 70 | 71 | //---------------------------------------- 72 | // 以下是保存状态 73 | //---------------------------------------- 74 | 75 | /** 76 | * 保存Metadata文件 77 | */ 78 | public static const SAVE_META:String = 'saveMeta'; 79 | 80 | /** 81 | * 保存SpriteSheet文件 82 | */ 83 | public static const SAVE_SHEET_PIC:String = 'saveSheet'; 84 | 85 | /** 86 | * 同时保存SpriteSheet和metadata文件 87 | */ 88 | public static const SAVE_ALL:String = 'saveAll'; 89 | 90 | /** 91 | * 保存序列 92 | */ 93 | public static const SAVE_SEQ:String = 'saveSeq'; 94 | 95 | //---------------------------------------- 96 | // 以下是其他状态 97 | //---------------------------------------- 98 | 99 | /** 100 | * 等待载入完毕的状态 101 | */ 102 | public static const WAIT_LOADED:String = 'waitLoaded'; 103 | 104 | /** 105 | * 正在建立的状态 106 | */ 107 | public static const PROCESSING:String = 'processing'; 108 | 109 | /** 110 | * 载入完成的状态 111 | */ 112 | public static const LOAD_DONE:String = 'loadDone'; 113 | 114 | /** 115 | * 将内容加入到spritesheet中的状态 116 | */ 117 | public static const ADD_TO_SS:String = 'addToSS'; 118 | 119 | /** 120 | * 在PicPanel界面将图片加入到Pic列表中的状态 121 | */ 122 | public static const ADD_TO_PIC_List:String = "addToPicList"; 123 | } 124 | } -------------------------------------------------------------------------------- /src/utils/Funs.as: -------------------------------------------------------------------------------- 1 | package utils 2 | { 3 | import flash.filesystem.File; 4 | import flash.geom.Rectangle; 5 | import org.zengrong.assets.AssetsType; 6 | import type.ExtendedNameType; 7 | import type.StateType; 8 | 9 | import mx.managers.PopUpManager; 10 | 11 | import gnu.as3.gettext.FxGettext; 12 | import gnu.as3.gettext.ISO_3166; 13 | import gnu.as3.gettext.ISO_639_1; 14 | import gnu.as3.gettext.Locale; 15 | 16 | import org.zengrong.air.utils.getDesc; 17 | import org.zengrong.utils.MathUtil; 18 | import org.zengrong.utils.SOUtil; 19 | 20 | import view.comps.Alert; 21 | 22 | public class Funs 23 | { 24 | public static function getLang():String 25 | { 26 | var __so:SOUtil = SOUtil.getSOUtil("sse"); 27 | //获取已经保存的显示语言 28 | var __lang:String = __so.get("lang"); 29 | //没有设置显示语言,则根据当前系统判断 30 | if(!__lang) 31 | { 32 | var __enus:String = mklocale(ISO_639_1.EN, ISO_3166.US); 33 | var __zhcn:String = mklocale(ISO_639_1.ZH, ISO_3166.CN); 34 | var __zhtw:String = mklocale(ISO_639_1.ZH, ISO_3166.TW); 35 | //若为简中或者繁中系统 36 | if( Locale.LANG == __zhcn || 37 | Locale.LANG == __zhtw ) 38 | { 39 | __lang = __zhcn; 40 | } 41 | //不是简中系统均使用英文 42 | else 43 | { 44 | __lang = __enus; 45 | } 46 | __so.save(__lang, "lang"); 47 | } 48 | return __lang; 49 | } 50 | 51 | public static function mklocale(iso639:String, iso3166:String):String 52 | { 53 | return ISO_639_1.codes[iso639]+"_"+ISO_3166.codes[iso3166]; 54 | } 55 | 56 | /** 57 | * 根据提供的Rectangle数组计算最终Sheet的宽高以及每帧在Sheet中的位置 58 | * @param $frameRect 当前帧的独立大小 59 | */ 60 | public static function calculateSize($frameRects:Vector., 61 | $newSizeRects:Vector., 62 | $whRect:Rectangle, 63 | $limitW:Boolean, 64 | $wh:int, 65 | $powOf2:Boolean=false, 66 | $square:Boolean=false):void 67 | { 68 | if($frameRects.length==0) return; 69 | var __frameRect:Rectangle = $frameRects[0]; 70 | $newSizeRects[0] = new Rectangle(0,0,__frameRect.width, __frameRect.height); 71 | var __rectInSheet:Rectangle = new Rectangle(0,0,__frameRect.width,__frameRect.height); 72 | trace('getSheetWH:', __rectInSheet, __frameRect, $whRect); 73 | //设置sheet的初始宽高 74 | if($limitW) 75 | { 76 | //若限制宽度小于帧的宽度,就扩大限制宽度 77 | $whRect.width = $wh; 78 | if($whRect.width<__frameRect.width) $whRect.width = __frameRect.width; 79 | //计算2的幂 80 | if($powOf2) $whRect.width = MathUtil.nextPowerOf2($whRect.width); 81 | $whRect.height = __frameRect.height; 82 | } 83 | else 84 | { 85 | $whRect.height = $wh; 86 | if($whRect.height<__frameRect.height) $whRect.height = __frameRect.height; 87 | if($powOf2) $whRect.height = MathUtil.nextPowerOf2($whRect.height); 88 | $whRect.width = __frameRect.width; 89 | } 90 | for (var i:int = 1; i < $frameRects.length; i++) 91 | { 92 | __frameRect = $frameRects[i]; 93 | updateRectInSheet(__rectInSheet, $whRect, __frameRect, $limitW); 94 | trace('getSheetWH:', __rectInSheet, __frameRect, $whRect); 95 | $newSizeRects[i] = __rectInSheet.clone(); 96 | } 97 | if($square) 98 | { 99 | //计算正方形的尺寸 100 | if($whRect.width!=$whRect.height) 101 | { 102 | //使用当前计算出的面积开方得到正方形的基准尺寸 103 | var __newWH:int = Math.sqrt($whRect.width*$whRect.height); 104 | //使用基准尺寸重新排列一次 105 | calculateSize($frameRects,$newSizeRects,$whRect,$limitW,__newWH, $powOf2); 106 | //trace('正方形计算1:', $whRect); 107 | //如果基准尺寸无法实现正方形尺寸,就使用结果WH中比较大的那个尺寸作为正方形边长 108 | if($whRect.width!=$whRect.height) 109 | { 110 | var __max:int = Math.max($whRect.width, $whRect.height); 111 | $whRect.width = __max; 112 | $whRect.height = __max; 113 | } 114 | //trace('正方形计算2:', $whRect); 115 | } 116 | } 117 | if($powOf2) 118 | { 119 | $whRect.width = MathUtil.nextPowerOf2($whRect.width); 120 | $whRect.height = MathUtil.nextPowerOf2($whRect.height); 121 | } 122 | } 123 | 124 | /** 125 | * 更新在Sheet中帧的Rect的位置,根据Rect位置计算出大Sheet的WH 126 | * 会直接修改$rectInSheet和$whRect参数的值。 127 | * @param $rectInSheet 当前处理的帧在整个Sheet中的位置和大小,会修改此参数的值 128 | * @param $whRect 保存Sheet的W和H,会修改此参数的值 129 | * @param $frameRect 要处理的帧大小的Rect 130 | * @param $limitW 为true代表限制宽度,否则是显示高度 131 | */ 132 | public static function updateRectInSheet($rectInSheet:Rectangle, 133 | $whRect:Rectangle, 134 | $frameRect:Rectangle, 135 | $limitW:Boolean):void 136 | { 137 | 138 | //限制宽度的计算 139 | if($limitW) 140 | { 141 | $rectInSheet.height = $frameRect.height; 142 | //若限制宽度小于帧的宽度,就扩大限制宽度,并进入新行 143 | if($whRect.width < $frameRect.width) 144 | { 145 | $whRect.width = $frameRect.width; 146 | newRow($rectInSheet, $frameRect, $whRect); 147 | } 148 | //如果这一行的宽度已经不够放下当前的位图,就进入新行 149 | else if($rectInSheet.right + $frameRect.width > $whRect.width) 150 | { 151 | newRow($rectInSheet, $frameRect, $whRect); 152 | } 153 | else 154 | { 155 | $rectInSheet.x += $rectInSheet.width; 156 | //如果当前帧比较高,就增加Sheet的高度 157 | if($whRect.height<$rectInSheet.bottom) 158 | $whRect.height = $rectInSheet.bottom; 159 | } 160 | //更新帧的宽 161 | $rectInSheet.width = $frameRect.width; 162 | } 163 | //限制高度的计算 164 | else 165 | { 166 | //更新帧的宽 167 | $rectInSheet.width = $frameRect.width; 168 | //若限制高度小于帧的高度,就扩大限制高度,并进入新列 169 | if($whRect.height < $frameRect.height) 170 | { 171 | $whRect.height = $frameRect.height; 172 | newColumn($rectInSheet, $frameRect, $whRect); 173 | } 174 | //如果这一列的高度已经放不下当前的位图,就进入新列 175 | else if($rectInSheet.bottom + $frameRect.height > $whRect.height) 176 | { 177 | newColumn($rectInSheet, $frameRect, $whRect); 178 | } 179 | else 180 | { 181 | //如果当前帧比Sheet还要宽,就增大Sheet的宽度 182 | $rectInSheet.y += $rectInSheet.height; 183 | if($whRect.width<$rectInSheet.right) 184 | $whRect.width = $rectInSheet.right; 185 | } 186 | 187 | $rectInSheet.height = $frameRect.height; 188 | } 189 | } 190 | 191 | private static function newRow($rectInSheet:Rectangle, $frameRect:Rectangle, $whRect:Rectangle):void 192 | { 193 | //让x回到行首 194 | $rectInSheet.x = 0; 195 | //更新新行的y值 196 | $rectInSheet.y = $whRect.height; 197 | //更新Sheet的高度 198 | $whRect.height += $frameRect.height; 199 | } 200 | 201 | private static function newColumn($rectInSheet:Rectangle, $frameRect:Rectangle, $whRect:Rectangle):void 202 | { 203 | $rectInSheet.y = 0; 204 | $rectInSheet.x = $whRect.width; 205 | $whRect.width += $frameRect.width; 206 | } 207 | 208 | public static function alert($text:String, $title:String=null):void 209 | { 210 | var __alert:Alert = PopUpManager.createPopUp(Global.root, Alert, true) as Alert; 211 | __alert.title = $title?FxGettext.gettext($title):FxGettext.gettext("Warning"); 212 | __alert.text = $text; 213 | var __xy:Array = getAlertXY(__alert); 214 | __alert.move(__xy[0], __xy[1]); 215 | } 216 | 217 | public static function confirm($text:String, $okHandler:Function, $cancelHandler:Function=null, $title:String=null):void 218 | { 219 | var __alert:Alert = PopUpManager.createPopUp(Global.root, Alert, true) as Alert; 220 | __alert.currentState = 'confirm'; 221 | __alert.title = $title?FxGettext.gettext($title):FxGettext.gettext("Please Confirm"); 222 | __alert.text = $text; 223 | __alert.okHandler = $okHandler; 224 | __alert.cancelHandler = $cancelHandler; 225 | var __xy:Array = getAlertXY(__alert); 226 | __alert.move(__xy[0], __xy[1]); 227 | } 228 | 229 | private static function getAlertXY($alert:Alert):Array 230 | { 231 | return [(Global.root.width-$alert.width)*.5, (Global.root.height-$alert.height)*.5]; 232 | } 233 | 234 | public static function getCreatedWith():String 235 | { 236 | return "Created with " + getDesc("name") + " v" + getDesc("versionNumber"); 237 | } 238 | 239 | public static function getXMLHeader($lineEnding:String):String 240 | { 241 | return '' +$lineEnding+ 242 | "" + $lineEnding + 243 | "" + $lineEnding; 244 | } 245 | 246 | /** 247 | * 根据载入的图片的地址,获取同名的metadata文件 248 | */ 249 | public static function getMetadataUrl($url:String, $type:String):String 250 | { 251 | var __dotIndex:int = $url.lastIndexOf('.'); 252 | if(__dotIndex == -1) 253 | return $url + '.'+$type; 254 | return $url.slice(0, __dotIndex) + '.'+$type; 255 | } 256 | 257 | public static function hasMetadataFile($url:String, $type:String="xml"):Boolean 258 | { 259 | var __metaUrl:String = getMetadataUrl($url, $type); 260 | var __file:File = new File(__metaUrl); 261 | return __file.exists; 262 | } 263 | 264 | /** 265 | * 根据当前传递的文件类型取得当前的界面状态 266 | * @return 267 | */ 268 | public static function getStateByFile($file:File):String 269 | { 270 | if(ExtendedNameType.SWF_FILTER.extension.indexOf($file.type) > -1) 271 | { 272 | return StateType.SWF; 273 | } 274 | else if( ExtendedNameType.ALL_PIC_FILTER.extension.indexOf($file.type) > -1) 275 | { 276 | if(hasMetadataFile($file.url, "xml")) return StateType.SS; 277 | return StateType.PIC; 278 | } 279 | return ''; 280 | } 281 | } 282 | } -------------------------------------------------------------------------------- /src/utils/Global.as: -------------------------------------------------------------------------------- 1 | package utils 2 | { 3 | import flash.display.Bitmap; 4 | import flash.display.BitmapData; 5 | import flash.display.Sprite; 6 | import flash.display.StageQuality; 7 | import flash.geom.Matrix; 8 | import flash.geom.Point; 9 | import flash.ui.Mouse; 10 | import flash.ui.MouseCursorData; 11 | 12 | public class Global 13 | { 14 | [Embed(source="/../asset/embed/chess.png")] 15 | public static const BMP_CHESS:Class; 16 | 17 | [Embed(source="/../asset/embed/about.txt",mimeType="application/octet-stream")] 18 | public static const ABOUT_TEXT:Class; 19 | 20 | //Assets.swf来自于Flex框架 %FLEX_SDK%\frameworks\projects\framework\assets\Assets.swf 21 | [Embed(source="Assets.swf",symbol="mx.skins.cursor.VBoxDivider")] 22 | public static const MC_CURSOR_VDIVIDER:Class; 23 | 24 | [Embed(source="Assets.swf",symbol="mx.skins.BoxDividerSkin")] 25 | public static const MC_BOX_DIVIDER:Class; 26 | 27 | public static const VDIVIDER:String = 'vdivider'; 28 | 29 | /** 30 | * 保存root对象 31 | */ 32 | public static var root:SpriteSheetEditor; 33 | 34 | public static var bmd_chess:BitmapData; 35 | 36 | public static var cursor_vdivider:MouseCursorData; 37 | 38 | public static function init($root:SpriteSheetEditor):void 39 | { 40 | root = $root; 41 | var __bmp:Bitmap = new BMP_CHESS as Bitmap; 42 | bmd_chess = __bmp.bitmapData; 43 | 44 | var __sp:Sprite = new MC_CURSOR_VDIVIDER as Sprite; 45 | var __bmd:BitmapData = new BitmapData(16, 16, true, 0x00000000); 46 | __bmd.drawWithQuality(__sp, new Matrix(1,0,0,1, 8, 8), null, null, null, true, StageQuality.BEST); 47 | cursor_vdivider = new MouseCursorData(); 48 | cursor_vdivider.data = Vector.([__bmd]); 49 | cursor_vdivider.hotSpot = new Point(8,8); 50 | Mouse.registerCursor(VDIVIDER, cursor_vdivider); 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /src/view/About.mxml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | ' + getDesc('name') + ' v'+ getDesc('versionNumber') +'

' 34 | +'

Author: zrong(zrongzrong@gmail.com)
Blog: http://www.zengrong.net

'; 35 | infoLabel.textFlow = TextConverter.importToFlow(__str, TextConverter.TEXT_FIELD_HTML_FORMAT); 36 | } 37 | 38 | ]]> 39 |
40 | 41 | 42 | 43 |
44 | -------------------------------------------------------------------------------- /src/view/comps/Alert.mxml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | {FxGettext.gettext("OK")} 11 | 12 | 13 | {FxGettext.gettext("Cancel")} 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /src/view/comps/BMPPreview.mxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 12 | 13 | 14 | 15 | [Event(name="previewClick", type="events.SSEvent")] 16 | 17 | 18 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /src/view/comps/BuildSetting.mxml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | [Event(name="build", type="events.SSEvent")] 11 | 12 | 13 | 14 | 15 | 16 | 17 | {FxGettext.gettext("Build Sprite Sheet")} 18 | {FxGettext.gettext("Optimize Sprite Sheet")} 19 | 20 | 21 | 22 | 23 | {FxGettext.gettext("Smooth")} 24 | 25 | 26 | {FxGettext.gettext("Transparent")} 27 | 28 | 29 | 30 | 31 | {FxGettext.gettext("Background")} 32 | 33 | 34 | 35 | 36 | 37 | {FxGettext.gettext("Select width or height of the SpriteSheet. Another dimension needed to automatically calculate.")} 38 | 39 | {FxGettext.gettext("Width")} 40 | {FxGettext.gettext("Height")} 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | {FxGettext.gettext("Trim blank")} 51 | {FxGettext.gettext("If selected, then in the top left corner of the pixel color as a benchmark, cutting off the edge of the redundant blank.")} 52 | 53 | 54 | {FxGettext.gettext("Reset frame size")} 55 | {FxGettext.gettext("If selected, reset the original frame to the size after pruning blank. In metadata, the trimmed frame size and the original frame size is same. Otherwise, it has only use in the trimmed size which has been saved Sprite Sheet, and save the original frame size and trimmed frame size in the metadata.")} 56 | 57 | 58 | 59 | 60 | 61 | {FxGettext.gettext("Power of 2")} 62 | {FxGettext.gettext("If selected, then output size are power of 2(e.g., 256,512)")} 63 | 64 | 65 | {FxGettext.gettext("Square")} 66 | {FxGettext.gettext("If selected, then output file is square, width and height are automatic identification")} 67 | 68 | 69 | 70 | 71 | {FxGettext.gettext("Build")} 72 | {FxGettext.gettext("Optimize")} 73 | 74 | 75 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /src/view/comps/FileManager.mxml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | [Event(name="selectionChange", type="events.SSEvent")] 7 | [Event(name="selectionChanging", type="events.SSEvent")] 8 | [Event(name="select", type="flash.events.Event")] 9 | 10 | 11 | {FxGettext.gettext("File list")} 12 | 13 | 16 | 17 | 18 | 19 | {FxGettext.gettext("File name")} 20 | 21 | 22 | {FxGettext.gettext("File size")} 23 | 24 | 25 | 26 | 27 | 28 | 29 | {FxGettext.gettext("Add multiple files. If you select items in the list, add the file will appear in the option above.")} 30 | 31 | 32 | {FxGettext.gettext("Delete the selected file from the list.")} 33 | 34 | 35 | {FxGettext.gettext("Move to top")} 36 | 37 | 38 | {FxGettext.gettext("move to bottom")} 39 | 40 | 41 | {FxGettext.gettext("Move up")} 42 | 43 | 44 | {FxGettext.gettext("Move down")} 45 | 46 | 47 | 48 | 1) return; 81 | this.dispatchEvent(new SSEvent(SSEvent.FILE_MANAGER_SELECTION_CHANGE)); 82 | } 83 | 84 | private function selectionChanging():void 85 | { 86 | //选择的行数大于1,不发给上层 87 | if(fileDG.selectionLength>1) return; 88 | this.dispatchEvent(new SSEvent(SSEvent.FILE_MANAGER_SELECTION_CHANGING)); 89 | } 90 | 91 | protected function handler_topAndBottomFileClick($event:MouseEvent):void 92 | { 93 | var __indexAdjust:int = ($event.currentTarget == topFile) ? -100 : 100; 94 | moveItem(__indexAdjust); 95 | } 96 | 97 | protected function handler_upAndDownFileclick($event:MouseEvent):void 98 | { 99 | var __indexAdjust:int = ($event.currentTarget == upFile) ? -1 : 1; 100 | moveItem(__indexAdjust); 101 | } 102 | 103 | protected function handler_delFileclick($event:MouseEvent):void 104 | { 105 | var __indices:Vector. = fileDG.selectedIndices; 106 | for(var i:int=__indices.length-1;i>=0;i--) 107 | { 108 | fileList.removeItemAt(__indices[i]); 109 | } 110 | delFile.enabled = false; 111 | upFile.enabled = false; 112 | downFile.enabled = false; 113 | selectionChange(); 114 | } 115 | 116 | protected function handler_addFileclick($event:MouseEvent):void 117 | { 118 | this.dispatchEvent(new Event(Event.SELECT)); 119 | } 120 | 121 | public function addFile2Manager($filelist:Array):void 122 | { 123 | var __selectedFiles:Array = $filelist; 124 | var __index:int = fileDG.selectedIndex>-1?fileDG.selectedIndex:fileList.length; 125 | trace(__selectedFiles, __index); 126 | for (var i:int = 0; i < __selectedFiles.length; i++) 127 | { 128 | fileList.addItemAt({file:__selectedFiles[i]}, __index+i); 129 | } 130 | } 131 | 132 | private function moveItem($indexAdjust:int):void 133 | { 134 | //向上还是向下调整 135 | var __indices:Vector. = fileDG.selectedIndices; 136 | var __selectedList:ArrayList = new ArrayList(); 137 | 138 | var i:int=0; 139 | //先删除后面的,避免影响列表的索引 140 | for(i=__indices.length-1;i>=0;i--) 141 | { 142 | __selectedList.addItemAt(fileList.removeItemAt(__indices[i]), 0); 143 | } 144 | //要插入的位置索引 145 | var __insertIndex:int = 0; 146 | //如果移动的范围大于1,就是顶部或底部移动 147 | if($indexAdjust<-1) 148 | { 149 | __insertIndex = 0; 150 | } 151 | else if($indexAdjust>1) 152 | { 153 | __insertIndex = fileList.length; 154 | } 155 | //否则就是上一项和下一项移动 156 | else 157 | { 158 | //要插入的位置索引就是最高一个项目的索引-1,或者最低的一个项目的索引+1 159 | __insertIndex = __indices[0] + $indexAdjust; 160 | //超出范围,就使用极值 161 | if($indexAdjust<0 && __insertIndex < 0) 162 | { 163 | __insertIndex = 0; 164 | } 165 | else if($indexAdjust>0 && __insertIndex > fileList.length) 166 | { 167 | __insertIndex = fileList.length; 168 | } 169 | } 170 | 171 | fileList.addAllAt(__selectedList, __insertIndex); 172 | //还原调整顺序之后的选择项目 173 | var __indicesNew:Vector. = new Vector.; 174 | for(i=0;i<__selectedList.length;i++) 175 | { 176 | __indicesNew[i] = fileList.getItemIndex(__selectedList.getItemAt(i)); 177 | } 178 | fileDG.selectedIndices = __indicesNew; 179 | } 180 | ]]> 181 | 182 | -------------------------------------------------------------------------------- /src/view/comps/FrameDataGrid.mxml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | {FxGettext.gettext("Frame number")} 11 | 12 | 13 | {FxGettext.gettext("Frame name")} 14 | 15 | 16 | {FxGettext.gettext("Trimmed size")} 17 | 18 | 19 | {FxGettext.gettext("Original size")} 20 | 21 | 22 | 23 | 24 | 27 | 28 | -------------------------------------------------------------------------------- /src/view/comps/FramesAndLabels.mxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | [Event(name="frameAndLabelChange", type="events.SSEvent")] 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | {FxGettext.gettext("Open preview windows")} 27 | 28 | 29 | 30 | 32 | {FxGettext.gettext("Use frame")} 33 | {FxGettext.gettext("Play the animation of selected frames")} 34 | 35 | 37 | {FxGettext.gettext("Use label")} 38 | {FxGettext.gettext("Play the animation of selected label")} 39 | 40 | 41 | 42 | 44 | {FxGettext.gettext("Trim")} 45 | {FxGettext.gettext("Display width and height of trimmed frame.")} 46 | 47 | 49 | {FxGettext.gettext("Original")} 50 | {FxGettext.gettext("Display the width and height of trimmed. In order to reduce file size, we could trim the blank. If the file does not trim, the original size and the trimmed size is same.")} 51 | 52 | 53 | 54 | 55 | 56 | {frameDG.dataProvider?FxGettext.gettext("All available frames:")+frameDG.dataProvider.length:FxGettext.gettext("The frames are not available.")} 57 | 58 | 59 | 60 | {FxGettext.gettext("Add image frame Or Sprite Sheet")} 61 | {FxGettext.gettext("If the selected files are image file, they will be added to the end of the current Sprite Sheet as some frames.\nIf they are Sprite Sheet files, they will be added to the end of the current Sprite Sheet with follows rules:\n1. All frames will be added to the Sprite Sheet at the end of current;\n2. If the label is the same name, the label in the Sprite Sheet do not import, but all frames in the label will be imported;\n3. If the name is the same name, the name in the Sprite Sheet do not import;\n4. If original Sprite Sheet contains frame name, but imported Sprite Sheet does not, all frame in the Sprite Sheet will be automatically named.")} 62 | 63 | 64 | 65 | 66 | {FxGettext.gettext("Remove frame")} 67 | {FxGettext.gettext("Remove a frame from the list. Update the Sprite Sheet immediately.")} 68 | 69 | 70 | {FxGettext.gettext("Selecte all")} 71 | 72 | 73 | 74 | 75 | {FxGettext.gettext("Move up")} 76 | {FxGettext.gettext("Move the frame's position, the frmae Numbers will change after moving.")} 77 | 78 | 79 | {FxGettext.gettext("Move down")} 80 | {FxGettext.gettext("Move the frame's position, the frmae Numbers will change after moving.")} 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | {FxGettext.gettext("use label")} 89 | 90 | 92 | 93 | 94 | {FxGettext.gettext("Enter label")} 95 | {FxGettext.gettext("Label format: letters + Numbers")} 96 | 97 | 98 | {labelDDL.selectedItem ? ("LABEL("+labelDDL.selectedItem.name+"),"+FxGettext.gettext("Number of frame:") + frameInLabelDG.dataProvider.length) : FxGettext.gettext("No selected label")} 99 | 100 | 101 | 103 | {FxGettext.gettext("Add label")} 104 | {FxGettext.gettext("Add a label to the list.")} 105 | 106 | 108 | {FxGettext.gettext("Remove label")} 109 | {FxGettext.gettext("Remove the selected label")} 110 | 111 | 113 | {FxGettext.gettext("Modify label")} 114 | 115 | 116 | 117 | 118 | {FxGettext.gettext("Add frame")} 119 | 120 | 121 | {FxGettext.gettext("Remove frame")} 122 | 123 | 124 | 125 | 126 | {FxGettext.gettext("Move up")} 127 | 128 | 129 | {FxGettext.gettext("Move down")} 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 0) 229 | { 230 | var __frame:FrameVO; 231 | for (var i:int = 0; i < frameDG.dataProvider.length; i++) 232 | { 233 | __frame = getFrameItemAt(i); 234 | //若找到位图对应的索引,判断键盘 235 | if(__frame.frameRect.containsPoint(__point)) 236 | { 237 | var ___selectedLen:int = frameDG.selectedIndices.length ; 238 | //在已经选择过帧的情况下,才处理键盘 239 | if(___selectedLen > 0) 240 | { 241 | //处理Control按键,不连续选择 242 | var __newIndices:Vector. = new Vector.; 243 | if($info.controlKey) 244 | { 245 | __newIndices[0] = i; 246 | for (var j:int = 0; j < ___selectedLen; j++) 247 | { 248 | if(i != frameDG.selectedIndices[j]) 249 | __newIndices.push(frameDG.selectedIndices[j]); 250 | } 251 | } 252 | //处理Shift按键,连续选择 253 | else if($info.shiftKey) 254 | { 255 | var __start:int = Math.min(frameDG.selectedIndices[0], i); 256 | var __end:int = Math.max(frameDG.selectedIndices[0], i); 257 | for (j = __start; j <= __end; j++) 258 | { 259 | __newIndices.push(j); 260 | } 261 | } 262 | if(__newIndices.length > 0) 263 | { 264 | frameDG.selectedIndices = __newIndices; 265 | frameDG.ensureCellIsVisible(__newIndices[0]); 266 | } 267 | else 268 | { 269 | frameDG.selectedIndex = i; 270 | frameDG.ensureCellIsVisible(i); 271 | } 272 | } 273 | else 274 | { 275 | frameDG.selectedIndex = i; 276 | frameDG.ensureCellIsVisible(i); 277 | } 278 | return; 279 | } 280 | } 281 | } 282 | } 283 | 284 | //---------------------------------------- 285 | // handler 286 | //---------------------------------------- 287 | protected function handler_allBTNclick($event:MouseEvent):void 288 | { 289 | var __indics:Vector. = new Vector.; 290 | for (var i:int = 0; i < frameDG.dataProvider.length; i++) 291 | { 292 | __indics[i] = i; 293 | } 294 | frameDG.selectedIndices = __indics; 295 | } 296 | 297 | protected function handler_dividedHeightDown($evt:MouseEvent):void 298 | { 299 | this.parent.addEventListener(MouseEvent.MOUSE_MOVE, handler_resizeHeight); 300 | this.parent.addEventListener(MouseEvent.MOUSE_UP, handler_mouseUp); 301 | this.parent.addEventListener(MouseEvent.RELEASE_OUTSIDE, handler_mouseUp); 302 | } 303 | 304 | private function handler_resizeHeight($evt:MouseEvent):void 305 | { 306 | // trace('contentGrpoup:',this.contentGroup.height); 307 | // trace(this.mouseY, _minHeight, this.height); 308 | if(this.height< this.minHeight) 309 | { 310 | this.height = this.minHeight; 311 | handler_mouseUp(null); 312 | return; 313 | } 314 | this.height = this.mouseY+10; 315 | } 316 | 317 | private function handler_mouseUp($evt:MouseEvent):void 318 | { 319 | this.parent.removeEventListener(MouseEvent.MOUSE_MOVE, handler_resizeHeight); 320 | this.parent.removeEventListener(MouseEvent.MOUSE_UP, handler_mouseUp); 321 | this.parent.removeEventListener(MouseEvent.RELEASE_OUTSIDE, handler_mouseUp); 322 | } 323 | 324 | protected function handler_labelEnterState($evt:FlexEvent):void 325 | { 326 | this.minHeight = 640; 327 | //更新容器实际高度 328 | this.addEventListener(FlexEvent.UPDATE_COMPLETE, handler_updateComp); 329 | //更新一次frame管理按钮的状态 330 | updateFrameBTNS(); 331 | //更新一次Label管理按钮的状态 332 | updateFrameInLabelBTNS(); 333 | //更新一次帧的状态 334 | updateFrameOrLabelGRP(); 335 | } 336 | 337 | protected function handler_frameEnterState($evt:FlexEvent):void 338 | { 339 | this.minHeight = 440; 340 | updateFrameBTNS(); 341 | updateFrameOrLabelGRP(); 342 | } 343 | 344 | protected function handler_updateComp($evt:FlexEvent):void 345 | { 346 | //trace('updateComp:', this.contentGroup.height, this.height); 347 | //若不更新,可能会出现容器内容被遮挡的情况 348 | if(this.height < this.contentGroup.height) this.height = this.contentGroup.height; 349 | this.removeEventListener(FlexEvent.UPDATE_COMPLETE, handler_updateComp); 350 | } 351 | 352 | //有可用Label的时候,才允许选择Frame或者Label显示 353 | public function updateFrameOrLabelGRP():void 354 | { 355 | var __enabled:Boolean = labelCB.selected && labelDDL.selectedItem; 356 | frameOrLabelGRP.enabled= __enabled; 357 | //不可选择的时候,返回默认选项 358 | if(!__enabled) frameOrLabelRBG.selectedValue = true; 359 | } 360 | 361 | /** 362 | * 更新与Frame相关的按钮状态 363 | */ 364 | public function updateFrameBTNS($playing:Boolean=false):void 365 | { 366 | //选中的帧中包含顶部或者底部帧的时候,禁止上移或者下移 367 | var __indices:Vector. = frameDG.selectedIndices; 368 | if(__indices.length > 0) 369 | { 370 | var __inTop:Boolean = false; 371 | var __inBottom:Boolean = false; 372 | for (var i:int = 0; i < __indices.length; i++) 373 | { 374 | if(__indices[i] == 0) 375 | __inTop = true; 376 | if(__indices[i] == frameDG.dataProvider.length-1) 377 | __inBottom = true; 378 | } 379 | upFrameBTN.enabled = !__inTop; 380 | downFrameBTN.enabled = !__inBottom; 381 | delFrameBTN.enabled = !$playing; 382 | //允许加入帧到label中 383 | addFrameToLabelBTN.enabled = labelCB.selected && labelDDL.selectedItem; 384 | } 385 | else 386 | { 387 | upFrameBTN.enabled = false; 388 | downFrameBTN.enabled = false; 389 | delFrameBTN.enabled = false; 390 | addFrameToLabelBTN.enabled = false; 391 | } 392 | selectAllFrameBTN.enabled = frameDG.dataProviderLength > 0; 393 | } 394 | 395 | /** 396 | * 更新与label相关按钮的状态 397 | */ 398 | public function updateFrameInLabelBTNS():void 399 | { 400 | var __index:int = frameInLabelDG.selectedIndex; 401 | if(__index > -1) 402 | { 403 | removeFrameFromLabelBTN.enabled = true; 404 | upFrameInLabelBTN.enabled = __index > 0; 405 | downFrameInLabelBTN.enabled = __index < (frameInLabelDG.dataProvider.length - 1); 406 | } 407 | else 408 | { 409 | removeFrameFromLabelBTN.enabled = false; 410 | upFrameInLabelBTN.enabled = false; 411 | downFrameInLabelBTN.enabled = false; 412 | } 413 | } 414 | 415 | //向上移动label中的帧 416 | private function handler_upFrameInLabelBTNClick($evt:MouseEvent):void 417 | { 418 | var __oldIndex:int = frameInLabelDG.selectedIndex; 419 | var __framesInLabel:ArrayList = selectedLabelFrameList; 420 | __framesInLabel.addItemAt(__framesInLabel.removeItemAt(__oldIndex), __oldIndex-1); 421 | frameInLabelDG.selectedIndex = __oldIndex -1; 422 | updateFrameInLabelBTNS(); 423 | } 424 | 425 | //向下移动label中的帧 426 | private function handler_downFrameInLabelBTNClick($evt:MouseEvent):void 427 | { 428 | var __oldIndex:int = frameInLabelDG.selectedIndex; 429 | var __framesInLabel:ArrayList = selectedLabelFrameList; 430 | __framesInLabel.addItemAt(__framesInLabel.removeItemAt(__oldIndex), __oldIndex+1); 431 | frameInLabelDG.selectedIndex = __oldIndex +1; 432 | updateFrameInLabelBTNS(); 433 | } 434 | 435 | //从label中移除帧 436 | private function handler_removeFrameFromLabelBTNClick($evt:MouseEvent):void 437 | { 438 | var __frames:ArrayList = selectedLabelFrameList; 439 | var __delItem:FrameVO = __frames.getItemAt(frameInLabelDG.selectedIndex) as FrameVO; 440 | __frames.removeItem(__delItem); 441 | updateFrameInLabelBTNS(); 442 | } 443 | 444 | //向label中添加帧 445 | private function handler_addFrameToLabelBTNClick($evt:MouseEvent):void 446 | { 447 | var __frames:Vector. = frameDG.selectedItems; 448 | var __framesInLabel:ArrayList = selectedLabelFrameList; 449 | for each(var __frame:FrameVO in __frames) 450 | { 451 | __framesInLabel.addItem(__frame); 452 | } 453 | updateFrameBTNS(); 454 | updateFrameInLabelBTNS(); 455 | } 456 | ]]> 457 | 458 | 459 | -------------------------------------------------------------------------------- /src/view/comps/ImagePreview.mxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 190 | 191 | 192 | -------------------------------------------------------------------------------- /src/view/comps/ImageTypeSetting.mxml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | {FxGettext.gettext("PNG image")} 10 | 11 | 12 | {FxGettext.gettext("JPEG image")} 13 | 14 | 15 | {FxGettext.gettext("JPEG-XR image")} 16 | 17 | 18 | 19 | {FxGettext.gettext("Compress:")} 20 | 21 | 22 | {FxGettext.gettext("For JPEG, bigger is better;For JPEG-XR, smaller is better.")} 23 | 24 | 25 | 26 | [Event(name="change", type="flash.events.Event")] 27 | 28 | 29 | 82 | 83 | -------------------------------------------------------------------------------- /src/view/comps/Preview.mxml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | [Event(name="previewLoadComplete", type="events.SSEvent")] 10 | [Event(name="transformChange", type="events.SSEvent")] 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 256 | 257 | 258 | -------------------------------------------------------------------------------- /src/view/comps/SSPreview.mxml: -------------------------------------------------------------------------------- 1 | 2 | 9 | {FxGettext.gettext("Bitmap animation preview")} 10 | 11 | 12 | 13 | 14 | {transControlBar} 15 | source 16 | 17 | 18 | 19 | 20 | 21 | {playBTN.selected?FxGettext.gettext("Pause"):FxGettext.gettext("Play")} 22 | 23 | 24 | 25 | 26 | 55 | 56 | -------------------------------------------------------------------------------- /src/view/comps/SaveSeqSetting.mxml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | [Event(name="saveSeq", type="events.SSEvent")] 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | {FxGettext.gettext("Prefix")} 18 | 19 | 20 | 21 | 22 | 23 | {FxGettext.gettext("Start at:")} 24 | 25 | 26 | 27 | 28 | 29 | {FxGettext.gettext("Digits:")} 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | {FxGettext.gettext("File name preview:")} 38 | 39 | 40 | 41 | 42 | {FxGettext.gettext("Save")} 43 | 44 | 45 | 57 | { 58 | var __names:Vector. = new Vector.($fileNum, true); 59 | for (var i:int = 0; i < $fileNum; i++) 60 | { 61 | __names[i] = getFileName(startNS.value+i); 62 | } 63 | return __names; 64 | } 65 | 66 | private function preview():void 67 | { 68 | _fileName = getFileName(startNS.value); 69 | } 70 | 71 | /** 72 | * 返回文件名的字符串形式(不包含扩展名),数字部分不足位数的补0 73 | */ 74 | private function getFileName($num:int):String 75 | { 76 | var __str:String = preTI.text; 77 | for(var i:int=0; i<_ten.length; i++) 78 | { 79 | //位数不够的数字补0 80 | if($num<_ten[i]) 81 | __str += '0'; 82 | } 83 | return __str + String($num) + imageSetting.imageType; 84 | } 85 | 86 | protected function handler_saveSeqBTNClick(event:MouseEvent):void 87 | { 88 | dispatchEvent(new SSEvent(SSEvent.SAVE_SEQ)); 89 | } 90 | 91 | protected function fillTen():void 92 | { 93 | //更新每位的最大值的数组 94 | _ten = []; 95 | for(var i:int=1;i 103 | 104 | 105 | -------------------------------------------------------------------------------- /src/view/comps/SaveSheetSetting.mxml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | [Event(name="savePic", type="events.SSEvent")] 13 | [Event(name="saveMeta", type="events.SSEvent")] 14 | [Event(name="saveAll", type="events.SSEvent")] 15 | 16 | 17 | 18 | 19 | {FxGettext.gettext("Sprite Sheet")} 20 | 21 | 22 | 23 | 24 | {FxGettext.gettext("Mask:")} 25 | 26 | 27 | 28 | {FxGettext.gettext("No mask")} 29 | {FxGettext.gettext("Horzontial mask")} 30 | {FxGettext.gettext("Vertical mask")} 31 | 32 | 33 | 34 | 35 | 36 | 37 | {FxGettext.gettext("Metedata")} 38 | 39 | 40 | {FxGettext.gettext("XML format")} 41 | 42 | 43 | {FxGettext.gettext("JSON format")} 44 | 45 | 46 | {FxGettext.gettext("TXT format")} 47 | 48 | 49 | {FxGettext.gettext("Starling format")} 50 | 51 | 52 | {FxGettext.gettext("Use simple metadata")} 53 | {FxGettext.gettext("If selected, coordinate and WH are saved only.")} 54 | 55 | 56 | {FxGettext.gettext("Include file name")} 57 | {FxGettext.gettext("If selected, the relationship between the image file name and the frame index are saved in metadata. Then, you can get the corresponding frame through the file name.")} 58 | 59 | 60 | 61 | 62 | 63 | {FxGettext.gettext("Save image")} 64 | 65 | 66 | {FxGettext.gettext("Save all")} 67 | 68 | 69 | {FxGettext.gettext("Save metadata")} 70 | 71 | 72 | 73 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /src/view/comps/TransformTool.as: -------------------------------------------------------------------------------- 1 | package view.comps 2 | { 3 | import events.SSEvent; 4 | import flash.events.Event; 5 | import flash.events.MouseEvent; 6 | import flash.geom.Point; 7 | import flash.geom.Rectangle; 8 | import spark.core.SpriteVisualElement; 9 | 10 | /** 11 | * 一个以拖动方式更改大小的矩形,用于确定截取范围 12 | * @author zrong(zengrong.net) 13 | * Creation: 2011-8-3 14 | * Modification: 2013-08-20 15 | */ 16 | [Event(name = "transformChange",type="events.SSEvent" )] 17 | public class TransformTool extends SpriteVisualElement 18 | { 19 | 20 | public function TransformTool() 21 | { 22 | super(); 23 | this.addEventListener(MouseEvent.MOUSE_DOWN, handler_mouseDown); 24 | } 25 | 26 | [Bindable] public var maxDragW:int; 27 | [Bindable] public var maxDragH:int; 28 | 29 | private var _handlerW:int = 10; 30 | private var _handlerH:int = 10; 31 | private var _handlerRectList:Object = { }; 32 | 33 | private var _mouseDownX:int = 0; 34 | private var _mouseDownY:int = 0; 35 | private var _curHandlerLoc:String; 36 | private var _oldRect:Rectangle; 37 | 38 | private function addCheckRelease():void 39 | { 40 | this.addEventListener(MouseEvent.MOUSE_UP, handler_mouseUp); 41 | this.addEventListener(MouseEvent.RELEASE_OUTSIDE, handler_mouseUp); 42 | } 43 | 44 | private function removeCheckRelease():void 45 | { 46 | this.removeEventListener(MouseEvent.MOUSE_UP, handler_mouseUp); 47 | this.removeEventListener(MouseEvent.RELEASE_OUTSIDE, handler_mouseUp); 48 | } 49 | 50 | private function addenterFrameHandler():void 51 | { 52 | this.addEventListener(Event.ENTER_FRAME, handler_enterFrame); 53 | } 54 | 55 | private function removeEnterFrameHandler():void 56 | { 57 | this.removeEventListener(Event.ENTER_FRAME, handler_enterFrame); 58 | } 59 | 60 | private function dispatchChange():void 61 | { 62 | this.dispatchEvent(new SSEvent(SSEvent.TRANSFORM_CHANGE, transformRect)); 63 | 64 | } 65 | 66 | private function draw():void 67 | { 68 | this.graphics.clear(); 69 | 70 | this.graphics.lineStyle(2, 0); 71 | this.graphics.beginFill(0, .2); 72 | this.graphics.drawRect(0, 0, this.width, this.height); 73 | this.graphics.endFill(); 74 | 75 | updateHandlerPos(); 76 | 77 | drawHandler(_handlerRectList.top); 78 | drawHandler(_handlerRectList.right); 79 | drawHandler(_handlerRectList.bottom); 80 | drawHandler(_handlerRectList.left); 81 | 82 | dispatchChange(); 83 | } 84 | 85 | private function updateHandlerPos():void 86 | { 87 | _handlerRectList["top"] = new Rectangle((this.width - _handlerW) / 2, 0, _handlerW, _handlerH); 88 | _handlerRectList["right"] = new Rectangle(this.width - _handlerW, (this.height-_handlerH)/2, _handlerW, _handlerH); 89 | _handlerRectList["bottom"] = new Rectangle((this.width - _handlerW) / 2, this.height-_handlerH, _handlerW, _handlerH); 90 | _handlerRectList["left"] = new Rectangle(0, (this.height-_handlerH)/2, _handlerW, _handlerH); 91 | } 92 | 93 | private function drawHandler($rect:Rectangle):void 94 | { 95 | this.graphics.lineStyle(2, 0xFFFFFF); 96 | this.graphics.beginFill(0); 97 | this.graphics.drawRect($rect.x, $rect.y, $rect.width, $rect.height); 98 | this.graphics.endFill(); 99 | } 100 | 101 | override public function set width($w:Number):void 102 | { 103 | super.width = $w; 104 | //trace("set width:", this.width); 105 | draw(); 106 | } 107 | 108 | override public function set height($h:Number):void 109 | { 110 | super.height = $h; 111 | //trace("set height:", this.height); 112 | draw(); 113 | } 114 | 115 | public function get transformRect():Rectangle 116 | { 117 | return new Rectangle(this.x, this.y, this.width, this.height); 118 | } 119 | 120 | public function set transformRect($rect:Rectangle):void 121 | { 122 | move($rect.x, $rect.y); 123 | resize($rect.width, $rect.height); 124 | } 125 | 126 | private function move($x:int, $y:int):void 127 | { 128 | this.x = $x; 129 | this.y = $y; 130 | dispatchChange(); 131 | } 132 | private function resize($w:int, $h:int):void 133 | { 134 | this.width = $w; 135 | this.height = $h; 136 | } 137 | 138 | private function getCurHandlerLoc():String 139 | { 140 | _mouseDownX = this.mouseX; 141 | _mouseDownY = this.mouseY; 142 | for (var __rectName:String in _handlerRectList) 143 | { 144 | var __rect:Rectangle = _handlerRectList[__rectName] as Rectangle; 145 | if(__rect.contains(_mouseDownX, _mouseDownY)) 146 | { 147 | _curHandlerLoc = __rectName; 148 | _oldRect = this.getRect(this.parent); 149 | return __rectName; 150 | } 151 | } 152 | _oldRect = null; 153 | return null; 154 | } 155 | 156 | protected function handler_mouseDown($event:MouseEvent):void 157 | { 158 | addCheckRelease(); 159 | addenterFrameHandler(); 160 | 161 | _curHandlerLoc = getCurHandlerLoc(); 162 | } 163 | 164 | protected function handler_mouseUp($event:Event):void 165 | { 166 | _curHandlerLoc = null; 167 | _oldRect = null; 168 | removeCheckRelease(); 169 | removeEnterFrameHandler(); 170 | } 171 | 172 | protected function handler_enterFrame($event:Event):void 173 | { 174 | var __mouseX:int = this.parent.mouseX; 175 | var __mouseY:int = this.parent.mouseY; 176 | var __x:int = __mouseX - _mouseDownX; 177 | var __y:int = __mouseY - _mouseDownY; 178 | //移动 179 | if(!_curHandlerLoc) 180 | { 181 | if(__mouseX -_mouseDownX< 0) __x = 0; 182 | else if(__mouseX - _mouseDownX > maxDragW - this.width) __x = maxDragW - this.width; 183 | if(__mouseY - _mouseDownY < 0) __y = 0; 184 | else if(__mouseY - _mouseDownY > maxDragH - this.height) __y = maxDragH - this.height ; 185 | move(__x, __y); 186 | return; 187 | } 188 | //下面是改变大小 189 | var __h:int = 0; 190 | var __w:int = 0; 191 | if (_curHandlerLoc == "top") 192 | { 193 | __h = _oldRect.height - (__mouseY - _oldRect.y); 194 | if (__h < 0) 195 | __h = 0; 196 | else if (__h > maxDragH - this.y) 197 | __h = maxDragH - this.y; 198 | if (__h > 0 && __mouseY > 0) 199 | this.y = __mouseY; 200 | this.height = __h; 201 | } 202 | else if (_curHandlerLoc == "bottom") 203 | { 204 | __h = __mouseY - _oldRect.y; 205 | if (__h < 0) 206 | __h = 0; 207 | else if (__h > maxDragH - this.y) 208 | __h = maxDragH - this.y; 209 | else 210 | //貌似高度计算有点问题 +2试试看 211 | __h += 2; 212 | this.height = __h; 213 | } 214 | else if (_curHandlerLoc == "left") 215 | { 216 | __w = _oldRect.width - (__mouseX - _oldRect.x); 217 | if (__w < 0) 218 | __w = 0; 219 | else if (__w > maxDragW - this.x) 220 | __w = maxDragW - this.x; 221 | if (__w > 0 && __mouseX > 0) 222 | this.x = __mouseX; 223 | this.width = __w; 224 | } 225 | else if (_curHandlerLoc == "right") 226 | { 227 | __w = __mouseX - _oldRect.x; 228 | if (__w < 0) 229 | __w = 0; 230 | else if (__w > maxDragW - this.x) 231 | __w = maxDragW - this.x; 232 | this.width = __w; 233 | } 234 | } 235 | } 236 | } 237 | -------------------------------------------------------------------------------- /src/view/comps/TransformToolControlBar.mxml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | [Event(name="transformUseCustomChange", type="events.SSEvent")] 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /src/view/comps/TransformToolControlBarForSS.as: -------------------------------------------------------------------------------- 1 | package view.comps 2 | { 3 | import gnu.as3.gettext.FxGettext; 4 | import mx.controls.Spacer; 5 | import spark.components.CheckBox; 6 | import spark.components.HGroup; 7 | import spark.components.Button; 8 | import spark.layouts.VerticalLayout; 9 | /** 10 | * 专用于SSPreview界面的大小设定 11 | * @author zrong 12 | */ 13 | public class TransformToolControlBarForSS extends TransformToolControlBar 14 | { 15 | public function TransformToolControlBarForSS() 16 | { 17 | super(); 18 | var __layout:VerticalLayout = new VerticalLayout(); 19 | __layout.horizontalAlign = "center"; 20 | this.layout = __layout; 21 | } 22 | 23 | public var saveResizeBTN:Button = new Button(); 24 | 25 | protected override function createChildren():void 26 | { 27 | super.createChildren(); 28 | var __grp:HGroup = new HGroup(); 29 | __grp.addElement(createCheckBox()); 30 | __grp.addElement(createSpacer()); 31 | __grp.addElement(createButton()); 32 | this.addElement(__grp); 33 | this.addElement(nsGrp); 34 | } 35 | 36 | private function createSpacer():Spacer 37 | { 38 | var __spacer:Spacer = new Spacer(); 39 | __spacer.percentHeight = 100; 40 | __spacer.height = 20; 41 | return __spacer; 42 | } 43 | 44 | private function createCheckBox():CheckBox 45 | { 46 | useCustomSizeCB.label = FxGettext.gettext("Adjust the original size(x,y,w,h)"); 47 | useCustomSizeCB.toolTip = FxGettext.gettext("Is selected, the original size is reduced. But you can still be executed 'Trim blank' again on the basis of reduced size."); 48 | return useCustomSizeCB; 49 | } 50 | 51 | private function createButton():Button 52 | { 53 | saveResizeBTN.enabled = false; 54 | saveResizeBTN.label = FxGettext.gettext("Do adjusting"); 55 | saveResizeBTN.toolTip = FxGettext.gettext("Recalculated according to the original size adjusted, and immediate optimization.\nThis action will directly modify the size of the original size.") 56 | return saveResizeBTN; 57 | } 58 | 59 | public function setResizeBtnEnable($enable:Boolean):void 60 | { 61 | saveResizeBTN.enabled = useCustom && $enable; 62 | } 63 | /** 64 | 65 | 66 | {FxGettext.gettext("Adjust the original size(x,y,w,h)")} 67 | {FxGettext.gettext("Is selected, the original size is reduced. But you can still be executed 'Trim blank' again on the basis of reduced size.")} 68 | 69 | 70 | 71 | {FxGettext.gettext("Do adjusting")} 72 | {FxGettext.gettext("Recalculated according to the original size adjusted, and immediate optimization.\nThis action will directly modify the size of the original size.")} 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | **/ 82 | } 83 | } -------------------------------------------------------------------------------- /src/view/comps/VDividedButton.mxml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /src/view/panel/PicPanel.mxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | {FxGettext.gettext("frame(x,y,w,h)")} 22 | 23 | 24 | {FxGettext.gettext("Custom size of the frame")} 25 | false 26 | 27 | 28 | 29 | 30 | 31 | 33 | 36 | 37 | 38 | {transControlBar} 39 | viewer 40 | 41 | 42 | 0) 163 | { 164 | var __namesvo:NamesVO = new NamesVO(); 165 | var __names:Vector. = new Vector.(fileM.fileList.length); 166 | var __namesIndex:Object = {}; 167 | var __dotIndex:int = 0; 168 | var __name:String = ''; 169 | var __main:String = ''; 170 | for(var i:int=0;i 260 | 261 | 262 | -------------------------------------------------------------------------------- /src/view/panel/SSPanel.mxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | {FxGettext.gettext("Save a Sprite Sheet")} 19 | 20 | 21 | {FxGettext.gettext("Save a sequence")} 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 151 | { 152 | return saveSeq.getFileNames($num); 153 | } 154 | 155 | private function getSaveVO():SaveVO 156 | { 157 | var __vo:SaveVO = new SaveVO(); 158 | __vo.picType = imageType; 159 | __vo.metaType = saveSheet.metaRBG.selectedValue.toString(); 160 | __vo.isSimple = isSimple; 161 | __vo.includeName = includeName; 162 | return __vo; 163 | } 164 | 165 | public function getSeqSaveVO():SaveVO 166 | { 167 | var __vo:SaveVO = getSaveVO(); 168 | __vo.quality = seqQualityValue; 169 | return __vo; 170 | } 171 | 172 | public function getSheetSaveVO():SaveVO 173 | { 174 | var __vo:SaveVO = getSaveVO(); 175 | __vo.quality = sheetQualityValue; 176 | return __vo; 177 | } 178 | ]]> 179 | 180 | 181 | -------------------------------------------------------------------------------- /src/view/panel/StartPanel.mxml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | {FxGettext.gettext("Open a swf file")} 10 | {FxGettext.gettext("Convert a swf file to Sprite Sheet in sequential frame.")} 11 | 12 | 13 | {FxGettext.gettext("Import image file")} 14 | {FxGettext.gettext("Convert a set of file to a Sprite Sheet.")} 15 | 16 | 17 | 18 | {FxGettext.gettext("Open a Sprite Sheet")} 19 | {FxGettext.gettext("Open a Sprite Sheet for edit and optimize.")} 20 | 21 | 22 | 24 | {FxGettext.gettext("Check update")} 25 | 26 | 28 | {FxGettext.gettext("About")} 29 | 30 | 31 | {FxGettext.gettext("Visit zrong's blog")} 32 | {FxGettext.gettext("Visit zengrong.net")} 33 | 34 | 35 | 36 | 37 | {FxGettext.gettext("Language:")} 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /src/view/panel/SwfPanel.mxml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | {FxGettext.gettext("frame(x,y,w,h)")} 16 | 17 | 18 | {FxGettext.gettext("Custom size of the frame")} 19 | false 20 | 21 | 22 | 23 | 24 | 25 | 26 | {FxGettext.gettext("1st frame(zero-based):")} 27 | 28 | 29 | 30 | 31 | 32 | 33 | {FxGettext.gettext("Total frames:")} 34 | 35 | 36 | 37 | 38 | 39 | 41 | 42 | 43 | {transControlBar} 44 | source 45 | true 46 | 47 | 48 | [Event(name="complete", type="flash.events.Event")] 49 | 50 | 51 | = firstFrameNS.value) 121 | { 122 | trace('drawing frame:', _frameNum-1) 123 | //如果没有设置_rectInSheet,应该是截取第一帧,这种情况下初始化rectInSheet、frameRect和whRect 124 | if(!_rectInSheet) 125 | { 126 | _frameRect = transControlBar.useCustom ? transControlBar.transformRect : new Rectangle(0,0,swf.sourceWidth, swf.sourceHeight); 127 | _rectInSheet = new Rectangle(0, 0, _frameRect.width, _frameRect.height); 128 | var __w:int=0; 129 | var __h:int=0; 130 | if(_limitW) 131 | { 132 | __w = buildSetting.whNS.value; 133 | __h = _frameRect.height; 134 | } 135 | else 136 | { 137 | __h = buildSetting.whNS.value; 138 | __w = _frameRect.width; 139 | } 140 | _whRect = new Rectangle(0,0,__w, __h); 141 | } 142 | else 143 | { 144 | //不是第一帧,直接更新rect 145 | Funs.updateRectInSheet(_rectInSheet, _whRect, _frameRect, _limitW); 146 | } 147 | var __bmd:BitmapData = drawBMD(_frameRect); 148 | //向Sheet中添加这个位图 149 | this.dispatchEvent(new SSEvent(SSEvent.ADD_FRAME, {bmd:__bmd, rect:_rectInSheet.clone()})); 150 | } 151 | //所有帧捕获完毕后取消侦听 152 | if (_frameNum - firstFrameNS.value >= totalFrameNS.value) 153 | { 154 | captureDone(); 155 | } 156 | } 157 | 158 | /** 159 | * 绘制当前帧,返回位图 160 | */ 161 | private function drawBMD($frameRect:Rectangle):BitmapData 162 | { 163 | var __bmd:BitmapData = new BitmapData($frameRect.width, $frameRect.height, buildSetting.transparentCB.selected, buildSetting.bgColorPicker.selectedColor); 164 | var __ma:Matrix = null; 165 | if(transControlBar.useCustom) 166 | { 167 | //需要向“左上角”移动,将当前帧绘制成位图 168 | __ma = new Matrix(); 169 | __ma.translate(-1*$frameRect.x, -1*$frameRect.y); 170 | } 171 | if(swf.enableDragContent) 172 | { 173 | if(!__ma) __ma = new Matrix; 174 | __ma.translate(swf.contentX, swf.contentY); 175 | } 176 | __bmd.draw(swf.content, __ma, null, null, null, buildSetting.smoothCB.selected); 177 | return __bmd; 178 | } 179 | ]]> 180 | 181 | 182 | -------------------------------------------------------------------------------- /src/view/panel/TopPanel.mxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | {FxGettext.gettext("Back to previous")} 10 | 11 | 12 | {FxGettext.gettext("Start")} 13 | 14 | 16 | 17 | 18 | 19 | 20 | 32 | 33 | -------------------------------------------------------------------------------- /src/vo/BrowseFileDoneVO.as: -------------------------------------------------------------------------------- 1 | package vo 2 | { 3 | import air.update.utils.StringUtils; 4 | import flash.filesystem.File; 5 | import org.zengrong.assets.AssetsType; 6 | /** 7 | * 选择一个或者一组文件成功后发出事件所带VO 8 | * @author zrong 9 | * Creation: 2013-06-18 10 | */ 11 | public class BrowseFileDoneVO 12 | { 13 | 14 | public function BrowseFileDoneVO($state:String=null, $files:Array=null) 15 | { 16 | openState = $state; 17 | selectedFiles = $files; 18 | } 19 | 20 | public var openState:String; 21 | public var selectedFiles:Array; 22 | 23 | /** 24 | * 如果选择的文件是SS格式,则这个值为AssetsType.SPRITE_SHEET 25 | * @see org.zengrong.assets.AssetsType 26 | */ 27 | public var fileType:String; 28 | 29 | /** 30 | * 若 fileType的值为AssetsType.SPRITE_SHEET,则这个值为SpriteSheetMetadataType中的值 31 | * @see org.zengrong.display.spritesheet.SpriteSheetMetadataType 32 | */ 33 | public var metaType:String; 34 | 35 | /** 36 | * 返回供Assets载入的列表 37 | * @return 38 | */ 39 | public function toAssetsList():Array 40 | { 41 | if(!selectedFiles && selectedFiles.length == 0) return null; 42 | var __file:File = null; 43 | var __urls:Array = []; 44 | var __urlobj:Object = null; 45 | for(var i:int=0;i; 16 | public var labelsFrame:Object; 17 | } 18 | } -------------------------------------------------------------------------------- /src/vo/LabelVO.as: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // zengrong.net 3 | // 创建者: zrong(zrongzrong@gmail.com) 4 | // 创建时间:2011-8-17 5 | //////////////////////////////////////////////////////////////////////////////// 6 | 7 | package vo 8 | { 9 | import mx.collections.ArrayList; 10 | 11 | /** 12 | * 保存一个Label的信息 13 | */ 14 | [Bindable] 15 | public class LabelVO 16 | { 17 | public function LabelVO($lableName:String, $labelFrames:ArrayList) 18 | { 19 | name = $lableName; 20 | frames = $labelFrames; 21 | } 22 | 23 | public var name:String; 24 | public var frames:ArrayList; 25 | 26 | /** 27 | * 返回frames中保存的所有帧的帧号 28 | */ 29 | public function getFramesIndex():Array 30 | { 31 | var __framesIndex:Array = []; 32 | for (var i:int = 0; i < frames.length; i++) 33 | { 34 | __framesIndex[i] = (frames.getItemAt(i) as FrameVO).frameNum; 35 | } 36 | return __framesIndex; 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /src/vo/NamesVO.as: -------------------------------------------------------------------------------- 1 | package vo 2 | { 3 | /** 4 | * 保存SpriteSheet中的Name相关的Key 5 | * @author zrong 6 | * 创建日期:2012-08-17 7 | */ 8 | public class NamesVO 9 | { 10 | public function NamesVO() 11 | { 12 | } 13 | 14 | public var hasName:Boolean; 15 | 16 | public var names:Vector.; 17 | 18 | public var namesIndex:Object; 19 | } 20 | } -------------------------------------------------------------------------------- /src/vo/RectsAndBmdsVO.as: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // zengrong.net 3 | // 创建者: zrong(zrongzrong@gmail.com) 4 | // 创建时间:2013-06-14 5 | //////////////////////////////////////////////////////////////////////////////// 6 | 7 | package vo 8 | { 9 | import flash.geom.Rectangle; 10 | import flash.display.BitmapData; 11 | 12 | /** 13 | * 保存Sheet的修改后的rect列表、原始的rect列表和位图列表 14 | */ 15 | [Bindable] 16 | public class RectsAndBmdsVO 17 | { 18 | public function RectsAndBmdsVO($bmds:Vector., $origin:Vector., $frame:Vector.) 19 | { 20 | bmds = $bmds; 21 | originRects = $origin; 22 | frameRects = $frame; 23 | } 24 | 25 | /** 26 | * 在大sheet中的rect列表 27 | */ 28 | public var frameRects:Vector.; 29 | 30 | /** 31 | * 原始的(在程序中使用的)rect列表 32 | */ 33 | public var originRects:Vector.; 34 | 35 | /** 36 | * 所有的BitmapData列表 37 | */ 38 | public var bmds:Vector.; 39 | } 40 | } -------------------------------------------------------------------------------- /src/vo/SaveVO.as: -------------------------------------------------------------------------------- 1 | package vo 2 | { 3 | import flash.display.BitmapData; 4 | import org.zengrong.display.spritesheet.ISpriteSheetMetadata; 5 | 6 | /** 7 | * 在保存执行之前暂存待保存的数据 8 | * @author zrong 9 | * 10 | */ 11 | public class SaveVO 12 | { 13 | public function SaveVO() 14 | { 15 | } 16 | 17 | /** 18 | * 要保存元数据 19 | */ 20 | public var metadata:ISpriteSheetMetadata; 21 | 22 | /** 23 | * 要保存的图像 24 | */ 25 | public var bitmapData:BitmapData; 26 | 27 | /** 28 | * 要保存的图像数组,用于保存序列图 29 | */ 30 | public var bitmapDataList:Vector.; 31 | 32 | /** 33 | * 要保存的文件名数组,用于保存序列图 34 | */ 35 | public var fileNameList:Vector.; 36 | 37 | /** 38 | * 图像文件类型 39 | */ 40 | public var picType:String; 41 | 42 | /** 43 | * 元数据类型 44 | */ 45 | public var metaType:String; 46 | 47 | /** 48 | * JPEG压缩质量 49 | */ 50 | public var quality:int; 51 | 52 | /** 53 | * 见StateType 54 | * @see type.StateType 55 | */ 56 | public var type:String; 57 | 58 | /** 59 | * 仅包含简单信息 60 | */ 61 | public var isSimple:Boolean; 62 | 63 | /** 64 | * 包含文件名 65 | */ 66 | public var includeName:Boolean; 67 | } 68 | } --------------------------------------------------------------------------------