Full Flex Display Object to Image - actionscript-3

I have a requirement for generating a UIComponent displayed into an Image. Am using the PNGEncoder as well as JPEGEncoder to generate the image.
var bd:BitmapData = new BitmapData(uiComp.measuredWidth,uiComp.measuredHeight);
bd.draw(uiComp, new Matrix());
var bitmap:Bitmap = new Bitmap(bd);
bytes = jpgenc.encode(bd);
The code is working perfectly in normaly scenarios. But the problem comes in low resolution screens, if the canvas is having scroll bar, only the displayed contents, i mean omitting the contents belows the scrolled location is coming. Is there any way that I can convert the complete canvas completely into an image, even if it having scroll bar! Please help!
Cheers, PK

I think ImageSnapshot can take a screenshot even if the component is cut off or even if its visible property is set to false.
import mx.core.IUIComponent;
import mx.graphics.ImageSnapshot;
private function takeSnapshot(source:IBitmapDrawable):void {
var imageSnap:ImageSnapshot = ImageSnapshot.captureImage(source);
var imageByteArray:ByteArray = imageSnap.data as ByteArray;
swfLoader.load(imageByteArray);
}

Using Imagesnap with PNGEncoder i was able to get the Screenshot with compression
import flash.filesystem.FileStream;
import flash.filesystem.File;
import flash.filesystem.FileMode;
import mx.graphics.ImageSnapshot;
import mx.graphics.codec.PNGEncoder;
...
...
...
...
ImageSnapshot.defaultEncoder = PNGEncoder;
var imageSnap:ImageSnapshot = ImageSnapshot.captureImage(FlexGlobals.topLevelApplication as IBitmapDrawable);
var stream:FileStream = openStream("screenshot.png");
stream.writeBytes(imageSnap.data);
stream.close();
...
...
...
...
private static function openStream(fileName:String):FileStream
{
var file:File = File.documentsDirectory.resolvePath(fileName);
var stream:FileStream = new FileStream();
stream.open(file, FileMode.WRITE);
return stream;
}

Related

Smooth image on load in as3

I am new here and a complete noob when it comes to as3. Somehow I have managed to put this together with some help from different places. And now I turn to you guys :)
I need to put smoothing on my images and thumbs that Im loading from an XML file. I have tried a lot of things but can't get any of it to work and I get this error:
Scene 1, Layer 'as3', Frame 1, Line 27 1120: Access of undefined property e. -> So I know var bitmapContent:Bitmap = Bitmap( e.target.content ); is the problem. but I have no idea what to use instead of e. I
this i what I have so far:
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.events.Event;
import flash.events.MouseEvent;
import fl.transitions.Tween;
import fl.transitions.easing.None;
import flash.display.Bitmap;
// Loads the first image//
var i =new Loader();
i.load(new URLRequest("images/1.jpg"));
mainLoader.addChild(i)
//Loads the XML file//
var picsXML:XML;
var xmlLoader:URLLoader = new URLLoader();
xmlLoader.addEventListener(Event.COMPLETE , xmlLoaded);
xmlLoader.load(new URLRequest("imagelist.xml"));
//Loads images into thumbs//
function xmlLoaded(event:Event):void{
picsXML = new XML(xmlLoader.data);
//trace(picsXML);
var bitmapContent:Bitmap = Bitmap( e.target.content );
bitmapContent.smoothing = true;
var thumbLoader:UILoader;
for (var i:uint=0; i<picsXML.image.length(); i++)
{
thumbLoader=UILoader(getChildByName("thumb"+i));
thumbLoader.load(new URLRequest("thumbs/"+picsXML.image[i].#file));
thumbLoader.buttonMode = true;
thumbLoader.addEventListener(MouseEvent.CLICK, thumbClicked);
thumbLoader.addEventListener(MouseEvent.CLICK, tester);
}
}
//Loads large image when thumb is clicked//
function thumbClicked(event:MouseEvent){
//var bitmapImage:Bitmap = event.target.content;
//bitmapImage.smoothing = true;
var thumbName:String = event.currentTarget.name;
var thumbIndex:uint = uint(thumbName.substr(5));
var fullPath:String = "images/"+picsXML.image[thumbIndex].#file;
mainLoader.load(new URLRequest(fullPath));
var myTween:Tween = new Tween(mainLoader,"alpha", None.easeNone, .3,1,18,false);
}
//Removes the first image when thumbs is clicked//
function tester(event:MouseEvent){
if (mainLoader.contains(i)) {
trace("hej")
mainLoader.removeChild(i);
}
}
If i get your code true problem is here: u import an external xml file which is probably contain your url's and name of pic's. U can't turn ur xml file into a bitmap.
If u want smoothing on your pictures u need to it after load ur pics or thumb's.
Probably ur problem will fix like this :) Hope this will help
Functions with arguments work like this: function Name ( input arg Name : input arg Type )
Firstly, your function xmlLoaded(event:Event) cannot have an input called event
but then you try to do a Bitmap( e.target.content ); so for that bitmap line to work you'd have to change your input name to e like so... xmlLoaded( e : Event );
Secondly, var bitmapContent:Bitmap = Bitmap( e.target.content ); is incorrect.
This is more correct var bitmapContent:Bitmap = img_Bytes_Loader.content as Bitmap; set a Loader's content as Bitmap not XML content (text) as Bitmap (pixels).
Anyways assuming your XML file looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<Items>
<mp3>
<url> track1.mp3 </url>
<image> image1.jpg </image>
</mp3>
<mp3>
<url> track2.mp3 </url>
<image> image2.jpg </image>
</mp3>
</Items>
Then your code should look something like this below :
var imgLoader_XML : URLRequest;
var picLoader : Loader = new Loader();
function xmlLoaded(event:Event):void
{
picsXML = new XML(xmlLoader.data);
//trace(picsXML);
imgLoader_XML = new URLRequest( picsXML.mp3[ index ].image ); //[index] could be replaced with [i] if FOR loop
picLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, picloadComplete);
picLoader.load (imgLoader_2);
}
public function picloadComplete(evt:Event)
{
yourContainer.addChild(picLoader);
yourContainer.width = 100;
yourContainer.height = 100;
yourContainer.alpha = 1;
}
Thanks for the inputs guys. It is greatly appreciated.
I figured it out. You were right, of course I can't put smoothing on the UILoader, so I had to target the content of the UILoader and run thumbLoader.addEventListener(Event.COMPLETE, smoothing); each time an image is importet.
Here is the entire working code (maybe it can help someone else :) :
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.events.Event;
import flash.events.MouseEvent;
import fl.transitions.Tween;
import fl.transitions.easing.None;
import flash.display.Bitmap;
import flash.display.Loader;
// Loads the first image//
var i =new Loader();
i.load(new URLRequest("images/1.jpg"));
mainLoader.addChild(i)
//Loads the XML file//
var picsXML:XML;
var xmlLoader:URLLoader = new URLLoader();
xmlLoader.addEventListener(Event.COMPLETE , xmlLoaded);
xmlLoader.load(new URLRequest("imagelist.xml"));
//Loads images into thumbs//
function xmlLoaded(event:Event):void{
picsXML = new XML(xmlLoader.data);
var thumbLoader :UILoader = new UILoader();
for (var i:uint=0; i<picsXML.image.length(); i++)
{
thumbLoader=UILoader(getChildByName("thumb"+i));
thumbLoader.load(new URLRequest("thumbs/"+picsXML.image[i].#file));
thumbLoader.buttonMode = true;
thumbLoader.addEventListener(MouseEvent.CLICK, thumbClicked);
thumbLoader.addEventListener(MouseEvent.CLICK, tester);
thumbLoader.addEventListener(Event.COMPLETE, smoothing);
}
}
function smoothing(e:Event):void{
if(e.currentTarget.content is Bitmap)
{
Bitmap(e.currentTarget.content).smoothing = true;
}
}
//Loads large image when thumb is clicked//
function thumbClicked(event:MouseEvent){
var thumbName:String = event.currentTarget.name;
var thumbIndex:uint = uint(thumbName.substr(5));
var fullPath:String = "images/"+picsXML.image[thumbIndex].#file;
mainLoader.load(new URLRequest(fullPath));
mainLoader.addEventListener(Event.COMPLETE, smoothing);
var myTween:Tween = new Tween(mainLoader,"alpha", None.easeNone, .3,1,18,false);
}
//Removes the first image when thumbs is clicked//
function tester(event:MouseEvent){
if (mainLoader.contains(i)) {
trace("hej")
mainLoader.removeChild(i);
}
}

How to add two UILoader inside a UILoader and save the contents of the UILoader using actionscript 3

I have been into a research these past hours in figuring out how to add a UILoader inside a UILoader and save all the contents of a UILoader. I have two instance of UILoader (loader_inner and loader_outer) and they are both placed manually using the UILoader component.
The code goes something like this:
loader_inner.load(new URLRequest("background_1.jpg"));
loader_outer.load(new URLRequest("rabbit.jpg"));
loader_outer.addChild(loader_inner);
var bitmapData:BitmapData = new BitmapData(loader_outer.width,loader_outer.height);
bitmapData.draw(loader_outer);
var jpgencoder:JPGEncoder = new JPGEncoder(100);
var mybyte:ByteArray = jpgencoder.encode(bitmapData);
var myfile:FileReference = new FileReference();
myfile.save(mybyte,"test.jpg");
The problem is during save, I can only see the a white image in file but not the two contents. I am expecting a background with a rabbit in the image file that is placed exactly on the two components drawn manually in the work space.
UILoader.load is an asynchronous action. As such, you are attempting to draw the loader to a bitmap before it has actually had a chance to load the images. You will need to listen for COMPLETE events on both inner and outer loaders:
import com.adobe.images.JPGEncoder;
import flash.display.Bitmap;
import flash.events.Event;
loader_inner.addEventListener(Event.COMPLETE, onLoadComplete);
loader_outer.addEventListener(Event.COMPLETE, onLoadComplete);
loader_inner.load(new URLRequest("background_1.jpg"));
loader_outer.load(new URLRequest("rabbit.jpg"));
loader_outer.addChild(loader_inner);
function onLoadComplete(e:Event):void
{
// check to make sure that *both* loaders have fully loaded
if(loader_inner.percentLoaded && loader_outer.percentLoaded)
{
var bitmapData:BitmapData = new BitmapData(loader_outer.width,loader_outer.height);
bitmapData.draw(loader_outer);
var jpgencoder:JPGEncoder = new JPGEncoder(100);
var mybyte:ByteArray = jpgencoder.encode(bitmapData);
var myfile:FileReference = new FileReference();
myfile.save(mybyte,"test.jpg");
}
}

As3 Convert ByteArray to Bitmap

Noob to As3 Bitmap stuff...
when i try to doing the following code it fails
bmd.setPixels(bmd.rect, decodeValue);
and the error message is:
Error: Error #2030: End of file was encountered.
The situation is i have store the image as binary into the database by convert the byteArray and now i would like to retrieve it and convert back to image.
Just to clear this up ByteArray Need to Place into Bitmap and then you can add to the movie Clip right?
import flash.display.Loader;
import flash.net.URLRequest;
import flash.display.Bitmap;
import flash.display.BitmapData;
import com.dynamicflash.util.Base64;
var loader:Loader;
var req:URLRequest;
var orig_mc:MovieClip;
var copy_mc:MovieClip;
function loaderCompleteHandler(evt:Event) {
//swap data
var ldr:Loader = evt.currentTarget.loader as Loader;
var origImg:Bitmap = (ldr.content as Bitmap);
var origBmd:BitmapData = origImg.bitmapData;
trace(origImg.bitmapData);
trace(origImg.width);
trace(origImg.height);
//Convert image byteData into Base64 String
var byteArray:ByteArray = new ByteArray();
byteArray.writeObject(origBmd);
var encoded:String = Base64.encodeByteArray(byteArray);
trace("\nENCODED:\n" + encoded);
var decoded:ByteArray = Base64.decodeToByteArray(encoded);
trace("\nDECODED:\n" + decoded.toString());
// convert base64 string back into movieclip
var newBmd:BitmapData = new BitmapData(origImg.width,origImg.height,"true",0xFFFFFFFF);
newBmd.setPixels(origBmd.rect, decoded);**// THIS THROWS AN " Error #2030: End of file was encountered."**
var image:Bitmap = new Bitmap(newBmd, "auto", true);
copy_mc.addChild(image);
copy_mc.x = origImg.width;
}
loader = new Loader();
req = new URLRequest("C:\\Data\\cutcord.jpg");
loader.load(req);
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loaderCompleteHandler);
// movieclip to display original image
orig_mc = new MovieClip();
orig_mc.addChild(loader);
addChild(orig_mc);
// movieclip to display image copy
copy_mc = new MovieClip();
addChild(copy_mc);
Anyone can help would be very appreciated :)
try this code :
var rect:Rectangle = new Rectangle(0,0,img.widht,img.height);
var byteArray:ByteArray = bitmapData.getPixels(rect);
var encoded:String = Base64.encodeByteArray(byteArray);
var decoded:ByteArray = Base64.decodeToByteArray(encoded);
decoded.position = 0;
var newBmd:BitmapData = new BitmapData(rect.width,rect.height,true,0xFFFFFFFF);
newBmd.setPixels(rect, decoded);
var image:Bitmap = new Bitmap(newBmd, "auto", true);
addChild(image);
anyway , Your idea of store string in server isnt too good ... Why You dont send ByteArray , not String ?
You can also encode bitmapData to JPG or PNG , and then send bytes to php.
since it is an image, you have it in a BitmapData, let's say "myBmp" ... then use the following to extract all the data from BitmapData:
var bytes:ByteArray = myBmp.getPixels(myBmp.rect);
and the following to write:
myBmp.setPixels(myBmp.rect, bytes);
note that only the raw 32 bit pixel data is stored in the ByteArray, without compression, nor the dimensions of the original image.
for compression, you should refer to the corelib.

what is the simpliest way to get jpg from bitmapData

I need to convert bitmapData grabbed from movie clip to jpeg or png. Is there some lib for that?
see this example in take portion that convert byte to image, i have given whole for your reference
package {
import encoding.JPGEncoder;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Loader;
import flash.display.Sprite;
import flash.utils.ByteArray;
import flash.events.Event
public class Converter extends Sprite {
[Embed(source = "image.jpg")]
private var image:Class
private const QUALITY:uint = 80;
public function Converter():void {
var bitmap:Bitmap = new image();
var bitmapData:BitmapData = bitmap.bitmapData;
//encode BitmapData to JPG
var encoder:JPGEncoder = new JPGEncoder(QUALITY);
var rawBytes:ByteArray = encoder.encode(bitmap.bitmapData);
//decode JPG ByteArray back to BitmapData
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, getBitmapData)
loader.loadBytes(rawBytes);
}
private function getBitmapData(e:Event):void {
var decodedBitmapData:BitmapData = Bitmap(e.target.content).bitmapData
trace(decodedBitmapData);
}
}
}
You can now use the native jpeg encoding built into Flash Player 11.3 and AIR 3.3.
var quality:int = 50;
var bounds:Rectangle = bitmapData.rect;
var result:ByteArray = bitmapData.encode(bounds, new JPEGEncoderOptions(50));
This requires -swf-version=16 be passed to the compiler.
This is not the simplest way, but depending on the dimensions of your image, may be worth a look. Jens Krause has compiled jpeglib with Alchemy, and it encodes much faster than as3corelib's version, or even Thibault Imbert's improved AS3 version:
http://www.websector.de/blog/2009/06/21/speed-up-jpeg-encoding-using-alchemy/

How can I make this Flash code work in IE when it's cached?

I have a flash file here, when the flash plays, it works fine, but in IE and if the flash was already loaded once and is now cached, it freezes up. After digging super deep on the internet I was able to find out the following:
There are a bunch of known bugs in
flash 9 and 10, one of those being an
issue with the Event.COMPLETE not
being fired from the main stage when
loading from cache when it's embedded
WMODE = "transparent" I'm not sure if
that's your issue, but it's worth
looking into. I've heard of a few
workarounds to the problem. One of
them being, not listening for for
progress or complete events at all and
just using a timed loop like
ENTER_FRAME or TIMER to watch the
bytesLoaded/bytesTotal.
My WMODE is window, but this makes the most sense to me. The loadText never gets set which tells me its not entering swfProgressHandle function. However the problem is I only wrote half this flash (everything inside init) in conjunction with someone else, but that other person I cannot get in contact with anymore. I am fairly new to flash so really don't know how to take his loading code and make it only run off timer events instead of progress and complete events (as said in the above quote) so that it will work in IE when cached. Can anyone help me on this? Most of the code is fine, it's just the beginning where those progress and complete handlers are for loading stuff that appears to be causing the issue.
package
{
//---Imports---
import flash.display.*;
import fl.transitions.Tween;
import fl.transitions.TweenEvent;
import fl.transitions.easing.*;
import flash.events.Event;
import flash.events.*;
import flash.events.IOErrorEvent;
import flash.events.ProgressEvent;
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.text.TextField;
import flash.utils.Timer;
import flash.utils.*;
import flash.text.Font;
public class FohLoader extends Sprite
{
//create and start load bar
private var loadBar:Sprite = new Sprite();
private var loadText:TextField = new TextField();
private var loadBarBg:Graphics = loadBar.graphics;
//load XML data
private var xmlLoader:URLLoader = new URLLoader();
private var xmlData:XML = new XML();
private var _queue:Array; //holds data objects of items to be loaded
private var _index:int; //the current item in the _queue
private var _images:Array; //holds DisplayObjects of the loaded images
public function FohLoader()
{
_queue = new Array();
_images = new Array();
_index = 0;
//waits for the stage to be created
addEventListener(Event.ADDED_TO_STAGE, stageReadyHandle);
}
private function stageReadyHandle(e:Event):void
{
removeEventListener(Event.ADDED_TO_STAGE, stageReadyHandle);
loadBarBg.lineStyle();
loadBarBg.beginFill(0x5a96c5, 1);
loadBarBg.drawRect(0, 0, 5, 10);
loadBarBg.endFill();
loadBar.x = (stage.stageWidth - 500)/2;
loadBar.y = 30;
loadBar.width = 5;
loadBar.height = 10;
this.addChild(loadBar);
loadText.x = (stage.stageWidth - 0)/2;
loadText.y = 50;
this.addChild(loadText);
//I have no idea if this crap works
//but you would have to do something like this if you want to keep your project to one swf file.
this.loaderInfo.addEventListener(ProgressEvent.PROGRESS, swfProgressHandle);
}
private function swfProgressHandle(e:ProgressEvent):void
{
//assumes you want the loadbar to be 500px at 100%
var getPercent:Number = bytesLoaded / e.bytesTotal;
trace(bytes_loaded + " of " + bytes_total + " loaded");
loadBar.width = getPercent * 150; //changed 500 to 150
loadText.text = String(Math.round(getPercent * 30) + "%"); //changed 100 to 30
if (e.bytesLoaded / e.bytesTotal >= 1)
{
e.target.removeEventListener(ProgressEvent.PROGRESS, swfProgressHandle);
loadXml();
}
}
private function loadXml()
{
xmlLoader.addEventListener(Event.COMPLETE, ParseXML);
xmlLoader.load(new URLRequest("flash.xml"));
}
private function ParseXML(e:Event):void
{
e.target.removeEventListener(Event.COMPLETE, ParseXML);
flashInputs = new XML(e.target.data);
//declare all XMl variables, terrible way to do it though
var imageURLList:XMLList = flashInputs.image_area.image.image_url;
var firmCount:XMLList = flashInputs.count_area.total_firms;
var quoteMsg:XMLList = flashInputs.quote_area.quote.quote_text;
var quoteOwner:XMLList = flashInputs.quote_area.quote.quote_owner;
var imageURL:XMLList = flashInputs.image_area.image.image_url;
var imageText:XMLList = flashInputs.image_area.image.image_text;
var quoteMsg0:XML = quoteMsg[0];
var quoteMsg1:XML = quoteMsg[1];
var quoteMsg2:XML = quoteMsg[2];
var quoteMsg3:XML = quoteMsg[3];
var quoteMsg4:XML = quoteMsg[4];
var quoteMsg5:XML = quoteMsg[5];
var quoteMsg6:XML = quoteMsg[6];
var quoteOwner0:XML = quoteOwner[0];
var quoteOwner1:XML = quoteOwner[1];
var quoteOwner2:XML = quoteOwner[2];
var quoteOwner3:XML = quoteOwner[3];
var quoteOwner4:XML = quoteOwner[4];
var quoteOwner5:XML = quoteOwner[5];
var quoteOwner6:XML = quoteOwner[6];
var imageText0:XML = imageText[0];
var imageText1:XML = imageText[1];
var imageText2:XML = imageText[2];
var imageText3:XML = imageText[3];
var imageText4:XML = imageText[4];
var imageText5:XML = imageText[5];
var imageText6:XML = imageText[6];
var imageURL0:XML = imageURL[0];
var imageURL1:XML = imageURL[1];
var imageURL2:XML = imageURL[2];
var imageURL3:XML = imageURL[3];
var imageURL4:XML = imageURL[4];
var imageURL5:XML = imageURL[5];
var imageURL6:XML = imageURL[6];
//loops through the imageURL array and adds each item to the queue
for each(var img:XML in imageURL)
{
addItem(String(img));
}
//loads the first item in the queue
loadItem();
}
//creates a new loader for the item
//adds a data object holding the item path and loader into the queue
private function addItem(path:String):void
{
var loader:Loader = new Loader();
_queue.push({loader:loader, path:path});
}
private function loadItem():void
{
_queue[_index].loader.contentLoaderInfo.addEventListener(Event.COMPLETE, imgCompleteHandle);
_queue[_index].loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, IOErrorHandle);
_queue[_index].loader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, imgProgressHandle);
_queue[_index].loader.load(new URLRequest(_queue[_index].path));
}
//checks the progress of each image, and increases the width of the load bar
private function imgProgressHandle(e:ProgressEvent):void
{
var perc:Number = e.bytesLoaded / e.bytesTotal;
//this line assumes you are loading 6 images, and want the loadbar to end up at 500px
//it also assumes the bar has already reached 30% (150px) from loading the swf
loadBar.width = 150 + (_index * (350 / 6)) + ((350 / 6) * perc);
//so the swf's 150 + (how many images have alrady loaded * the width each image needs to affect the bar) +
//(same thing * percent of current image loaded)
//sounds right, might have to mess with that.
}
//this just stops flash from outputting an error if the image fails to load
private function IOErrorHandle(e:IOErrorEvent):void
{
e.target.removeEventListener(Event.COMPLETE, imgCompleteHandle);
e.target.removeEventListener(IOErrorEvent.IO_ERROR, IOErrorHandle);
trace("Error handled, sir.");
trace("The problem was that, " + e);
}
private function imgCompleteHandle(e:Event):void
{
e.target.removeEventListener(Event.COMPLETE, imgCompleteHandle);
e.target.removeEventListener(ProgressEvent.PROGRESS, imgProgressHandle);
e.target.removeEventListener(IOErrorEvent.IO_ERROR, IOErrorHandle);
//adds the image to the _images array
_images.push(e.target.content);
//increments the load counter
_index++;
//checks to see if the queue is finished or not
if (_index < _queue.length)
{
trade("Not done loading, loading another item");
loadItem();
}
else
{
_index = 0;
_queue = [];
killLoadBar();
init();
}
}
private function killLoadBar()
{
this.removeChild(loadBar);
this.removeChild(loadText);
}
If you dont mind the flash loading every time and not using the cache you could just append a cache breaker to the swf url.
Any random thing will do.
Here's a example using swfobject (http://code.google.com/p/swfobject/)
<script type="text/javascript">
var flashvars = {};
var params = {};
var attributes = {};
swfobject.embedSWF("myContent.swf?rand="+Math.random(), "myContent", "300", "120", "9.0.0","expressInstall.swf", flashvars, params, attributes);
</script>
This should work around any IE cache bugs.
If you still get the error with this, then it's should not be cache related.
After taking a quick look at this, I can see what might be happening.
You listen for ADDED_TO_STAGE.
You handle ADDED_TO_STAGE and then start listening for PROGRESS.
You then set the loadText, and load the XML if progress is "done".
The problem here seems to be the "done" part and the progress handling. First, the
loaderInfo object has a COMPLETE event. Why not use it? (http://livedocs.adobe.com/flex/3/langref/flash/display/LoaderInfo.html)
Then you could skip the whole bytesLoaded/bytesTotal check.
Where I think the applicatation might be freezing is when the loaderInfo has cached resources and skips the "PROGRESS" step altogether. Then you would never get into the LoadXML code, and never, therefore, parse the xml.
You can install firebug in Firefox and check whether you're even attempting to load the XML file using the "net" tab. (or use a tool like filemon).