I'm trying save XML data to an iPad 4 with AIR 3.4 for iOS and really can't tell if this is working or not. No events are being fired apparently. Any help is greatly appreciated.
private function saveData(e:MouseEvent):void {
var name:String = AssetManager.SAVE_ANNOTATIONS_NAME
var file:File = new File()
file = File.applicationStorageDirectory.resolvePath(name + "xml");
var xml:XML = _canvas.getObjectData(FormatType.DEGRAFA);
var fileStream:FileStream = new FileStream();
fileStream.open(file, FileMode.WRITE);
fileStream.writeUTF(xml.toString());
fileStream.addEventListener(ProgressEvent.PROGRESS, onFileStream);
fileStream.addEventListener(Event.ACTIVATE, onFileStream);
fileStream.addEventListener(Event.OPEN, onFileStream);
fileStream.addEventListener(Event.DEACTIVATE, onFileStream);
fileStream.addEventListener(IOErrorEvent.IO_ERROR, onFileStream);
fileStream.addEventListener(Event.COMPLETE, onFileStream);
}
protected function onFileStream(event:Event):void
{
trace('filestream event was ' + event)
fileStream.close();
}
I seemed to have fixed it with this:
private function saveFile(event:MouseEvent):void
{
var xml:XML = _canvas.getObjectData(FormatType.DEGRAFA);
trace('xml is ' + xml.toXMLString())
var file:File = File.documentsDirectory.resolvePath("annotations.xml");
var fileStream:FileStream = new FileStream();
fileStream.openAsync(file, FileMode.WRITE);
fileStream.writeUTFBytes(xml.toXMLString());
fileStream.addEventListener(Event.CLOSE, fileClosed);
fileStream.close();
function fileClosed(event:Event):void {
trace("File Saved");
}
}
You are writing BEFORE adding the listeners. Proper order should be:
var fileStream:FileStream = new FileStream();
// all the listeners here
fileStream.open(file, FileMode.WRITE);
fileStream.writeUTF(xml.toString());
You must take note of the command you are using to open the file stream. If you use filestream.openAsync then the file stream is opened asynchronously, meaning you will have to wait for the Event.OPEN event on the filestream object. If you use filestream.open, then you can call functions on the filestream object immediately without waiting for an OPEN event. For me the jump to ActionScript, and its asynchronous nature, took some time to get used to.
Related
I am trying to import a SQL database into my Adobe Air iOS app. I have the invoke working and everything seems to work but the new database file can't be read. Below is my code.
function onInvoke(event:InvokeEvent):void{
if(event.arguments && event.arguments.length)
{
contentUri = event.arguments[0] as String;
file_db = new File(contentUri);
fs_db = new FileStream();
fs_db.addEventListener(Event.COMPLETE, import_db);
fs_db.openAsync(file_db, FileMode.READ);
}
}
My import function looks like this:
function import_db(event:Event):void{
fs_db.removeEventListener(Event.COMPLETE, import_db);
var fs:FileStream = new FileStream();
var myfile:File=File.applicationStorageDirectory.resolvePath("testDB.db");
var fileContent:String = fs_db.readUTFBytes(fs_db.bytesAvailable);
fs.open(myfile,FileMode.WRITE);
fs.writeUTFBytes(fileContent);
fs.addEventListener(Event.CLOSE, fileClosed);
fs.close();
function fileClosed(e:Event):void{
// do other stuff
}
}
Every thing seems to execute but when I try to connect to the database, I get SQL error:
Error #2044: Unhandled SQLErrorEvent:. errorID=3138, operation=open , message=Error #3138: File opened is not a database file.
Any guidance is appreciated
Figured it out, read the bytes into a bytearray and then into the file.
var mybytes:ByteArray=new ByteArray();
fs_db.readBytes(mybytes,0,fs_db.bytesAvailable);
fs.openAsync(myfile,FileMode.WRITE);
fs.writeBytes(mybytes,0,mybytes.length);
I'm working on simple iOS game where you have e.g. 10 levels and once you completed one the next level will unlock. I create the xml file here:
private function SaveProgress()
{
addChild(myTextField);
var GameSaveXML:XML =
<LEVEL>
<LEVEL_01>false</LEVEL_01>
<LEVEL_02>false</LEVEL_02>
<LEVEL_03>false</LEVEL_03>
<LEVEL_04>false</LEVEL_04>
<LEVEL_05>false</LEVEL_05>
<LEVEL_06>false</LEVEL_06>
<LEVEL_07>false</LEVEL_07>
<LEVEL_08>false</LEVEL_08>
<LEVEL_09>false</LEVEL_09>
<LEVEL_10>false</LEVEL_10>
</LEVEL>;;
//file.deleteFile();
var file:File = File.documentsDirectory.resolvePath("LevelsSaved.xml");
if (file.exists)
{
trace("EXISTS");
trace(GameSaveXML);
}
else
{
var fileStream = new FileStream();
fileStream.open(file, FileMode.WRITE);
var outputString:String = '<?xml version="1.0" encoding="utf-8"?>\n';
outputString += GameSaveXML.toXMLString();
fileStream.writeUTFBytes(outputString);
//GameSaveXML.replace(2,<LEVEL_03>true</LEVEL_03>);
trace(GameSaveXML);
fileStream.close();
trace("File Was Created");
}
}
I'm really struggling with loading the file and checking what levels are unlocked (true) and what levels are still locked (false). Can you please help? Thanks a lot!
If you know how to write xml, can't you read it the same way?
var content:String = fileStream.readUTFBytes(fileStream.bytesAvailable);
var xml:XML = new XML(content);
if (xml.LEVEL_01 == 'true') trace('unlocked');
else trace('locked');
or you can use URLLoader to load xml as string
I'm 99% sure I did not undestand the question - sorry then :p
**I have an air app for iOS I have been developing. I am trying to capture a picture, save the file to the storage directory (not Camera Roll), and save the file name in an sqlite db.
I have tried so many different variations of this, but when it comes to writing the filestream to save the app hangs. Testing on iPad 3. Does ANYONE have a suggestion? This has been driving me nuts for days. I have searched the web but I am stumped.**
public var temp:File; // File Object to save name in database
protected function selectPicture():void
{
myCam = new CameraUI();
myCam.addEventListener(MediaEvent.COMPLETE, onComplete);
myCam.launch(MediaType.IMAGE);
}
protected function onComplete(event:MediaEvent):void {
//imageProblem.source = event.data.file.url;
var cameraUI:CameraUI = event.target as CameraUI;
var mediaPromise:MediaPromise = event.data;
var mpLoader:Loader = new Loader();
mpLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onMediaPromiseLoaded);
mpLoader.loadFilePromise(mediaPromise);
}
private function onMediaPromiseLoaded(e:Event):void
{
var mpLoaderInfo:LoaderInfo = e.target as LoaderInfo;
mpLoaderInfo.removeEventListener(Event.COMPLETE, onMediaPromiseLoaded);
this.imageProblem.source = mpLoaderInfo.loader;
var stream:FileStream = new FileStream();
stream.addEventListener(Event.COMPLETE, showComplete);
stream.addEventListener(IOErrorEvent.IO_ERROR, showError);
try{
this.messages.text = "Starting";
stream.open( temp, FileMode.WRITE );
stream.writeBytes(mpLoaderInfo.bytes);
stream.close();
}catch(e:Error){
this.messages.text = e.message;
}
}
protected function showError(e:IOErrorEvent):void{
this.messages.text = e.toString();
}
protected function showComplete(e:Event):void{
this.messages.text = "Completed Writing";
this.imgName.text = temp.url;
imagefile = temp;
deleteFlag = 1;
}
Application hangs due to you are trying to use file operation in Sync mode.
You need to use Async Mode operation instead of sync mode file operation.
stream.openAsync( temp, FileMode.WRITE );
Try with this
var stream:FileStream = new FileStream();
stream.addEventListener(Event.COMPLETE, showComplete);
stream.addEventListener(IOErrorEvent.IO_ERROR, showError);
stream.openAsync( temp, FileMode.WRITE );
stream.writeBytes(mpLoaderInfo.bytes);
stream.close();
Note when using async operation you need not use try catch.For handling error listen IOErrorEvent will catch if any error occurs.
I finally got this to work, I added comments below in the code to explain why it wasn't working.
public var temp:File;
protected function selectPicture():void
{
myCam = new CameraUI();
myCam.addEventListener(MediaEvent.COMPLETE, onComplete);
myCam.launch(MediaType.IMAGE);
}
protected function onComplete(event:MediaEvent):void {
//imageProblem.source = event.data.file.url;
var cameraUI:CameraUI = event.target as CameraUI;
var mediaPromise:MediaPromise = event.data;
var mpLoader:Loader = new Loader();
mpLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onMediaPromiseLoaded);
mpLoader.loadFilePromise(mediaPromise);
}
private function onMediaPromiseLoaded(e:Event):void
{
var mpLoaderInfo:LoaderInfo = e.target as LoaderInfo;
mpLoaderInfo.removeEventListener(Event.COMPLETE, onMediaPromiseLoaded);
this.imageProblem.source = mpLoaderInfo.loader;
/// Here was the solution
var bitmapDataA:BitmapData = new BitmapData(mpLoaderInfo.width, mpLoaderInfo.height);
bitmapDataA.draw(mpLoaderInfo.content,null,null,null,null,true);
/// I had to cast the loaderInfo as BitmapData
var bitmapDataB:BitmapData = resizeimage(bitmapDataA, int(mpLoaderInfo.width / 4), int(mpLoaderInfo.height/ 4)); // function to shrink the image
var c:CameraRoll = new CameraRoll();
c.addBitmapData(bitmapDataB);
var now:Date = new Date();
var f:File = File.applicationStorageDirectory.resolvePath("IMG" + now.seconds + now.minutes + ".jpg");
var stream:FileStream = new FileStream()
stream.open(f, FileMode.WRITE);
// Then had to redraw and encode as a jpeg before writing the file
var bytes:ByteArray = new ByteArray();
bytes = bitmapDataB.encode(new Rectangle(0,0, int(mpLoaderInfo.width / 4) , int(mpLoaderInfo.height / 4)), new JPEGEncoderOptions(80), bytes);
stream.writeBytes(bytes,0,bytes.bytesAvailable);
stream.close();
this.imgName.text = f.url;
imagefile = f;
deleteFlag = 1;
}
I'm struggling with a easy problem. I want to download an image from web using this code:
WebRequest requestPic = WebRequest.Create(#"http://something.com/" + id + ".jpg");
WebResponse responsePic = await requestPic.GetResponseAsync();
Now I wanted to write the WebResponse's stream in a StorageFile (eg. create a file id.jpg in the app's storage), but I haven't found any way to achieve that. I searched the web for it, but no success - all ways incompatible Stream types and so on.
Could you please help?
I have found the following solution, which works and is not too complicated.
public async static Task<StorageFile> SaveAsync(
Uri fileUri,
StorageFolder folder,
string fileName)
{
var file = await folder.CreateFileAsync(fileName, CreationCollisionOption.ReplaceExisting);
var downloader = new BackgroundDownloader();
var download = downloader.CreateDownload(
fileUri,
file);
var res = await download.StartAsync();
return file;
}
You will need to read the response stream into a buffer then write the data to a StorageFile. THe following code shows an example:
var fStream = responsePic.GetResponseStream();
var file = await ApplicationData.Current.LocalFolder.CreateFileAsync("testfile.txt");
using (var ostream = await file.OpenStreamForWriteAsync())
{
int count = 0;
do
{
var buffer = new byte[1024];
count = fStream.Read(buffer, 0, 1024);
await ostream.WriteAsync(buffer, 0, count);
}
while (fStream.CanRead && count > 0);
}
That can be done using the C++ REST SDK in Windows Store Apps. It's explained by HTTP Client Tutorial.
i use the following code:
protected function videoDisplay_playheadUpdateHandler(event:mx.events.VideoEvent):void
{
if(!captured && videoDisplay.playheadTime>=0){
capture();
}
}
private function capture():void
{
var bmpData:BitmapData = new BitmapData(videoDisplay.width, videoDisplay.height);
bmpData.draw(videoDisplay);
captured = true;
store(...); //????????
}
in order to capture a frame from a videoDisplay object
1) is it correct or am i doing something wrong?
2) what can i do to store the bmpData as .jpg at my computer?
i am using flex4.5 and it is an air app...
any ideas??
Thanks in advance!!
The following code should help you
var jpegEncoder:JPEGEncoder = new JPEGEncoder(90);
var jpgSource:BitmapData = new BitmapData(videoDisplay.width,videoDisplay.height);
jpgSource.draw(this);
var fileReference:FileReference = new FileReference();
fileReference.save(jpegEncoder.encode(jpgSource),"videoImage.jpg");
To use jpeg encode you need to have to import
import mx.graphics.codec.JPEGEncoder;
The above changes should be enough to allow the user to take a snapshot of a running video.
Please note, that with this the user will be prompted to select the location of the file.
Incase you want a silent save, let me know, I will put up the required code.
Somewhere in your application keep an image tag as follows.Most apt place should be just below the video.
<mx:Image scaleContent="true" width="150" height="120" maintainAspectRatio="false" id="myScaledSnapshot"/>
Now with this done, do the following changes in your code:
private function capture(filename:String):void
{
var bitmapData:BitmapData = new BitmapData(videoDisplay.width, videoDisplay.height);
bitmapData.draw(videoDisplay,new Matrix());
var bitmap : Bitmap = new Bitmap(bitmapData);
var jpg:JPEGEncoder = new JPEGEncoder();
var ba:ByteArray = jpg.encode(bitmapData);
myImageSnapshot.source=ba;
var jpegEncoder:JPEGEncoder = new JPEGEncoder(50);
var imageSnapshot:ImageSnapshot = ImageSnapshot.captureImage(this.myImageSnapshot,90,jpegEncoder);
var imageByteArray:ByteArray = imageSnapshot.data;
var newImage:File = File.desktopDirectory.resolvePath("KioskThumbs/"+filename+".jpg");
fileStream = new FileStream();
fileStream.open(newImage, FileMode.UPDATE);
fileStream.writeBytes(imageByteArray);
fileStream.close();
captured = true;
}
The above code really doesnt do anything special.
Its just using an image 'component' from flex, making it do the work for scaling the Video image, then taking the snapshot of this resized image component, and then writing it into a file.
My capture at last is:
private function capture(filename:String):void
{
var bitmapData:BitmapData = new BitmapData(videoDisplay.width, videoDisplay.height);
bitmapData.draw(videoDisplay,new Matrix());
var bitmap : Bitmap = new Bitmap(bitmapData);
var jpg:JPEGEncoder = new JPEGEncoder();
var ba:ByteArray = jpg.encode(bitmapData);
var newImage:File = File.desktopDirectory.resolvePath("KioskThumbs/"+filename+".jpg");
fileStream = new FileStream();
fileStream.open(newImage, FileMode.UPDATE);
fileStream.writeBytes(ba);
fileStream.close();
captured = true;
}
it works fine except the fact that i want to scale the photo lets say to 150 width 120height and not BitmapData(videoDisplay.width,videoDisplay.height); what can i do to solve that?
Thanks a lot all of you!