getExportCharset();
if(empty($encoding)){
$encoding = "UTF-8";
}
parent::__construct($orientation,$unit,$format,$unicode,$encoding,$diskcache);
$this->module = $GLOBALS['module'];
$this->bean = &$bean;
$this->sugarpdf_object_map = $sugarpdf_object_map;
if(!empty($_REQUEST["sugarpdf"])){
$this->action = $_REQUEST["sugarpdf"];
}
}
/**
* This method will be called from the controller and is not meant to be overridden.
*/
function process(){
$this->preDisplay();
$this->display();
}
/**
* This method will display the errors on the page.
*/
function displayErrors(){
foreach($this->errors as $error) {
echo '' . $error . '
';
}
}
/**
* [OVERRIDE] - This method is meant to overidden in a subclass. The purpose of this method is
* to allow a view to do some preprocessing before the display method is called. This becomes
* useful when you have a view defined at the application level and then within a module
* have a sub-view that extends from this application level view. The application level
* view can do the setup in preDisplay() that is common to itself and any subviews
* and then the subview can just override display(). If it so desires, can also override
* preDisplay().
*/
function preDisplay(){
// set document information
$this->SetCreator(PDF_CREATOR);
$this->SetAuthor(PDF_AUTHOR);
$this->SetTitle(PDF_TITLE);
$this->SetSubject(PDF_SUBJECT);
$this->SetKeywords(PDF_KEYWORDS);
// set other properties
$compression=false;
if(PDF_COMPRESSION == "on"){
$compression=true;
}
$this->SetCompression($compression);
$protection=array();
if(PDF_PROTECTION != ""){
$protection=explode(",",PDF_PROTECTION);
}
$this->SetProtection($protection,blowfishDecode(blowfishGetKey('sugarpdf_pdf_user_password'), PDF_USER_PASSWORD),blowfishDecode(blowfishGetKey('sugarpdf_pdf_owner_password'), PDF_OWNER_PASSWORD));
$this->setCellHeightRatio(K_CELL_HEIGHT_RATIO);
$this->setJPEGQuality(intval(PDF_JPEG_QUALITY));
$this->setPDFVersion(PDF_PDF_VERSION);
// set default header data
$this->setHeaderData(PDF_HEADER_LOGO, PDF_HEADER_LOGO_WIDTH, PDF_HEADER_TITLE, PDF_HEADER_STRING);
// set header and footer fonts
$this->setHeaderFont(Array(PDF_FONT_NAME_MAIN, '', PDF_FONT_SIZE_MAIN));
$this->setFooterFont(Array(PDF_FONT_NAME_DATA, '', PDF_FONT_SIZE_DATA));
//set margins
$this->SetMargins(PDF_MARGIN_LEFT, PDF_MARGIN_TOP, PDF_MARGIN_RIGHT);
$this->setHeaderMargin(PDF_MARGIN_HEADER);
$this->setFooterMargin(PDF_MARGIN_FOOTER);
//set auto page breaks
$this->SetAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM);
//set image scale factor
$this->setImageScale(PDF_IMAGE_SCALE_RATIO);
//set some language-dependent strings
//$this->setLanguageArray($l);
// ---------------------------------------------------------
}
/**
* [OVERRIDE] - This method is meant to overidden in a subclass.
*/
function display(){
$this->AddPage();
$this->SetFont(PDF_FONT_NAME_MAIN,'B',16);
$this->MultiCell(0,0,'Tcpdf class for this module and action has not been implemented.',0,'C');
$this->Info();
}
/**
* [OVERRIDE]
* This method override the regular Header() method to enable the custom image directory in addition to the OOB image directory.
* This method is used to render the page header.
* It is automatically called by AddPage().
* @access public
* @see include/tcpdf/TCPDF#Header()
*/
public function Header() {
$ormargins = $this->getOriginalMargins();
$headerfont = $this->getHeaderFont();
$headerdata = $this->getHeaderData();
if (($headerdata['logo']) AND ($headerdata['logo'] != K_BLANK_IMAGE)) {
// START SUGARPDF
$logo = K_PATH_CUSTOM_IMAGES.$headerdata['logo'];
$imsize = @getimagesize($logo);
if ($imsize === FALSE) {
// encode spaces on filename
$logo = str_replace(' ', '%20', $logo);
$imsize = @getimagesize($logo);
if ($imsize === FALSE) {
$logo = K_PATH_IMAGES.$headerdata['logo'];
}
}
// END SUGARPDF
$this->Image($logo, $this->GetX(), $this->getHeaderMargin(), $headerdata['logo_width']);
$imgy = $this->getImageRBY();
} else {
$imgy = $this->GetY();
}
$cell_height = round(($this->getCellHeightRatio() * $headerfont[2]) / $this->getScaleFactor(), 2);
// set starting margin for text data cell
if ($this->getRTL()) {
$header_x = $ormargins['right'] + ($headerdata['logo_width'] * 1.1);
} else {
$header_x = $ormargins['left'] + ($headerdata['logo_width'] * 1.1);
}
$this->SetTextColor(0, 0, 0);
// header title
$this->SetFont($headerfont[0], 'B', $headerfont[2] + 1);
$this->SetX($header_x);
$this->Cell(0, $cell_height, $headerdata['title'], 0, 1, '', 0, '', 0);
// header string
$this->SetFont($headerfont[0], $headerfont[1], $headerfont[2]);
$this->SetX($header_x);
$this->MultiCell(0, $cell_height, $headerdata['string'], 0, '', 0, 1, '', '', true, 0, false);
// print an ending header line
$this->SetLineStyle(array('width' => 0.85 / $this->getScaleFactor(), 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0)));
$this->SetY((2.835 / $this->getScaleFactor()) + max($imgy, $this->GetY()));
if ($this->getRTL()) {
$this->SetX($ormargins['right']);
} else {
$this->SetX($ormargins['left']);
}
$this->Cell(0, 0, '', 'T', 0, 'C');
}
/**
* [OVERRIDE] SetFont method in TCPDF Library
* This method override the regular SetFont() method to enable the custom font directory in addition to the OOB font directory.
*
* @param string $family Family font. It can be either a name defined by AddFont() or one of the standard Type1 families (case insensitive):
- times (Times-Roman)
- timesb (Times-Bold)
- timesi (Times-Italic)
- timesbi (Times-BoldItalic)
- helvetica (Helvetica)
- helveticab (Helvetica-Bold)
- helveticai (Helvetica-Oblique)
- helveticabi (Helvetica-BoldOblique)
- courier (Courier)
- courierb (Courier-Bold)
- courieri (Courier-Oblique)
- courierbi (Courier-BoldOblique)
- symbol (Symbol)
- zapfdingbats (ZapfDingbats)
It is also possible to pass an empty string. In that case, the current family is retained.
* @param string $style Font style. Possible values are (case insensitive):- empty string: regular
- B: bold
- I: italic
- U: underline
- D: line trough
or any combination. The default value is regular. Bold and italic styles do not apply to Symbol and ZapfDingbats basic fonts or other fonts when not defined.
* @param float $size Font size in points. The default value is the current size. If no size has been specified since the beginning of the document, the value taken is 12
* @param string $fontfile The font definition file. By default, the name is built from the family and style, in lower case with no spaces.
* @access public
* @see include/tcpdf/TCPDF#SetFont()
*/
public function SetFont($family, $style='', $size=0, $fontfile='') {
if(empty($fontfile) && defined('K_PATH_CUSTOM_FONTS')){
// This will force addFont to search the custom directory for font before the OOB directory
$fontfile = K_PATH_CUSTOM_FONTS."phantomFile.phantom";
}
parent::SetFont($family, $style, $size, $fontfile);
}
function Info(){
$this->SetFont(PDF_FONT_NAME_MAIN,'',12);
$this->MultiCell(0,0,'---',0,'L');
$this->MultiCell(0,0,'Class: '.get_class($this),0,'L');
$this->MultiCell(0,0,'Extends: '.get_parent_class($this),0,'L');
$this->MultiCell(0,0,'---',0,'L');
$this->MultiCell(0,0,'Module: '.$this->module,0,'L');
$this->MultiCell(0,0,'Tcpdf Action: '.$this->action,0,'L');
$this->MultiCell(0,0,'Bean ID: '.$this->bean->getFieldValue('id'),0,'L');
$this->SetFont(PDF_FONT_NAME_MAIN,'',12);
$this->MultiCell(0,0,'---',0,'L');
}
/**
* [OVERRIDE] Cell method in tcpdf library.
* Handle charset conversion and HTML entity decode.
* This method override the regular Cell() method to apply the prepare_string() function to
* the string to print in the PDF.
* The cell method is used by all the methods which print text (Write, MultiCell).
* @see include/tcpdf/TCPDF#Cell()
*/
public function Cell($w, $h=0, $txt='', $border=0, $ln=0, $align='', $fill=0, $link='', $stretch=0) {
parent::Cell($w, $h, prepare_string($txt), $border, $ln, $align, $fill, $link, $stretch);
}
/**
* This Ln1() method will always print a line break of one line height.
* The regular Ln() method print a line break which has the height of the last printed cell.
*/
public function Ln1() {
parent::Ln($this->FontSize * $this->cell_height_ratio + 2 * $this->cMargin, false);
}
/**
* This method allow printing a table using the MultiCell method with a formatted options array in parameter
* Options :
* header options override the regular options for the header's cells - $options['header']
* cell options override the regular options for the specific cell - Array[line number (0 to x)][cell header]['options']
* @param $item Array[line number (0 to x)][cell header] = Cell content OR
* Array[line number (0 to x)][cell header]['value'] = Cell content AND
* Array[line number (0 to x)][cell header]['options'] = Array[cell properties] = values
* @param $options Array which can contain : width (array 'column name'=>'width value + % OR nothing'), isheader (bool), header (array), fill (string: HTML color), ishtml (bool) default: false, border (0: no border (defaul), 1: frame or all of the following characters: L ,T ,R ,B), align (L: left align, C: center, R: right align, J: justification)
* @see MultiCell()
*/
public function writeCellTable($item, $options=NULL){
// Save initial font values
$fontFamily = $this->getFontFamily();
$fontSize = $this->getFontSizePt();
$fontStyle = $this->getFontStyle();
$this->SetTextColor(0, 0, 0);
$options = $this->initOptionsForWriteCellTable($options, $item);
// HEADER
if(!isset($options['isheader']) || $options['isheader'] == true){
$headerOptions = $options;
if(!empty($options['header']) && is_array($options['header'])){
$headerOptions = $this->initOptionsForWriteCellTable($options['header'], $item);
}
foreach($item[0] as $k => $v){
$header[$k]=$k;
}
$h = $this->getLineHeightFromArray($header, $options["width"]);
foreach($header as $v){
$this->MultiCell($options["width"][$v],$h,$v,$headerOptions['border'],$headerOptions['align'],$headerOptions['fillstate'],0,'','',true,0,$headerOptions['ishtml']);
}
$this->SetFillColorArray($this->convertHTMLColorToDec($options['fill']));
$this->Ln();
}
// MAIN
// default font
$this->SetFont($fontFamily,$fontStyle,$fontSize);
$this->SetTextColor(0, 0, 0);
$even=true;
// LINES
foreach($item as $k=>$line){
$even=!$even;
$h = $this->getLineHeightFromArray($line, $options["width"]);
//CELLS
foreach($line as $kk=>$cell){
$cellOptions = $options;
$value = $cell;
if(is_array($cell)){
$value = $cell['value'];
if(!empty($cell['options']) && is_array($cell['options'])){
$cellOptions = $this->initOptionsForWriteCellTable($cell['options'], $item);
}
}
if($even && !empty($options['evencolor'])){
$this->SetFillColorArray($this->convertHTMLColorToDec($options['evencolor']));
$cellOptions['fillstate']=1;
}else if(!$even && !empty($options['oddcolor'])){
$this->SetFillColorArray($this->convertHTMLColorToDec($options['oddcolor']));
$cellOptions['fillstate']=1;
}
$this->MultiCell($options["width"][$kk],$h,$value,$cellOptions['border'],$cellOptions['align'],$cellOptions['fillstate'],0,'','',true,0,$cellOptions['ishtml']);
$this->SetFillColorArray($this->convertHTMLColorToDec($options['fill']));
}
$this->Ln();
}
$this->SetFont($fontFamily,$fontStyle,$fontSize);
$this->SetTextColor(0, 0, 0);
}
/**
* This method allow printing a table using the writeHTML method with a formatted array in parameter
* This method can also return the table as HTML code
* @param $item Array[line number (0 to x)][cell header] = Cell content OR
* Array[line number (0 to x)][cell header]['value'] = Cell content AND
* Array[line number (0 to x)][cell header]['options'] = Array[cell properties] = values
* @param $returnHtml (bool) Return the table as HTML code instead of printing the HTML table
* @param $options Array which can contain : table (array of "HTML proprty"=>"value"),td (array of "HTML proprty"=>"value"), tr (array of "HTML proprty"=>"value"), isheader(bool), header (array of "HTML proprty"=>"value"), width (array 'column name'=>'width value + unit OR nothing')
* @return the HTML code if $returnHtml set to true
*/
public function writeHTMLTable($item, $returnHtml=false, $options=NULL){
//TODO ISSUE - width in % for the td have to be multiply by the number of column.
// ex: for a width of 20% in a table of 6 columns the width will have to be 120% (20*6).
$html="";
$line="";
if(!empty($options)){
foreach($options as $k=>$v){
$tmp[strtolower($k)]=$v;
}
$options=$tmp;
}else{
$options=array();
}
if(!isset($options["isheader"]) || $options["isheader"] == true){
if(!empty($options["header"])){
foreach($options["header"] as $k=>$v){
$tmp[strtolower($k)]=$v;
}
$options["header"]=$tmp;
}else{
$options["header"]=array("tr"=>array("bgcolor"=>"#DCDCDC"),"td"=>array());
}
foreach($item[0] as $k => $v){
if(!empty($options["width"]))$options["header"]["td"]["width"]=$options["width"][$k];
$line.=$this->wrap("td", $k, $options["header"]);
}
$html.=$this->wrap("tr", $line, $options["header"]);
}
foreach ($item as $k=>$v){
$line="";
foreach($v as $kk => $vv){
if(!empty($options["width"]) && isset($options["width"][$kk]))$options["td"]["width"]=$options["width"][$kk];
$line.=$this->wrap("td", $vv, $options);
}
$html.=$this->wrap("tr", $line, $options);
}
$html=$this->wrap("table", $html, $options);
if($returnHtml){
return $html;
}else{
$this->writeHTML($html);
}
}
/**
* return the HTML code of the value wrap with the tag $tag. This method handle options (general and specific)
* @param $tag
* @param $value
* @param $options
* @return the HTML wrapped code
*/
private function wrap($tag, $value, $options){
if(empty($options[$tag])){
$options[$tag] = array();
}
if(is_array($value)){
if(isset($value["options"])){
// The options of a specific entity overwrite the general options
$options[$tag] = $value["options"];
}
if(isset($value["value"])){
$value = $value["value"];
}else{
$value = "";
}
}
return wrapTag($tag, $value, $options[$tag]);
}
/**
* Return the heigth of a line depending of the width, the font and the content
* @param $line Array containing the data of all the cells of the line
* @param $width Array containing the width of all the cells of the line
* @return The heigth of the line
*/
private function getLineHeightFromArray($line, $width){
$h=0;
foreach($line as $kk=>$cell){
$cellValue = $cell;
if(is_array($cellValue)){
$tmp = $cellValue['value'];
$cellValue = $tmp;
}
if($h<$this->getNumLines($cellValue, $width[$kk])){
$h=$this->getNumLines($cellValue, $width[$kk]);
}
}
return $h * $this->FontSize * $this->cell_height_ratio + 2 * $this->cMargin;
}
/**
* Private method for writeCellTable which format and initialize the options array.
* @param $options array
* @param $item array
* @return $options array
*/
private function initOptionsForWriteCellTable($options, $item){
if(!empty($options)){
foreach($options as $k=>$v){
$tmp[strtolower($k)]=$v;
}
$options=$tmp;
}else{
$options=array();
}
// set to default if empty
if(empty($options["width"]) || !is_array($options["width"])){
$colNum = count($item[0]);
$defaultWidth = $this->getRemainingWidth()/$colNum;
foreach($item[0] as $k => $v){
$options["width"][$k]=$defaultWidth;
}
}else{
foreach($options["width"] as $k => $v){
$options["width"][$k] = $this->getHTMLUnitToUnits($v, $this->getRemainingWidth());
}
}
if(empty($options["border"])){
$options["border"]=0;
}
if(empty($options["align"])){
$options["align"]="L";
}
if(empty($options['ishtml'])){
$options['ishtml'] = false;
}
if(empty($options['border'])){
$options['border'] = 0;
}
if(!empty($options['fill'])){
$this->SetFillColorArray($this->convertHTMLColorToDec($options['fill']));
$options['fillstate']=1;
}else{
$options['fill']="#FFFFFF";//white
$options['fillstate']=0;
}
if(!empty($options['fontfamily'])){
$fontFamily = $options['fontfamily'];
}else{
$fontFamily = $this->getFontFamily();
}
if(!empty($options['fontsize'])){
$fontSize = $options['fontsize'];
}else{
$fontSize = $this->getFontSizePt();
}
if(!empty($options['fontstyle'])){
$fontStyle = $options['fontstyle'];
}else{
$fontStyle = $this->getFontStyle();
}
if(!empty($options['textcolor'])){
$this->SetTextColorArray($this->convertHTMLColorToDec($options['textcolor']));
}else{
$this->SetTextColor(0, 0, 0);//black
}
$this->SetFont($fontFamily, $fontStyle, $fontSize);
return $options;
}
/**
* This is method is fix for a better handling of the count. This method now handle the line break
* between words.
* This method returns the estimated number of lines required to print the text.
* @param string $txt text to print
* @param float $w width of cell. If 0, they extend up to the right margin of the page.
* @return int Return the estimated number of lines.
* @access public
* @since 4.5.011
* @OVERRIDE
*/
public function getNumLines($txt, $w=0) {
$lines = 0;
if (empty($w) OR ($w <= 0)) {
if ($this->rtl) {
$w = $this->x - $this->lMargin;
} else {
$w = $this->w - $this->rMargin - $this->x;
}
}
// max column width
$wmax = $w - (2 * $this->cMargin);
// remove carriage returns
$txt = str_replace("\r", '', $txt);
// divide text in blocks
$txtblocks = explode("\n", $txt);
// for each block;
foreach ($txtblocks as $block) {
// estimate the number of lines
if(empty($block)){
$lines++;
// If the block is in more than one line
}else if(ceil($this->GetStringWidth($block) / $wmax)>1){
//devide in words
$words = explode(" ", $block);
//TODO explode with space is not the best things to do...
$wordBlock = "";
$first=true;
$lastNum = 0;
$run = false;
for($i=0; $iGetStringWidth($wordBlock) / $wmax)>1){
if($first){
$lastNum = ceil($this->GetStringWidth($wordBlock) / $wmax);
$run = true;
$first = false;
}else{
if($run && $lastNum == ceil($this->GetStringWidth($wordBlock) / $wmax)){
// save the number of line if it is the last loop
if($i+1 == count($words)){
$lines += ceil($this->GetStringWidth($wordBlock) / $wmax);
}
continue;
}else{
$first = true;
$lines += ceil($this->GetStringWidth( substr($wordBlock, 0, (strlen($wordBlock) - strlen(" ".$words[$i]))) ) / $wmax);
$i--;
$lastNum = 0;
$run = false;
}
}
}else{
$first = false;
}
// save the number of line if it is the last loop
if($i+1 == count($words)){
$lines += ceil($this->GetStringWidth($wordBlock) / $wmax);
}
}
}else{
$lines++;
}
}
return $lines;
}
/**
* Disable zlib output compression if we are downloading the PDF.
*
* @see TCPDF::Output()
*/
public function Output($name='doc.pdf', $dest='I')
{
if ( $dest == 'I' || $dest == 'D') {
ini_set('zlib.output_compression', 'Off');
}
return parent::Output($name,$dest);
}
}