PageRenderTime 75ms CodeModel.GetById 20ms RepoModel.GetById 8ms app.codeStats 1ms

/application/helpers/dompdf/include/cpdf_adapter.cls.php

https://bitbucket.org/hlevine/myclientbase-south-african-version
PHP | 902 lines | 347 code | 142 blank | 413 comment | 38 complexity | 55d705e3e52b92acb9ed6d11dd117217 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.1, GPL-2.0
  1. <?php
  2. /**
  3. * DOMPDF - PHP5 HTML to PDF renderer
  4. *
  5. * File: $RCSfile: cpdf_adapter.cls.php,v $
  6. * Created on: 2004-08-04
  7. * Modified on: 2008-01-05
  8. *
  9. * Copyright (c) 2004 - Benj Carson <benjcarson@digitaljunkies.ca>
  10. * Portions copyright (c) 2008 - Orion Richardson <orionr@yahoo.com>
  11. *
  12. * This library is free software; you can redistribute it and/or
  13. * modify it under the terms of the GNU Lesser General Public
  14. * License as published by the Free Software Foundation; either
  15. * version 2.1 of the License, or (at your option) any later version.
  16. *
  17. * This library is distributed in the hope that it will be useful,
  18. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  20. * Lesser General Public License for more details.
  21. *
  22. * You should have received a copy of the GNU Lesser General Public License
  23. * along with this library in the file LICENSE.LGPL; if not, write to the
  24. * Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
  25. * 02111-1307 USA
  26. *
  27. * Alternatively, you may distribute this software under the terms of the
  28. * PHP License, version 3.0 or later. A copy of this license should have
  29. * been distributed with this file in the file LICENSE.PHP . If this is not
  30. * the case, you can obtain a copy at http://www.php.net/license/3_0.txt.
  31. *
  32. * The latest version of DOMPDF might be available at:
  33. * http://www.digitaljunkies.ca/dompdf
  34. *
  35. * @link http://www.digitaljunkies.ca/dompdf
  36. * @copyright 2004 Benj Carson
  37. * @author Benj Carson <benjcarson@digitaljunkies.ca>
  38. * @contributor Orion Richardson <orionr@yahoo.com>
  39. * @contributor Helmut Tischer <htischer@weihenstephan.org>
  40. * @package dompdf
  41. * @version 0.5.1
  42. *
  43. * Changes
  44. * @contributor Helmut Tischer <htischer@weihenstephan.org>
  45. * @version 0.5.1.htischer.20090507
  46. * - On gif to png conversion tmp file creation, clarify tmp name and add to tmp deletion list only on success
  47. * - On gif to png conversion, when available add direct from gd without tmp file, skip image load if already cached.
  48. * to safe CPU time and memory
  49. * @contributor Helmut Tischer <htischer@weihenstephan.org>
  50. * @version dompdf_trunk_with_helmut_mods.20090524
  51. * - Pass temp and fontcache folders to Cpdf, to making Cpdf independent from dompdf
  52. * @version dompdf_trunk_with_helmut_mods.20090528
  53. * - fix text position according to glyph baseline to match background rectangle
  54. */
  55. /* $Id: cpdf_adapter.cls.php,v 1.22 2009-04-29 04:11:35 benjcarson Exp $ */
  56. // FIXME: Need to sanity check inputs to this class
  57. require_once(DOMPDF_LIB_DIR . "/class.pdf.php");
  58. /**
  59. * PDF rendering interface
  60. *
  61. * CPDF_Adapter provides a simple stateless interface to the stateful one
  62. * provided by the Cpdf class.
  63. *
  64. * Unless otherwise mentioned, all dimensions are in points (1/72 in). The
  65. * coordinate origin is in the top left corner, and y values increase
  66. * downwards.
  67. *
  68. * See {@link http://www.ros.co.nz/pdf/} for more complete documentation
  69. * on the underlying {@link Cpdf} class.
  70. *
  71. * @package dompdf
  72. */
  73. class CPDF_Adapter implements Canvas {
  74. /**
  75. * Dimensions of paper sizes in points
  76. *
  77. * @var array;
  78. */
  79. static $PAPER_SIZES = array("4a0" => array(0,0,4767.87,6740.79),
  80. "2a0" => array(0,0,3370.39,4767.87),
  81. "a0" => array(0,0,2383.94,3370.39),
  82. "a1" => array(0,0,1683.78,2383.94),
  83. "a2" => array(0,0,1190.55,1683.78),
  84. "a3" => array(0,0,841.89,1190.55),
  85. "a4" => array(0,0,595.28,841.89),
  86. "a5" => array(0,0,419.53,595.28),
  87. "a6" => array(0,0,297.64,419.53),
  88. "a7" => array(0,0,209.76,297.64),
  89. "a8" => array(0,0,147.40,209.76),
  90. "a9" => array(0,0,104.88,147.40),
  91. "a10" => array(0,0,73.70,104.88),
  92. "b0" => array(0,0,2834.65,4008.19),
  93. "b1" => array(0,0,2004.09,2834.65),
  94. "b2" => array(0,0,1417.32,2004.09),
  95. "b3" => array(0,0,1000.63,1417.32),
  96. "b4" => array(0,0,708.66,1000.63),
  97. "b5" => array(0,0,498.90,708.66),
  98. "b6" => array(0,0,354.33,498.90),
  99. "b7" => array(0,0,249.45,354.33),
  100. "b8" => array(0,0,175.75,249.45),
  101. "b9" => array(0,0,124.72,175.75),
  102. "b10" => array(0,0,87.87,124.72),
  103. "c0" => array(0,0,2599.37,3676.54),
  104. "c1" => array(0,0,1836.85,2599.37),
  105. "c2" => array(0,0,1298.27,1836.85),
  106. "c3" => array(0,0,918.43,1298.27),
  107. "c4" => array(0,0,649.13,918.43),
  108. "c5" => array(0,0,459.21,649.13),
  109. "c6" => array(0,0,323.15,459.21),
  110. "c7" => array(0,0,229.61,323.15),
  111. "c8" => array(0,0,161.57,229.61),
  112. "c9" => array(0,0,113.39,161.57),
  113. "c10" => array(0,0,79.37,113.39),
  114. "ra0" => array(0,0,2437.80,3458.27),
  115. "ra1" => array(0,0,1729.13,2437.80),
  116. "ra2" => array(0,0,1218.90,1729.13),
  117. "ra3" => array(0,0,864.57,1218.90),
  118. "ra4" => array(0,0,609.45,864.57),
  119. "sra0" => array(0,0,2551.18,3628.35),
  120. "sra1" => array(0,0,1814.17,2551.18),
  121. "sra2" => array(0,0,1275.59,1814.17),
  122. "sra3" => array(0,0,907.09,1275.59),
  123. "sra4" => array(0,0,637.80,907.09),
  124. "letter" => array(0,0,612.00,792.00),
  125. "legal" => array(0,0,612.00,1008.00),
  126. "ledger" => array(0,0,1224.00, 792.00),
  127. "tabloid" => array(0,0,792.00, 1224.00),
  128. "executive" => array(0,0,521.86,756.00),
  129. "folio" => array(0,0,612.00,936.00),
  130. "commerical #10 envelope" => array(0,0,684,297),
  131. "catalog #10 1/2 envelope" => array(0,0,648,864),
  132. "8.5x11" => array(0,0,612.00,792.00),
  133. "8.5x14" => array(0,0,612.00,1008.0),
  134. "11x17" => array(0,0,792.00, 1224.00));
  135. /**
  136. * Instance of Cpdf class
  137. *
  138. * @var Cpdf
  139. */
  140. private $_pdf;
  141. /**
  142. * PDF width, in points
  143. *
  144. * @var float
  145. */
  146. private $_width;
  147. /**
  148. * PDF height, in points
  149. *
  150. * @var float;
  151. */
  152. private $_height;
  153. /**
  154. * Current page number
  155. *
  156. * @var int
  157. */
  158. private $_page_number;
  159. /**
  160. * Total number of pages
  161. *
  162. * @var int
  163. */
  164. private $_page_count;
  165. /**
  166. * Text to display on every page
  167. *
  168. * @var array
  169. */
  170. private $_page_text;
  171. /**
  172. * Array of pages for accesing after rendering is initially complete
  173. *
  174. * @var array
  175. */
  176. private $_pages;
  177. /**
  178. * Array of temporary cached images to be deleted when processing is complete
  179. *
  180. * @var array
  181. */
  182. private $_image_cache;
  183. /**
  184. * Class constructor
  185. *
  186. * @param mixed $paper The size of paper to use in this PDF ({@link CPDF_Adapter::$PAPER_SIZES})
  187. * @param string $orientation The orienation of the document (either 'landscape' or 'portrait')
  188. */
  189. function __construct($paper = "letter", $orientation = "portrait") {
  190. if ( is_array($paper) )
  191. $size = $paper;
  192. else if ( isset(self::$PAPER_SIZES[mb_strtolower($paper)]) )
  193. $size = self::$PAPER_SIZES[mb_strtolower($paper)];
  194. else
  195. $size = self::$PAPER_SIZES["letter"];
  196. if ( mb_strtolower($orientation) == "landscape" ) {
  197. $a = $size[3];
  198. $size[3] = $size[2];
  199. $size[2] = $a;
  200. }
  201. $this->_pdf = new Cpdf($size, false, DOMPDF_FONT_CACHE, DOMPDF_TEMP_DIR);
  202. $this->_pdf->addInfo("Creator", "dompdf");
  203. // Silence pedantic warnings about missing TZ settings
  204. if ( function_exists("date_default_timezone_get") ) {
  205. $tz = @date_default_timezone_get();
  206. date_default_timezone_set("UTC");
  207. $this->_pdf->addInfo("CreationDate", date("Y-m-d"));
  208. date_default_timezone_set($tz);
  209. } else {
  210. $this->_pdf->addInfo("CreationDate", date("Y-m-d"));
  211. }
  212. $this->_width = $size[2] - $size[0];
  213. $this->_height= $size[3] - $size[1];
  214. $this->_pdf->openHere('Fit');
  215. $this->_page_number = $this->_page_count = 1;
  216. $this->_page_text = array();
  217. $this->_pages = array($this->_pdf->getFirstPageId());
  218. $this->_image_cache = array();
  219. }
  220. /**
  221. * Class destructor
  222. *
  223. * Deletes all temporary image files
  224. */
  225. function __destruct() {
  226. foreach ($this->_image_cache as $img) {
  227. //debugpng
  228. if (DEBUGPNG) print '[__destruct unlink '.$img.']';
  229. if (!DEBUGKEEPTEMP)
  230. unlink($img);
  231. }
  232. }
  233. /**
  234. * Returns the Cpdf instance
  235. *
  236. * @return Cpdf
  237. */
  238. function get_cpdf() { return $this->_pdf; }
  239. /**
  240. * Add meta information to the PDF
  241. *
  242. * @param string $label label of the value (Creator, Producter, etc.)
  243. * @param string $value the text to set
  244. */
  245. function add_info($label, $value) {
  246. $this->_pdf->addInfo($label, $value);
  247. }
  248. /**
  249. * Opens a new 'object'
  250. *
  251. * While an object is open, all drawing actions are recored in the object,
  252. * as opposed to being drawn on the current page. Objects can be added
  253. * later to a specific page or to several pages.
  254. *
  255. * The return value is an integer ID for the new object.
  256. *
  257. * @see CPDF_Adapter::close_object()
  258. * @see CPDF_Adapter::add_object()
  259. *
  260. * @return int
  261. */
  262. function open_object() {
  263. $ret = $this->_pdf->openObject();
  264. $this->_pdf->saveState();
  265. return $ret;
  266. }
  267. /**
  268. * Reopens an existing 'object'
  269. *
  270. * @see CPDF_Adapter::open_object()
  271. * @param int $object the ID of a previously opened object
  272. */
  273. function reopen_object($object) {
  274. $this->_pdf->reopenObject($object);
  275. $this->_pdf->saveState();
  276. }
  277. /**
  278. * Closes the current 'object'
  279. *
  280. * @see CPDF_Adapter::open_object()
  281. */
  282. function close_object() {
  283. $this->_pdf->restoreState();
  284. $this->_pdf->closeObject();
  285. }
  286. /**
  287. * Adds a specified 'object' to the document
  288. *
  289. * $object int specifying an object created with {@link
  290. * CPDF_Adapter::open_object()}. $where can be one of:
  291. * - 'add' add to current page only
  292. * - 'all' add to every page from the current one onwards
  293. * - 'odd' add to all odd numbered pages from now on
  294. * - 'even' add to all even numbered pages from now on
  295. * - 'next' add the object to the next page only
  296. * - 'nextodd' add to all odd numbered pages from the next one
  297. * - 'nexteven' add to all even numbered pages from the next one
  298. *
  299. * @see Cpdf::addObject()
  300. *
  301. * @param int $object
  302. * @param string $where
  303. */
  304. function add_object($object, $where = 'all') {
  305. $this->_pdf->addObject($object, $where);
  306. }
  307. /**
  308. * Stops the specified 'object' from appearing in the document.
  309. *
  310. * The object will stop being displayed on the page following the current
  311. * one.
  312. *
  313. * @param int $object
  314. */
  315. function stop_object($object) {
  316. $this->_pdf->stopObject($object);
  317. }
  318. /**
  319. * @access private
  320. */
  321. function serialize_object($id) {
  322. // Serialize the pdf object's current state for retrieval later
  323. return $this->_pdf->serializeObject($id);
  324. }
  325. /**
  326. * @access private
  327. */
  328. function reopen_serialized_object($obj) {
  329. return $this->_pdf->restoreSerializedObject($obj);
  330. }
  331. //........................................................................
  332. /**
  333. * Returns the PDF's width in points
  334. * @return float
  335. */
  336. function get_width() { return $this->_width; }
  337. /**
  338. * Returns the PDF's height in points
  339. * @return float
  340. */
  341. function get_height() { return $this->_height; }
  342. /**
  343. * Returns the current page number
  344. * @return int
  345. */
  346. function get_page_number() { return $this->_page_number; }
  347. /**
  348. * Returns the total number of pages in the document
  349. * @return int
  350. */
  351. function get_page_count() { return $this->_page_count; }
  352. /**
  353. * Sets the current page number
  354. *
  355. * @param int $num
  356. */
  357. function set_page_number($num) { $this->_page_number = $num; }
  358. /**
  359. * Sets the page count
  360. *
  361. * @param int $count
  362. */
  363. function set_page_count($count) { $this->_page_count = $count; }
  364. /**
  365. * Sets the stroke colour
  366. *
  367. * See {@link Style::set_colour()} for the format of the color array.
  368. * @param array $color
  369. */
  370. protected function _set_stroke_color($color) {
  371. list($r, $g, $b) = $color;
  372. $this->_pdf->setStrokeColor($r, $g, $b);
  373. }
  374. /**
  375. * Sets the fill colour
  376. *
  377. * See {@link Style::set_colour()} for the format of the colour array.
  378. * @param array $color
  379. */
  380. protected function _set_fill_color($color) {
  381. list($r, $g, $b) = $color;
  382. $this->_pdf->setColor($r, $g, $b);
  383. }
  384. /**
  385. * Sets line transparency
  386. * @see Cpdf::setLineTransparency()
  387. *
  388. * Valid blend modes are (case-sensitive):
  389. *
  390. * Normal, Multiply, Screen, Overlay, Darken, Lighten,
  391. * ColorDodge, ColorBurn, HardLight, SoftLight, Difference,
  392. * Exclusion
  393. *
  394. * @param string $mode the blending mode to use
  395. * @param float $opacity 0.0 fully transparent, 1.0 fully opaque
  396. */
  397. protected function _set_line_transparency($mode, $opacity) {
  398. $this->_pdf->setLineTransparency($mode, $opacity);
  399. }
  400. /**
  401. * Sets fill transparency
  402. * @see Cpdf::setFillTransparency()
  403. *
  404. * Valid blend modes are (case-sensitive):
  405. *
  406. * Normal, Multiply, Screen, Overlay, Darken, Lighten,
  407. * ColorDogde, ColorBurn, HardLight, SoftLight, Difference,
  408. * Exclusion
  409. *
  410. * @param string $mode the blending mode to use
  411. * @param float $opacity 0.0 fully transparent, 1.0 fully opaque
  412. */
  413. protected function _set_fill_transparency($mode, $opacity) {
  414. $this->_pdf->setFillTransparency($mode, $opacity);
  415. }
  416. /**
  417. * Sets the line style
  418. *
  419. * @see Cpdf::setLineStyle()
  420. *
  421. * @param float width
  422. * @param string cap
  423. * @param string join
  424. * @param array dash
  425. */
  426. protected function _set_line_style($width, $cap, $join, $dash) {
  427. $this->_pdf->setLineStyle($width, $cap, $join, $dash);
  428. }
  429. //........................................................................
  430. /**
  431. * Remaps y coords from 4th to 1st quadrant
  432. *
  433. * @param float $y
  434. * @return float
  435. */
  436. protected function y($y) { return $this->_height - $y; }
  437. // Canvas implementation
  438. function line($x1, $y1, $x2, $y2, $color, $width, $style = array(),
  439. $blend = "Normal", $opacity = 1.0) {
  440. //pre_r(compact("x1", "y1", "x2", "y2", "color", "width", "style"));
  441. $this->_set_stroke_color($color);
  442. $this->_set_line_style($width, "butt", "", $style);
  443. $this->_set_line_transparency($blend, $opacity);
  444. $this->_pdf->line($x1, $this->y($y1),
  445. $x2, $this->y($y2));
  446. }
  447. //........................................................................
  448. /**
  449. * Convert a GIF image to a PNG image
  450. *
  451. * @return string The url of the newly converted image
  452. */
  453. protected function _convert_gif_to_png($image_url) {
  454. if ( !function_exists("imagecreatefromgif") ) {
  455. throw new DOMPDF_Exception("Function imagecreatefromgif() not found. Cannot convert gif image: $image_url. Please install the image PHP extension.");
  456. }
  457. $old_err = set_error_handler("record_warnings");
  458. $im = imagecreatefromgif($image_url);
  459. if ( $im ) {
  460. imageinterlace($im, 0);
  461. $filename = tempnam(DOMPDF_TEMP_DIR, "gifdompdf_img_").'.png';
  462. $this->_image_cache[] = $filename;
  463. imagepng($im, $filename);
  464. } else {
  465. $filename = DOMPDF_LIB_DIR . "/res/broken_image.png";
  466. }
  467. restore_error_handler();
  468. return $filename;
  469. }
  470. function rectangle($x1, $y1, $w, $h, $color, $width, $style = array(),
  471. $blend = "Normal", $opacity = 1.0) {
  472. $this->_set_stroke_color($color);
  473. $this->_set_line_style($width, "square", "miter", $style);
  474. $this->_set_line_transparency($blend, $opacity);
  475. $this->_pdf->rectangle($x1, $this->y($y1) - $h, $w, $h);
  476. }
  477. //........................................................................
  478. function filled_rectangle($x1, $y1, $w, $h, $color, $blend = "Normal", $opacity = 1.0) {
  479. $this->_set_fill_color($color);
  480. $this->_set_line_style(1, "square", "miter", array());
  481. $this->_set_line_transparency($blend, $opacity);
  482. $this->_set_fill_transparency($blend, $opacity);
  483. $this->_pdf->filledRectangle($x1, $this->y($y1) - $h, $w, $h);
  484. }
  485. //........................................................................
  486. function polygon($points, $color, $width = null, $style = array(),
  487. $fill = false, $blend = "Normal", $opacity = 1.0) {
  488. $this->_set_fill_color($color);
  489. $this->_set_stroke_color($color);
  490. $this->_set_line_transparency($blend, $opacity);
  491. $this->_set_fill_transparency($blend, $opacity);
  492. if ( !$fill && isset($width) )
  493. $this->_set_line_style($width, "square", "miter", $style);
  494. // Adjust y values
  495. for ( $i = 1; $i < count($points); $i += 2)
  496. $points[$i] = $this->y($points[$i]);
  497. $this->_pdf->polygon($points, count($points) / 2, $fill);
  498. }
  499. //........................................................................
  500. function circle($x, $y, $r1, $color, $width = null, $style = null,
  501. $fill = false, $blend = "Normal", $opacity = 1.0) {
  502. $this->_set_fill_color($color);
  503. $this->_set_stroke_color($color);
  504. $this->_set_line_transparency($blend, $opacity);
  505. $this->_set_fill_transparency($blend, $opacity);
  506. if ( !$fill && isset($width) )
  507. $this->_set_line_style($width, "round", "round", $style);
  508. $this->_pdf->ellipse($x, $this->y($y), $r1, 0, 0, 8, 0, 360, 1, $fill);
  509. }
  510. //........................................................................
  511. function image($img_url, $img_type, $x, $y, $w, $h) {
  512. //debugpng
  513. if (DEBUGPNG) print '[image:'.$img_url.'|'.$img_type.']';
  514. $img_type = mb_strtolower($img_type);
  515. switch ($img_type) {
  516. case "jpeg":
  517. case "jpg":
  518. //debugpng
  519. if (DEBUGPNG) print '!!!jpg!!!';
  520. $this->_pdf->addJpegFromFile($img_url, $x, $this->y($y) - $h, $w, $h);
  521. break;
  522. case "png":
  523. //debugpng
  524. if (DEBUGPNG) print '!!!png!!!';
  525. $this->_pdf->addPngFromFile($img_url, $x, $this->y($y) - $h, $w, $h);
  526. break;
  527. case "gif":
  528. // Convert gifs to pngs
  529. //DEBUG_IMG_TEMP
  530. //if (0) {
  531. if ( method_exists( $this->_pdf, "addImagePng" ) ) {
  532. //debugpng
  533. if (DEBUGPNG) print '!!!gif addImagePng!!!';
  534. //If optimization to direct png creation from gd object is available,
  535. //don't create temp file, but place gd object directly into the pdf
  536. if ( method_exists( $this->_pdf, "image_iscached" ) &&
  537. $this->_pdf->image_iscached($img_url) ) {
  538. //If same image has occured already before, no need to load because
  539. //duplicate will anyway be eliminated.
  540. $img = null;
  541. } else {
  542. $img = @imagecreatefromgif($img_url);
  543. if (!$img) {
  544. return;
  545. }
  546. imageinterlace($img, 0);
  547. }
  548. $this->_pdf->addImagePng($img_url, $x, $this->y($y) - $h, $w, $h, $img);
  549. } else {
  550. //debugpng
  551. if (DEBUGPNG) print '!!!gif addPngFromFile!!!';
  552. $img_url = $this->_convert_gif_to_png($img_url);
  553. $this->_pdf->addPngFromFile($img_url, $x, $this->y($y) - $h, $w, $h);
  554. }
  555. break;
  556. default:
  557. //debugpng
  558. if (DEBUGPNG) print '!!!unknown!!!';
  559. break;
  560. }
  561. return;
  562. }
  563. //........................................................................
  564. function text($x, $y, $text, $font, $size, $color = array(0,0,0),
  565. $adjust = 0, $angle = 0, $blend = "Normal", $opacity = 1.0) {
  566. list($r, $g, $b) = $color;
  567. $this->_pdf->setColor($r, $g, $b);
  568. $this->_set_line_transparency($blend, $opacity);
  569. $this->_set_fill_transparency($blend, $opacity);
  570. $font .= ".afm";
  571. $this->_pdf->selectFont($font);
  572. //Font_Metrics::get_font_height($font, $size) ==
  573. //$this->get_font_height($font, $size) ==
  574. //$this->_pdf->selectFont($font),$this->_pdf->getFontHeight($size)
  575. //- FontBBoxheight+FontHeightOffset, scaled to $size, in pt
  576. //$this->_pdf->getFontDescender($size)
  577. //- Descender scaled to size
  578. //
  579. //$this->_pdf->fonts[$this->_pdf->currentFont] sizes:
  580. //['FontBBox'][0] left, ['FontBBox'][1] bottom, ['FontBBox'][2] right, ['FontBBox'][3] top
  581. //Maximum extent of all glyphs of the font from the baseline point
  582. //['Ascender'] maximum height above baseline except accents
  583. //['Descender'] maximum depth below baseline, negative number means below baseline
  584. //['FontHeightOffset'] manual enhancement of .afm files to trim windows fonts. currently not used.
  585. //Values are in 1/1000 pt for a font size of 1 pt
  586. //
  587. //['FontBBox'][1] should be close to ['Descender']
  588. //['FontBBox'][3] should be close to ['Ascender']+Accents
  589. //in practice, FontBBox values are a little bigger
  590. //
  591. //The text position is referenced to the baseline, not to the lower corner of the FontBBox,
  592. //for what the left,top corner is given.
  593. //FontBBox spans also the background box for the text.
  594. //If the lower corner would be used as reference point, the Descents of the glyphs would
  595. //hang over the background box border.
  596. //Therefore compensate only the extent above the Baseline.
  597. //
  598. //print '<pre>['.$font.','.$size.','.$this->_pdf->getFontHeight($size).','.$this->_pdf->getFontDescender($size).','.$this->_pdf->fonts[$this->_pdf->currentFont]['FontBBox'][3].','.$this->_pdf->fonts[$this->_pdf->currentFont]['FontBBox'][1].','.$this->_pdf->fonts[$this->_pdf->currentFont]['FontHeightOffset'].','.$this->_pdf->fonts[$this->_pdf->currentFont]['Ascender'].','.$this->_pdf->fonts[$this->_pdf->currentFont]['Descender'].']</pre>';
  599. //
  600. //$this->_pdf->addText($x, $this->y($y) - Font_Metrics::get_font_height($font, $size), $size, $text, $angle, $adjust);
  601. //$this->_pdf->addText($x, $this->y($y) - $size, $size, $text, $angle, $adjust);
  602. //$this->_pdf->addText($x, $this->y($y) - $this->_pdf->getFontHeight($size)-$this->_pdf->getFontDescender($size), $size, $text, $angle, $adjust);
  603. $this->_pdf->addText($x, $this->y($y) - ($this->_pdf->fonts[$this->_pdf->currentFont]['FontBBox'][3]*$size)/1000, $size, $text, $angle, $adjust);
  604. }
  605. //........................................................................
  606. /**
  607. * Add a named destination (similar to <a name="foo">...</a> in html)
  608. *
  609. * @param string $anchorname The name of the named destination
  610. */
  611. function add_named_dest($anchorname) {
  612. $this->_pdf->addDestination($anchorname,"Fit");
  613. }
  614. //........................................................................
  615. /**
  616. * Add a link to the pdf
  617. *
  618. * @param string $url The url to link to
  619. * @param float $x The x position of the link
  620. * @param float $y The y position of the link
  621. * @param float $width The width of the link
  622. * @param float $height The height of the link
  623. */
  624. function add_link($url, $x, $y, $width, $height) {
  625. $y = $this->y($y) - $height;
  626. if ( strpos($url, '#') === 0 ) {
  627. // Local link
  628. $name = substr($url,1);
  629. if ( $name )
  630. $this->_pdf->addInternalLink($name, $x, $y, $x + $width, $y + $height);
  631. } else {
  632. $this->_pdf->addLink(rawurldecode($url), $x, $y, $x + $width, $y + $height);
  633. }
  634. }
  635. //........................................................................
  636. function get_text_width($text, $font, $size, $spacing = 0) {
  637. $this->_pdf->selectFont($font);
  638. $ascii = utf8_decode($text);
  639. // // Hack for &nbsp;
  640. // $ascii = str_replace("\xA0", " ", $ascii);
  641. return $this->_pdf->getTextWidth($size, $ascii, $spacing);
  642. }
  643. //........................................................................
  644. function get_font_height($font, $size) {
  645. $this->_pdf->selectFont($font);
  646. return $this->_pdf->getFontHeight($size);
  647. }
  648. //........................................................................
  649. /**
  650. * Writes text at the specified x and y coordinates on every page
  651. *
  652. * The strings '{PAGE_NUM}' and '{PAGE_COUNT}' are automatically replaced
  653. * with their current values.
  654. *
  655. * See {@link Style::munge_colour()} for the format of the colour array.
  656. *
  657. * @param float $x
  658. * @param float $y
  659. * @param string $text the text to write
  660. * @param string $font the font file to use
  661. * @param float $size the font size, in points
  662. * @param array $color
  663. * @param float $adjust word spacing adjustment
  664. * @param float $angle angle to write the text at, measured CW starting from the x-axis
  665. */
  666. function page_text($x, $y, $text, $font, $size, $color = array(0,0,0),
  667. $adjust = 0, $angle = 0) {
  668. $_t = "text";
  669. $this->_page_text[] = compact("_t", "x", "y", "text", "font", "size", "color", "adjust", "angle");
  670. }
  671. //........................................................................
  672. /**
  673. * Processes a script on every page
  674. *
  675. * The variables $pdf, $PAGE_NUM, and $PAGE_COUNT are available.
  676. *
  677. * This function can be used to add page numbers to all pages
  678. * after the first one, for example.
  679. *
  680. * @param string $code the script code
  681. * @param string $type the language type for script
  682. */
  683. function page_script($code, $type = "text/php") {
  684. $_t = "script";
  685. $this->_page_text[] = compact("_t", "code", "type");
  686. }
  687. //........................................................................
  688. function new_page() {
  689. $this->_page_count++;
  690. $ret = $this->_pdf->newPage();
  691. $this->_pages[] = $ret;
  692. return $ret;
  693. }
  694. //........................................................................
  695. /**
  696. * Add text to each page after rendering is complete
  697. */
  698. protected function _add_page_text() {
  699. if ( !count($this->_page_text) )
  700. return;
  701. $page_number = 1;
  702. $eval = null;
  703. foreach ($this->_pages as $pid) {
  704. $this->reopen_object($pid);
  705. foreach ($this->_page_text as $pt) {
  706. extract($pt);
  707. switch ($_t) {
  708. case "text":
  709. $text = str_replace(array("{PAGE_NUM}","{PAGE_COUNT}"),
  710. array($page_number, $this->_page_count), $text);
  711. $this->text($x, $y, $text, $font, $size, $color, $adjust, $angle);
  712. break;
  713. case "script":
  714. if (!$eval) {
  715. $eval = new PHP_Evaluator($this);
  716. }
  717. $eval->evaluate($code, array('PAGE_NUM' => $page_number, 'PAGE_COUNT' => $this->_page_count));
  718. break;
  719. }
  720. }
  721. $this->close_object();
  722. $page_number++;
  723. }
  724. }
  725. /**
  726. * Streams the PDF directly to the browser
  727. *
  728. * @param string $filename the name of the PDF file
  729. * @param array $options associative array, 'Attachment' => 0 or 1, 'compress' => 1 or 0
  730. */
  731. function stream($filename, $options = null) {
  732. // Add page text
  733. $this->_add_page_text();
  734. $options["Content-Disposition"] = $filename;
  735. $this->_pdf->stream($options);
  736. }
  737. //........................................................................
  738. /**
  739. * Returns the PDF as a string
  740. *
  741. * @return string
  742. */
  743. function output($options = null) {
  744. // Add page text
  745. $this->_add_page_text();
  746. if ( isset($options["compress"]) && $options["compress"] != 1 )
  747. $debug = 1;
  748. else
  749. $debug = 0;
  750. return $this->_pdf->output($debug);
  751. }
  752. //........................................................................
  753. /**
  754. * Returns logging messages generated by the Cpdf class
  755. *
  756. * @return string
  757. */
  758. function get_messages() { return $this->_pdf->messages; }
  759. }
  760. ?>