Adobe Air. Strange bug with URLStream or FileStream - actionscript-3

I've used examples from here Download a file with Adobe AIR and built app that downloads files from server.
I'll try to explain error by steps.
1) Adobe Air app downloaded xml file from server http://example.com/data/init.xml
2) I've opened it and all ok.
3) Adobe Air app again downloaded the same file from server. Now, if I open it with Notepad it says that init.xml is binary file. If I remove init.xml from disk and try again - the same. init.xml is a binary file. Reopen air app doesn't work.
4) I changed init.xml on server to init123.xml and downloaded it again. init123.xml was opened as normal xml file. If I again download it, then step 3 - init123.xml is a binary file.
Where could be the error?
Thank you.
OS - Windows 7
MD5 of files also changed.
This could be solved it I add random number to the end of url.
urlStream.load(new URLRequest(remoteFile+'?'+Math.random()));
but this
urlStream.load(new URLRequest(remoteFile));
makes file binary if I load it second time.
Source
private function startDownloading():void
{
destFile.nativePath = destDirectory +destFileBase;
fileStream = new FileStream();
fileStream.addEventListener(OutputProgressEvent.OUTPUT_PROGRESS, outputProgress);
fileStream.addEventListener(IOErrorEvent.IO_ERROR, fileAccessError);
fileStream.openAsync(destFile, FileMode.WRITE);
urlStream = new URLStream();
urlStream.addEventListener(ProgressEvent.PROGRESS, progress);
urlStream.addEventListener(Event.COMPLETE, complete);
urlStream.addEventListener(SecurityErrorEvent.SECURITY_ERROR, urlStreamSecurityError);
urlStream.addEventListener(IOErrorEvent.IO_ERROR, urlStreamIOError);
urlStream.load(new URLRequest(remoteFile));
}
protected function fileAccessError(event:IOErrorEvent):void
{
urlStream.close();
fileStream.close();
}
protected function outputProgress(event:OutputProgressEvent):void
{
if(event.bytesPending == 0 && downloadCompleteFlag ) {
}
}
protected function urlStreamIOError(event:IOErrorEvent):void
{
trace('error 2');
}
protected function urlStreamSecurityError(event:SecurityErrorEvent):void
{
trace('error 2');
}
protected function progress(event:ProgressEvent):void
{
var bytes :ByteArray = new ByteArray();
var thisStart :uint = currentPosition;
currentPosition += urlStream.bytesAvailable;
urlStream.readBytes( bytes, thisStart );
fileStream.writeBytes( bytes, thisStart );
}
protected function complete(event:Event):void
{
urlStream.close();
fileStream.close();
downloadCompleteFlag = true;
}

Try emptying the destination file. You are probably keeping the previous bytes in init.xml.

You are reading into and writing from your ByteArray in the wrong position. You have:
// In "progress" function
urlStream.readBytes( bytes, thisStart );
fileStream.writeBytes( bytes, thisStart );
where thisStart is the current number of bytes available in urlStream.
When using URLStream.readBytes() position refers to the position you want to start reading into bytes. Likewise, the position parameter in FileStream.writeBytes() refers to the position you want to start reading from bytes. Since bytes is reinstantiated every time progress() is called you should always start your reading and writing from a position of 0.

From what I can tell the image is being cached which would cause an instant load of the file.
Your code does not deal with that since in your complete function you are not doing fileStream.writeBytes which would make for an empty file.
This is not tested code but you need to do something like this.
protected function progress(event:ProgressEvent):void
{
var bytes :ByteArray = new ByteArray();
var thisStart :uint = currentPosition;
currentPosition += urlStream.bytesAvailable;
urlStream.readBytes(bytes, thisStart );
if(bytes.length > 0){
fileStream.writeBytes( bytes, thisStart );
}
}
protected function complete(event:Event):void
{
progress(event);// call progress to verify data is written
urlStream.close();
fileStream.close();
downloadCompleteFlag = true;
}

Related

How to share the image in the application as3

I am using the Android-Sharing-Extension-ANE.
How to share an image as result from my application code?
This code does not work
var bitmap:Bitmap = ...;
// encoding image by native encoder (availible on FP 11.3/AIR 3.3 or newer)
var bitmapBytes:ByteArray = bitmap.bitmapData.encode(new Rectangle(0, 0, bitmap.width, bitmap.height), new JPEGEncoderOptions(70)));
var file:File = File.documentsDirectory.resolvePath("image_for_share.jpg");
var stream:FileStream = new FileStream(); // write file to local memory
stream.open(file, FileMode.WRITE);
stream.writeBytes(fileBytes);
stream.close();
SharingExtension.shareImage(file, "Choser title", "Message"));
"How do I share an image with this ANE I use Animate CC?"
From the "Read Me" of that ANE:
How to use:
Connect com.illuzor.extensions.SharingExtension.ane file to your
Android AIR project.
Import com.illuzor.sharingextension.SharingExtension;
Since it's not clear what your exact problem is (because not enough information given)...
(1) Did you import the required Class files?
import com.illuzor.sharingextension.SharingExtension;
btn_Share.addEventListener (MouseEvent.CLICK, shareAndroid);
function shareAndroid (event: MouseEvent): void
{
//# If this works then replace with bitmap code (use shareImage)
SharingExtension.shareText ("AS3 Test", "This text is from AS3 code");
}
(2) Did you add (connect) the ANE to your project (in Settings)?
Read this for advise on adding an ANE: https://www.adobe.com/devnet/air/articles/using-ane-in-flash.html

FLEX/AS3 How to open docx/odt file

I have function that create docx or odt file. I need automaticly to open this file in microsoft/libre office, right after creation complete. How to coding this in flex/as3 ?
protected function create003(docType:String, patientID:String):void
{
create003Result.token = nhealthReports.create003(docType, patientID);
}
protected function getFormModuleDataResult_resultHandler(event:ResultEvent):void
{
var pathToFile:String;
pathToFile=create003Result.lastResult; // this is path to created file
// here i need some code from you
}
<nhealthreports:NhealthReports id="nhealthReports"
showBusyCursor="true"/>
<s:CallResponder id="create003Result" result="getFormModuleDataResult_resultHandler(event)"/>
So you'd need to first download the file to the user's machine and then open it. Something like this should do it (copy pasted stuff from my projects so you might need to adjust it a bit).
Also your server might need a crossdomain file so your app can load files from it.
private function getFormModuleDataResult_resultHandler(event:ResultEvent):void
{
// load file
var loader:URLLoader = new URLLoader();
loader.addEventListener(Event.COMPLETE, onLoadingComplete);
loader.dataFormat = URLLoaderDataFormat.BINARY;
loader.load(new URLRequest(pathToFile));
}
private function onLoadingComplete(event:Event):void
{
// get the data as bytearray
var data:ByteArray = event.target.data;
// you will probably need to figure this out from your server path or define your own here
var fileName:String = "MyFilename.doc";
// create a file under the application storage directory (C:\Users\YOURUSERHERE\AppData\Roaming\RateBook\Local Store)
// you can store the file anywhere but it is recommended to do it here
// as users with restricted access on their machines (non-admin users) might have trouble saving the files elsewhere
var file:File = File.applicationStorageDirectory.resolvePath(fileName);
//create a file stream to be able to write the content of the file
var fileStream:FileStream = new FileStream();
//open the file stream and set for Write
fileStream.open(file, FileMode.WRITE);
//writes the bytes
fileStream.writeBytes(data, 0, data.length);
//close the stream
fileStream.close();
// by now the file should be saved to disk, let's open it
// Naturally this assumes that the user have the file extension (like .doc) associated with the correct program (MS Word)
file.openWithDefaultApplication();
}

Save JPG from CDROM to PC

I am using following function to Save the output from SWF and send it to a PHP page so that it creates JPG, my problem if there is not INTERNET connection and the SWF is in a CDROM can the Save function be used in FLASH so that it outputs JPG and save it on a computer.
In short can we Save movieclip output as an JPG
/**
Screenshot and jpg output
**/
import flash.display.BitmapData;
import flash.geom.Matrix;
//Buttons handlers. Should add an extra function because delegate doesn't allow to pass parameters
shaF.onPress = mx.utils.Delegate.create(this,makeShadow);
//Helper functions to pass parameters
function makeShadow() { capture(0) }
/*
create a function that takes a snapshot of the Video object whenever it is called
and shows in different clips
*/
function capture(nr){
this["snapshot"+nr] = new BitmapData(abc._width,abc._height);
//the bitmap object with no transformations applied
this["snapshot"+nr].draw(abc,new Matrix());
var t:MovieClip = createEmptyMovieClip("bitmap_mc"+nr,nr);
//positions clip in correct place
//t._x = 350; t._y = 10+(nr*130); t._xscale = t._yscale = 50
//display the specified bitmap object inside the movie clip
t.attachBitmap(this["snapshot"+nr],1);
output(nr);
//attachMovie("print_but", "bot"+nr, 100+nr, {_x:t._x+t._width+50, _y:t._y+t._height/2})
}
//Create a new bitmapdata, resize it 50 %, pass image data to a server script
// using a LoadVars object (large packet)
function output(nr){
//Here we will copy pixels data
var pixels:Array = new Array()
//Create a new BitmapData
var snap = new BitmapData(this["snapshot"+nr].width, this["snapshot"+nr].height);
//Matrix to scale the new image
myMatrix = new Matrix();
myMatrix.scale(1, 1)
//Copy image
snap.draw(this["snapshot"+nr], myMatrix);
var w:Number = snap.width, tmp
var h:Number = snap.height
//Build pixels array
for(var a=0; a<=w; a++){
for(var b=0; b<=h; b++){
tmp = snap.getPixel32(a, b).toString(16)
//if(tmp == "-fcffff")
//{
//tmp="-ff0000";
//}
pixels.push(tmp.substr(1))
}
}
//Create the LoadVars object and pass data to PHP script
var output:LoadVars = new LoadVars()
output.img = pixels.toString()
output.height = h
output.width = w
//The page (and this movie itself) should be in a server to work
output.send("show.php", "output", "POST")
}
stop()
Since you already have the BitmapData, this is fairly easy. Modifying your output function:
//Copy image
snap.draw(this["snapshot"+nr], myMatrix);
//Now check if we want to save as JPG instead of sending data to the server
if (runningFromCdrom) {
var encoder:JPEGEncoder = new JPEGEncoder();
var bytes:ByteArray = encoder.encode(snap);
var file:FileReference = new FileReference();
file.save(bytes);
} else {
// ...the rest of your output method...
}
How to determine the runningFromCdrom value is up to you. If the SWF is being run inside an HTML document, the best way to tell if the program is being run from a CD-ROM would be to specify it in the FlashVars.
Yes, you can save JPEG's directly from Flash. There is no need for the intermediate step to PHP.
You can use one of these JPEG encoders:
https://github.com/mikechambers/as3corelib
http://www.switchonthecode.com/tutorials/flex-tutorial-an-asynchronous-jpeg-encoder
I would recommend the second as it can work asynchronously (kind of) which means your UI shouldn't lock up while encoding the JPEG.

fzip: zipping a file takes full memory

I'm using fzip to zip the contents of a folder. The folder contains 4 files of 500MB, the problem is that this uses all of my computers memory. Is there a way to prevent this? And lock the memory at 20% or something?
this is my code:
public function packageFileParser(filesToZip:Array):void {
for (var i:uint = 0; i < filesToZip.length; i++) {
if (filesToZip[i]["isDirectory"] == true) {
packageFileParser(filesToZip[i].getDirectoryListing());
} else {
if (filesToZip[i]["isHidden"] == false) {
var byteLoader:UrlURLLoader = new UrlURLLoader();
byteLoader.dataFormat = URLLoaderDataFormat.BINARY;
byteLoader.addEventListener (flash.events.Event.COMPLETE, urlLoaderCompleteHandler);
var fileRequest:URLRequest = new URLRequest ("/"+filesToZip[i]["nativePath"]);
byteLoader.load (fileRequest);
}
}
}
}
private function urlLoaderCompleteHandler(event:flash.events.Event):void {
var saveZip : Function = function(zip : FZip) : void {
var out : ByteArray = new ByteArray();
zip.serialize(out);
var fs : FileStream = new FileStream;
targetFile = File.desktopDirectory.resolvePath(zipName);
fs.open(targetFile, FileMode.WRITE);
fs.writeBytes(out);
out.clear();
fs.close();
};
var fullpath:String = event.target.urlRequest.url;
var filename:String = fullpath.substr(fullpath.lastIndexOf("/")+1,fullpath.length);
var filepath:String = fullpath.substr(0,fullpath.lastIndexOf("/")+1);
filepath = filepath.split("/Users/Thibaut/Desktop/testfolder").join("");
zip.addFile(filepath+filename, event.target.data);
saveZip(zip);
}
AFAIK, FZip library creates entire archive in memory and then saves it to disk. There's nothing you can do except to change library. Try airxzip from coltware, it served me well (I think there was no big memory loads even on large archives, because they were flushed to disk while adding files to them.)
Also, if you're using AIR capabilities (FileStream class), you should add "air" tag to the question, it changes a lot compared to plain AS3.

AS3 Saving Local File under iOS

I am opening and testing data using the FileStream class which is supposed to avoid file security issues. It works fine until I try to save to a local file. When I test under adl I get a security error which I though was ok (at least it was attempting to save) until the app was packaged and tested on a device, but the file fails to save. Any ideas?
public class FilesApp extends MovieClip {
var file:File;
var xmldata:XML;
public function FilesApp() {
// constructor code
LoadButton.addEventListener(MouseEvent.MOUSE_DOWN,xml_load);
ParseButton.addEventListener(MouseEvent.MOUSE_DOWN,xml_parse);
SaveButton.addEventListener(MouseEvent.MOUSE_DOWN,xml_save);
}
public function xml_load (e:MouseEvent):void
{
file = File.applicationDirectory;
file = file.resolvePath("./Data/data.xml");
var fileStream:FileStream = new FileStream();
fileStream.open(file, FileMode.READ);
var str:String = fileStream.readMultiByte(file.size, File.systemCharset);
fileStream.close();
DataText.text = str;
xmldata = XML(str);
trace('xml file loaded');
}
public function xml_save (e:MouseEvent):void
{
var writeStream:FileStream = new FileStream();
writeStream.open(file, FileMode.WRITE);
writeStream.writeUTF("<xml><name>Changed</name><score>5000</score></xml>");
writeStream.close();
trace('xml file saved');
}
public function xml_parse (e:MouseEvent):void
{
trace('xml file saved');
DataText.text = "Your name is:"+xmldata.name+" Your best score is:"+xmldata.score;
}
}
You cannot save data in File.applicationDirectory, it is meant to be immutable. Store it in File.applicationStorageDirectory instead. There is also File.documentsDirectory - current user documents directory, if you are sure you need to litter it with your files :)
For me, switching to readUTF() worked.
Also, the two lines initializing "file" should be in the constructor, else you cannot call "xml_save" (you'll have to do "xml_load" first).
Thanks
did you try Filereference.save()?
It fails because you are using writeUTF to do the write and readMultiByte to do the read.
If you switch to readUTF it will work.