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

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");

Related

Find the color of a pixel at a point within a VGroup

I'm having trouble with this code can anybody help...
var imageMap:ImageSnapshot= ImageSnapshot.captureImage(object);
var pixelValue:uint = imageMap.bitmapData.getPixel(x, y);
According to the documentation, there is no bitmapData property of the ImageSnap class. Instead you can use the static ImageSnapshot.captureBitmapData function to get a BitmapData snapshot of your object.
var imageMap:BitmapData = ImageSnapshot.captureBitmapData(object);
var pixelValue:uint = imageMap.getPixel(x,y);

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)

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/

embedding sources dynamically

is it possible to embed sources dynamically. instead of doing this
[Embed(source = '../../../../assets/levels/test.xml')]
I could probably do something like this
var src = '../../../../assets/levels/test.xml'
[Embed(source = src )]
It's not possible for anything within metadata annotations to be dynamic :/. That is, you can't place variables into metadata annotations. If that was possible, there would be SO many cool possibilities. So your first option is the only way to directly embed xml.
You could, however, write a custom metadata parser that figured out how to load (not embed) your xml file. Something like:
[LoadFile]
public var source:String = "../../../../assets/levels/test.xml";
I would implement that like the code below (just wrote this right now, haven't tested it). And then you'd "process" your class via something like MyMetadataUtil.process(this). Lots of ways to do that.
public function extractMetadata(target:Object):void
{
var description:XML = flash.utils.describeType(target);
var tag:String = "LoadFile"
var metadata:XMLList = description.accessor.metadata.(#name == tag);
metadata += description.variable.metadata.(#name == tag);
var i:int = 0;
var n:int = metadata.length();
// usually called a 'directive'
// holds values from metadata annotation
var token:Object = {};
for (i; i < n; i++)
{
metadataXML = metadata[i];
token.property = metadataXML.parent().#name;
// token.source = myClass.source;
token.source = target[token.property];
var request:URLRequest = new URLRequest(token.source);
var loader:URLLoader = new URLLoader();
loader.addEventListener(Event.COMPLETE, loader_completeHandler);
loader.addEventListener(IOErrorEvent.IO_ERROR, loader_ioErrorHandler);
loader.load(request);
}
}
protected function loader_completeHandler(event:Event):void
{
event.currentTarget.removeEventListener(event.type, loader_completeHandler);
trace("SUCCESSFULLY LOADED FILE!");
}
protected function loader_ioErrorHandler(event:Event):void
{
event.currentTarget.removeEventListener(event.type, loader_ioErrorHandler);
}
That stuff would go into some util/manager/processor class. Then anywhere in your code, you could use this:
[LoadFile]
public var source:String = "myFile.xml";
And that could be dynamic. Check out the Swiz Framework for some example source code on how to implement custom metadata processors. Or even better, Openflux's MetaUtil. Once you set that up once, you can do some hardcore stuff in your code. Makes coding fun and fast.
Hope that helps,
Lance
Your use case is basically why I created the ability to add extra frames to Flex SWFs that are treated as late-loaded modules. Instead of embedding your level, stream it in after the main application.
Documentation on -frame is sparse. Sorry! Here's some external stuff, that links back to stuff I wrote and Alex Harui wrote. Good luck!
http://www.richinternet.de/blog/index.cfm?entry=FF295F89-DAD8-CCDC-960413842BC0D478

Resources