FileReference and HttpService Browse Image Modify it then Upload it - apache-flex

I am trying to do an image uploader, user can:
- browse local file with button.browse
- select one and save it as a FileReference.
- then we do FileReference.load() then bind the data to our image control.
- after we make a rotation on it and change the data of image.
- and to finish we upload it to a server.
To change the data of image i get the matrix of the displayed image and transform it then i re-use the new matrix and bind it to my old image:
private function TurnImage():void
{
//Turn it
var m:Matrix = _img.transform.matrix;
rotateImage(m);
_img.transform.matrix = m;
}
Now the mater is that i really don't know how to send the data as a file to my server cause its not stored in the FileReference and data inside FileReference is readOnly so we can't change it or create a new, so i can't use .upload();.
Then i tried HttpService.send but i can't figure out how you send a file and not a mxml.

You can use URLLoader to send Binary ByteArray to server, like:
var urlRequest : URLRequest = new URLRequest();
urlRequest.url = 'path to your server';
urlRequest.contentType = 'multipart/form-data; boundary=' + UploadPostHelper.getBoundary();
urlRequest.method = URLRequestMethod.POST;
urlRequest.data = UploadPostHelper.getPostData( 'image.jpg', byteArray );
urlRequest.requestHeaders.push( new URLRequestHeader( 'Cache-Control', 'no-cache' ) );
// create the image loader & send the image to the server:<br />
var urlLoader : URLLoader = new URLLoader();
urlLoader.dataFormat = URLLoaderDataFormat.BINARY;
urlLoader.load( urlRequest );
First get bitmapdata for the image:
// set up a new bitmapdata object that matches the dimensions of the captureContainer;
var bmd : BitmapData = new BitmapData( captureContainer.width, captureContainer.height, true, 0xFFFFFFFF );
// draw the bitmapData from the captureContainer to the bitmapData object:<br />
bmd.draw( captureContainer, new Matrix(), null, null, null, true );
Then get byteArray:
var byteArray : ByteArray = new JPGEncoder( 90 ).encode( bmd );
and use the above URLLoader code to send image to server.
It will work fine, except you wouldn't get the file upload progress like the one you get from FileReference.upload. If you can make upload progress work using URLLoader, please post your answer here.

Related

Flex BitmapData.draw() only draws a white rectangle -- can I draw all elements of a display object?

I am trying to save a component as a JPG file and I can't seem to get the BitmapData.draw() to give me the pixels I'm expecting and instead I am seeing a plain white rectangle when I open the resulting JPG file. I am first creating an object which contains an image and a caption (the MultigraphCanvas below) and when I display the object as a pop up it looks perfect -- however when I try to draw it as a bitmap and then encode and save it as a JPG I don't end up with the same image I can display on the screen. Here's the code:
private function saveAsFile(title:String):void
{
// make a canvas containing the multigraph and title
var multigraphCanvas:MultigraphCanvas = new MultigraphCanvas();
multigraphCanvas.initialize();
multigraphCanvas.multigraphGroup = multigraphGroup;
multigraphCanvas.titleText.text = title;
this.addElement(multigraphCanvas);
var matrix:Matrix = new Matrix()
matrix.tx = 0;
matrix.ty = 0;
var multigraphCanvasBitmapData:BitmapData = new BitmapData(multigraphCanvas.width, multigraphCanvas.height, true, 0xffffffff);
multigraphCanvasBitmapData.draw(multigraphCanvas, matrix);
var multigraphCanvasImage:Image = new Image();
multigraphCanvasImage.load(new Bitmap(multigraphCanvasBitmapData));
multigraphCanvasImage.content.width = multigraphCanvas.width;
multigraphCanvasImage.content.height = multigraphCanvas.height;
var multigraphCanvasImageBitmapData:BitmapData = new BitmapData(multigraphCanvas.width, multigraphCanvas.height, true, 0xffffffff);
multigraphCanvasImageBitmapData.draw(multigraphCanvasImage);
// DEBUGGING
PopUpManager.addPopUp(multigraphCanvas, this);
// DEBUGGING
var debugImage:Image = new Image();
debugImage.source = multigraphCanvasImageBitmapData;
var debugTitleWindow:TitleWindow = new TitleWindow();
debugTitleWindow.addElement(debugImage);
PopUpManager.addPopUp(debugTitleWindow, this);
// encode the canvas bitmap into a JPG byte array
var jpgEncoder:JPEGEncoder = new JPEGEncoder(85);
var jpgByteArray:ByteArray = jpgEncoder.encode(multigraphCanvasImageBitmapData);
// save the JPG byte array as a file
var fileReference:FileReference = new FileReference();
fileReference.save(jpgByteArray, title + ".jpg");
}
Can I expect for the BitmapData.draw() method to draw each component of the display object it's passed, or does it just render the topmost element and none of the children (this is what it looks like to me)?
I believe that components need to be in the display tree for BitmapData.draw() to be able to render them.
I have been up for the last 24 hours so if the function is broke don't blame me :)
This is a stripped down version of a function I have that takes a snapshot of the container(c1) and sends it off to the server. I was base64 encoding as that was what the Java guy wanted for the back-end. You will have to massage the setting for your needs. I cut out a lot of the stuff I had in this function
private function getSnapShot( e:MouseEvent ):String{
var matrix:Matrix = new Matrix()
matrix.tx = 0;
matrix.ty = 0;
var finished1:BitmapData = new BitmapData(this.c1.width,this.c1.height,true,0xffffffff);
finished1.draw( this.c1, matrix );
var myImage:Image = new Image();
myImage.load( new Bitmap(finished1) );
myImage.content.width = this.c1.width;
myImage.content.height = this.c1.height;
var finished:BitmapData = new BitmapData(this.c1.width,this.c1.height,true,0xffffffff);
finished.draw(myImage);
myImage = null;
var encoder:JPEGEncoder = new JPEGEncoder();
var data:ByteArray = encoder.encode(finished);
var b64:Base64Encoder = new Base64Encoder()
b64.encodeBytes( data )
return b64.toString();
}
you probably only need to return "data" which is the JPG
Check the registration point of the source display object container.
Let's imagine the following scenario:
The display object container contains a visual like a rectangle and this DisplayObjectContainer has the registration at the bottom left so no content is available at x,y = 1,1.
BitmapData.draw would copy the content starting from 0,0(if you don't specify otherwise via a matrix translation) so you will get an empty white area(or the default fill color of the BitmapData)

how to send byte array to server in flash builder (Flex 4)

I have a video file in my local system.I am using windows XP in my system. Now i want to send this video file byte array to server in Flash Builder (Flex 4). I am using PHP at server end.
How can i do this? Please guide
Thanks
Socket.writeBytes() will do what you need.
Via this link:
.
// serialization
var serializedSound:ByteArray;
serializedSound = serializeSound(sound);
serializedSound.position = 0;
// unserialization
var newSound:Sound = new Sound();
newSound.addEventListener(SampleDataEvent.SAMPLE_DATA, deserialize);
newSound.play();
function serializeSound(sound:Sound):ByteArray
{
var result:ByteArray = new ByteArray();
while( sound.extract(result, 8192) ){
result.position = result.length;
}
return result;
}
function deserialize(e:SampleDataEvent):void
{
for ( var c:int=0; c<8192; c++ ) {
if(serializedSound.bytesAvailable < 2) break;
e.data.writeFloat(serializedSound.readFloat());
e.data.writeFloat(serializedSound.readFloat());
}
}
Do you need just sending the bytearray to PHP or also getting the bytearray?
For sending the bytearray you can use Zend_AMF:
http://framework.zend.com/download/amf
It will handle all the conversion, and in php you will get the bytearray as a string through a variable (I use variable reference as: &$file to save some memory on calling of method)
Here is some code snippet it can help you:
Sending ByteArray to Zend_Amf
For getting the ByteArray you can use the FileReference load() method to get all the bytearray of a local file.
You do know that creating a ByteArray of the video in Flex is literally storing that video to memory right? Any kind of large or uncompressed video would use an enormous amount of client side memory which could cause errors if Flash hits its memory limit.
I don't think you're going about this the right way. What I recommend you do is instead just upload the video to the server which the server than then access the bytes within it. If you want to upload the video to the server, look at this tutorial here which shows how to upload the file from Flex and a PHP script to get and store the file: http://livedocs.adobe.com/flex/3/html/17_Networking_and_communications_7.html#118972
From here, PHP could then access the bytes if you are so inclined.
AS3 Code:
uploadURL = new URLRequest();
uploadURL.url = "upload.php?fileName=videotrack";
uploadURL.contentType = 'application/octet-stream';
uploadURL.method = URLRequestMethod.POST;
uploadURL.data = rawBytes;
urlLoader = new URLLoader();
urlLoader.addEventListener(Event.COMPLETE, completeHandler);
urlLoader.load(uploadURL);
rawBytes is the byte array that you want to upload to the server.
PHP Code
$fileName = $_REQUEST['fileName'] . ".mp3";
$fp = fopen( $fileName, 'wb' );
fwrite( $fp, $GLOBALS[ 'HTTP_RAW_POST_DATA' ] );
fclose( $fp );
I've used a .mp3 extension because my byte array was data from a mp3 file, but you can set the extension to whatever type of file your byte array represents.

Converting a flex component w/images to bitmap

I am trying to take images I am placing in a flex canvas component to a bitmap. I was able to get to the point where I'm not getting an error but then no image shows up and the image I save out as a jpg is blank. I imagine I'm not setting the bitmap data correctly but can't figure out what I am doing wrong.
Here is the code where I am converting it to a bitmap:
var imageSnap:ImageSnapshot = ImageSnapshot.captureImage(_renderPop);
var imageByteArray:ByteArray = imageSnap.data as ByteArray;
var bLoader:Loader = new Loader();
bLoader.loadBytes(imageByteArray);
var bmd:BitmapData = new BitmapData(500,500);
bmd.draw(bLoader);
var imgTest:Image = new Image();
imgTest.source = bmd;
_renderPop.renderCanvas.addChild(imgTest);
var fileRef:FileReference = new FileReference();
fileRef.save(bLoader, 'testImage.jpg');
_renderPop.renderCanvas is where I am placing the images. Anybody see anything wrong?
Your "loader" code is wrong. Just after capturing image you may at once save data with FileReference:
var imageSnap:ImageSnapshot = ImageSnapshot.captureImage(_renderPop);
var fileRef:FileReference = new FileReference();
fileRef.save(imageSnap.data, 'testImage.png');
That imageSnap contains not BitmapData but png image bytes. In order to show image you need to capture BitmapData but not image and create Bitmap from bitmap data:
var bmd:BitmapData = ImageSnapshot.captureBitmapData(_renderPop);
var imgTest:Image = new Image();
imgTest.source = new Bitmap(bmd);
_renderPop.renderCanvas.addChild(imgTest);
In result locally testImage.png is created on file system and it is shown in canvas. If you need jpg you should specify:
var imageSnap:ImageSnapshot = ImageSnapshot.captureImage(_renderPop, 0, new JPEGEncoder());
In your code:
var bLoader:Loader = new Loader();
bLoader.loadBytes(imageByteArray);
...you're assuming that the bytes are being loaded immediately; try putting an event listener on the loader as follows:
bLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, completeHandler);
private function completeHandler(event:Event):void
{
// ... the rest of your code goes here
}
The loadBytes functions works like the load function in that they are both asynchronous processes so you'll need the event listener. It is a little counter-intuitive, and i've made the same mistake myself several times.
If that doesn't work, maybe leave out the contentLoaderInfo property, but the above should work...
Let me know if you come right :)

Flex sending snapshot without using base64Encode

var is:ImageSnapshot = myImagesnapshot;
var str:String = ImageSnapshot.encodeImageAsBase64(is);
As of now, I am sending my jpeg data to the server with the code above.
The problem is that it almost doubles the size of the data.
Is there a way to send the image data directly without using any encoding.
base64 increases size by a third, so if you really have about 100% overhead, you have a problem elsewhere.
haven't looked at the sources to well, but from the reference it seems, you could retrieve the binary data directly.
just tuck that into a URLRequest and send it per POST.
Here is a sample of sending image data without using Base64 :
var myEncoder:JPGEncoder = new JPGEncoder(100);
var byteArray:ByteArray = myEncoder.encode(bitmapData);
var header:URLRequestHeader = new URLRequestHeader("Content-type", "application/octet-stream");
var url:String = "../../default.php";
var saveJPG:URLRequest = new URLRequest(url);
saveJPG.requestHeaders.push(header);
saveJPG.method = URLRequestMethod.POST;
saveJPG.data = byteArray;
On PHP side, I need to access :
$globalS["HTTP_raw_post_data"]
You can save the snapshot as jpg or png.
Take a look at:
http://blog.flexexamples.com/2007/12/07/using-the-imagesnapshot-class-to-capture-images-as-jpegs-or-pngs-in-flex-3/

How can I send another variable with FileReference Upload?

I have a problem with the filereference class using the upload function.
I want to send the folderLocation variable with fileReference.upload().
Below I try to describe my strategy.
var folderLocation : String = "photos/myUniqueFolder/";
private var serverSideScript:String = "http://localhost/project/phpFlexMechanism/upload.php";
urlRequest = new URLRequest(serverSideScript);
fileReferenceList.addEventListener(Event.SELECT, fileSelectedHandler);
private function fileSelectedHandler(event:Event):void {
// upload the file to the server side script
fileReference.addEventListener(Event.COMPLETE, uploadCompleteHandler);
fileReference.upload(urlRequest);
}
In PHP I use this to get the the file and uploaded
$folder = $_POST['folder'];
$tempFile = $_FILES['Filedata']['tmp_name'];
$fileName = $_FILES['Filedata']['name'];
$fileSize = $_FILES['Filedata']['size'];
move_uploaded_file($tempFile, "../user/$folder/uploadImages/" . $fileName);
But how can I send the folder through the "upload reference"?
I would think that, since you FileReference needs a URLRequest, you would be able to piggy back that information through the URLRequest itself by using the flash.net.URLVariables object.
I've not had time to test this, but have you tried:
// put this right after you instantiate urlRequest;
var urlVars:URLVariables = new URLVariables();
urlVars.targetFolder = folderLocation;
urlRequest.method = "post";
urlRequest.data = urlVar;
That should let you do:
//replace your last line with these two.
$folder = $_REQUEST[ "targetFolder" ];
move_uploaded_file($tempFile, "../user/$folder/uploadImages/" . $fileName);
in PHP.
the easiest thing you can do is just send it through with a get header in the upload function
so the code looks as follows
private var serverSideScript:String = "http://localhost/project/phpFlexMechanism/upload.php?extraVar=value&extraVarB=value2";
fileReference.upload(urlRequest);
then in the php script you just use
$_GET['extraValue']
$_GET['valueVarB']

Resources