views:

579

answers:

4

Hi,

in my project, I let users pick pictures using the FileReference class. I then load these pictures into their .data properties, using the load() function. After this I perform some local manipulation and send them to the server.

What I would like to do, is to be able to iterate over the picked FileReferences again, load them into .data properties, perform different manipulation and send them to the server once again. I know that I should be able to do this from user-invoked event, that is not an issue here.

Problem is, once the FileReference is loaded for the first time, I can not unload it in any way, and I can not keep the data for all the pictures in the memory because these are huge.

So I guess there is only one thing I can do, which is performing a DeepCopy on the FileReference... Then I could load the first version, scrap it and use the copy for the second 'run'.

I tried to use ObjectUtil.copy, but when I access e.g. .name property of the copy, it fails with:

Error #2037: Functions called in incorrect sequence, or earlier call was unsuccessful.

at flash.net::FileReference/get name()

the relevant snippet:

registerClassAlias("FileReference",FileReference);
masterFileList.addItem(FileReference(ObjectUtil.copy(fr_load.fileList[i])));
trace(masterFileList[i].name)

Is it true that there are some protected properties of FileReference class that prevent it from being copied? If it is so, can I sidestep this somehow? Or is there any other solution to my overall problem?

I appreciate any hints/ideas!

+1  A: 

Hi,

you cant use a ObjectUtil.copy. This method is designed for copying only data objects (VO classes).

you should create a new FileReference and copy the porperties, one by one. Create a function to do this..

Daniel Schmitz
Hi, thanks for the answer. But have you ever tried to copy a FileReference object like that? I mean, the crucial properties are probably protected and the once that are public appear to be read only. You can access .data only after you load() the FR, so you can copy the data after this. But this is not what I wanted. I need to copy it before loading it. This way I can load it in the first run and in the second run separately.
supo
+1  A: 

Would copying it to a temporary file and then uploading the temporary file work? For example

        var fileRef:FileReference = new FileReference();
        fileRef.browse();

        ......................

        var tmpFile:File =  File.createTempFile();
        try {
            var tmpFileStream:FileStream = new FileStream();
            tmpFileStream.open(tmpFile, FileMode.WRITE);
            trace("Opened file: " + tmpFile.nativePath);
            tmpFileStream.writeBytes(fileRef.data);
            trace("copied file");
        } catch ( error:Error ) {
            trace("Unable to open file " + tmpFile.nativePath + "\n");
            throw error;
        }
Ryan K
Do you suggest storing all the pictures in the full quality in the memory and then uploading from the memory? That is not going to help, because even small number of images (like 10) that are even not of the best quality (lets say 3MB/each) take a few hundreds of megabytes of RAM, even if I encode them into JPEG and store them after that. And I'd like to work with 100 images or more.
supo
Hmm wait a second, now I saw that you are creating a file there. Isn't createTempFile bound to AIR? I failed to mention it, but this is not an AIR application.
supo
+1  A: 

I'm thinking that the operation is completely disallowed, for good reasons. If you can duplicate a new FileReference through ActionScript code, then you'd also be able to manufacture a FileReference object through ActionScript code. Of course, that'd be a pretty bad security hole if you could force the upload of an arbitrary file.

Keeping a copy of the data in memory really isn't that bad of a solution. After all, it's temporary. The typical client computer should be able to manage a few hundred extra MB of data with no problem. It's certainly a better option than having their browser do two separate uploads, which is what your attempted solution would end up doing.

A completely different potential solution to this problem is to avoid image manipulation by Flex altogether. Flex could post the uploaded file directly to the server, and the server could do the image manipulation itself. Of course, if the manipulation is driven through user interactions, then that wouldn't work at all.

Jacob
Few hundred extra MB? AFAIK there is no way I can store 1 picture in less than 50 MB of RAM. These pictures are jpegs and weight about 1-5MB when compressed on disk.I would like to work with 100 pictures at least, which makes it 5GB of RAM, which is not acceptable by any means. The other alternative you suggest occurred me as well. The manipulation is not user driven, BUT this approach would require the user to wait until all the pictures are uploaded in good quality and this can take like an hour. I don't want to force the user to wait that long in the beginning of his work with the app..
supo
If you can suggest a way HOW to store the images in RAM more efficiently, that would be cool. So far I tried basic bitmaps which is stupid and then I tried encoding them to Jpeg and storing them as bytes..
supo
You wouldn't have to store all of the hundreds of pictures at once. You could process them one at a time, releasing the temporary buffer after you finish with each one.
Jacob
Hmm what do you mean by "keeping the copy of the data in memory" then?In order to be able to process and upload it again I can either reload the files with different filerefferences OR I can keep them in the memory and them process and upload them from it. I thought you were suggesting the second option right?
supo
A: 

I was trying to do almost exactly what you were doing, and I almost gave up after reading some of the answers, but I think I found a way to do it. I've found that if you have a FileReference object, if you call load() multiple times, it will work, but the main problem is that you're keeping the high-res bytes in memory after the first load. As you've mentioned, for people who don't know image processing, this is a big no-no.

The way to get around this is that after your first load(), you need to call the cancel() method on FileReference. From my testing so far, it looks like that will clear our the bytes in the FileReference, and load() will still work if you call it a second time later. I've only tried it on my system so far, but it works fine there. Just a word of caution, this isn't explicitly-defined behavior in the API, so it is definitely subject to change, but it may help get you where you need to go in the mean time.

Hope that helps.

danopkt