Can I get a zip swflite file?

I used the openfl process command to generate a bundle, but I found that when I request it via http, it is still a multiple request, not a one-time load. In addition, if you add compression such as zip, the size can be smaller, but it seems that this can not be loaded properly?

Can I get a one-time join to load the SWF?

Please help me thank you.

Theoretically, we could join the SWF support with the PAK style libraries, but currently these two library types cannot be mixed. I’m thinking either we should consider changes to the library system to allow multiple “processors” (sort of like Webpack and other systems) so you can mix-and-match, or just direct improvements to SWF. It’s slower to load images if it’s done that way on HTML5, but I understand that that isn’t always the only concern

I believe that decompression will take less time than multiple requests from the network. Thank you for your answer, I will see if there is any way to optimize this problem. :grinning:

Recently, I have supported the SWF zip. I rewrote the SWFLiteLibrary implementation, implemented the loading process myself, and then passed the zip list to the SWFLiteLibrary object, letting the SWFLiteLibrary object read the ZIP resource.

This can run normally on C and HTML5. The zip is generated by simply compressing the *.bundle folder into a zip.

package zygame.utils.load;

import lime.app.Future;
import lime.app.Promise;
import lime.graphics.Image;
import openfl._internal.symbols.BitmapSymbol;
import haxe.zip.Entry;
import openfl._internal.formats.swf.SWFLite;
import openfl.utils.Assets;
import zygame.utils.AssetsUtils;
import haxe.io.Bytes;
import lime._internal.format.Deflate;

#if android
import sys.io.File;
import sys.FileSystem;
#end

@:keep 
class SWFLiteLibrary extends #if (openfl <= '8.3.0') openfl._internal.swf.SWFLiteLibrary #else openfl._internal.formats.swf.SWFLiteLibrary #end {

    /**
     * 弃用
     */
    // public static var WEB_PATH:String;

    /**
     * SWF文件名
     */
    public var name:String;

    /**
     * 已经解析好的ZIPList列表
     */
    public var zipList:List<Entry>;

    override public function load ():Future<lime.utils.AssetLibrary> {
		
		if (id != null) {
			
			preload.set (id, true);
			
		}
		
		var promise = new Promise<lime.utils.AssetLibrary> ();
		preloading = true;
		
		var onComplete = function (data) {
			
			cachedText.set (id, data);
			
			swf = SWFLite.unserialize (data);
			swf.library = this;
			
			var bitmapSymbol:BitmapSymbol;
			
			for (symbol in swf.symbols) {
				
				if (Std.is (symbol, BitmapSymbol)) {
					
					bitmapSymbol = cast symbol;
					
					if (bitmapSymbol.className != null) {
						
						imageClassNames.set (bitmapSymbol.className, bitmapSymbol.path);
						
					}
					
				}
				
			}
			
			SWFLite.instances.set (instanceID, swf);
			
			__load ().onProgress (promise.progress).onError (promise.error).onComplete (function (_) {
				
				preloading = false;
				promise.complete (this);
				
			});
			
		}
		
		if (Assets.exists (id)) {
			
			#if (js && html5)
			for (id in paths.keys ()) {
				
				preload.set (id, true);
				
			}
			#end
			
			loadText (id).onError (promise.error).onComplete (onComplete);
			
		} else {
			
			for (id in paths.keys ()) {
				
				preload.set (id, true);
				
			}
			
			var path = null;
			
			if (paths.exists (id)) {
				
				path = paths.get (id);
				
			} else {
				
				path = (rootPath != null && rootPath != "") ? rootPath + "/" + id : id;
				
			}

            var binPath:String = StringUtils.getName(path);
            var entry:Entry = AssetsUtils.findZipData(zipList,binPath);
            var bytes:Bytes = entry.compressed?Deflate.decompress(entry.data):entry.data;
            onComplete(bytes.toString());
			
		}
		
		return promise.future;
		
	}

    override public function loadText (id:String):Future<String> {
        var entry:Entry = AssetsUtils.findZipData(zipList,id);
        var bytes:Bytes = entry.compressed?Deflate.decompress(entry.data):entry.data;
        return Future.withValue(bytes.toString());
    }

    override public function loadImage (id:String):Future<Image> {
        var entry:Entry = AssetsUtils.findZipData(zipList,id);
        var bytes:Bytes = entry.compressed?Deflate.decompress(entry.data):entry.data;
        return Image.loadFromBytes(bytes);
    }
    
    /**
     * 载入逻辑重写
     * @param id 图片ID
     * @return Future<Image>
     */
    override private function __loadImage (id:String):Future<Image> {
        return super.loadImage(id);
	}

    /**
     * 释放ZIP资源
     */
    public function releaseZip():Void
    {
        if(zipList != null)
        {
            zipList.clear();
            zipList = null;
        }
    }

    /**
     * 释放unload
     */
    override public function unload():Void
    {
        super.unload();
        var images:Map<String, Image> = cachedImages;
        var iter:Iterator<String> = images.keys();
        while(iter.hasNext())
        {
            var key:String = iter.next();
            var img:Image = images.get(key);
            images.remove(key);
        }
        cachedImages = null;
    }
}

Hello can you share how you to use .zip from .bundle swf?

Thanks.

/**
     * SwfliteParse
     */
    private function onSwfliteParse(bytes:Bytes, call:SWFLiteLibrary->Void,errorCall:String->Void):Void
    {
        var input:BytesInput = new BytesInput(bytes);
        var zip:Zip = new Zip(input);
        var list:List<Entry> = zip.read();
        var entry:Entry = AssetsUtils.findZipData(list,"library.json");
        if(entry != null)
        {
            //解压
            var bytes:Bytes = entry.compressed?Deflate.decompress(entry.data):entry.data;                    
            AssetManifest.loadFromBytes(bytes,_rootPath).onComplete(function(manifest:AssetManifest):Void{
                manifest.libraryType = "zygame.utils.load.SWFLiteLibrary";
                var swf:SWFLiteLibrary = fromManifest(manifest,list);
                swf.name = zygame.utils.StringUtils.getName(_path);
                swf.load().onComplete(function(_):Void{
                    swf.releaseZip();
                    call(swf);
                }).onError(function(_):Void{
                    errorCall("加载SWFLite文件失败");
                });
            }).onError(function(err:Dynamic):Void{
                errorCall("加载SWFLite文件失败");
            });
        }
        else
        {
            errorCall("非SWFLite文件");
        }
    }

This is a major parsing code; you need to load the zip binary data to the first argument. Then you need to have a custom SWFLiteLibrary class for parsing Zip resources, you can refer to the one I provided above.

and:

/**
     * 在ZIP中查找资源
     * @return Entry
     */
    public static function findZipData(list:List<Entry>,fileName:String):Entry
    {
        for(entry in list)
        {
            if(entry.fileName.indexOf(fileName) != -1)
            {
                return entry;
            }
        }
        return null;
    }

Maybe a simple full example source code that only contain .zip and load 1 animation movieclip will be great help. Or use and edit NyanCat-example become .zip and load it.

Thanks.

Maybe I can give you an example tomorrow.

Thank you very much, I’m really appreciate it :slight_smile:

Hi, I can’t seem to upload resources. I am trying to tell you the steps:

  1. You need to export a bundle resource, such as:
    openfl process Assets/library.swf
  2. Copy the code to Source/Main.hx:
package;


import openfl.utils.ByteArray;
import openfl.display.Sprite;
import openfl.Assets;
import haxe.io.BytesInput;
import haxe.io.BytesInput;
import haxe.zip.Reader in Zip;
import haxe.zip.Entry;
import haxe.io.Bytes;
import lime._internal.format.Deflate;
import openfl.display3D.Context3DTextureFormat;
import openfl.display3D.textures.Texture;
import lime.app.Future;
import lime.app.Promise;
import lime.graphics.Image;
import openfl._internal.symbols.BitmapSymbol;
import haxe.zip.Entry;
import openfl._internal.formats.swf.SWFLite;
import openfl.utils.Assets;
import haxe.io.Bytes;
import lime._internal.format.Deflate;
import lime.utils.AssetManifest;
import lime.app.Future;
import lime.app.Promise;
import lime.graphics.Image;
import openfl._internal.symbols.BitmapSymbol;
import haxe.zip.Entry;
import openfl._internal.formats.swf.SWFLite;
import openfl.utils.Assets;
import haxe.io.Bytes;
import lime._internal.format.Deflate;


class Main extends Sprite {
	
	
	public function new () {
		
		super ();
		
		openfl.utils.Assets.loadBytes("assets/library.zip").onComplete((bytes:ByteArray)->{
			trace("Bytes loaded!");
			SWFLoader.loadSwfBytes(bytes,"",(swf)->{
				trace("SwfLiteLibrary loaded:",swf);
				var cat = swf.getMovieClip("NyanCatAnimation");
				addChild (cat);
			},(err)->{
				trace("SwfLiteLibrary load error!");
			});
		});

		
	}
	
	
}

class SWFLoader {

	/**
     * SwfliteParse
     */
    public static function loadSwfBytes(bytes:ByteArray, rootPath:String, call:SWFLiteLibrary->Void,errorCall:String->Void):Void
    {
        var input:BytesInput = new BytesInput(bytes);
        var zip:Zip = new Zip(input);
        var list:List<Entry> = zip.read();
        var entry:Entry = findZipData(list,"library.json");
        if(entry != null)
        {
            //解压
            var bytes:Bytes = entry.compressed?Deflate.decompress(entry.data):entry.data;                    
            AssetManifest.loadFromBytes(bytes,rootPath).onComplete(function(manifest:AssetManifest):Void{
                manifest.libraryType = "SWFLiteLibrary";
                var swf:SWFLiteLibrary = SWFLoader.fromManifest(manifest,list);
                swf.load().onComplete(function(_):Void{
                    swf.releaseZip();
                    call(swf);
                }).onError(function(_):Void{
                    errorCall("加载SWFLite文件失败");
                });
            }).onError(function(err:Dynamic):Void{
                errorCall("加载SWFLite文件失败");
            });
        }
        else
        {
            errorCall("非SWFLite文件");
        }
    }

	/**
     * 在ZIP中查找资源
     * @return Entry
     */
    public static function findZipData(list:List<Entry>,fileName:String):Entry
    {
        for(entry in list)
        {
            if(entry.fileName.indexOf(fileName) != -1)
            {
                return entry;
            }
        }
        return null;
    }

	/**
     * 加载SWFLiteLibrary
     * @param manifest 
     * @param list 
     * @return SWFLiteLibrary
     */
    public static function fromManifest (manifest:AssetManifest,list:List<Entry>):SWFLiteLibrary {

		if (manifest == null) return null;

		var library:SWFLiteLibrary = null;

        var libraryClass = Type.resolveClass (manifest.libraryType);

        if (libraryClass != null) {

            library = Type.createInstance (libraryClass, manifest.libraryArgs);
            library.zipList = list;

        } else {

            trace ("[ZYGAME]SWFLiteLoader:Could not find library type: " + manifest.libraryType);
            return null;

        }

		@:privateAccess library.__fromManifest (manifest);

		return library;

	}

}

@:keep
class SWFLiteLibrary extends #if (openfl <= '8.3.0') openfl._internal.swf.SWFLiteLibrary #else openfl._internal.formats.swf.SWFLiteLibrary #end {
	/**
	 * SWF文件名
	 */
	public var name:String;

	/**
	 * 已经解析好的ZIPList列表
	 */
	public var zipList:List<Entry>;

	override public function load():Future<lime.utils.AssetLibrary> {
		if (zipList == null) {
			return super.load();
		}

		if (id != null) {
			preload.set(id, true);
		}

		var promise = new Promise<lime.utils.AssetLibrary>();
		preloading = true;

		var onComplete = function(data) {
			cachedText.set(id, data);

			swf = SWFLite.unserialize(data);
			swf.library = this;

			var bitmapSymbol:BitmapSymbol;

			for (symbol in swf.symbols) {
				if (Std.is(symbol, BitmapSymbol)) {
					bitmapSymbol = cast symbol;

					if (bitmapSymbol.className != null) {
						imageClassNames.set(bitmapSymbol.className, bitmapSymbol.path);
					}
				}
			}

			SWFLite.instances.set(instanceID, swf);

			__load().onProgress(promise.progress).onError(promise.error).onComplete(function(_) {
				preloading = false;
				promise.complete(this);
			});
		}

		if (Assets.exists(id)) {
			#if (js && html5)
			for (id in paths.keys()) {
				preload.set(id, true);
			}
			#end

			loadText(id).onError(promise.error).onComplete(onComplete);
		} else {
			for (id in paths.keys()) {
				preload.set(id, true);
			}

			var path = null;

			if (paths.exists(id)) {
				path = paths.get(id);
			} else {
				path = (rootPath != null && rootPath != "") ? rootPath + "/" + id : id;
			}

			var binPath:String = StringUtils.getName(path);
			var entry:Entry = SWFLoader.findZipData(zipList, binPath);
			var bytes:Bytes = entry.compressed ? Deflate.decompress(entry.data) : entry.data;
			onComplete(bytes.toString());
		}

		return promise.future;
	}

	override public function loadText(id:String):Future<String> {
		if (zipList == null) {
			return super.loadText(id);
		}
		var entry:Entry = SWFLoader.findZipData(zipList, id);
		var bytes:Bytes = entry.compressed ? Deflate.decompress(entry.data) : entry.data;
		return Future.withValue(bytes.toString());
	}

	override public function loadImage(id:String):Future<Image> {
		if (zipList == null) {
			return super.loadImage(id);
		}
		var entry:Entry = SWFLoader.findZipData(zipList, id);
		var bytes:Bytes = entry.compressed ? Deflate.decompress(entry.data) : entry.data;
		return Image.loadFromBytes(bytes);
	}

	/**
	 * 载入逻辑重写
	 * @param id 图片ID
	 * @return Future<Image>
	 */
	override private function __loadImage(id:String):Future<Image> {
		if (zipList == null) {
			return super.__loadImage(id);
		}
		return super.loadImage(id);
	}

	/**
	 * 释放ZIP资源
	 */
	public function releaseZip():Void {
		if (zipList != null) {
			zipList.clear();
			zipList = null;
		}
	}

	/**
	 * 释放unload
	 */
	override public function unload():Void {
		super.unload();
		var images:Map<String, Image> = cachedImages;
		var iter:Iterator<String> = images.keys();
		while (iter.hasNext()) {
			var key:String = iter.next();
			var img:Image = images.get(key);
			images.remove(key);
		}
		cachedImages = null;
	}
	
}


class StringUtils {

	/**
     *  获取字符串的名字,不带路径、扩展名
     *  @param data - 
     *  @return String
     */
    public static function getName(data:String):String
    {
        if(data == null)
            return data;
        data = data.substr(data.lastIndexOf("/")+1);
        data = data.substr(0,data.lastIndexOf("."));
        return data;
    }

}
  1. Finally you only need to run the command:
    lime test html5

edit:
This is the effect I got when I changed the NyanCat project.

1 Like

If you want, on the dev version of OpenFL and Lime we are working on a new SWF file format which is temporarily called type="animate":

<library path="my.swf" type="animate" preload="true" />

The dev version also uses this when running openfl process my.swf to process a file in advance. The goal is to finalize a backward-compatible format which is the same when processing individually or when embedding as a library.

This library also uses the newer AssetBundle type in Lime which is a zipped library – so an animate-style SWF library is zipped into only one file per library

Would appreciate any help testing it or contributions to continue to improve it! @rainy it was directly inspired by your work :slight_smile:

4 Likes

Thank you @rainy, It’s working great!!

Where I can download the dev version? I tried use Openfl 8.9.1 and Lime 7.5.0 was not working.

It’s on Github only until we’re ready for a new release :slight_smile: