Converting a flex component w/images to bitmap - apache-flex

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 :)

Related

PurePDF - best way to add good quality snapshot of a display object

Anyone have any experience with PurePDF and adding a display object to the page? In AlivePDF, you do something like this:
pdfObject.addImage(yourDisplayObject,...)
where yourDisplayObject is a class that inherits from DisplayObject. AlivePDF internally takes care of converting this into an image and adding the image to the pdf page.
What would be the equivalent of this for purePDF?
Any purePDF experts out there?
I use PurePDF. This code will take an object like UIComponent, turn it into a bitmap and put it in your pdf.
var matrix : Matrix = new Matrix();
var pageSize:RectangleElement = PageSize.A4;
var mainImage : BitmapData = new BitmapData(_objectToPrint.width,_objectToPrint.height,false, 0xFFFFFF);
mainImage.draw(_objectToPrint,matrix);
var bytes:ByteArray = new ByteArray();
var document:PdfDocument = PdfWriter.create(bytes, pageSize).pdfDocument;
document.setMargins(0,0,0,0);
document.open();
var imageElement : ImageElement = ImageElement.getBitmapDataInstance(mainImage, false);
document.add(imageElement);
document.close();
new FileReference().save(bytes,"yourPDF.pdf");

Is it possible to load a local file without having to ask the user to browse to it first in an AIR Application?

I'm writing a small application for myself and instead of using a database I'd like to just use Excel to store the small amount of data I have on my local file system. I want to be able to load that data without having to use the typical FileReference browse() method as it would just be annoying to do every time I use the application.
The code below seems to find the file fine as the file.exists method below and most of the other attributes seem to be correct but the file.data is always null.
I'm guessing this is a security issue and that's why I'm running into this problem but I thought I'd ask and see if there is in fact a way around this problem.
var file:File = new File(fullPath + "\\" + currentFolder + ".txt");
if(file.exists) {
var byteArray:ByteArray = file.data;
}
If you want to read the content of a file, use the following code:
var stream:FileStream = new FileStream();
stream.open("some path here", FileMode.READ);
var fileData:String = stream.readUTFBytes(stream.bytesAvailable);
trace(fileData);
The data property is inherited from FileReference class and it will be populated only after a load call (see this link).
You're close, you just need to combine that with a FileStream object
var fileStream:FileStream = new FileStream();
fileStream.open(file, FileMode.READ);
var str:String = fileStream.readMultiByte(file.size, File.systemCharset);
trace(str);
more info here

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)

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/

FileReference and HttpService Browse Image Modify it then Upload it

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.

Resources