cpdf_adapter.cls.php 28 KB

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