Skip to content

Instantly share code, notes, and snippets.

@claus
Created June 8, 2011 18:04
Show Gist options
  • Save claus/1014957 to your computer and use it in GitHub Desktop.
Save claus/1014957 to your computer and use it in GitHub Desktop.
Create SWF with PNGs
package
{
// Dependencies:
// as3swf.swc
// as3commons-bytecode-1.0-RC1.swc
// as3commons-lang-0.3.2.swc
// as3commons-logging-2.0.swc
// as3commons-reflect-1.3.4.swc
// MinimalComps_0_9_9.swc
import com.bit101.components.List;
import com.bit101.components.PushButton;
import com.codeazur.as3swf.SWF;
import com.codeazur.as3swf.SWFData;
import com.codeazur.as3swf.data.SWFSymbol;
import com.codeazur.as3swf.data.consts.BitmapType;
import com.codeazur.as3swf.tags.TagDefineBitsJPEG2;
import com.codeazur.as3swf.tags.TagDoABC;
import com.codeazur.as3swf.tags.TagEnd;
import com.codeazur.as3swf.tags.TagFileAttributes;
import com.codeazur.as3swf.tags.TagShowFrame;
import com.codeazur.as3swf.tags.TagSymbolClass;
import org.as3commons.bytecode.abc.AbcFile;
import org.as3commons.bytecode.abc.enum.Opcode;
import org.as3commons.bytecode.emit.IAbcBuilder;
import org.as3commons.bytecode.emit.IClassBuilder;
import org.as3commons.bytecode.emit.ICtorBuilder;
import org.as3commons.bytecode.emit.IPackageBuilder;
import org.as3commons.bytecode.emit.impl.AbcBuilder;
import org.as3commons.bytecode.io.AbcSerializer;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.net.FileFilter;
import flash.net.FileReference;
import flash.utils.ByteArray;
public class PNGPacker extends Sprite
{
private var swf:SWF;
private var imgWidth:Number;
private var imgHeight:Number;
private var abcBuilder:IAbcBuilder;
private var packageBuilder:IPackageBuilder;
private var symbolClass:TagSymbolClass;
private var currentCharacterId:uint;
private var list:List;
private static const PACKAGENAME:String = "png";
private static const CLASSNAME:String = "BitmapDataClass";
public function PNGPacker()
{
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE
addChild(new PushButton(this, 10, 10, "Add PNG", function():void {
var ref:FileReference = new FileReference();
ref.addEventListener(Event.SELECT, function(e:Event):void { ref.load(); });
ref.addEventListener(Event.COMPLETE, function(e:Event):void { addPNG(ref.data, ref.name); });
ref.browse([new FileFilter("PNG (*.png)", "*.png")]);
}));
addChild(new PushButton(this, 120, 10, "Save SWF", function():void {
var ba:ByteArray = publish();
var ref:FileReference = new FileReference();
ref.save(ba, 'Untitled.swf');
init();
}));
addChild(new PushButton(this, 230, 10, "Clear SWF", function():void {
init();
}));
list = new List(this, 10, 50);
list.enabled = false;
list.width = 400;
list.height = 300;
addChild(list);
init();
}
private function addPNG(data:ByteArray, filename:String):void
{
if(determinePNGSize(data))
{
var className:String = CLASSNAME + "_" + currentCharacterId;
var classBuilder:IClassBuilder = packageBuilder.defineClass(className, "flash.display.BitmapData");
classBuilder.isDynamic = true;
// BitmapData subclasses need a custom constructor, for example:
// public function BitmapDataSubclass(width:int = 550, height:int = 400) {
// super(width, height)
// }
var ctorBuilder:ICtorBuilder = classBuilder.defineConstructor();
ctorBuilder.defineArgument("int", true, imgWidth);
ctorBuilder.defineArgument("int", true, imgHeight);
ctorBuilder.addOpcode(Opcode.getlocal_0)
.addOpcode(Opcode.pushscope)
.addOpcode(Opcode.getlocal_0)
.addOpcode(Opcode.getlocal_1)
.addOpcode(Opcode.getlocal_2)
.addOpcode(Opcode.constructsuper, [2])
.addOpcode(Opcode.returnvoid);
symbolClass.symbols.push(SWFSymbol.create(currentCharacterId, PACKAGENAME + "." + className));
var defineBitsJPEG2:TagDefineBitsJPEG2 = new TagDefineBitsJPEG2();
defineBitsJPEG2.characterId = currentCharacterId;
defineBitsJPEG2.bitmapType = BitmapType.PNG;
defineBitsJPEG2.bitmapData.writeBytes(data);
swf.tags.push(defineBitsJPEG2);
list.addItem(filename + " (id: " + currentCharacterId + ")");
currentCharacterId++;
}
}
private function init():void
{
swf = new SWF();
swf.tags.push(new TagFileAttributes());
abcBuilder = new AbcBuilder();
packageBuilder = abcBuilder.definePackage(PACKAGENAME);
symbolClass = new TagSymbolClass();
list.removeAll();
currentCharacterId = 1;
}
private function publish():ByteArray
{
var abcFile:AbcFile = abcBuilder.build();
var abcSerializer:AbcSerializer = new AbcSerializer();
var abcBytes:ByteArray = abcSerializer.serializeAbcFile(abcFile);
swf.tags.push(TagDoABC.create(abcBytes));
swf.tags.push(symbolClass);
swf.tags.push(new TagShowFrame());
swf.tags.push(new TagEnd());
var swfData:SWFData = new SWFData();
swf.publish(swfData);
return swfData;
}
// Source: http://www.wischik.com/lu/programmer/get-image-size.html
private function determinePNGSize(data:ByteArray):Boolean {
// PNG: the first frame is by definition an IHDR frame, which gives dimensions
if (data[0] == 0x89
&& data[1] == 0x50 && data[2] == 0x4e && data[3] == 0x47 // "PNG"
&& data[4] == 0x0D && data[5] == 0x0A && data[6] == 0x1A && data[7] == 0x0A
&& data[12] == 0x49 && data[13] == 0x48 && data[14] == 0x44 && data[15] == 0x52) { // "IHDR"
imgWidth = (data[16] << 24) | (data[17] << 16) | (data[18] << 8) | data[19];
imgHeight = (data[20] << 24) | (data[21] << 16) | (data[22] << 8) | data[23];
return true;
}
trace("WARNING: determinePNGSize(): No size found");
return false;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment