Select to view content in your preferred language

Save UIComponent to a file (jpg)

2222
17
05-12-2011 05:05 AM
AshleyOwens
Emerging Contributor
I am attempting to save a UIComponent that includes a title, subtitle, map and textarea to a file in jpg format. Can anyone provide a simple example of this?  Thank you!
Tags (2)
0 Kudos
17 Replies
ReneRubalcava
Honored Contributor
It's been a while since I've done this, but you can turn the component to a bitmap
something like
var bmd:BitmapData = new BitmapData(com.width, comp.height);
bmd.draw(comp, new Matrix());
var bm:Bitmap = new Bitmap(bmd);

Then you can use a jpeg encoder to save the bitmapdata to a jpeg file.

Flex Framework provides it's own JPEGEncoder
mx.graphics.codec.JPEGEncoderYou just pass the BitmapData to the encoder and it does the work.

Here is a demo of how to use the jpegencoder to save the image to disc.
http://ntt.cc/2009/01/09/as3corelib-tutorialhow-to-use-jpegencoder-and-pngencoder-class-in-flex.html

Hope that helps.
0 Kudos
AshleyOwens
Emerging Contributor
Thank you for your response!  I keep getting error "ArgumentError: Error #2015: Invalid BitmapData." on the line where I create my BitmapData object (scroll to the bottom of the code to see where I create my BitmapData).
private function saveFile():void
{
 var zoomSliderVisibleBeforePrint:Boolean;
 if (map.zoomSliderVisible)
 {
  map.zoomSliderVisible = false;
  zoomSliderVisibleBeforePrint = true;
 }
 var printJob:FlexPrintJob = new FlexPrintJob();
 var h:Number = printJob.pageHeight;
 var w:Number = printJob.pageWidth;
 //VGROUP
 var printBox:VGroup = new VGroup();
 printBox.styleName = "PrintBox";
 printBox.width = map.width;
 //VGROUP inner
 var printBoxTitle:VGroup = new VGroup();
 var printBoxSubTitle:VGroup = new VGroup();
 var selectedAlign:String = LRCa[LRCcbo.selectedIndex];
 printBox.horizontalAlign=LRCa[LRCcbo.selectedIndex].toString().toLocaleLowerCase();

 this.addChild(printBox);     
 
 try
 {
  //TITLE
  var printTitle:Label = new Label();
  printTitle.text = txtTitle.text;
  if (titleFontSize!=0)
  {
   printTitle.setStyle("fontSize", titleFontSize);
  }
  else
  {
   printTitle.setStyle("fontSize", h / 12);
  }
  if (titleFontWeight!="")
   printTitle.setStyle("fontWeight", titleFontWeight);
  printTitle.percentWidth = 100;
  printBoxTitle.addElement(printTitle);
  //SUBTITLE
  var printSubtitle:Label = new Label();
  printSubtitle.text = txtSubtitle.text;
  if (subtitleFontSize!=0)
  {
   printSubtitle.setStyle("fontSize", subtitleFontSize);
  }
  else
  {
   printSubtitle.setStyle("fontSize", h / 24);
  }
  if (subtitleFontWeight!="")
  {
   printSubtitle.setStyle("fontWeight", subtitleFontWeight); 
  }
  printSubtitle.percentWidth = 100;
  printBoxSubTitle.addElement(printSubtitle);


  printBox.addElement(printBoxTitle);
  printBox.addElement(printBoxSubTitle);
  
  //MAP
  var bmpMap:BitmapData = ImageSnapshot.captureBitmapData(map);
  var printImg:BitmapImage = new BitmapImage();
  printImg.smooth = true;
  printImg.source = bmpMap;
  printBox.addElement(printImg);
  //COPYRIGHT
  var now:Date = new Date();
  var printCopy:Label = new Label();
  printCopy.text = copyright + " " + now.toLocaleString() + ".";
  if (copyrightFontSize!=0)
  {
   printCopy.setStyle("fontSize", copyrightFontSize);
  }
  else
  {
   printCopy.setStyle("fontSize", h / 48);
  }
  if (copyrightFontWeight!="")
  {
   printCopy.setStyle("fontWeight", copyrightFontWeight); 
  }
  printCopy.percentWidth = 100;
  printBox.addElement(printCopy);

  //COMMENTS
  if(txtComments.textFlow.getText())
  {       
   var spacerLabel:Label = new Label();
   spacerLabel.text = " ";
   //set the comment title:
   var printCommentTitleLabel:Label = new Label();
   printCommentTitleLabel.setStyle("fontSize", h / 24);
   printCommentTitleLabel.text = "Comments:  ";
   //set the comments:
   var printComment:Label = new Label();
   printComment.setStyle("fontSize", h / 48);
   printComment.text = txtComments.textFlow.getText();       
   //add to container:
   var printBoxComments:VGroup = new VGroup();
   printBoxComments.percentWidth = 100;
   printBoxComments.addElement(spacerLabel);
   printBoxComments.addElement(printCommentTitleLabel);
   printBoxComments.addElement(printComment);
   printBox.addElement(printBoxComments); 
  }     
 }
 finally
 {
 }    

 var bd:BitmapData = new BitmapData(printBox.width, printBox.height); //ArgumentError: Error #2015: Invalid BitmapData.    
 bd.draw(printBox, new Matrix());
 var pngEnc:PNGEncoder = new PNGEncoder();
 var imgData:ByteArray = pngEnc.encode(bd);  
 fileReference = new FileReference();
 fileReference.save(imgData,"TIGER.png");
}
0 Kudos
ReneRubalcava
Honored Contributor
It looks like it should work and I just tested the BitmapData to PNG part and it works for me.
The only thing I can think of is maybe you need to explicitly set height where you set the width.
printBox.width = map.width;
printBox.height = map.height;


Since you are creating the printBox in your function, it never actually gets added to the application stage, which is ok. But the events that occur when a Component is added (visually) to an application do the leg work for you of defining the componets width/height based on it's children.
In this case, since the component is just used in this function, those lifecycle events never happen, thus printBox.height is proabably null.
Explicitly setting it should work... I think 🙂
0 Kudos
AshleyOwens
Emerging Contributor
Thanks Rene!  It now prompts me to save the file.  When I open the saved file, however, the image is blank.  Seems like I'm still missing something...
0 Kudos
ReneRubalcava
Honored Contributor
Looking at your code, I see that you are adding the printbox to your app at some point.
I think the bitmap->png code is firing before the component has had a chance to draw.
You can try waiting for the addedToStage event
printBox.addEventListener(Event.ADDED_TO_STAGE, printBoxReady);
this.addChild(printBox);

function printBoxReady(e:Event):void
{
    // code to turn your printbox into bitmapdata and encode to png
    // and initialize your filereference
}


At that point, you should be able to see your component, so it is fully drawn and ready.
You'll probably want to wait to do this.addChild() until after you have added everything into printbox you want to add.
0 Kudos
AshleyOwens
Emerging Contributor
I added the following to my finally block -
finally
{      
 printBox.addEventListener(Event.ADDED_TO_STAGE, printBoxReady);
 this.addChild(printBox); 
}

And then created the printBoxReady function -
function printBoxReady(e:Event):void
{    
 var bd:BitmapData = new BitmapData(printBox.width, printBox.height); 
 bd.draw(printBox, new Matrix());
 var pngEnc:PNGEncoder = new PNGEncoder();
 var imgData:ByteArray = pngEnc.encode(bd);    
 fileReference = new FileReference();
 fileReference.save(imgData,"TIGER.png");
}


But the resulting saved PNG is still blank!
0 Kudos
ReneRubalcava
Honored Contributor
Hmm, sorry, at this point, I'm at a loss.
I tried pretty much the same to save a map and it worked.

Can you see the preview on your screen with everything added to it?
0 Kudos
AshleyOwens
Emerging Contributor
It's weird, a preview shows up just underneath my widget when I click "Save to File". I can see the subtitle and map, and the map is displaying backwards! See attached screen shot.
0 Kudos
ReneRubalcava
Honored Contributor
Ok, I tried a few things, modifying the Print Widget in Flexviewer and it's not the addedToStage event you want to listen for. Sorry, I forgot that in Flex, the FlexEvent.CreationComplete is what fires when all flex components are done being created.

When that fiires, you can encode the component to PNG/JPG. But, here's the rub. You can't use FileReference on FlexEvents, they're sandboxed for security purposes. So, you would probably need to create a small preview window, then have second button to actually save the data.

I reviewed the print functionality in one of my apps,and this how we do it for PDF saves. I need to create a preview, then a button to actually save the file.

Rather than post snippets or the whole thing here, you can see the dirty way I modified the print widget to do this.
https://gist.github.com/969352

Hope that helps.
Sorry I had to dust off the cobwebs on this one 🙂
0 Kudos