PageRenderTime 49ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/include/Sugarpdf/Sugarpdf.php

https://bitbucket.org/cviolette/sugarcrm
PHP | 693 lines | 415 code | 66 blank | 212 comment | 87 complexity | 7e44d3d7308df3c1e5fad15c776c88ee MD5 | raw file
Possible License(s): LGPL-2.1, MPL-2.0-no-copyleft-exception, BSD-3-Clause
  1. <?php
  2. if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
  3. /*********************************************************************************
  4. * SugarCRM Community Edition is a customer relationship management program developed by
  5. * SugarCRM, Inc. Copyright (C) 2004-2012 SugarCRM Inc.
  6. *
  7. * This program is free software; you can redistribute it and/or modify it under
  8. * the terms of the GNU Affero General Public License version 3 as published by the
  9. * Free Software Foundation with the addition of the following permission added
  10. * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
  11. * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
  12. * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
  13. *
  14. * This program is distributed in the hope that it will be useful, but WITHOUT
  15. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  16. * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
  17. * details.
  18. *
  19. * You should have received a copy of the GNU Affero General Public License along with
  20. * this program; if not, see http://www.gnu.org/licenses or write to the Free
  21. * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  22. * 02110-1301 USA.
  23. *
  24. * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
  25. * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
  26. *
  27. * The interactive user interfaces in modified source and object code versions
  28. * of this program must display Appropriate Legal Notices, as required under
  29. * Section 5 of the GNU Affero General Public License version 3.
  30. *
  31. * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
  32. * these Appropriate Legal Notices must retain the display of the "Powered by
  33. * SugarCRM" logo. If the display of the logo is not reasonably feasible for
  34. * technical reasons, the Appropriate Legal Notices must display the words
  35. * "Powered by SugarCRM".
  36. ********************************************************************************/
  37. if(file_exists('custom/include/Sugarpdf/sugarpdf_config.php')){
  38. require_once('custom/include/Sugarpdf/sugarpdf_config.php');
  39. } else {
  40. require_once('include/Sugarpdf/sugarpdf_config.php');
  41. }
  42. require_once('include/tcpdf/tcpdf.php');
  43. require_once('include/Sugarpdf/SugarpdfHelper.php');
  44. class Sugarpdf extends TCPDF
  45. {
  46. /**
  47. * Stretch options constants
  48. */
  49. const STRETCH_NONE = 0;
  50. const STRETCH_SCALE = 1;
  51. const STRETCH_SCALE_FORCED = 2;
  52. const STRETCH_SPACING = 3;
  53. const STRETCH_SPACING_FORCED = 4;
  54. /**
  55. * This array is meant to hold an objects/data that we would like to pass between
  56. * the controller and the view. The bean will automatically be set for us, but this
  57. * is meant to hold anything else.
  58. */
  59. var $sugarpdf_object_map = array();
  60. /**
  61. * The name of the current module.
  62. */
  63. var $module = '';
  64. /**
  65. * The name of the current action.
  66. */
  67. var $action = '';
  68. /**
  69. */
  70. var $bean = null;
  71. /**
  72. * Any errors that occured this can either be set by the view or the controller or the model
  73. */
  74. var $errors = array();
  75. /**
  76. * Use to set the filename of the output pdf file.
  77. */
  78. var $fileName = PDF_FILENAME;
  79. /**
  80. * Use for the ACL access.
  81. */
  82. var $aclAction = PDF_ACL_ACCESS;
  83. /**
  84. * Constructor which will peform the setup.
  85. */
  86. function __construct($bean = null, $sugarpdf_object_map = array(),$orientation=PDF_PAGE_ORIENTATION, $unit=PDF_UNIT, $format=PDF_PAGE_FORMAT, $unicode=true, $encoding='UTF-8', $diskcache=false){
  87. global $locale;
  88. // $encoding = $locale->getExportCharset();
  89. if(empty($encoding)){
  90. $encoding = "UTF-8";
  91. }
  92. parent::__construct($orientation,$unit,$format,$unicode,$encoding,$diskcache);
  93. $this->module = $GLOBALS['module'];
  94. $this->bean = $bean;
  95. $this->sugarpdf_object_map = $sugarpdf_object_map;
  96. if(!empty($_REQUEST["sugarpdf"])){
  97. $this->action = $_REQUEST["sugarpdf"];
  98. }
  99. }
  100. /**
  101. * This method will be called from the controller and is not meant to be overridden.
  102. */
  103. function process(){
  104. $this->preDisplay();
  105. $this->display();
  106. }
  107. /**
  108. * This method will display the errors on the page.
  109. */
  110. function displayErrors(){
  111. foreach($this->errors as $error) {
  112. echo '<span class="error">' . $error . '</span><br>';
  113. }
  114. }
  115. /**
  116. * [OVERRIDE] - This method is meant to overidden in a subclass. The purpose of this method is
  117. * to allow a view to do some preprocessing before the display method is called. This becomes
  118. * useful when you have a view defined at the application level and then within a module
  119. * have a sub-view that extends from this application level view. The application level
  120. * view can do the setup in preDisplay() that is common to itself and any subviews
  121. * and then the subview can just override display(). If it so desires, can also override
  122. * preDisplay().
  123. */
  124. function preDisplay(){
  125. // set document information
  126. $this->SetCreator(PDF_CREATOR);
  127. $this->SetAuthor(PDF_AUTHOR);
  128. $this->SetTitle(PDF_TITLE);
  129. $this->SetSubject(PDF_SUBJECT);
  130. $this->SetKeywords(PDF_KEYWORDS);
  131. // set other properties
  132. $compression=false;
  133. if(PDF_COMPRESSION == "on"){
  134. $compression=true;
  135. }
  136. $this->SetCompression($compression);
  137. $protection=array();
  138. if(PDF_PROTECTION != ""){
  139. $protection=explode(",",PDF_PROTECTION);
  140. }
  141. $this->SetProtection($protection,blowfishDecode(blowfishGetKey('sugarpdf_pdf_user_password'), PDF_USER_PASSWORD),blowfishDecode(blowfishGetKey('sugarpdf_pdf_owner_password'), PDF_OWNER_PASSWORD));
  142. $this->setCellHeightRatio(K_CELL_HEIGHT_RATIO);
  143. $this->setJPEGQuality(intval(PDF_JPEG_QUALITY));
  144. $this->setPDFVersion(PDF_PDF_VERSION);
  145. // set default header data
  146. $this->setHeaderData(PDF_HEADER_LOGO, PDF_HEADER_LOGO_WIDTH, PDF_HEADER_TITLE, PDF_HEADER_STRING);
  147. // set header and footer fonts
  148. $this->setHeaderFont(Array(PDF_FONT_NAME_MAIN, '', PDF_FONT_SIZE_MAIN));
  149. $this->setFooterFont(Array(PDF_FONT_NAME_DATA, '', PDF_FONT_SIZE_DATA));
  150. //set margins
  151. $this->SetMargins(PDF_MARGIN_LEFT, PDF_MARGIN_TOP, PDF_MARGIN_RIGHT);
  152. $this->setHeaderMargin(PDF_MARGIN_HEADER);
  153. $this->setFooterMargin(PDF_MARGIN_FOOTER);
  154. //set auto page breaks
  155. $this->SetAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM);
  156. //set image scale factor
  157. $this->setImageScale(PDF_IMAGE_SCALE_RATIO);
  158. //set some language-dependent strings
  159. //$this->setLanguageArray($l);
  160. // ---------------------------------------------------------
  161. }
  162. /**
  163. * [OVERRIDE] - This method is meant to overidden in a subclass.
  164. */
  165. function display(){
  166. $this->AddPage();
  167. $this->SetFont(PDF_FONT_NAME_MAIN,'B',16);
  168. $this->MultiCell(0,0,'Tcpdf class for this module and action has not been implemented.',0,'C');
  169. $this->Info();
  170. }
  171. /**
  172. * [OVERRIDE]
  173. * This method override the regular Header() method to enable the custom image directory in addition to the OOB image directory.
  174. * This method is used to render the page header.
  175. * It is automatically called by AddPage().
  176. * @access public
  177. * @see include/tcpdf/TCPDF#Header()
  178. */
  179. public function Header() {
  180. $ormargins = $this->getOriginalMargins();
  181. $headerfont = $this->getHeaderFont();
  182. $headerdata = $this->getHeaderData();
  183. if (($headerdata['logo']) AND ($headerdata['logo'] != K_BLANK_IMAGE)) {
  184. // START SUGARPDF
  185. $logo = K_PATH_CUSTOM_IMAGES.$headerdata['logo'];
  186. $imsize = @getimagesize($logo);
  187. if ($imsize === FALSE) {
  188. // encode spaces on filename
  189. $logo = str_replace(' ', '%20', $logo);
  190. $imsize = @getimagesize($logo);
  191. if ($imsize === FALSE) {
  192. $logo = K_PATH_IMAGES.$headerdata['logo'];
  193. }
  194. }
  195. // END SUGARPDF
  196. $this->Image($logo, $this->GetX(), $this->getHeaderMargin(), $headerdata['logo_width']);
  197. $imgy = $this->getImageRBY();
  198. } else {
  199. $imgy = $this->GetY();
  200. }
  201. $cell_height = round(($this->getCellHeightRatio() * $headerfont[2]) / $this->getScaleFactor(), 2);
  202. // set starting margin for text data cell
  203. if ($this->getRTL()) {
  204. $header_x = $ormargins['right'] + ($headerdata['logo_width'] * 1.1);
  205. } else {
  206. $header_x = $ormargins['left'] + ($headerdata['logo_width'] * 1.1);
  207. }
  208. $this->SetTextColor(0, 0, 0);
  209. // header title
  210. $this->SetFont($headerfont[0], 'B', $headerfont[2] + 1);
  211. $this->SetX($header_x);
  212. $this->Cell(0, $cell_height, $headerdata['title'], 0, 1, '', 0, '', 0);
  213. // header string
  214. $this->SetFont($headerfont[0], $headerfont[1], $headerfont[2]);
  215. $this->SetX($header_x);
  216. $this->MultiCell(0, $cell_height, $headerdata['string'], 0, '', 0, 1, '', '', true, 0, false);
  217. // print an ending header line
  218. $this->SetLineStyle(array('width' => 0.85 / $this->getScaleFactor(), 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0)));
  219. $this->SetY((2.835 / $this->getScaleFactor()) + max($imgy, $this->GetY()));
  220. if ($this->getRTL()) {
  221. $this->SetX($ormargins['right']);
  222. } else {
  223. $this->SetX($ormargins['left']);
  224. }
  225. $this->Cell(0, 0, '', 'T', 0, 'C');
  226. }
  227. /**
  228. * [OVERRIDE] SetFont method in TCPDF Library
  229. * This method override the regular SetFont() method to enable the custom font directory in addition to the OOB font directory.
  230. *
  231. * @param string $family Family font. It can be either a name defined by AddFont() or one of the standard Type1 families (case insensitive):<ul><li>times (Times-Roman)</li><li>timesb (Times-Bold)</li><li>timesi (Times-Italic)</li><li>timesbi (Times-BoldItalic)</li><li>helvetica (Helvetica)</li><li>helveticab (Helvetica-Bold)</li><li>helveticai (Helvetica-Oblique)</li><li>helveticabi (Helvetica-BoldOblique)</li><li>courier (Courier)</li><li>courierb (Courier-Bold)</li><li>courieri (Courier-Oblique)</li><li>courierbi (Courier-BoldOblique)</li><li>symbol (Symbol)</li><li>zapfdingbats (ZapfDingbats)</li></ul> It is also possible to pass an empty string. In that case, the current family is retained.
  232. * @param string $style Font style. Possible values are (case insensitive):<ul><li>empty string: regular</li><li>B: bold</li><li>I: italic</li><li>U: underline</li><li>D: line trough</li></ul> 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.
  233. * @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
  234. * @param string $fontfile The font definition file. By default, the name is built from the family and style, in lower case with no spaces.
  235. * @access public
  236. * @see include/tcpdf/TCPDF#SetFont()
  237. */
  238. public function SetFont($family, $style='', $size=0, $fontfile='') {
  239. if(empty($fontfile) && defined('K_PATH_CUSTOM_FONTS')){
  240. // This will force addFont to search the custom directory for font before the OOB directory
  241. $fontfile = K_PATH_CUSTOM_FONTS."phantomFile.phantom";
  242. }
  243. parent::SetFont($family, $style, $size, $fontfile);
  244. }
  245. function Info(){
  246. $this->SetFont(PDF_FONT_NAME_MAIN,'',12);
  247. $this->MultiCell(0,0,'---',0,'L');
  248. $this->MultiCell(0,0,'Class: '.get_class($this),0,'L');
  249. $this->MultiCell(0,0,'Extends: '.get_parent_class($this),0,'L');
  250. $this->MultiCell(0,0,'---',0,'L');
  251. $this->MultiCell(0,0,'Module: '.$this->module,0,'L');
  252. $this->MultiCell(0,0,'Tcpdf Action: '.$this->action,0,'L');
  253. $this->MultiCell(0,0,'Bean ID: '.$this->bean->getFieldValue('id'),0,'L');
  254. $this->SetFont(PDF_FONT_NAME_MAIN,'',12);
  255. $this->MultiCell(0,0,'---',0,'L');
  256. }
  257. /**
  258. * [OVERRIDE] Cell method in tcpdf library.
  259. * Handle charset conversion and HTML entity decode.
  260. * This method override the regular Cell() method to apply the prepare_string() function to
  261. * the string to print in the PDF.
  262. * The cell method is used by all the methods which print text (Write, MultiCell).
  263. * @see include/tcpdf/TCPDF#Cell()
  264. */
  265. public function Cell($w, $h=0, $txt='', $border=0, $ln=0, $align='', $fill=0, $link='', $stretch=0) {
  266. parent::Cell($w, $h, prepare_string($txt), $border, $ln, $align, $fill, $link, $stretch);
  267. }
  268. /**
  269. * This Ln1() method will always print a line break of one line height.
  270. * The regular Ln() method print a line break which has the height of the last printed cell.
  271. */
  272. public function Ln1() {
  273. parent::Ln($this->FontSize * $this->cell_height_ratio + 2 * $this->cMargin, false);
  274. }
  275. /**
  276. * This method allow printing a table using the MultiCell method with a formatted options array in parameter
  277. * Options :
  278. * header options override the regular options for the header's cells - $options['header']
  279. * cell options override the regular options for the specific cell - Array[line number (0 to x)][cell header]['options']
  280. * @param $item Array[line number (0 to x)][cell header] = Cell content OR
  281. * Array[line number (0 to x)][cell header]['value'] = Cell content AND
  282. * Array[line number (0 to x)][cell header]['options'] = Array[cell properties] = values
  283. * @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), stretch (array 'column name'=>stretch type)
  284. * @see MultiCell()
  285. */
  286. public function writeCellTable($item, $options=NULL)
  287. {
  288. // Save initial font values
  289. $fontFamily = $this->getFontFamily();
  290. $fontSize = $this->getFontSizePt();
  291. $fontStyle = $this->getFontStyle();
  292. $this->SetTextColor(0, 0, 0);
  293. $options = $this->initOptionsForWriteCellTable($options, $item);
  294. // HEADER
  295. if(!isset($options['isheader']) || $options['isheader'] == true){
  296. $headerOptions = $options;
  297. if(!empty($options['header']) && is_array($options['header'])){
  298. $headerOptions = $this->initOptionsForWriteCellTable($options['header'], $item);
  299. }
  300. foreach($item[0] as $k => $v){
  301. $header[$k]=$k;
  302. }
  303. $h = $this->getLineHeightFromArray($header, $options["width"]);
  304. foreach ($header as $v)
  305. $this->MultiCell($options["width"][$v],$h,$v,$headerOptions['border'],$headerOptions['align'],$headerOptions['fillstate'],0,'','',true, $options['stretch'][$v], $headerOptions['ishtml']);
  306. $this->SetFillColorArray($this->convertHTMLColorToDec($options['fill']));
  307. $this->Ln();
  308. }
  309. // MAIN
  310. // default font
  311. $this->SetFont($fontFamily,$fontStyle,$fontSize);
  312. $this->SetTextColor(0, 0, 0);
  313. $even=true;
  314. $firstrow = true;
  315. // LINES
  316. foreach($item as $k=>$line){
  317. $even=!$even;
  318. $h = $this->getLineHeightFromArray($line, $options["width"]);
  319. // in the case when cell height is greater than page height
  320. // need to adjust the current page number
  321. // so the following output will not overlap the previous output
  322. if ($this->getNumPages() != $this->getPage()) {
  323. $this->setPage($this->getNumPages());
  324. }
  325. $firstcell = true;
  326. //CELLS
  327. foreach($line as $kk=>$cell){
  328. $cellOptions = $options;
  329. $value = $cell;
  330. if(is_array($cell)){
  331. $value = $cell['value'];
  332. if(!empty($cell['options']) && is_array($cell['options'])){
  333. $cellOptions = $this->initOptionsForWriteCellTable($cell['options'], $item);
  334. }
  335. }
  336. //Bug45077-replacing single quote entities
  337. $value=str_replace("&#039;","'",$value);
  338. //Bug45077-replacing double quote entities
  339. $value=str_replace("&quot;",'"',$value);
  340. if($even && !empty($options['evencolor'])){
  341. $this->SetFillColorArray($this->convertHTMLColorToDec($options['evencolor']));
  342. $cellOptions['fillstate']=1;
  343. }else if(!$even && !empty($options['oddcolor'])){
  344. $this->SetFillColorArray($this->convertHTMLColorToDec($options['oddcolor']));
  345. $cellOptions['fillstate']=1;
  346. }
  347. if ($firstrow) {
  348. $this->MultiCell($options["width"][$kk],$h,$value,$cellOptions['border'],$cellOptions['align'],$cellOptions['fillstate'],0,'','',true, $options['stretch'][$kk], $cellOptions['ishtml'], true, 0, false);
  349. } else {
  350. if ($firstcell) {
  351. // add page only once (for the first cell)
  352. $this->MultiCell($options["width"][$kk],$h,$value,$cellOptions['border'],$cellOptions['align'],$cellOptions['fillstate'],0,'','',true,0,$cellOptions['ishtml'], true, 0, true);
  353. $firstcell = false;
  354. } else {
  355. $this->MultiCell($options["width"][$kk],$h,$value,$cellOptions['border'],$cellOptions['align'],$cellOptions['fillstate'],0,'','',true,0,$cellOptions['ishtml'], true, 0, false);
  356. }
  357. }
  358. $this->SetFillColorArray($this->convertHTMLColorToDec($options['fill']));
  359. }
  360. $this->Ln();
  361. $firstrow = false;
  362. }
  363. $this->SetFont($fontFamily,$fontStyle,$fontSize);
  364. $this->SetTextColor(0, 0, 0);
  365. }
  366. /**
  367. * This method allow printing a table using the writeHTML method with a formatted array in parameter
  368. * This method can also return the table as HTML code
  369. * @param $item Array[line number (0 to x)][cell header] = Cell content OR
  370. * Array[line number (0 to x)][cell header]['value'] = Cell content AND
  371. * Array[line number (0 to x)][cell header]['options'] = Array[cell properties] = values
  372. * @param $returnHtml (bool) Return the table as HTML code instead of printing the HTML table
  373. * @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')
  374. * @return the HTML code if $returnHtml set to true
  375. */
  376. public function writeHTMLTable($item, $returnHtml=false, $options=NULL){
  377. //TODO ISSUE - width in % for the td have to be multiply by the number of column.
  378. // ex: for a width of 20% in a table of 6 columns the width will have to be 120% (20*6).
  379. $html="";
  380. $line="";
  381. if(!empty($options)){
  382. foreach($options as $k=>$v){
  383. $tmp[strtolower($k)]=$v;
  384. }
  385. $options=$tmp;
  386. }else{
  387. $options=array();
  388. }
  389. if(!isset($options["isheader"]) || $options["isheader"] == true){
  390. if(!empty($options["header"])){
  391. foreach($options["header"] as $k=>$v){
  392. $tmp[strtolower($k)]=$v;
  393. }
  394. $options["header"]=$tmp;
  395. }else{
  396. $options["header"]=array("tr"=>array("bgcolor"=>"#DCDCDC"),"td"=>array());
  397. }
  398. foreach($item[0] as $k => $v){
  399. if(!empty($options["width"]))$options["header"]["td"]["width"]=$options["width"][$k];
  400. $line.=$this->wrap("td", $k, $options["header"]);
  401. }
  402. $html.=$this->wrap("tr", $line, $options["header"]);
  403. }
  404. foreach ($item as $k=>$v){
  405. $line="";
  406. foreach($v as $kk => $vv){
  407. if(!empty($options["width"]) && isset($options["width"][$kk]))$options["td"]["width"]=$options["width"][$kk];
  408. $line.=$this->wrap("td", $vv, $options);
  409. }
  410. $html.=$this->wrap("tr", $line, $options);
  411. }
  412. $html=$this->wrap("table", $html, $options);
  413. if($returnHtml){
  414. return $html;
  415. }else{
  416. $this->writeHTML($html);
  417. }
  418. }
  419. /**
  420. * return the HTML code of the value wrap with the tag $tag. This method handle options (general and specific)
  421. * @param $tag
  422. * @param $value
  423. * @param $options
  424. * @return the HTML wrapped code
  425. */
  426. private function wrap($tag, $value, $options){
  427. if(empty($options[$tag])){
  428. $options[$tag] = array();
  429. }
  430. if(is_array($value)){
  431. if(isset($value["options"])){
  432. // The options of a specific entity overwrite the general options
  433. $options[$tag] = $value["options"];
  434. }
  435. if(isset($value["value"])){
  436. $value = $value["value"];
  437. }else{
  438. $value = "";
  439. }
  440. }
  441. return wrapTag($tag, $value, $options[$tag]);
  442. }
  443. /**
  444. * Return the heigth of a line depending of the width, the font and the content
  445. * @param $line Array containing the data of all the cells of the line
  446. * @param $width Array containing the width of all the cells of the line
  447. * @return The heigth of the line
  448. */
  449. private function getLineHeightFromArray($line, $width){
  450. $h=0;
  451. foreach($line as $kk=>$cell){
  452. $cellValue = $cell;
  453. if(is_array($cellValue)){
  454. $tmp = $cellValue['value'];
  455. $cellValue = $tmp;
  456. }
  457. if($h<$this->getNumLines($cellValue, $width[$kk])){
  458. $h=$this->getNumLines($cellValue, $width[$kk]);
  459. }
  460. }
  461. return $h * $this->FontSize * $this->cell_height_ratio + 2 * $this->cMargin;
  462. }
  463. /**
  464. * Private method for writeCellTable which format and initialize the options array.
  465. * @param $options array
  466. * @param $item array
  467. * @return $options array
  468. */
  469. private function initOptionsForWriteCellTable($options, $item){
  470. if(!empty($options)){
  471. foreach($options as $k=>$v){
  472. $tmp[strtolower($k)]=$v;
  473. }
  474. $options=$tmp;
  475. }else{
  476. $options=array();
  477. }
  478. // set to default if empty
  479. if(empty($options["width"]) || !is_array($options["width"])){
  480. $colNum = count($item[0]);
  481. $defaultWidth = $this->getRemainingWidth()/$colNum;
  482. foreach($item[0] as $k => $v){
  483. $options["width"][$k]=$defaultWidth;
  484. }
  485. }else{
  486. foreach($options["width"] as $k => $v){
  487. $options["width"][$k] = $this->getHTMLUnitToUnits($v, $this->getRemainingWidth());
  488. }
  489. }
  490. if(empty($options["border"])){
  491. $options["border"]=0;
  492. }
  493. if(empty($options["align"])){
  494. $options["align"]="L";
  495. }
  496. if(empty($options['ishtml'])){
  497. $options['ishtml'] = false;
  498. }
  499. if(empty($options['border'])){
  500. $options['border'] = 0;
  501. }
  502. foreach($item[0] as $k => $v)
  503. if (empty($options['stretch'][$k]))
  504. $options['stretch'][$k] = self::STRETCH_NONE;
  505. if(!empty($options['fill'])){
  506. $this->SetFillColorArray($this->convertHTMLColorToDec($options['fill']));
  507. $options['fillstate']=1;
  508. }else{
  509. $options['fill']="#FFFFFF";//white
  510. $options['fillstate']=0;
  511. }
  512. if(!empty($options['fontfamily'])){
  513. $fontFamily = $options['fontfamily'];
  514. }else{
  515. $fontFamily = $this->getFontFamily();
  516. }
  517. if(!empty($options['fontsize'])){
  518. $fontSize = $options['fontsize'];
  519. }else{
  520. $fontSize = $this->getFontSizePt();
  521. }
  522. if(!empty($options['fontstyle'])){
  523. $fontStyle = $options['fontstyle'];
  524. }else{
  525. $fontStyle = $this->getFontStyle();
  526. }
  527. if(!empty($options['textcolor'])){
  528. $this->SetTextColorArray($this->convertHTMLColorToDec($options['textcolor']));
  529. }else{
  530. $this->SetTextColor(0, 0, 0);//black
  531. }
  532. $this->SetFont($fontFamily, $fontStyle, $fontSize);
  533. return $options;
  534. }
  535. /**
  536. * This is method is fix for a better handling of the count. This method now handle the line break
  537. * between words.
  538. * This method returns the estimated number of lines required to print the text.
  539. * @param string $txt text to print
  540. * @param float $w width of cell. If 0, they extend up to the right margin of the page.
  541. * @return int Return the estimated number of lines.
  542. * @access public
  543. * @since 4.5.011
  544. * @OVERRIDE
  545. */
  546. public function getNumLines($txt, $w=0) {
  547. $lines = 0;
  548. if (empty($w) OR ($w <= 0)) {
  549. if ($this->rtl) {
  550. $w = $this->x - $this->lMargin;
  551. } else {
  552. $w = $this->w - $this->rMargin - $this->x;
  553. }
  554. }
  555. // max column width
  556. $wmax = $w - (2 * $this->cMargin);
  557. // remove carriage returns
  558. $txt = str_replace("\r", '', $txt);
  559. // divide text in blocks
  560. $txtblocks = explode("\n", $txt);
  561. // for each block;
  562. foreach ($txtblocks as $block) {
  563. // estimate the number of lines
  564. if(empty($block)){
  565. $lines++;
  566. // If the block is in more than one line
  567. }else if(ceil($this->GetStringWidth($block) / $wmax)>1){
  568. //divide into words
  569. $words = explode(" ", $block);
  570. //TODO explode with space is not the best things to do...
  571. $wordBlock = "";
  572. $first=true;
  573. $lastNum = 0;
  574. $run = false;
  575. for($i=0; $i<count($words); $i++){
  576. if($first){
  577. $wordBlock = $words[$i];
  578. }else{
  579. $wordBlock .= " ".$words[$i];
  580. }
  581. if(ceil($this->GetStringWidth($wordBlock) / $wmax)>1){
  582. if($first){
  583. $lastNum = ceil($this->GetStringWidth($wordBlock) / $wmax);
  584. $run = true;
  585. $first = false;
  586. }else{
  587. if($run && $lastNum == ceil($this->GetStringWidth($wordBlock) / $wmax)){
  588. // save the number of line if it is the last loop
  589. if($i+1 == count($words)){
  590. $lines += ceil($this->GetStringWidth($wordBlock) / $wmax);
  591. }
  592. continue;
  593. }else{
  594. $first = true;
  595. $lines += ceil($this->GetStringWidth( substr($wordBlock, 0, (strlen($wordBlock) - strlen(" ".$words[$i]))) ) / $wmax);
  596. $i--;
  597. $lastNum = 0;
  598. $run = false;
  599. }
  600. }
  601. }else{
  602. $first = false;
  603. }
  604. // save the number of line if it is the last loop
  605. if($i+1 == count($words)){
  606. $lines += ceil($this->GetStringWidth($wordBlock) / $wmax);
  607. }
  608. }
  609. }else{
  610. $lines++;
  611. }
  612. }
  613. return $lines;
  614. }
  615. /**
  616. * Disable zlib output compression if we are downloading the PDF.
  617. *
  618. * @see TCPDF::Output()
  619. */
  620. public function Output($name='doc.pdf', $dest='I')
  621. {
  622. if ( $dest == 'I' || $dest == 'D') {
  623. ini_set('zlib.output_compression', 'Off');
  624. }
  625. return parent::Output($name,$dest);
  626. }
  627. }