Am making an android app using AIR for Android and as3. Following is my code to save image into device gallery. The image gets saved but I want to show a loader while the image is getting saved. This code does not work approprietely. Please point out if I am making any mistake here.
mysaveBtn.addEventListener(MouseEvent.CLICK, ftnSave);
function ftnSave():void
{
mysaveBtn.removeEventListener(MouseEvent.CLICK, ftnSave);
mysaveBtn.visible = false;
var jpgSource:BitmapData = new BitmapData(1080, 1920);
jpgSource.draw(myTheme);
var jpgEncoder:JPGEncoder = new JPGEncoder(100);
var imgByteData:ByteArray = jpgEncoder.encode(jpgSource);
var fs : FileStream = new FileStream();
var targetFile : File = File.desktopDirectory.resolvePath('/sdcard/DCIM/Camera/image.jpg');
fs.open(targetFile, FileMode.WRITE);
fs.writeBytes(imgByteData);
fs.close();
if( CameraRoll.supportsAddBitmapData ){
new CameraRoll().addBitmapData(jpgSource);
mysaveBtn.visible = true;
mysaveBtn.addEventListener(MouseEvent.CLICK, ftnSave);
}
}
You can use the class "Asynchronous Image Encoders"
This class can also save large images to prevent freezing your application .
Related
I have a problem saving the Xfinium PDF. I loaded a document and simply draw the line across the page and save. The file generated but when I used that file and loaded back to PdfFixedDocument I have the error
Root entry is missing in file trailer
My code is very simple :
var pdf = new PdfFixedDocument (document.Location);
var page = pdf.Pages [pageIndex];
var graphics = page.Graphics;
var directory = FileUtilities.GetExternalPrivateDirectory (PdfCore.CACHE_DIRECTORY);
//var png = FileUtilities.GetFile (directory + "/test.pdf");
//var rawStream = File.OpenWrite (png.AbsolutePath);
var stream = new FileStream (directory + "/test.pdf", FileMode.Create);
pdf.BeginSave (stream);
graphics.DrawLine(new Xfinium.Pdf.Graphics.PdfPen (),
new Xfinium.Pdf.Graphics.PdfPoint (0,0),
new Xfinium.Pdf.Graphics.PdfPoint (page.Width, page.Height));
page.SaveGraphics ();
pdf.EndSave ();
Instead of manually creating the stream and using BeginSave / EndSave, just try using Save:
var pdf = new PdfFixedDocument();
var page = pdf.Pages.Add();
var graphics = page.Graphics;
graphics.DrawLine(new Xfinium.Pdf.Graphics.PdfPen(),
new Xfinium.Pdf.Graphics.PdfPoint(0, 0),
new Xfinium.Pdf.Graphics.PdfPoint(page.Width, page.Height));
var directory = Environment.GetExternalStoragePublicDirectory(Environment.DirectoryDownloads);
pdf.Save(Path.Combine(directory.Path, "test.pdf"));
Java.IO.File pdfFILE = new Java.IO.File(Path.Combine(directory.Path, "test.pdf"));
Intent intent = new Intent(Intent.ActionView);
intent.SetDataAndType(Uri.FromFile(pdfFILE), "application/pdf");
StartActivity(intent);
I believe that the PDF document is not properly written to file because the stream is not closed. Try adding these lines at the end of your code (after pdf.EndSave()):
stream.Flush();
stream.Close();
The BeginSave/SaveGraphics/EndSave mode should be used when creating pages with heavy content, such as vector maps, and you want to reduce memory consumption by calling SaveGraphics after drawing a certain number of graphic objects (SaveGraphics can be called multiple times for a page).
For your scenario you can simplify the code as follows (like SushiHangover suggested):
var pdf = new PdfFixedDocument (document.Location);
var page = pdf.Pages [pageIndex];
var graphics = page.Graphics;
graphics.DrawLine(new Xfinium.Pdf.Graphics.PdfPen (),
new Xfinium.Pdf.Graphics.PdfPoint (0,0),
new Xfinium.Pdf.Graphics.PdfPoint (page.Width, page.Height));
var directory = FileUtilities.GetExternalPrivateDirectory(PdfCore.CACHE_DIRECTORY);
pdf.Save(directory + "/test.pdf");
Disclaimer: I work for the company that develops XFINIUM.PDF library.
.Save (document path) is massively slow when it comes to e.g.: 100 pages and lots of data so the end file has about 145MB or more, then the saving operation takes 2 minutes pls - this is ways to slow so I will try the BeginSave and EndSave approach also
Where is the best location to save in Android mobile using AIR and how? Im trying to figure out where i can save my file. Im creating a MEMO App where the user can save his/her File, my question is, where is the best location in Android Mobile so save?
That is what File.applicationStorageDirectory is for.
You can save whatever data you want to the file (XML, JSON, AMF, sqlite database), and you can save asynchronously to avoid UI hangs.
Example saving string data (such as serialized XML or JSON):
function save(data:String):void {
var file:File = File.applicationStorageDirectory.resolvePath("preferences.data");
var fileStream:FileStream = new FileStream();
fileStream.open(file, FileMode.WRITE); // or openAsync()
fileStream.writeUTFBytes(data);
fileStream.close();
}
function load():String {
var file:File = File.applicationStorageDirectory.resolvePath("preferences.data");
var fileStream:FileStream = new FileStream();
fileStream.open(file, FileMode.READ);
var data:String = fileStream.readUTFBytes(fileStream.bytesAvailable);
fileStream.close();
return data;
}
Im making a Test Maker App for both Desktop and Android. I was able to save and load in Desktop but failed on Android. I can ONLY save my file, but i cannot load my saved file. The Android device says "No files were found". It doesnt even open a file browser. The type of saving and loading that im doing is the type where the user can actually look for his project and open it. Im currently using FileReference to do this. It works on Desktop but not on Android Mobile. Can somebody help me with this?
I'm pretty sure you can't use a FileReference on mobile (though someone feel free to correct me if wrong).
On mobile, you should use the File & FileStream classes for loading/saving local files.
Here is an example, of using a compile time constant you could create (to determine if desktop or AIR) and loading appropriately into and out of a textfield called textfield:
CONFIG::air {
var file:File = File.applicationStorageDirectory.resolvePath("myFile.txt");
if(file.exists){
var stream:FileStream = new FileStream();
stream.open(file, FileMode.READ);
textfield.text = stream.readUTF(); //this may need to changed depending what kind of file data you're reading
stream.close();
}else{
data = "default value"; //file doesn't exist yet
}
}
CONFIG::desktop {
//use your file reference code to populate the data variable
}
And to save: (assuming you have a textfield whose text you want to save)
var fileStream:FileStream = new FileStream();
fileStream.open(file, FileMode.WRITE);
fileStream.writeUTF(textfield.text);
fileStream.close();
There are other save methods besides writeUTF (which is for plain text) writeObject is good for saving custom object when combined with flash.net.registerClassAlias
File classes are in the flash.filesystem package
EDIT
Here is something you can try for letting the user pick the location on AIR.
var file:File = File.applicationStorageDirectory;
file.addEventListener(Event.SELECT, onFileSelected);
file.browseForOpen("Open Your File", [new FileFilter("Text Files", "*.txt")]);
function onFileSelected(e:Event):void {
var stream:FileStream = new FileStream();
stream.open(e.target as File, FileMode.READ);
textField.text = stream.readUTF();
}
var saveFile:File = File.applicationStorageDirectory.resolvePath("myFile.txt");
saveFile.addEventListener(Event.SELECT, onSaveSelect);
saveFile.browseForSave("Save Your File");
function onSaveSelect(e:Event):void {
var file:File = e.target as File;
var stream:FileStream = new FileStream();
stream.open(file, FileMode.WRITE);
stream.writeUTF(textField.text);
stream.close();
}
I'm trying to save an image to my android phone is a specific directory.
Somehow I spent hours but couldn't get it to work. I hope someone can help me understand why my code isn't working or if there is another way to do it.
public function SaveTheImage(me:MouseEvent):void
{
ImageSaverBMD.draw(ImageHolder);
var jpgEncoder:JPGEncoder = new JPGEncoder(100);
var jpgBytes:ByteArray = jpgEncoder.encode(ImageSaverBMD);
var myFile:File = File.documentsDirectory.resolvePath("/sdcard / DCIM / Camera/testingimage.jpg");
var fs:FileStream = new FileStream();
fs.open(myFile, FileMode.WRITE);
fs.writeBytes(jpgBytes, 0, jpgBytes.length);
fs.close();
}
There are many steps in your algorithm that could cause the bug, with the code you provided I could make a few guesses, but there is a better way.
First of all try this code:
var s:Shape = new Shape();
s.graphics.beginFill(0);
s.graphics.drawCircle( 20, 20, 20);
s.graphics.endFill();
var bd:BitmapData = new BitmapData(40, 40, false);
bd.draw(s);
var jpgEncoder:JPGEncoder = new JPGEncoder(100);
var bytes:ByteArray = jpgEncoder.encode(bd);
var f:File = File.applicationDirectory;
var fs:FileStream = new FileStream();
fs.open(f, FileMode.WRITE);
fs.writeBytes(bytes);
fs.close();
This should save a 80x80 pixels black circle in your provided directory. See if it works. If not: check permissions to have external storage.
If it works, start removing the code block-by-block from top to bottom:
Remove the top two blocks and put your ImageSaverBMD.draw(ImageHolder) line. Maybe the problem is with that class? It could be that the bitmap data size was wrong or the matrix for drawing had incorrect translation.
The JPGEncoder is probably OK, it's a common used framework, but sometimes when I copy it into my source files I need to change the package in the .as file. Is your package correct?
Your URL in the File object has spaces, could that be your problem, try using a simple URL first and see if that works. It could be the problem that you try to navigate to an absolute URL with a relative URL pattern (I could be wrong on this, usually I have different approach of navigating to a folder).
Hope that helps!
private function export():void
{
var today_date:Date = new Date();
var thismonth:uint = today_date.getMonth();
var today_time;
var currentTime:Date = new Date();
var minutes = currentTime.getMinutes();
var seconds = currentTime.getSeconds();
var hours = currentTime.getHours() * 30 + currentTime.getMinutes() / 2;
var mnth:Array = new Array('January','February','March','April','May','June','July','August','September','October','November','December');
var fileName:String = (today_date.getDate()+mnth[thismonth]+today_date.getFullYear()+"_"+currentTime.hours + currentTime.minutes + currentTime.seconds+".png");
//trace(fileName);// displays current date in United States date format
var bmd:BitmapData = new BitmapData(board.width, board.height);//(600, 290);
bmd.draw(board);
var ba:ByteArray = PNGEncoder.encode(bmd);
// var file:File = File.applicationDirectory;
//var file:FileReference = new FileReference();
var fs : FileStream = new FileStream();
var targetFile : File = File.documentsDirectory.resolvePath(fileName);
//var targetFile : File = File.applicationDirectory.resolvePath(fileName);
fs.open(targetFile, FileMode.WRITE);
fs.writeBytes(ba);
fs.close();
//file.addEventListener(Event.COMPLETE, saveSuccessful);
saveDialog = new SaveDialog();
addChild(saveDialog);
test = setInterval(showMessage,2000);
//var test = setInterval(showMessage,3000);
saveDialog.closeBtn.addEventListener(MouseEvent.MOUSE_UP, closeSaveDialog);
//file.save(ba, fileName);
}
This code is way cool! Try it. It creates a folder in your user called .007 and saves an mp3 called yahoo.mp3.
It will also do it on an android device if permissions are set correctly.
Once it creates a folder and saves the mp3 it will loop thru the folder and get the file path and the file name.
MY QUESTION IS: How do you access it and play the sound on Android? It works on the desktop as you can see if you test it But not on the droid. Any ideas why?
import flash.filesystem.*;
var urlString:String = "http://YourWebsite.com/YourSound.mp3";
var urlReq:URLRequest = new URLRequest(urlString);
var urlStream:URLStream = new URLStream();
var fileData:ByteArray = new ByteArray();
urlStream.addEventListener(Event.COMPLETE, loaded);
urlStream.load(urlReq);
function loaded(event:Event):void
{
urlStream.readBytes(fileData, 0, urlStream.bytesAvailable);
writeAirFile();
}
function writeAirFile():void
{
var file:File = File.userDirectory.resolvePath(".007/Yahoo.mp3");
var fileStream:FileStream = new FileStream();
fileStream.open(file, FileMode.WRITE);
fileStream.writeBytes(fileData, 0, fileData.length);
fileStream.close();
trace("The file is written.");
var desktop:File = File.userDirectory.resolvePath(".0");
var files:Array = desktop.getDirectoryListing();
for (var i:uint = 0; i < files.length; i++)
{
trace(files[i].nativePath);// gets the path of the files
trace(files[i].name);// gets the name
var mySound:Sound = new Sound();
var myChannel:SoundChannel = new SoundChannel();
var lastPosition:Number = 0;
mySound.load(new URLRequest(files[0].nativePath));
myChannel = mySound.play();
}
}
file:// <-------The Answer!
Got it! The file path needed to access the "sdcard" on a Android phone must begin with: file://
If you want to load a sound from your phone it would look like this. Here is the one important line needed. I will post full code below.
mySound.load(new URLRequest("file://mnt/sdcard/AnyFolder/YourSound.mp3"));
Since I was using a loop above getting all the files in a particular folder this is the code that worked for me in the example above.
mySound.load(new URLRequest("file://"+files[0].nativePath));
FULL CODE TO LOAD AND PLAY SOUND ON DROID
var mySound:Sound = new Sound();
var myChannel:SoundChannel = new SoundChannel();
var lastPosition:Number = 0;
mySound.load(new URLRequest("file://mnt/sdcard/AnyFolder/YourSound.mp3"));
myChannel = mySound.play();
I worked very hard on to find this answer. I hope this helps many. Please remember to +1 if this code has helped you. :)
I love StackOverflow! :)