Wednesday, January 18, 2012

Flash AS3 + PHP: Publishing your flash contents into a PDF file (2)

Last week, I have shown you how to create a downloadable PDF using Flex + PHP + the Alive PDF library. As for this week, I shall move on to the step of printing out & breaking up a big datagrid into multiple pages.

The following would be the source file of my Main Application in Flex.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
    creationComplete="creationCompleteHandler(event)">
 <mx:Script>
  <![CDATA[
   //Import the classes that are needed.
   import com.extentPDF.ExtendingPDF;
   
   import mx.collections.ArrayCollection;
   import mx.controls.dataGridClasses.DataGridColumn;
   import mx.events.FlexEvent;
   
   //Array to store the random data that I'm going to create
   private var dataArray:Array = new Array();
   private var dataColArray:ArrayCollection = new ArrayCollection();
   
   //Array to store the column sequence
   private var dgColumns:Array = new Array();
   
   protected function creationCompleteHandler(event:FlexEvent):void
   {
    //Add the respective column names into the array.
    dgColumns.push(new DataGridColumn("Name"));
    dgColumns.push(new DataGridColumn("Description"));
    dgColumns.push(new DataGridColumn("Price"));
    dgColumns.push(new DataGridColumn("Unit"));
    //Set the columns of the datagrid.
    dgDisplay.columns = dgColumns;
    
    //Create random data
    var j:int = 0;
    var tempObject:Object;
    for(var i:int = 1; i <= 100; i ++)
    {
     tempObject = new Object();
     if(i % 2 == 1)
     {
      tempObject.Name = "Item " + i;
     }else{
      tempObject.Name = "Product " + i;
     }
     tempObject.Price = "S$" + i;
     j = Math.round(Math.random() * 100);
     tempObject.Unit = i * j;
     tempObject.Description = "Description " + i;
     dataArray.push(tempObject);
    }
    //Pass the data into the datagrid
    dataColArray.source = dataArray;
    dgDisplay.dataProvider = dataColArray;
   }
   
   //Upon clicking on the button, make a downloadable pdf.
   protected function clickHandler(event:MouseEvent):void
   {
    saveContent();
   }  
   
   //Function that will be creating the downloadable PDF
   //with the help of PHP
   private function saveContent():void
   {
    //Create a new instance of ExtendingPDF class.
    var tempPDF:ExtendingPDF = new ExtendingPDF();
    //Add it to this application.
    this.addChild(tempPDF);
    this.validateNow();
    
    //Specify the first row that you are displaying
    var start:int = 0;
    //Specify the last row that you are displaying
    var end:int = 1;
    //Used to specify the row number of the data
    var row:int = 0;
    //Array to create a reference to the 'dataArray'
    //based on the start and the end
    var dummyArray:Array;
    //Array to store the result of the check upon
    //the PDF
    var checkResult:Array = null;
    //Should be add the last known good view to the PDF? 
    var mustInsertPrev:Boolean = false;
    //Loop through all the rows of the 'dataArray'
    //Add the view into the PDF if the view can fit in
    //else keep on adding a new row until it reach a point
    //where the new row cannot be added and then add the 
    //last known good view into the PDF.
    while(end <= dataArray.length)
    {
     dummyArray = new Array();
     row = 0;
     for(var i:int = start; i < end; i ++)
     {
      dummyArray[row] = dataArray[i];
      row ++;
     }
     dataColArray.source = dummyArray;
     dgDisplay.dataProvider = dataColArray;
     dgDisplay.verticalScrollPolicy = "off";
     dgDisplay.height = dgDisplay.headerHeight +
      dgDisplay.measureHeightOfItems(start, end - start);
     dgDisplay.validateNow();
     mustInsertPrev = false;
     checkResult = tempPDF.checkContentSize2PDFPage(dgDisplay);
     if(checkResult[0] == 1)
     {
      if((start + 1) == end)
      {
       tempPDF.addPage();
       checkResult = tempPDF.checkContentSize2PDFPage(dgDisplay);
       if(checkResult[0] == 0)
       {
        mustInsertPrev = false;
       }else{
        mustInsertPrev = true;
       }
      }else{
       mustInsertPrev = true;
      }
      if(mustInsertPrev)
      {
       end --;
       dummyArray = new Array();
       row = 0;
       for(i = start; i < end; i ++)
       {
        dummyArray[row] = dataArray[i];
        row ++;
       }
       dataColArray.source = dummyArray;
       dgDisplay.dataProvider = dataColArray;
       dgDisplay.verticalScrollPolicy = "off";
       dgDisplay.height = dgDisplay.headerHeight +
        dgDisplay.measureHeightOfItems(start, end - start);
       dgDisplay.validateNow();
       tempPDF.addContent2PDFPage(dgDisplay);
       start = end;
       end ++;
      }
     }else{
      end ++;
      if(end > dataArray.length)
      {
       tempPDF.addContent2PDFPage(dgDisplay);
      }
     }
    }
    //Create the PDF file that can be downloaded
    tempPDF.createContent();
    //Restore everything back to the state before
    //the PDF was created.
    dataColArray.source = dataArray;
    dgDisplay.dataProvider = dataColArray;
    dgDisplay.verticalScrollPolicy = "auto";
    dgDisplay.height = 200;
    container.addChildAt(dgDisplay,0);
    this.removeChild(tempPDF);
    this.validateNow();
   }
   
  ]]>
 </mx:Script>
 <mx:VBox id="container" width="100%" height="100%" 
    horizontalAlign="center" verticalAlign="middle">
  <mx:DataGrid id="dgDisplay" height="200"/>
  <mx:Button label="Print Content Now!" click="clickHandler(event)"/>
 </mx:VBox>
</mx:Application>

A Custom Class that I had created to handle the printing...
package com.extentPDF
{
 import flash.display.DisplayObject;
 import flash.geom.Point;
 
 import mx.containers.Canvas;
 
 import org.alivepdf.display.Display;
 import org.alivepdf.layout.Layout;
 import org.alivepdf.layout.Mode;
 import org.alivepdf.layout.Orientation;
 import org.alivepdf.layout.Position;
 import org.alivepdf.layout.Resize;
 import org.alivepdf.layout.Size;
 import org.alivepdf.layout.Unit;
 import org.alivepdf.pages.Page;
 import org.alivepdf.pdf.PDF;
 import org.alivepdf.saving.Download;
 import org.alivepdf.saving.Method;
 
 public class ExtendingPDF extends Canvas
 {
  //Path to the Php file used to generate the pdf file
  private var phpUrl:String = "http://bestkirdape.freeiz.com/php/create.php";
  
  //File Name that I'm giving the pdf file
  private var strFilename:String = "PrintOut_Of_MultipleViewWithAlivePDF.pdf";
  
  private var myPDF:PDF;
  private var pdfHeight:int = 0;
  
  public function ExtendingPDF()
  {
   //Specify the settings of the PDF
   //In my case, I'm using a PORTRAIT view, a size of A4
   //and everything will be calculated in POINT.
   myPDF = new PDF(Orientation.PORTRAIT, 
    Unit.POINT, Size.A4);
   //Set the Display Mode of the PDF when it was opened.
   myPDF.setDisplayMode (Display.FULL_PAGE, Layout.SINGLE_PAGE);
   //Set the Margins (left, top, right, bottom)
   myPDF.setMargins(40,60,40,60);
   addPage();
  }
  
  //Create a new page into the PDF.
  public function addPage():void
  {
   var newPage:Page = new Page ( Orientation.PORTRAIT, 
    Unit.POINT, Size.A4 );
   //Add a Page to the PDF
   myPDF.addPage(newPage);
   pdfHeight = 0;
  }
  
  //This function is used to add the content into the current page
  public function addContent2PDFPage(content:DisplayObject):void
  {
   var resultArray:Array = checkContentSize2PDFPage(content);
   //Check if the content can fit into the current page
   //else need to create a new page
   if (resultArray[0] == 1)
   {
    addPage();
   }
   //Add the content into a Canvas first before adding into
   //the current page of the pdf.
   var tempContainer:Canvas = new Canvas();
   this.addChild(tempContainer);
   tempContainer.width = Math.floor(content.width) + 4;
   tempContainer.height = Math.floor(content.height) + 4;
   tempContainer.setStyle("backgroundAlpha",0);
   tempContainer.addChild(content);
   content.x = 0;
   content.y = 0;
   tempContainer.validateNow();
   this.validateNow();
   
   //Adds like a screen capture and capture a screen shot
   //of the content
   myPDF.addImage(tempContainer, new Resize(Mode.NONE, 
    Position.LEFT), 0, pdfHeight, (resultArray[1] as Point).x, 
    (resultArray[1] as Point).y);
   pdfHeight = pdfHeight + (resultArray[1] as Point).y + 10;
   
   //remove views that are not needed
   this.removeChild(tempContainer);
  }
  
  //This function is used to check whether the content 
  //can fit into the current page
  public function checkContentSize2PDFPage(content:DisplayObject):Array
  {
   var pageWidth:Number = myPDF.getCurrentPage().w - 80;
   var pageHeight:Number = myPDF.getCurrentPage().h - 120;
   var imgScaleFactor:Number = content.width/content.height;
   
   var pw:int = 0;
   var ph:int = 0;
   pw = Math.floor(pageWidth);
   ph = Math.floor(pw/imgScaleFactor);
   var tempArray:Array = new Array();
   var tempPoint:Point = new Point();
   tempPoint.x = pw;
   tempPoint.y = ph;
   
   if ((pdfHeight + ph) > pageHeight)
   {
    tempArray[0] = 1;
   }else{
    tempArray[0] = 0;
   }
   tempArray[1] = tempPoint;
   return tempArray;
  }  
  
  //Create the PDF file that can be downloaded
  public function createContent():void
  {
   myPDF.save( Method.REMOTE, phpUrl, Download.ATTACHMENT, strFilename);
  }   
 }
}

* Click here to view the demo of this example.
^ Click here for the source files of this demo.

~ Click here for the website of 'Alive PDF'.
- Click here for the Documentation of the classes of 'Alive PDF'.
** Click here for the older tutorials on 'Alive PDF'.

No comments:

Post a Comment