Accessing multiple bitmap images in a swc file by using getdefinitionbyname - actionscript-3

I received from my client a SWC file with hundreds of png images that all have AS Linkage such as image1_1_1, image1_1_2, image1_2_1, image2_1_3 and so on. I have these same linkage names in an XML file that i'm loading.
All the images are linked with the BitmapData class as base class.
The problem is that when i try to dynamically create new bitmaps from the xml file and the linkage names by using getDefinitionByName i get the following error:
ReferenceError: Error #1065: Variable image1_1_1 is not defined.
My code for creating the bitmaps is as follows:
var BmDataClass:Class = getDefinitionByName(xmlImage) as Class;
var image:Bitmap = new Bitmap(new BmDataClass());
where xmlImage is the variable in a for each loop, looping through the xml file.
I trace xmlImage so i know it coresponds to the correct name in the SWC file.
Does anyone have any idea why i get this error?
Would appreciate any hints or solutions :-)

try this:
var imageName:String = "xxx";
var myClass:Class = getDefinitionByName(imageName) as Class;
var bmp:BitmapData = new myClass(0, 0) as BitmapData;
var img:Bitmap = new Bitmap(bmp);

The answer seems to have been as described in the accepted Answer to this thread
Instantiate a class from a string in ActionScript 3
And also slightly explained on this page
http://producerism.com/blog/flashpunk-dame-and-lua-tutorial-part-6/
under the paragraph titled getDefinitionByName
Which for me sadly messed up a large part of the project. Ah well... new solutions presents themselves every day :-)

Related

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

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

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.

Flash Var Loader Issue

I have three classes and a container .swf:
Game - this loads all assets and game mechanics.
Tile - Creates a square and loads image an image via flash Var.
TicTacToe.as - This creates a game instance and is linked via container.swf
In my Game class I have the following code which works fine when I save and compile, and is able to load my images when I update to my .asp page(I am getting the data from a db and passing to flash vars).
var gridUrl:String = "img/" + loaderInfo.parameters.theme + "grid.png";
var gridPos:XMLList = theXML.GRID;
gridLoader.load(new URLRequest(gridUrl));
grid = new MovieClip();
grid.addChild(gridLoader);
When I add this code to the Tile.as to load an image for the square I get a compiler error 1009: Cannot access a property or method of a null object reference. with an error on this line:
var tileBurl:String = "img/" + loaderInfo.parameters.theme + "square.jpg";
Its working in the Game.as class but this same line isn't in my Tile.as and I can't figure out why, even locally when it can't find the variables Game.as simply lists them as "undefined" where as in Tile.as it throws a fit at loaderInfo.parameters, and loaderInfo lists them as "null". Any Help would be appreciated thanks!
It looks that in the time of calling loaderInfo object, this is not yet prepared. Try to delay execution of the code for example by adding empty frame at the begining.

Difference between getDefinition and getDefinitionByName in AS3

Can somebody explain what is the difference between getDefinitionByName and getDefinition inA AS3?
When I load an external SWF I can't use getDefinitionByName because I get an Error #1065.
But using externalSWF_ContentLoaderInfo.applicationDomain.getDefinition works OK.
So, why getDefinitionByName doesn't find the className?
I mean, if the definition is inside the applicationDomain of the loaded SWF, why is not in the main SWF too? (I'm using Flex).
Offtopic: I can't create new tags so I can't add the tags getDefinition and getDefinitionByName :(
getDefinition is a method of an ApplicationDomain which returns a definition of a class, namespace or function.
getDefinitionByName is a package-level function from flash.utils which returns a Class object that you can use to instantiate new Objects. The definition must already be loaded somewhere in your ApplicationDomain.
The reason you can't make getDefinitionByName with an external SWF is that it is loaded into a separate ApplicationDomain. Your second example works because you are targeting the correct ApplicationDomain. To make your first example work you must load the external SWF into your current ApplicationDomain like this:
var request:URLRequest = new URLRequest("externalSWF.swf");
var context:LoaderContext = new LoaderContext();
context.applicationDomain = ApplicationDomain.currentDomain;
var loader:Loader = new Loader();
loader.load(request,context);
This works because it passes the current ApplicationDomain as a property of the loader context.