• Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
    Dedicated community for Japanese speakers
  • 한국 커뮤니티
    Dedicated community for Korean speakers
Exit
Locked
0

FileReference.upload with CameraRoll Media Promise

Guest
May 06, 2011 May 06, 2011

Copy link to clipboard

Copied

    I have been trying to wrap my head around this all day...

With the new cs5.5 and air2.6, you can access the mediaPromise object of a selected CameraRoll item.  I want to be able to upload a selected image to a file server.  I know how to do it via the filereference class and upload method, but I can't do that here because you have to have a user browse for an imaget to select with the filreference.browse() method. 

Is there a way to push the camera roll media promise object (or just the path) to the filereference.upload method to accomplish this, or were we given access to the camera roll to *ONLY*  be able to view the pictures and not actually send them anywhere?

TOPICS
Development

Views

17.5K

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 1 Correct answer

Mentor , May 09, 2011 May 09, 2011

The issue is probably that the underlying data source of the media promise is asynchronous rather than synchronous. When you first get the media selected event, the data hasn't been read yet, so bytesAvailable is still zero. You have to add an event listener to the data source and wait for progress events or the complete event before accessing the data.

Caveat, this is how it works on Android. I don't have an iOS device to test on -- and will be at a conference this week, so I won't be able to bo

...

Votes

Translate

Translate
Mentor ,
May 06, 2011 May 06, 2011

Copy link to clipboard

Copied

AIR extends FileReference with the File class. Using File, you can get a valid file object from the mediaPromise object and then call the upload() method on it.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Guest
May 06, 2011 May 06, 2011

Copy link to clipboard

Copied

Thanks for the reply Joe.

I will test this, but perhaps you know off the top of your head:  Will you be able to create a File with MediaPromise.relativePath and reference it that way?  And if so, will that work for both android and ios?

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Mentor ,
May 06, 2011 May 06, 2011

Copy link to clipboard

Copied

Now that I think about it, you are unlikely to get a valid file path on iOS. (I know you won't get one directly from the CameraUI, but it would make sense that the same would be true with CameraRoll, given the locked-down nature of the iOS file system.) On Android, you should be able to create a File object directly from the relativePath property.

So you could save the image data as a temp file and then use upload(), or use the URLLoader class with the HTTP POST method.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Guest
May 06, 2011 May 06, 2011

Copy link to clipboard

Copied

Ok I tested this on Android and it worked perfect.  I was able to browse the camera roll, select an image, and upload it to my server:

var file:File = imagePromise.file;

file.upload(req);

So i didn't need the relative path, just the filereference object itself from the mediaPromise.

It did not work on ios however. Tracing out the mediaPromise file property returns null. 

You think saving the mediaPromise data to my localDirectory first might do the trick?  I would have to open up the camera roll, select an image, load that image, then create a new bitmapdata object of that image, right? Then save it as an image on your loca directory, THEN upload it.  That seems kind of a workload for something that is easy on Android....  Would you suggest i encode it as a jpg or png then, or can you just save the data as a temp.file, or am I thinking about this incorrectly?

Message was edited by: tgKalsch

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Mentor ,
May 06, 2011 May 06, 2011

Copy link to clipboard

Copied

I think -- but haven't actually done this -- that you could read the data from the object returned by MediaPromise.open() and write the data directly to a temp file, or write it to an in-memory ByteArray object and upload that.

If you created a BitmapData object first, then you would have to re-encode the image.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Guest
May 06, 2011 May 06, 2011

Copy link to clipboard

Copied

I will give that a spin and report back, Thanks!

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Guest
May 06, 2011 May 06, 2011

Copy link to clipboard

Copied

After re-reading your previous post, I am going to use the MediaPromise.open() method and see what that results in, reply back soon..

Ok this is what was tripping me up earlier too, and i just scrapped it before:

When I select an image from the image roll (in IOS), I have the following function for the select event:

private function imageSelected( event:MediaEvent ):void

            {

                log( "Image selected..." );

              temp = File.createTempFile();  //Creates a new temp file

               fs = new FileStream();

               fs.addEventListener(Event.COMPLETE, fileSaved);

               fs.openAsync(temp, FileMode.WRITE);

               fs.writeUTFBytes(event.data);

            }

With this i get an error:

Implicit coercion of a value of type flash.media:MediaPromise to an unrelated type String.

So the writeUTFBytes method needs to have a string passed to it, and the event.data is a MediaPromise object.  Suggestions?

Message was edited by: tgKalsch

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Mentor ,
May 06, 2011 May 06, 2011

Copy link to clipboard

Copied

You will have to explicitly read the data:

fs.writeUTFBytes(event.data.readUTFBytes(event.data.bytesAvailable));

I'm not sure that UTF Bytes is the right thing to use. I don't think all possible bytes are included in the UTF-8 set.

Something like the following should work, though:

var tempArray:ByteArray = new ByteArray();

event.data.readBytes( tempArray );

tempArray.position = 0; //maybe not necessary

fs.writeBytes( tempArray );

tempArray = null;

Of course it would be more resource efficient to upload the byte array directly with post, although more complex.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Guest
May 06, 2011 May 06, 2011

Copy link to clipboard

Copied

The event.data is the MediaPromise object, you can't use readBytes on it. 

event.data.open() traced out sais filereference object though.  Do you mean to add .open() to each of those statements?

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Mentor ,
May 06, 2011 May 06, 2011

Copy link to clipboard

Copied

Yes, that's essentially what I meant:

var foo:IDataInput = event.data.open();

foo.readBytes(...)

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Guest
May 09, 2011 May 09, 2011

Copy link to clipboard

Copied

using:

var foo:IDataInput = event.data.open();

I then try to trace out:

foo.bytesAvailable();

and I get 0.  This means that it is not working correct?

Also, I am not entirely learned on opening, reading, saving bytes from an object.  If you have or know of a url that has a working example of code that gets the bytes from the mediapromise idatainput and saves it to a tempFile, it would be greatly aprpeciated.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Guest
May 09, 2011 May 09, 2011

Copy link to clipboard

Copied

After further testing, it still appears there is no way to access the path / file / bytes from a mediapromise image on ios.

in the imageSelected Function:

var imagePromise:MediaPromise = event.data;

trace(imagePromise.file); // returns null

trace(imagePromise.relativePath; // returns null

var foo:IDataInput = event.data.open();

trace(foo.bytesAvailable) // returns 0trace(foo.bytesAvailable) // returns 0

trace(foo.length) // returns 0

var tempArray:ByteArray = new ByteArray();

foo.readBytes(ByteArray);

trace(tempArray.length); // returns 0

trace(tempArray.bytesAvailable); //returns 0

Can someone from adobe please verify that it is 100% impossible to access the cameraRoll image and actually have either the file reference or at least the bytes available?  I want to be able to select an image from the cameraRoll and upload it to a server.

Thanks!

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
May 09, 2011 May 09, 2011

Copy link to clipboard

Copied

I haven't needed to do what you're trying, but it seems like you are trying to do things directly from the MediaPromise. That's before the image itself exists. Wouldn't you also need to do something like the last part of this example code?:

http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/media/CameraUI.html#includeExamplesSummary

That example takes a new picture, but if you're using CameraRoll.browseForImage() to get the image, you still have a MediaEvent to listen for, and the code should be the same from that point onwards.

Once the Loader you have used to do:

imageLoader.loadFilePromise(imagePromise);

has happened, then you can get the bitmap from the loader:

var image:Bitmap = Bitmap(imageLoader.content)

and then the bitmapdata from the bitmap:

var bitmap:BitmapData = image.bitmapData;

Would that be enough to then upload to a server?

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Guest
May 09, 2011 May 09, 2011

Copy link to clipboard

Copied

The difference between that example and what I want though is I want to be able to browse for any image.

What I am developing is an app that lets you submit an image.  So I don't want it to be where you have to take the image right before you submit it.  I want to be able to select any image in your camera roll and upload that.  I will try it by physically loading the image to a loader and try to upload it that way and report back, but that seems pretty inefficient.. having to load the image, then grab the data, then save it to a local temp file, THEN upload it to server.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
May 09, 2011 May 09, 2011

Copy link to clipboard

Copied

I think you failed to read all of my message., especially the part where I say "but if you're using CameraRoll.browseForImage() to get the image". Isn't that the routine you're using to let them browse for a photo? If it is, it still returns a MediaPromise that you'll need to load into a Loader.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Mentor ,
May 09, 2011 May 09, 2011

Copy link to clipboard

Copied

The issue is probably that the underlying data source of the media promise is asynchronous rather than synchronous. When you first get the media selected event, the data hasn't been read yet, so bytesAvailable is still zero. You have to add an event listener to the data source and wait for progress events or the complete event before accessing the data.

Caveat, this is how it works on Android. I don't have an iOS device to test on -- and will be at a conference this week, so I won't be able to borrow one.

Here's an example of reading the media promise data directly without using a temp file or loader as an intermediate step:

package
{
    import flash.desktop.NativeApplication;
    import flash.display.Loader;
    import flash.display.Sprite;
    import flash.display.StageAlign;
    import flash.display.StageScaleMode;
    import flash.events.ErrorEvent;
    import flash.events.Event;
    import flash.events.IEventDispatcher;
    import flash.events.IOErrorEvent;
    import flash.events.MediaEvent;
    import flash.media.CameraRoll;
    import flash.media.MediaPromise;
    import flash.utils.ByteArray;
    import flash.utils.IDataInput;
   
    public class CameraRollMediaPromiseExample extends Sprite
    {
        private var cameraRoll:CameraRoll = new CameraRoll();
       
        public function CameraRollMediaPromiseExample()
        {
            this.stage.align = StageAlign.TOP_LEFT;
            this.stage.scaleMode = StageScaleMode.NO_SCALE;
           
            if( CameraRoll.supportsBrowseForImage )
            {
                trace( "Initializing app..." );
               
                cameraRoll.addEventListener( MediaEvent.SELECT, imageSelected );
                cameraRoll.addEventListener( Event.CANCEL, browseCanceled );
                cameraRoll.addEventListener( ErrorEvent.ERROR, mediaError );
                cameraRoll.browseForImage();
            }
            else
            {
                trace( "Image browse is not supported.");
            }

        }
       
        private var dataSource:IDataInput;
        private var eventSource:IEventDispatcher;
       
        private function imageSelected( event:MediaEvent ):void
        {
            trace( "Media selected..." );
           
            var imagePromise:MediaPromise = event.data;
            dataSource = imagePromise.open();
           
            if( imagePromise.isAsync )
            {
                trace( "Asynchronous media promise." );
                eventSource = dataSource as IEventDispatcher;
                trace( eventSource );
               
                eventSource.addEventListener( Event.COMPLETE, onDataComplete );               
            }
            else
            {
                trace( "Synchronous media promise." );
                readMediaData();
            }
        }
       
        private function onDataComplete( event:Event ):void
        {
            trace("Data load complete");
            readMediaData();
        }
       
        private function browseCanceled( event:Event ):void
        {
            trace( "Media select canceled." );
            NativeApplication.nativeApplication.exit();
        }
       
        private function readMediaData():void
        {
            var imageBytes:ByteArray = new ByteArray();
            dataSource.readBytes( imageBytes );
           
            //the rest of this is just testing what we actually read
            trace(imageBytes.length);
            imageBytes.position = 0;
            var string:String = imageBytes.readUTFBytes( 300 );
            trace( string );
        }
       
        private function mediaError( error:ErrorEvent ):void
        {
            trace( "Error:" + error.text );
            NativeApplication.nativeApplication.exit();
        }
       
    }
}

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Guest
May 10, 2011 May 10, 2011

Copy link to clipboard

Copied

Thanks for the post Joe.  I will try this out for iOS and report back

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Guest
May 10, 2011 May 10, 2011

Copy link to clipboard

Copied

One thing worth pointing out though.  To my knowledge this won't negate the need to use a tempFile (at least for my purposes) because my original script needs a fileReference object to call the upload method.  So at some point in this script there has to be a physical file reference, and the best way to do that might be to just create a tempFile, and upload that, right?

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Guest
May 10, 2011 May 10, 2011

Copy link to clipboard

Copied

Ok, after testing, I finally found that this DOES work for ios and android.

Joe's code above is correct. Checking for async vs sync is key.  This will give you the bytes from the mediaPromise even if you are in ios.

I still don't see any way around getting the actual image to uplaod to a server other than to physically save it in your storage directory, upload it, then delete it.  I was able to do this:

var temp:File = File.applicationStorageDirectoy.resolvePath("myImage.jpg");

fs = new FileStream()

fs.openAsync(temp. FileMode.WRITE);

fs.writeBytes(imageBytes);

timer = new Timer(1500, 6);

timer.addEventListener(TimerEVent.TIMER, onTimer);

timer.start();

//the onTimer function checks if the temp file size is greater than 0, and if it is it will upload the file to my server, then delete the file

I am happy with this result, but if someone has a more efficient way, or a way to make it so you don't have to create a new file, save the file, upload the file, then delete the file.. i am all ears!

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Mentor ,
May 10, 2011 May 10, 2011

Copy link to clipboard

Copied

You should be able to use the URLLoader class and the POST action to send the data directly.

Here's an example by a well known Flash developer that looks pretty straight forward (I haven't tested it myself):

http://blog.joa-ebert.com/2006/05/01/save-bytearray-to-file-with-php/

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Mentor ,
May 17, 2011 May 17, 2011

Copy link to clipboard

Copied

import flash.events.MediaEvent;

I'm not able to import the above MediaEvent, its not coming in the list even I targeted AIR 2.5. What has to do?

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Participant ,
May 17, 2011 May 17, 2011

Copy link to clipboard

Copied

trying to make sense of all this. I have my image loaded onto the stage, but how do i save it's path and the reload it once the app loads again?

I don't want to upload it to a server I just want to get it back in my app.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Mentor ,
May 17, 2011 May 17, 2011

Copy link to clipboard

Copied

Joeboy_UK,

This is easy on Android, less so on iOS.

If you are only deploying to Android, you should be able to save the native path of the image and load it again using a Loader object. You could save the path in a SharedObject, file, or database.

On iOS, you can't access the file through a native path, so to save it, you would have to copy the image data to a file that you create in the application storage directory or temp directory, save the path to THAT file, and then load it when your app starts up.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Participant ,
May 18, 2011 May 18, 2011

Copy link to clipboard

Copied

am doing it on iOS.

I understand what yo are saying so as the image loads I need to gather the byte data then save it to a reference and reload that reference

I understand the theory now need to try and work out how to code it

much thanks

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines