Actionscript 3, reading two files then triggering a function, best practice - actionscript-3

I need to read a part of two files, and once both parts of both files are loaded to trigger a function that does some work.
What is the best way to approach this problem.
I am currently triggering the second file load once the first is loaded, however it seems poor coding style, I think this because my OO code starts looking procedural.
EDIT: So its an Air based app so using filestream.
In the end I found I actually needed to read each file in a different way. Because I need the same part of both files, and I dont know the file size, I need to read one file first and once I have fileStream.bytesAvailable and position, I can then look for the same data from the second file. I found I must handle files smaller than my read size and the end of files beyond multiples of my read size.

You don't specified what file and from where you wont to load the file but you can actually load multiples files in parallel.
If you want to read only part of file from local machine you can use AIR's FileStream class - very easy and you don't have to load whole few hundreds MB file:
import flash.filesystem.*;
var file:File = File.documentsDirectory;
file = file.resolvePath("Apollo Test/test.txt");
var fileStream:FileStream = new FileStream();
fileStream.open(file, FileMode.READ);
var str:String = fileStream.readMultiByte(file.size, File.systemCharset);
trace(str);
fileStream.close();
Another option is to use URLStream and listen for ProgressEvent.PROGRESSevents to read data of partially loaded file.
You may also want to see NetStream class which is used to stream video.

there is many options, using File, FileStream is only available on air applications.
The File class extends the FileReference class. The FileReference
class, which is available in Flash® Player as well as Adobe® AIR®,
represents a pointer to a file, but the File class adds properties and
methods that are not exposed in Flash Player (in a SWF running in a
browser), due to security considerations.
as noted above, if you are creating a non-AIR application, FileReference should be used instead of FileStream and File classes, as you dont tagged AIR in your question.
FileReference does not provide any open("path") to you (due to security considerations), but a browse method will be available and ask's your client's for selecting a file. here is an example, which also explain how to trigger a function when opening is done:
var filereference:FileReference = new FileReference();
filereference.addEventListener(Event.SELECT, onFileSelected);
var text_files:FileFilter = new FileFilter("Text Files","*.txt; *.html;*.htm;*.php");
var all_files:FileFilter = new FileFilter("All Files (*.*)","*.*");
filereference.browse([text_files, all_files]);
// triggered when a file is selected by user
function onFileSelected(e:Event):void {
filereference.removeEventListener(Event.SELECT, onFileSelected);
filereference.addEventListener(Event.COMPLETE, onFileLoaded);
filereference.load();
}
// triggered when file loading is complete
function onFileSelected(e:Event):void {
var data:ByteArray = fileReference["data"];
filereference.removeEventListener(Event.COMPLETE, onFileSelected);
}
two more events to be listened for suddenly error's occurred and displaying a progress bar for loading progress (its sync):
IOErrorEvent.IO_ERROR and ProgressEvent.PROGRESS

Related

patching actionscript without constantly rebuilding swf

How can I patch actionscript without constantly rebuilding sfw?
There is a fairly large actionscript project that I need to modify and resulting swf is used on a live site. The problem I have is that I need to make quick small updates to the swf and it's not acceptable to update the swf on live site ten time a day (I don't control that part, I need to ask another person to put the result on live site).
What options do I have to workaround that issue? I'm a complete noob when it comes to actionscript and all flash related stuff and I'm not even sure what is possible and what isn't. I'm thinking about the following approaches, which ones are possible/acceptable?
Imagine that live site is on www.livesite.com/game.html and this page loads www.livesite.com/flashgame.swf. In that flashgame.swf among many others there is a class com/livesite/Magic.as that gets instantiated and instance of that class has a member variable xxx123 of class com/livesite/MagicWork.as. I only need to modify this MagicWork class. Now, I simply modify it, build and ask to put updated flashgame.swf live. So, I want to avoid that manual step.
All my ideas can be split in two basic approaches: 1) keep flashgame.swf totally unmodified and then load flashgame.mod.swf that contains alternative implementation of that MagicWork class, then using javascript access internals of instance of that Magic class and update its xxx123 member to be an instance of MagicWork class from flashgame.mode.swf. I'd need to modify game.html to load my javascript so that my js file would load flashgame.mod.swf and patch code inside flashgame.swf. By patching I mean javascript-style overwriting of Magic.xxx123 to a new value. flashgame.mode.swf would ideally reside on my own host that I control. Is that kind of stuff possible, if not what's not possible?
2) I could make one-time change in flashgame.swf so that it would effectively load itself my own code at runtime and patch it's xxx123 member. Is that possible?
I had already written a note about loading runtime shared libraries previously. I'll put the most essential parts of the process here, and add a link to the full article at the end.
You need to tag your main application entry point in the following manner.
[Frame(factoryClass="Preloader")]
public class Main extends Sprite
{
}
Then create a class called Preloader.
public class Preloader
{
public function Preloader()
{
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, this.loader_completeHandler);
loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, this.loader_ioErrorHandler);
var request:URLRequest = new URLRequest("math.swf");
var context:LoaderContext = new LoaderContext(false, ApplicationDomain.currentDomain);
loader.load(request, context);
}
private function loader_completeHandler(event:Event):void
{
var mainClass:Class = getDefinitionByName("Main") as Class;
var mainInstance:Main = new mainClass();
this.addChild(mainInstance);
}
}
The full implementation of the Main class is like this.
[Frame(factoryClass="Preloader")]
public function Main()
{
var integer:IntegerArithmetic = new IntegerArithmetic(); // Type declared in math.swf
var operand1:int = 10;
var operand2:int = 10;
var result:int = integer.add(operand1, operand2);
}
Deploying Runtime Shared Libraries
The confusing bit about using a runtime shared library is realizing that the SWF has to be extracted from the SWC at the time of deploying the application. This was not immediately obvious and I ended up spending days placing a compiled SWC file in various locations and wondering why the application was unable to load it at runtime. An obscure article on the Adobe website made explicit this particular step and set things straight.
The full article along with the same example is available at http://www.notadesigner.com/runtime-shared-libraries-with-plain-actionscript/.

Save image with pure Flash?

Very simple: How do I save an image with pure Flash only?
Example code:
var bitmap: BitmapData = new BitmapData(100, 100, true, 0);
bitmap.draw(this);
var data: ByteArray = bitmap.getPixels(bitmap.rect);
var f: FileReference = new FileReference();
f.save(data, "test.bmp");
This saves me a file of 40,000 bytes (4 * 100 * 100). I checked it with hex editor and it is the pixels of my bitmap/sprite. Now I don't care what image type comes out of this. I just want it saved in a format that I can display with common image editors. I don't want to install extra stuff. Can I do it with Flash only, no AIR, no JPGEncoder, no nothing extra?
(This function is not for customers to use anyways.)
I found a solution.
First off, you need to make sure that you are targeting a Flash Player with at least version 11.3, and compile the SWF with at least a version of 18 (or at least, 18 worked for me).
The BitmapData Class has its own method called encode which will handle the encoding work for you, either for JPEG or PNG. Here is how to do it:
var bitmap:BitmapData = new BitmapData(100,100,true,0);
bitmap.draw(this);
var data:ByteArray = new ByteArray();
var o:PNGEncoderOptions = new PNGEncoderOptions();
bitmap.encode(bitmap.rect, o, data);
var f:FileReference= new FileReference();
f.save(data, "test.png");
The third parameter of encode is the output Bytearray where the encoded Bytearray will get saved.
AS3 Documentation
You can still use PNGEncoder or JPGEncoder and still be "pure flash". If you're missing the libraries you can get them (and others) in the as3corelib swc library. Just include the swc in your library path.
If for some reason it's not pure enough, I suppose you could always go in to the source code of the library and copy out the specific PNGEncoder or JPGEncoder class and repurpose it for your uses.

Loading multiple swf files

Like every programmer I´m facing a tricky challenge, and I hope someone could share with me some knowledge.
 
I'm creating a game, and for each game component(such as audio, video, pictures), I´ve created a swf file(library). At the main file, I am trying to load my swf files using the Loader class.
 
I would like to make a preloader and I want to calculate the percentage of bytes loaded from of all of my swf files. I´ve realized that loading 3 loaders at the same time makes my game slow. I tried to upload one file at a time, but I don´t know how to catch the bytes loaded from my files without using ProgressEvent(Here I can access bytesTotal variable).
 
Does anyone faced a similar problem and could share a tip or a link?
 
 
Regards and Good Friday!
I strongly recommend you the GreenSock's LoaderMax library. It simplifies and enhances the entire process. It's easy to setup and small.
import com.greensock.*;
import com.greensock.loading.*;
import com.greensock.events.LoaderEvent;
import com.greensock.loading.display.*;
// Create a LoaderMax named "gameQueue" and bind onProgress, onComplete and onError listeners
var queue:LoaderMax = new LoaderMax({name:"gameQueue", onProgress:progressHandler, onComplete:completeHandler, onError:errorHandler});
// Append several loaders
queue.append( new XMLLoader("xml/data.xml", {name:"xmlDoc"}) );
queue.append( new ImageLoader("img/photo1.jpg", {name:"photo1", estimatedBytes:2400, container:this, alpha:0, width:250, height:150, scaleMode:"proportionalInside"}) );
queue.append( new SWFLoader("swf/child.swf", {name:"childClip", estimatedBytes:3000, container:this, x:250, autoPlay:false}) );
queue.append( new MP3Loader("mp3/audio.mp3", {name:"audio", repeat:2, autoPlay:true}) );
// Run
queue.load();
function progressHandler(event:LoaderEvent):void {
trace("progress: " + event.target.progress);
}
function completeHandler(event:LoaderEvent):void {
var image:ContentDisplay = LoaderMax.getContent("photo1");
TweenLite.to(image, 1, {alpha:1, y:100});
trace(event.target + " is complete!");
}
function errorHandler(event:LoaderEvent):void {
trace("error occured with " + event.target + ": " + event.text);
}
You can display the progress of individual loaders or groups of loaders.
In order to accurately calculate the overall progress of a group of loaders, it’s important to know the total file size (bytesTotal) of each child loader. But if some files haven’t started loading yet, how could your loader possibly know their sizes?
There's no TCP packet, that will inform you about the final size when the progress starts.
Remember: get is like a stream. You'll never know the final size, until the file is ready!
new ImageLoader("1.jpg", {estimatedBytes:26000});
A simple workaround:
Generate a xml or json list, that contains the url and the total size of each preloadable element. You can do this with some automation in php (for example), check this SO answer.
Preload the xml/json file-list with LoaderMax and parse it in AS3.
Load all files from within the xml and add the correct file size. That's it.
You can find the full AS3 documentation here.
Start to load your files, get file size and close the stream immediately after you received size info.
And then load your files one by one as you wanted.
Or compile your main swf with merged into code libraries(if this is suitable for you).

Compiling SWF runtime from adobeAir application

I have problem in creating swf file runtime from an adobe air application. For example I create animation using https://github.com/jamesflorentino/Flip-Planes-AS3, I have converted the Sprite extension to MovieClip, the animation runs very good. Now I would like to make the animation could be save as swf file by user.
I have tried as3swf with script like this:
private function createSwf():void{
//let make example the Main class is taken from github above
var _main:Main = new Main();
// in this case i use AS3SWF plugin
var _swf:SWF = new SWF(_main.loaderInfo.bytes);
// this is for copy byteArray from the _swf convertor
var buffer:ByteArray = new ByteArray();
_swf.publish(buffer);
saveToDesktop(buffer);
}
private function saveToDesktop(_ba:ByteArray):void{
// create the file on the desktop
var myFile:File = File.desktopDirectory.resolvePath("demo.swf");
// create a FileStream to write the file
var fs:FileStream = new FileStream();
// add a listener so you know when its finished saving
fs.addEventListener(Event.CLOSE, fileWritten);
// open the file
fs.openAsync(myFile, FileMode.WRITE);
// write the bytearray to it
fs.writeBytes(_ba);
// close the file
fs.close();
}
private function fileWritten(e:Event):void{
trace("new swf file is created");
}
After all those process i got generated swf in my desktop folder with name demo.swf but when i open the file, it is only a white background with error message:
VerifyError: Error #1014: Class flash.events::NativeWindowBoundsEvent could not be found.
at flash.display::MovieClip/nextFrame()
at mx.managers::SystemManager/deferredNextFrame()[E:\dev\4.y\frameworks\projects\framework\src\mx\managers\SystemManager.as:278]
at mx.managers::SystemManager/preloader_preloaderDocFrameReadyHandler()[E:\dev\4.y\frameworks\projects\framework\src\mx\managers\SystemManager.as:2627]
at flash.events::EventDispatcher/dispatchEventFunction()
at flash.events::EventDispatcher/dispatchEvent()
at mx.preloaders::Preloader/timerHandler()[E:\dev\4.y\frameworks\projects\framework\src\mx\preloaders\Preloader.as:515]
at flash.utils::Timer/_timerDispatch()
at flash.utils::Timer/tick()
please help me what is the best way to create swf file runtime, both from script side or command line side as long as not server side because it is desktop application.
Many Thanks
Creating a SWF at runtime is not going to be the same as taking an in memory byte array representation of an animation and saving it with a SWF extension.
If you want to build a SWF from AIR; you may consider bundling the Flex Framework with your application and use a NativeProcess to trigger mxmlc to generate a SWF. You'll need source code [or SWCs] to do this, though, it won't work with already compiled assets/classes from your running application.
Or you may want to review the file format for a SWF and go about creating it manually from your AIR application. I have no doubt this is possible, but I do not expect it to be trivial.

How to save BitmapData to Bitmap *.bmp file, or much faster JPE Encoding method

I have a Flash / Actionscript 3 based desktop app wrapped in an *.exe using Zinc 4.0. I am using Flash Pro CS5.
I need to start saving very large image files locally. I have messed around with JPG Encoding these images before saving them to a local file via Zinc. I solved the actionscirpt timeout issue using This "asyncronous like" method. Encoding a 1.5 MP image takes about 5 seconds which is alright, but encoding an 8 MP image file takes about 40 seconds, which is not acceptable.
One idea I had is to save the BitmapData locally to a temporary Bitmap file (*.bmp), without having the end user to wait for JPG Encoding in Flash, and then use my already existing image processor (written in C#) to read the bitmap file and encode it without waiting on Flash to do it, effectively offloading the task away from the user.
I have used BitmapData.getPixels() to try and write the byte array directly to the file, using the same Zinc method as I do successfully with encoded JPGs, but the *.bmp file is unreadable. Are there some file headers that would need to be included in addition to the BitmapData getPixel()'s byte array to successfully save a bitmap image? If so how could I successfully add them to the byte array before writing to file?
Any guidance, clarification or other solutions much appreciated.
I've found a solution for my needs, and just in case others have similar needs:
To save an actual Bitmap (*.bmp) file, Engineer's suggested Btimap encoder class was awesome. Very fast on the actual encoding; however, since my file writing call in Zinc is synchronous and bitmap files are a lot larger than JPGs it really just moved my bottle neck from encoding to the file saving, so I decided to look elsewhere. If Zinc had an asynchronous binary file writing method that would not lock up the GUI I would have been happy, but until then this is not the solution for me.
I stumbled across a Flash Alchemy solution, with great results. Instead of waitint abour 40 seconds to encode an 8 MP image, it now only takes a few seconds. This is what I did:
Downloaded the jpegencoder.swc from this page and saved it in my project directory
Added the swc: Publish Settings > Flash (tab) > Script: Actionscript 3.0 "Settings..." button > Library path (tab)> and added that .swc with Link Type = "Merged into code"
Then used it :
(below is my modified code with just the basics)
import flash.utils.ByteArray;
import flash.display.BitmapData;
import cmodule.aircall.CLibInit; //Important: This namespace changed from previous versions
var byteArrayResults:ByteArray; //Holds the encoded byte array results
public static function startEncoding(bitmapData:BitmapData):void {
var jpeginit:CLibInit = new CLibInit(); // get library
var jpeglib:Object = jpeginit.init(); // initialize library exported class to an object
var imageBA:ByteArray = bitmapData.getPixels(bitmapData.rect); //Getpixels of bitmapData
byteArrayResults = new ByteArray();
imageBA.position = 0;
jpeglib.encodeAsync(encodeComplete, imageBA, byteArrayResults, bitmapData.width, bitmapData.height, 80);
}
private static function encodeComplete(thing:*):void
{
// Do stuff with byteArrayResults
}
You may find this link useful as well:
http://last.instinct.se/graphics-and-effects/using-the-fast-asynchronous-alchemy-jpeg-encoder-in-flash/640
my answer is late but maby it helps.
i developed a AIR mobile app to save imgs from the device camera on the device and upload it to the server.
since air 3.3 you have this bitmapdata encode functionality:
var ba:ByteArray = new ByteArray();
var bd:BitmapData = new BitmapData(_lastCameraPhotoTmpBmp.width, _lastCameraPhotoTmpBmp.height);
bd.draw(_lastCameraPhotoTmpBmp);
bd.encode(new Rectangle(0, 0, 1024, 768), new JPEGEncoderOptions(80), ba);
var localFile:File = File.applicationStorageDirectory.resolvePath("bild.jpg");
var fileAccess:FileStream = new FileStream();
fileAccess.open(localFile, FileMode.WRITE);
fileAccess.writeBytes(ba, 0, ba.length);
fileAccess.close();
the encode to jpg takes ~100ms on mobile devices in my tests.
greetings stefan