Abstract.php 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175
  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://framework.zend.com/license/new-bsd
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@zend.com so we can send you a copy immediately.
  14. *
  15. * @category Zend
  16. * @package Zend_Pdf
  17. * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
  18. * @license http://framework.zend.com/license/new-bsd New BSD License
  19. * @version $Id: Style.php 20096 2010-01-06 02:05:09Z bkarwin $
  20. */
  21. require_once 'Zend/Pdf/Canvas/Interface.php';
  22. /** Internally used classes */
  23. require_once 'Zend/Pdf/Element.php';
  24. require_once 'Zend/Pdf/Element/Array.php';
  25. require_once 'Zend/Pdf/Element/String/Binary.php';
  26. require_once 'Zend/Pdf/Element/Boolean.php';
  27. require_once 'Zend/Pdf/Element/Dictionary.php';
  28. require_once 'Zend/Pdf/Element/Name.php';
  29. require_once 'Zend/Pdf/Element/Null.php';
  30. require_once 'Zend/Pdf/Element/Numeric.php';
  31. require_once 'Zend/Pdf/Element/String.php';
  32. /**
  33. * Canvas is an abstract rectangle drawing area which can be dropped into
  34. * page object at specified place.
  35. *
  36. * @package Zend_Pdf
  37. * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
  38. * @license http://framework.zend.com/license/new-bsd New BSD License
  39. */
  40. abstract class Zend_Pdf_Canvas_Abstract implements Zend_Pdf_Canvas_Interface
  41. {
  42. /**
  43. * Drawing instructions
  44. *
  45. * @var string
  46. */
  47. protected $_contents = '';
  48. /**
  49. * Current font
  50. *
  51. * @var Zend_Pdf_Resource_Font
  52. */
  53. protected $_font = null;
  54. /**
  55. * Current font size
  56. *
  57. * @var float
  58. */
  59. protected $_fontSize;
  60. /**
  61. * Current style
  62. *
  63. * @var Zend_Pdf_Style
  64. */
  65. protected $_style = null;
  66. /**
  67. * Counter for the "Save" operations
  68. *
  69. * @var integer
  70. */
  71. protected $_saveCount = 0;
  72. /**
  73. * Add procedureSet to the Page description
  74. *
  75. * @param string $procSetName
  76. */
  77. abstract protected function _addProcSet($procSetName);
  78. /**
  79. * Attach resource to the canvas
  80. *
  81. * Method returns a name of the resource which can be used
  82. * as a resource reference within drawing instructions stream
  83. * Allowed types: 'XObject' (image), 'Font', 'ExtGState'
  84. *
  85. * @param string $type
  86. * @param Zend_Pdf_Resource $resource
  87. * @return string
  88. */
  89. abstract protected function _attachResource($type, Zend_Pdf_Resource $resource);
  90. /**
  91. * Draw a canvas at the specified location
  92. *
  93. * If upper right corner is not specified then canvas heght and width
  94. * are used.
  95. *
  96. * @param Zend_Pdf_Canvas_Interface $canvas
  97. * @param float $x1
  98. * @param float $y1
  99. * @param float $x2
  100. * @param float $y2
  101. * @return Zend_Pdf_Canvas_Interface
  102. */
  103. public function drawCanvas($canvas, $x1, $y1, $x2 = null, $y2 = null)
  104. {
  105. /** @todo implementation */
  106. return $this;
  107. }
  108. /**
  109. * Set fill color.
  110. *
  111. * @param Zend_Pdf_Color $color
  112. * @return Zend_Pdf_Canvas_Interface
  113. */
  114. public function setFillColor(Zend_Pdf_Color $color)
  115. {
  116. $this->_addProcSet('PDF');
  117. $this->_contents .= $color->instructions(false);
  118. return $this;
  119. }
  120. /**
  121. * Set line color.
  122. *
  123. * @param Zend_Pdf_Color $color
  124. * @return Zend_Pdf_Canvas_Interface
  125. */
  126. public function setLineColor(Zend_Pdf_Color $color)
  127. {
  128. $this->_addProcSet('PDF');
  129. $this->_contents .= $color->instructions(true);
  130. return $this;
  131. }
  132. /**
  133. * Set line width.
  134. *
  135. * @param float $width
  136. * @return Zend_Pdf_Canvas_Interface
  137. */
  138. public function setLineWidth($width)
  139. {
  140. $this->_addProcSet('PDF');
  141. $widthObj = new Zend_Pdf_Element_Numeric($width);
  142. $this->_contents .= $widthObj->toString() . " w\n";
  143. return $this;
  144. }
  145. /**
  146. * Set line dashing pattern
  147. *
  148. * Pattern is an array of floats: array(on_length, off_length, on_length, off_length, ...)
  149. * or Zend_Pdf_Page::LINE_DASHING_SOLID constant
  150. * Phase is shift from the beginning of line.
  151. *
  152. * @param mixed $pattern
  153. * @param array $phase
  154. * @return Zend_Pdf_Canvas_Interface
  155. */
  156. public function setLineDashingPattern($pattern, $phase = 0)
  157. {
  158. $this->_addProcSet('PDF');
  159. require_once 'Zend/Pdf/Page.php';
  160. if ($pattern === Zend_Pdf_Page::LINE_DASHING_SOLID) {
  161. $pattern = array();
  162. $phase = 0;
  163. }
  164. $dashPattern = new Zend_Pdf_Element_Array();
  165. $phaseEleemnt = new Zend_Pdf_Element_Numeric($phase);
  166. foreach ($pattern as $dashItem) {
  167. $dashElement = new Zend_Pdf_Element_Numeric($dashItem);
  168. $dashPattern->items[] = $dashElement;
  169. }
  170. $this->_contents .= $dashPattern->toString() . ' '
  171. . $phaseEleemnt->toString() . " d\n";
  172. return $this;
  173. }
  174. /**
  175. * Set current font.
  176. *
  177. * @param Zend_Pdf_Resource_Font $font
  178. * @param float $fontSize
  179. * @return Zend_Pdf_Canvas_Interface
  180. */
  181. public function setFont(Zend_Pdf_Resource_Font $font, $fontSize)
  182. {
  183. $this->_addProcSet('Text');
  184. $fontName = $this->_attachResource('Font', $font);
  185. $this->_font = $font;
  186. $this->_fontSize = $fontSize;
  187. $fontNameObj = new Zend_Pdf_Element_Name($fontName);
  188. $fontSizeObj = new Zend_Pdf_Element_Numeric($fontSize);
  189. $this->_contents .= $fontNameObj->toString() . ' ' . $fontSizeObj->toString() . " Tf\n";
  190. return $this;
  191. }
  192. /**
  193. * Set the style to use for future drawing operations on this page
  194. *
  195. * @param Zend_Pdf_Style $style
  196. * @return Zend_Pdf_Canvas_Interface
  197. */
  198. public function setStyle(Zend_Pdf_Style $style)
  199. {
  200. $this->_addProcSet('Text');
  201. $this->_addProcSet('PDF');
  202. if ($style->getFont() !== null) {
  203. $this->setFont($style->getFont(), $style->getFontSize());
  204. }
  205. $this->_contents .= $style->instructions($this->_dictionary->Resources);
  206. $this->_style = $style;
  207. return $this;
  208. }
  209. /**
  210. * Get current font.
  211. *
  212. * @return Zend_Pdf_Resource_Font $font
  213. */
  214. public function getFont()
  215. {
  216. return $this->_font;
  217. }
  218. /**
  219. * Get current font size
  220. *
  221. * @return float $fontSize
  222. */
  223. public function getFontSize()
  224. {
  225. return $this->_fontSize;
  226. }
  227. /**
  228. * Return the style, applied to the page.
  229. *
  230. * @return Zend_Pdf_Style
  231. */
  232. public function getStyle()
  233. {
  234. return $this->_style;
  235. }
  236. /**
  237. * Save the graphics state of this page.
  238. * This takes a snapshot of the currently applied style, position, clipping area and
  239. * any rotation/translation/scaling that has been applied.
  240. *
  241. * @todo check for the open paths
  242. * @throws Zend_Pdf_Exception - if a save is performed with an open path
  243. * @return Zend_Pdf_Canvas_Interface
  244. */
  245. public function saveGS()
  246. {
  247. $this->_saveCount++;
  248. $this->_addProcSet('PDF');
  249. $this->_contents .= " q\n";
  250. return $this;
  251. }
  252. /**
  253. * Restore the graphics state that was saved with the last call to saveGS().
  254. *
  255. * @throws Zend_Pdf_Exception - if there is no previously saved state
  256. * @return Zend_Pdf_Canvas_Interface
  257. */
  258. public function restoreGS()
  259. {
  260. if ($this->_saveCount-- <= 0) {
  261. require_once 'Zend/Pdf/Exception.php';
  262. throw new Zend_Pdf_Exception('Restoring graphics state which is not saved');
  263. }
  264. $this->_contents .= " Q\n";
  265. return $this;
  266. }
  267. /**
  268. * Set the transparancy
  269. *
  270. * $alpha == 0 - transparent
  271. * $alpha == 1 - opaque
  272. *
  273. * Transparency modes, supported by PDF:
  274. * Normal (default), Multiply, Screen, Overlay, Darken, Lighten, ColorDodge, ColorBurn, HardLight,
  275. * SoftLight, Difference, Exclusion
  276. *
  277. * @param float $alpha
  278. * @param string $mode
  279. * @return Zend_Pdf_Canvas_Interface
  280. */
  281. public function setAlpha($alpha, $mode = 'Normal')
  282. {
  283. $this->_addProcSet('Text');
  284. $this->_addProcSet('PDF');
  285. $graphicsState = new Zend_Pdf_Resource_GraphicsState();
  286. $graphicsState->setAlpha($alpha, $mode);
  287. $gStateName = $this->_attachResource('ExtGState', $graphicsState);
  288. $gStateNameObject = new Zend_Pdf_Element_Name($gStateName);
  289. $this->_contents .= $gStateNameObject->toString() . " gs\n";
  290. return $this;
  291. }
  292. /**
  293. * Intersect current clipping area with a circle.
  294. *
  295. * @param float $x
  296. * @param float $y
  297. * @param float $radius
  298. * @param float $startAngle
  299. * @param float $endAngle
  300. * @return Zend_Pdf_Canvas_Interface
  301. */
  302. public function clipCircle($x, $y, $radius, $startAngle = null, $endAngle = null)
  303. {
  304. $this->clipEllipse($x - $radius, $y - $radius,
  305. $x + $radius, $y + $radius,
  306. $startAngle, $endAngle);
  307. return $this;
  308. }
  309. /**
  310. * Intersect current clipping area with a polygon.
  311. *
  312. * Method signatures:
  313. * drawEllipse($x1, $y1, $x2, $y2);
  314. * drawEllipse($x1, $y1, $x2, $y2, $startAngle, $endAngle);
  315. *
  316. * @todo process special cases with $x2-$x1 == 0 or $y2-$y1 == 0
  317. *
  318. * @param float $x1
  319. * @param float $y1
  320. * @param float $x2
  321. * @param float $y2
  322. * @param float $startAngle
  323. * @param float $endAngle
  324. * @return Zend_Pdf_Canvas_Interface
  325. */
  326. public function clipEllipse($x1, $y1, $x2, $y2, $startAngle = null, $endAngle = null)
  327. {
  328. $this->_addProcSet('PDF');
  329. if ($x2 < $x1) {
  330. $temp = $x1;
  331. $x1 = $x2;
  332. $x2 = $temp;
  333. }
  334. if ($y2 < $y1) {
  335. $temp = $y1;
  336. $y1 = $y2;
  337. $y2 = $temp;
  338. }
  339. $x = ($x1 + $x2)/2.;
  340. $y = ($y1 + $y2)/2.;
  341. $xC = new Zend_Pdf_Element_Numeric($x);
  342. $yC = new Zend_Pdf_Element_Numeric($y);
  343. if ($startAngle !== null) {
  344. if ($startAngle != 0) { $startAngle = fmod($startAngle, M_PI*2); }
  345. if ($endAngle != 0) { $endAngle = fmod($endAngle, M_PI*2); }
  346. if ($startAngle > $endAngle) {
  347. $endAngle += M_PI*2;
  348. }
  349. $clipPath = $xC->toString() . ' ' . $yC->toString() . " m\n";
  350. $clipSectors = (int)ceil(($endAngle - $startAngle)/M_PI_4);
  351. $clipRadius = max($x2 - $x1, $y2 - $y1);
  352. for($count = 0; $count <= $clipSectors; $count++) {
  353. $pAngle = $startAngle + ($endAngle - $startAngle)*$count/(float)$clipSectors;
  354. $pX = new Zend_Pdf_Element_Numeric($x + cos($pAngle)*$clipRadius);
  355. $pY = new Zend_Pdf_Element_Numeric($y + sin($pAngle)*$clipRadius);
  356. $clipPath .= $pX->toString() . ' ' . $pY->toString() . " l\n";
  357. }
  358. $this->_contents .= $clipPath . "h\nW\nn\n";
  359. }
  360. $xLeft = new Zend_Pdf_Element_Numeric($x1);
  361. $xRight = new Zend_Pdf_Element_Numeric($x2);
  362. $yUp = new Zend_Pdf_Element_Numeric($y2);
  363. $yDown = new Zend_Pdf_Element_Numeric($y1);
  364. $xDelta = 2*(M_SQRT2 - 1)*($x2 - $x1)/3.;
  365. $yDelta = 2*(M_SQRT2 - 1)*($y2 - $y1)/3.;
  366. $xr = new Zend_Pdf_Element_Numeric($x + $xDelta);
  367. $xl = new Zend_Pdf_Element_Numeric($x - $xDelta);
  368. $yu = new Zend_Pdf_Element_Numeric($y + $yDelta);
  369. $yd = new Zend_Pdf_Element_Numeric($y - $yDelta);
  370. $this->_contents .= $xC->toString() . ' ' . $yUp->toString() . " m\n"
  371. . $xr->toString() . ' ' . $yUp->toString() . ' '
  372. . $xRight->toString() . ' ' . $yu->toString() . ' '
  373. . $xRight->toString() . ' ' . $yC->toString() . " c\n"
  374. . $xRight->toString() . ' ' . $yd->toString() . ' '
  375. . $xr->toString() . ' ' . $yDown->toString() . ' '
  376. . $xC->toString() . ' ' . $yDown->toString() . " c\n"
  377. . $xl->toString() . ' ' . $yDown->toString() . ' '
  378. . $xLeft->toString() . ' ' . $yd->toString() . ' '
  379. . $xLeft->toString() . ' ' . $yC->toString() . " c\n"
  380. . $xLeft->toString() . ' ' . $yu->toString() . ' '
  381. . $xl->toString() . ' ' . $yUp->toString() . ' '
  382. . $xC->toString() . ' ' . $yUp->toString() . " c\n"
  383. . "h\nW\nn\n";
  384. return $this;
  385. }
  386. /**
  387. * Intersect current clipping area with a polygon.
  388. *
  389. * @param array $x - array of float (the X co-ordinates of the vertices)
  390. * @param array $y - array of float (the Y co-ordinates of the vertices)
  391. * @param integer $fillMethod
  392. * @return Zend_Pdf_Canvas_Interface
  393. */
  394. public function clipPolygon($x, $y, $fillMethod = Zend_Pdf_Page::FILL_METHOD_NON_ZERO_WINDING)
  395. {
  396. $this->_addProcSet('PDF');
  397. $firstPoint = true;
  398. foreach ($x as $id => $xVal) {
  399. $xObj = new Zend_Pdf_Element_Numeric($xVal);
  400. $yObj = new Zend_Pdf_Element_Numeric($y[$id]);
  401. if ($firstPoint) {
  402. $path = $xObj->toString() . ' ' . $yObj->toString() . " m\n";
  403. $firstPoint = false;
  404. } else {
  405. $path .= $xObj->toString() . ' ' . $yObj->toString() . " l\n";
  406. }
  407. }
  408. $this->_contents .= $path;
  409. if ($fillMethod == Zend_Pdf_Page::FILL_METHOD_NON_ZERO_WINDING) {
  410. $this->_contents .= " h\n W\nn\n";
  411. } else {
  412. // Even-Odd fill method.
  413. $this->_contents .= " h\n W*\nn\n";
  414. }
  415. return $this;
  416. }
  417. /**
  418. * Intersect current clipping area with a rectangle.
  419. *
  420. * @param float $x1
  421. * @param float $y1
  422. * @param float $x2
  423. * @param float $y2
  424. * @return Zend_Pdf_Canvas_Interface
  425. */
  426. public function clipRectangle($x1, $y1, $x2, $y2)
  427. {
  428. $this->_addProcSet('PDF');
  429. $x1Obj = new Zend_Pdf_Element_Numeric($x1);
  430. $y1Obj = new Zend_Pdf_Element_Numeric($y1);
  431. $widthObj = new Zend_Pdf_Element_Numeric($x2 - $x1);
  432. $height2Obj = new Zend_Pdf_Element_Numeric($y2 - $y1);
  433. $this->_contents .= $x1Obj->toString() . ' ' . $y1Obj->toString() . ' '
  434. . $widthObj->toString() . ' ' . $height2Obj->toString() . " re\n"
  435. . " W\nn\n";
  436. return $this;
  437. }
  438. // ------------------------------------------------------------------------------------------
  439. /**
  440. * Draw a circle centered on x, y with a radius of radius.
  441. *
  442. * Method signatures:
  443. * drawCircle($x, $y, $radius);
  444. * drawCircle($x, $y, $radius, $fillType);
  445. * drawCircle($x, $y, $radius, $startAngle, $endAngle);
  446. * drawCircle($x, $y, $radius, $startAngle, $endAngle, $fillType);
  447. *
  448. *
  449. * It's not a really circle, because PDF supports only cubic Bezier curves.
  450. * But _very_ good approximation.
  451. * It differs from a real circle on a maximum 0.00026 radiuses
  452. * (at PI/8, 3*PI/8, 5*PI/8, 7*PI/8, 9*PI/8, 11*PI/8, 13*PI/8 and 15*PI/8 angles).
  453. * At 0, PI/4, PI/2, 3*PI/4, PI, 5*PI/4, 3*PI/2 and 7*PI/4 it's exactly a tangent to a circle.
  454. *
  455. * @param float $x
  456. * @param float $y
  457. * @param float $radius
  458. * @param mixed $param4
  459. * @param mixed $param5
  460. * @param mixed $param6
  461. * @return Zend_Pdf_Canvas_Interface
  462. */
  463. public function drawCircle($x, $y, $radius, $param4 = null, $param5 = null, $param6 = null)
  464. {
  465. $this->drawEllipse($x - $radius, $y - $radius,
  466. $x + $radius, $y + $radius,
  467. $param4, $param5, $param6);
  468. return $this;
  469. }
  470. /**
  471. * Draw an ellipse inside the specified rectangle.
  472. *
  473. * Method signatures:
  474. * drawEllipse($x1, $y1, $x2, $y2);
  475. * drawEllipse($x1, $y1, $x2, $y2, $fillType);
  476. * drawEllipse($x1, $y1, $x2, $y2, $startAngle, $endAngle);
  477. * drawEllipse($x1, $y1, $x2, $y2, $startAngle, $endAngle, $fillType);
  478. *
  479. * @todo process special cases with $x2-$x1 == 0 or $y2-$y1 == 0
  480. *
  481. * @param float $x1
  482. * @param float $y1
  483. * @param float $x2
  484. * @param float $y2
  485. * @param mixed $param5
  486. * @param mixed $param6
  487. * @param mixed $param7
  488. * @return Zend_Pdf_Canvas_Interface
  489. */
  490. public function drawEllipse($x1, $y1, $x2, $y2, $param5 = null, $param6 = null, $param7 = null)
  491. {
  492. if ($param5 === null) {
  493. // drawEllipse($x1, $y1, $x2, $y2);
  494. $startAngle = null;
  495. $fillType = Zend_Pdf_Page::SHAPE_DRAW_FILL_AND_STROKE;
  496. } else if ($param6 === null) {
  497. // drawEllipse($x1, $y1, $x2, $y2, $fillType);
  498. $startAngle = null;
  499. $fillType = $param5;
  500. } else {
  501. // drawEllipse($x1, $y1, $x2, $y2, $startAngle, $endAngle);
  502. // drawEllipse($x1, $y1, $x2, $y2, $startAngle, $endAngle, $fillType);
  503. $startAngle = $param5;
  504. $endAngle = $param6;
  505. if ($param7 === null) {
  506. $fillType = Zend_Pdf_Page::SHAPE_DRAW_FILL_AND_STROKE;
  507. } else {
  508. $fillType = $param7;
  509. }
  510. }
  511. $this->_addProcSet('PDF');
  512. if ($x2 < $x1) {
  513. $temp = $x1;
  514. $x1 = $x2;
  515. $x2 = $temp;
  516. }
  517. if ($y2 < $y1) {
  518. $temp = $y1;
  519. $y1 = $y2;
  520. $y2 = $temp;
  521. }
  522. $x = ($x1 + $x2)/2.;
  523. $y = ($y1 + $y2)/2.;
  524. $xC = new Zend_Pdf_Element_Numeric($x);
  525. $yC = new Zend_Pdf_Element_Numeric($y);
  526. if ($startAngle !== null) {
  527. if ($startAngle != 0) { $startAngle = fmod($startAngle, M_PI*2); }
  528. if ($endAngle != 0) { $endAngle = fmod($endAngle, M_PI*2); }
  529. if ($startAngle > $endAngle) {
  530. $endAngle += M_PI*2;
  531. }
  532. $clipPath = $xC->toString() . ' ' . $yC->toString() . " m\n";
  533. $clipSectors = (int)ceil(($endAngle - $startAngle)/M_PI_4);
  534. $clipRadius = max($x2 - $x1, $y2 - $y1);
  535. for($count = 0; $count <= $clipSectors; $count++) {
  536. $pAngle = $startAngle + ($endAngle - $startAngle)*$count/(float)$clipSectors;
  537. $pX = new Zend_Pdf_Element_Numeric($x + cos($pAngle)*$clipRadius);
  538. $pY = new Zend_Pdf_Element_Numeric($y + sin($pAngle)*$clipRadius);
  539. $clipPath .= $pX->toString() . ' ' . $pY->toString() . " l\n";
  540. }
  541. $this->_contents .= "q\n" . $clipPath . "h\nW\nn\n";
  542. }
  543. $xLeft = new Zend_Pdf_Element_Numeric($x1);
  544. $xRight = new Zend_Pdf_Element_Numeric($x2);
  545. $yUp = new Zend_Pdf_Element_Numeric($y2);
  546. $yDown = new Zend_Pdf_Element_Numeric($y1);
  547. $xDelta = 2*(M_SQRT2 - 1)*($x2 - $x1)/3.;
  548. $yDelta = 2*(M_SQRT2 - 1)*($y2 - $y1)/3.;
  549. $xr = new Zend_Pdf_Element_Numeric($x + $xDelta);
  550. $xl = new Zend_Pdf_Element_Numeric($x - $xDelta);
  551. $yu = new Zend_Pdf_Element_Numeric($y + $yDelta);
  552. $yd = new Zend_Pdf_Element_Numeric($y - $yDelta);
  553. $this->_contents .= $xC->toString() . ' ' . $yUp->toString() . " m\n"
  554. . $xr->toString() . ' ' . $yUp->toString() . ' '
  555. . $xRight->toString() . ' ' . $yu->toString() . ' '
  556. . $xRight->toString() . ' ' . $yC->toString() . " c\n"
  557. . $xRight->toString() . ' ' . $yd->toString() . ' '
  558. . $xr->toString() . ' ' . $yDown->toString() . ' '
  559. . $xC->toString() . ' ' . $yDown->toString() . " c\n"
  560. . $xl->toString() . ' ' . $yDown->toString() . ' '
  561. . $xLeft->toString() . ' ' . $yd->toString() . ' '
  562. . $xLeft->toString() . ' ' . $yC->toString() . " c\n"
  563. . $xLeft->toString() . ' ' . $yu->toString() . ' '
  564. . $xl->toString() . ' ' . $yUp->toString() . ' '
  565. . $xC->toString() . ' ' . $yUp->toString() . " c\n";
  566. switch ($fillType) {
  567. case Zend_Pdf_Page::SHAPE_DRAW_FILL_AND_STROKE:
  568. $this->_contents .= " B*\n";
  569. break;
  570. case Zend_Pdf_Page::SHAPE_DRAW_FILL:
  571. $this->_contents .= " f*\n";
  572. break;
  573. case Zend_Pdf_Page::SHAPE_DRAW_STROKE:
  574. $this->_contents .= " S\n";
  575. break;
  576. }
  577. if ($startAngle !== null) {
  578. $this->_contents .= "Q\n";
  579. }
  580. return $this;
  581. }
  582. /**
  583. * Draw an image at the specified position on the page.
  584. *
  585. * @param Zend_Pdf_Image $image
  586. * @param float $x1
  587. * @param float $y1
  588. * @param float $x2
  589. * @param float $y2
  590. * @return Zend_Pdf_Canvas_Interface
  591. */
  592. public function drawImage(Zend_Pdf_Resource_Image $image, $x1, $y1, $x2, $y2)
  593. {
  594. $this->_addProcSet('PDF');
  595. $imageName = $this->_attachResource('XObject', $image);
  596. $imageNameObj = new Zend_Pdf_Element_Name($imageName);
  597. $x1Obj = new Zend_Pdf_Element_Numeric($x1);
  598. $y1Obj = new Zend_Pdf_Element_Numeric($y1);
  599. $widthObj = new Zend_Pdf_Element_Numeric($x2 - $x1);
  600. $heightObj = new Zend_Pdf_Element_Numeric($y2 - $y1);
  601. $this->_contents .= "q\n"
  602. . '1 0 0 1 ' . $x1Obj->toString() . ' ' . $y1Obj->toString() . " cm\n"
  603. . $widthObj->toString() . ' 0 0 ' . $heightObj->toString() . " 0 0 cm\n"
  604. . $imageNameObj->toString() . " Do\n"
  605. . "Q\n";
  606. return $this;
  607. }
  608. /**
  609. * Draw a LayoutBox at the specified position on the page.
  610. *
  611. * @internal (not implemented now)
  612. *
  613. * @param Zend_Pdf_Element_LayoutBox $box
  614. * @param float $x
  615. * @param float $y
  616. * @return Zend_Pdf_Canvas_Interface
  617. */
  618. public function drawLayoutBox($box, $x, $y)
  619. {
  620. /** @todo implementation */
  621. return $this;
  622. }
  623. /**
  624. * Draw a line from x1,y1 to x2,y2.
  625. *
  626. * @param float $x1
  627. * @param float $y1
  628. * @param float $x2
  629. * @param float $y2
  630. * @return Zend_Pdf_Canvas_Interface
  631. */
  632. public function drawLine($x1, $y1, $x2, $y2)
  633. {
  634. $this->_addProcSet('PDF');
  635. $x1Obj = new Zend_Pdf_Element_Numeric($x1);
  636. $y1Obj = new Zend_Pdf_Element_Numeric($y1);
  637. $x2Obj = new Zend_Pdf_Element_Numeric($x2);
  638. $y2Obj = new Zend_Pdf_Element_Numeric($y2);
  639. $this->_contents .= $x1Obj->toString() . ' ' . $y1Obj->toString() . " m\n"
  640. . $x2Obj->toString() . ' ' . $y2Obj->toString() . " l\n S\n";
  641. return $this;
  642. }
  643. /**
  644. * Draw a polygon.
  645. *
  646. * If $fillType is Zend_Pdf_Page::SHAPE_DRAW_FILL_AND_STROKE or
  647. * Zend_Pdf_Page::SHAPE_DRAW_FILL, then polygon is automatically closed.
  648. * See detailed description of these methods in a PDF documentation
  649. * (section 4.4.2 Path painting Operators, Filling)
  650. *
  651. * @param array $x - array of float (the X co-ordinates of the vertices)
  652. * @param array $y - array of float (the Y co-ordinates of the vertices)
  653. * @param integer $fillType
  654. * @param integer $fillMethod
  655. * @return Zend_Pdf_Canvas_Interface
  656. */
  657. public function drawPolygon($x, $y,
  658. $fillType = Zend_Pdf_Page::SHAPE_DRAW_FILL_AND_STROKE,
  659. $fillMethod = Zend_Pdf_Page::FILL_METHOD_NON_ZERO_WINDING)
  660. {
  661. $this->_addProcSet('PDF');
  662. $firstPoint = true;
  663. foreach ($x as $id => $xVal) {
  664. $xObj = new Zend_Pdf_Element_Numeric($xVal);
  665. $yObj = new Zend_Pdf_Element_Numeric($y[$id]);
  666. if ($firstPoint) {
  667. $path = $xObj->toString() . ' ' . $yObj->toString() . " m\n";
  668. $firstPoint = false;
  669. } else {
  670. $path .= $xObj->toString() . ' ' . $yObj->toString() . " l\n";
  671. }
  672. }
  673. $this->_contents .= $path;
  674. switch ($fillType) {
  675. case Zend_Pdf_Page::SHAPE_DRAW_FILL_AND_STROKE:
  676. if ($fillMethod == Zend_Pdf_Page::FILL_METHOD_NON_ZERO_WINDING) {
  677. $this->_contents .= " b\n";
  678. } else {
  679. // Even-Odd fill method.
  680. $this->_contents .= " b*\n";
  681. }
  682. break;
  683. case Zend_Pdf_Page::SHAPE_DRAW_FILL:
  684. if ($fillMethod == Zend_Pdf_Page::FILL_METHOD_NON_ZERO_WINDING) {
  685. $this->_contents .= " h\n f\n";
  686. } else {
  687. // Even-Odd fill method.
  688. $this->_contents .= " h\n f*\n";
  689. }
  690. break;
  691. case Zend_Pdf_Page::SHAPE_DRAW_STROKE:
  692. $this->_contents .= " S\n";
  693. break;
  694. }
  695. return $this;
  696. }
  697. /**
  698. * Draw a rectangle.
  699. *
  700. * Fill types:
  701. * Zend_Pdf_Page::SHAPE_DRAW_FILL_AND_STROKE - fill rectangle and stroke (default)
  702. * Zend_Pdf_Page::SHAPE_DRAW_STROKE - stroke rectangle
  703. * Zend_Pdf_Page::SHAPE_DRAW_FILL - fill rectangle
  704. *
  705. * @param float $x1
  706. * @param float $y1
  707. * @param float $x2
  708. * @param float $y2
  709. * @param integer $fillType
  710. * @return Zend_Pdf_Canvas_Interface
  711. */
  712. public function drawRectangle($x1, $y1, $x2, $y2, $fillType = Zend_Pdf_Page::SHAPE_DRAW_FILL_AND_STROKE)
  713. {
  714. $this->_addProcSet('PDF');
  715. $x1Obj = new Zend_Pdf_Element_Numeric($x1);
  716. $y1Obj = new Zend_Pdf_Element_Numeric($y1);
  717. $widthObj = new Zend_Pdf_Element_Numeric($x2 - $x1);
  718. $height2Obj = new Zend_Pdf_Element_Numeric($y2 - $y1);
  719. $this->_contents .= $x1Obj->toString() . ' ' . $y1Obj->toString() . ' '
  720. . $widthObj->toString() . ' ' . $height2Obj->toString() . " re\n";
  721. switch ($fillType) {
  722. case Zend_Pdf_Page::SHAPE_DRAW_FILL_AND_STROKE:
  723. $this->_contents .= " B*\n";
  724. break;
  725. case Zend_Pdf_Page::SHAPE_DRAW_FILL:
  726. $this->_contents .= " f*\n";
  727. break;
  728. case Zend_Pdf_Page::SHAPE_DRAW_STROKE:
  729. $this->_contents .= " S\n";
  730. break;
  731. }
  732. return $this;
  733. }
  734. /**
  735. * Draw a rounded rectangle.
  736. *
  737. * Fill types:
  738. * Zend_Pdf_Page::SHAPE_DRAW_FILL_AND_STROKE - fill rectangle and stroke (default)
  739. * Zend_Pdf_Page::SHAPE_DRAW_STROKE - stroke rectangle
  740. * Zend_Pdf_Page::SHAPE_DRAW_FILL - fill rectangle
  741. *
  742. * radius is an integer representing radius of the four corners, or an array
  743. * of four integers representing the radius starting at top left, going
  744. * clockwise
  745. *
  746. * @param float $x1
  747. * @param float $y1
  748. * @param float $x2
  749. * @param float $y2
  750. * @param integer|array $radius
  751. * @param integer $fillType
  752. * @return Zend_Pdf_Canvas_Interface
  753. */
  754. public function drawRoundedRectangle($x1, $y1, $x2, $y2, $radius,
  755. $fillType = Zend_Pdf_Page::SHAPE_DRAW_FILL_AND_STROKE)
  756. {
  757. $this->_addProcSet('PDF');
  758. if(!is_array($radius)) {
  759. $radius = array($radius, $radius, $radius, $radius);
  760. } else {
  761. for ($i = 0; $i < 4; $i++) {
  762. if(!isset($radius[$i])) {
  763. $radius[$i] = 0;
  764. }
  765. }
  766. }
  767. $topLeftX = $x1;
  768. $topLeftY = $y2;
  769. $topRightX = $x2;
  770. $topRightY = $y2;
  771. $bottomRightX = $x2;
  772. $bottomRightY = $y1;
  773. $bottomLeftX = $x1;
  774. $bottomLeftY = $y1;
  775. //draw top side
  776. $x1Obj = new Zend_Pdf_Element_Numeric($topLeftX + $radius[0]);
  777. $y1Obj = new Zend_Pdf_Element_Numeric($topLeftY);
  778. $this->_contents .= $x1Obj->toString() . ' ' . $y1Obj->toString() . " m\n";
  779. $x1Obj = new Zend_Pdf_Element_Numeric($topRightX - $radius[1]);
  780. $y1Obj = new Zend_Pdf_Element_Numeric($topRightY);
  781. $this->_contents .= $x1Obj->toString() . ' ' . $y1Obj->toString() . " l\n";
  782. //draw top right corner if needed
  783. if ($radius[1] != 0) {
  784. $x1Obj = new Zend_Pdf_Element_Numeric($topRightX);
  785. $y1Obj = new Zend_Pdf_Element_Numeric($topRightY);
  786. $x2Obj = new Zend_Pdf_Element_Numeric($topRightX);
  787. $y2Obj = new Zend_Pdf_Element_Numeric($topRightY);
  788. $x3Obj = new Zend_Pdf_Element_Numeric($topRightX);
  789. $y3Obj = new Zend_Pdf_Element_Numeric($topRightY - $radius[1]);
  790. $this->_contents .= $x1Obj->toString() . ' ' . $y1Obj->toString() . ' '
  791. . $x2Obj->toString() . ' ' . $y2Obj->toString() . ' '
  792. . $x3Obj->toString() . ' ' . $y3Obj->toString() . ' '
  793. . " c\n";
  794. }
  795. //draw right side
  796. $x1Obj = new Zend_Pdf_Element_Numeric($bottomRightX);
  797. $y1Obj = new Zend_Pdf_Element_Numeric($bottomRightY + $radius[2]);
  798. $this->_contents .= $x1Obj->toString() . ' ' . $y1Obj->toString() . " l\n";
  799. //draw bottom right corner if needed
  800. if ($radius[2] != 0) {
  801. $x1Obj = new Zend_Pdf_Element_Numeric($bottomRightX);
  802. $y1Obj = new Zend_Pdf_Element_Numeric($bottomRightY);
  803. $x2Obj = new Zend_Pdf_Element_Numeric($bottomRightX);
  804. $y2Obj = new Zend_Pdf_Element_Numeric($bottomRightY);
  805. $x3Obj = new Zend_Pdf_Element_Numeric($bottomRightX - $radius[2]);
  806. $y3Obj = new Zend_Pdf_Element_Numeric($bottomRightY);
  807. $this->_contents .= $x1Obj->toString() . ' ' . $y1Obj->toString() . ' '
  808. . $x2Obj->toString() . ' ' . $y2Obj->toString() . ' '
  809. . $x3Obj->toString() . ' ' . $y3Obj->toString() . ' '
  810. . " c\n";
  811. }
  812. //draw bottom side
  813. $x1Obj = new Zend_Pdf_Element_Numeric($bottomLeftX + $radius[3]);
  814. $y1Obj = new Zend_Pdf_Element_Numeric($bottomLeftY);
  815. $this->_contents .= $x1Obj->toString() . ' ' . $y1Obj->toString() . " l\n";
  816. //draw bottom left corner if needed
  817. if ($radius[3] != 0) {
  818. $x1Obj = new Zend_Pdf_Element_Numeric($bottomLeftX);
  819. $y1Obj = new Zend_Pdf_Element_Numeric($bottomLeftY);
  820. $x2Obj = new Zend_Pdf_Element_Numeric($bottomLeftX);
  821. $y2Obj = new Zend_Pdf_Element_Numeric($bottomLeftY);
  822. $x3Obj = new Zend_Pdf_Element_Numeric($bottomLeftX);
  823. $y3Obj = new Zend_Pdf_Element_Numeric($bottomLeftY + $radius[3]);
  824. $this->_contents .= $x1Obj->toString() . ' ' . $y1Obj->toString() . ' '
  825. . $x2Obj->toString() . ' ' . $y2Obj->toString() . ' '
  826. . $x3Obj->toString() . ' ' . $y3Obj->toString() . ' '
  827. . " c\n";
  828. }
  829. //draw left side
  830. $x1Obj = new Zend_Pdf_Element_Numeric($topLeftX);
  831. $y1Obj = new Zend_Pdf_Element_Numeric($topLeftY - $radius[0]);
  832. $this->_contents .= $x1Obj->toString() . ' ' . $y1Obj->toString() . " l\n";
  833. //draw top left corner if needed
  834. if ($radius[0] != 0) {
  835. $x1Obj = new Zend_Pdf_Element_Numeric($topLeftX);
  836. $y1Obj = new Zend_Pdf_Element_Numeric($topLeftY);
  837. $x2Obj = new Zend_Pdf_Element_Numeric($topLeftX);
  838. $y2Obj = new Zend_Pdf_Element_Numeric($topLeftY);
  839. $x3Obj = new Zend_Pdf_Element_Numeric($topLeftX + $radius[0]);
  840. $y3Obj = new Zend_Pdf_Element_Numeric($topLeftY);
  841. $this->_contents .= $x1Obj->toString() . ' ' . $y1Obj->toString() . ' '
  842. . $x2Obj->toString() . ' ' . $y2Obj->toString() . ' '
  843. . $x3Obj->toString() . ' ' . $y3Obj->toString() . ' '
  844. . " c\n";
  845. }
  846. switch ($fillType) {
  847. case Zend_Pdf_Page::SHAPE_DRAW_FILL_AND_STROKE:
  848. $this->_contents .= " B*\n";
  849. break;
  850. case Zend_Pdf_Page::SHAPE_DRAW_FILL:
  851. $this->_contents .= " f*\n";
  852. break;
  853. case Zend_Pdf_Page::SHAPE_DRAW_STROKE:
  854. $this->_contents .= " S\n";
  855. break;
  856. }
  857. return $this;
  858. }
  859. /**
  860. * Draw a line of text at the specified position.
  861. *
  862. * @param string $text
  863. * @param float $x
  864. * @param float $y
  865. * @param string $charEncoding (optional) Character encoding of source text.
  866. * Defaults to current locale.
  867. * @throws Zend_Pdf_Exception
  868. * @return Zend_Pdf_Canvas_Interface
  869. */
  870. public function drawText($text, $x, $y, $charEncoding = '')
  871. {
  872. if ($this->_font === null) {
  873. require_once 'Zend/Pdf/Exception.php';
  874. throw new Zend_Pdf_Exception('Font has not been set');
  875. }
  876. $this->_addProcSet('Text');
  877. $textObj = new Zend_Pdf_Element_String($this->_font->encodeString($text, $charEncoding));
  878. $xObj = new Zend_Pdf_Element_Numeric($x);
  879. $yObj = new Zend_Pdf_Element_Numeric($y);
  880. $this->_contents .= "BT\n"
  881. . $xObj->toString() . ' ' . $yObj->toString() . " Td\n"
  882. . $textObj->toString() . " Tj\n"
  883. . "ET\n";
  884. return $this;
  885. }
  886. /**
  887. * Close the path by drawing a straight line back to it's beginning.
  888. *
  889. * @internal (needs implementation)
  890. *
  891. * @throws Zend_Pdf_Exception - if a path hasn't been started with pathMove()
  892. * @return Zend_Pdf_Canvas_Interface
  893. */
  894. public function pathClose()
  895. {
  896. /** @todo implementation */
  897. return $this;
  898. }
  899. /**
  900. * Continue the open path in a straight line to the specified position.
  901. *
  902. * @internal (needs implementation)
  903. *
  904. * @param float $x - the X co-ordinate to move to
  905. * @param float $y - the Y co-ordinate to move to
  906. * @return Zend_Pdf_Canvas_Interface
  907. */
  908. public function pathLine($x, $y)
  909. {
  910. /** @todo implementation */
  911. return $this;
  912. }
  913. /**
  914. * Start a new path at the specified position. If a path has already been started,
  915. * move the cursor without drawing a line.
  916. *
  917. * @internal (needs implementation)
  918. *
  919. * @param float $x - the X co-ordinate to move to
  920. * @param float $y - the Y co-ordinate to move to
  921. * @return Zend_Pdf_Canvas_Interface
  922. */
  923. public function pathMove($x, $y)
  924. {
  925. /** @todo implementation */
  926. return $this;
  927. }
  928. /**
  929. * Rotate the page.
  930. *
  931. * @param float $x - the X co-ordinate of rotation point
  932. * @param float $y - the Y co-ordinate of rotation point
  933. * @param float $angle - rotation angle
  934. * @return Zend_Pdf_Canvas_Interface
  935. */
  936. public function rotate($x, $y, $angle)
  937. {
  938. $cos = new Zend_Pdf_Element_Numeric(cos($angle));
  939. $sin = new Zend_Pdf_Element_Numeric(sin($angle));
  940. $mSin = new Zend_Pdf_Element_Numeric(-$sin->value);
  941. $xObj = new Zend_Pdf_Element_Numeric($x);
  942. $yObj = new Zend_Pdf_Element_Numeric($y);
  943. $mXObj = new Zend_Pdf_Element_Numeric(-$x);
  944. $mYObj = new Zend_Pdf_Element_Numeric(-$y);
  945. $this->_addProcSet('PDF');
  946. $this->_contents .= '1 0 0 1 ' . $xObj->toString() . ' ' . $yObj->toString() . " cm\n"
  947. . $cos->toString() . ' ' . $sin->toString() . ' ' . $mSin->toString() . ' ' . $cos->toString() . " 0 0 cm\n"
  948. . '1 0 0 1 ' . $mXObj->toString() . ' ' . $mYObj->toString() . " cm\n";
  949. return $this;
  950. }
  951. /**
  952. * Scale coordination system.
  953. *
  954. * @param float $xScale - X dimention scale factor
  955. * @param float $yScale - Y dimention scale factor
  956. * @return Zend_Pdf_Canvas_Interface
  957. */
  958. public function scale($xScale, $yScale)
  959. {
  960. $xScaleObj = new Zend_Pdf_Element_Numeric($xScale);
  961. $yScaleObj = new Zend_Pdf_Element_Numeric($yScale);
  962. $this->_addProcSet('PDF');
  963. $this->_contents .= $xScaleObj->toString() . ' 0 0 ' . $yScaleObj->toString() . " 0 0 cm\n";
  964. return $this;
  965. }
  966. /**
  967. * Translate coordination system.
  968. *
  969. * @param float $xShift - X coordinate shift
  970. * @param float $yShift - Y coordinate shift
  971. * @return Zend_Pdf_Canvas_Interface
  972. */
  973. public function translate($xShift, $yShift)
  974. {
  975. $xShiftObj = new Zend_Pdf_Element_Numeric($xShift);
  976. $yShiftObj = new Zend_Pdf_Element_Numeric($yShift);
  977. $this->_addProcSet('PDF');
  978. $this->_contents .= '1 0 0 1 ' . $xShiftObj->toString() . ' ' . $yShiftObj->toString() . " cm\n";
  979. return $this;
  980. }
  981. /**
  982. * Translate coordination system.
  983. *
  984. * @param float $x - the X co-ordinate of axis skew point
  985. * @param float $y - the Y co-ordinate of axis skew point
  986. * @param float $xAngle - X axis skew angle
  987. * @param float $yAngle - Y axis skew angle
  988. * @return Zend_Pdf_Canvas_Interface
  989. */
  990. public function skew($x, $y, $xAngle, $yAngle)
  991. {
  992. $tanXObj = new Zend_Pdf_Element_Numeric(tan($xAngle));
  993. $tanYObj = new Zend_Pdf_Element_Numeric(-tan($yAngle));
  994. $xObj = new Zend_Pdf_Element_Numeric($x);
  995. $yObj = new Zend_Pdf_Element_Numeric($y);
  996. $mXObj = new Zend_Pdf_Element_Numeric(-$x);
  997. $mYObj = new Zend_Pdf_Element_Numeric(-$y);
  998. $this->_addProcSet('PDF');
  999. $this->_contents .= '1 0 0 1 ' . $xObj->toString() . ' ' . $yObj->toString() . " cm\n"
  1000. . '1 ' . $tanXObj->toString() . ' ' . $tanYObj->toString() . " 1 0 0 cm\n"
  1001. . '1 0 0 1 ' . $mXObj->toString() . ' ' . $mYObj->toString() . " cm\n";
  1002. return $this;
  1003. }
  1004. /**
  1005. * Writes the raw data to the page's content stream.
  1006. *
  1007. * Be sure to consult the PDF reference to ensure your syntax is correct. No
  1008. * attempt is made to ensure the validity of the stream data.
  1009. *
  1010. * @param string $data
  1011. * @param string $procSet (optional) Name of ProcSet to add.
  1012. * @return Zend_Pdf_Canvas_Interface
  1013. */
  1014. public function rawWrite($data, $procSet = null)
  1015. {
  1016. if (! empty($procSet)) {
  1017. $this->_addProcSet($procSet);
  1018. }
  1019. $this->_contents .= $data;
  1020. return $this;
  1021. }
  1022. }