4119
4976
* @param $text_to_convert Text to convert.
4120
4977
* @return string converted
4122
function unhtmlentities($text_to_convert) {
4123
require_once(dirname(__FILE__).'/html_entity_decode_php4.php');
4124
return html_entity_decode_php4($text_to_convert);
4979
public function unhtmlentities($text_to_convert) {
4980
return html_entity_decode($text_to_convert, ENT_QUOTES, $this->encoding);
4983
// ENCRYPTION METHODS ----------------------------------
4984
// SINCE 2.0.000 (2008-01-02)
4986
* Compute encryption key depending on object number where the encrypted data is stored
4987
* @param int $n object number
4988
* @since 2.0.000 (2008-01-02)
4990
protected function _objectkey($n) {
4991
return substr($this->_md5_16($this->encryption_key.pack('VXxx',$n)),0,10);
4995
* Put encryption on PDF document
4996
* @since 2.0.000 (2008-01-02)
4998
protected function _putencryption() {
4999
$this->_out('/Filter /Standard');
5000
$this->_out('/V 1');
5001
$this->_out('/R 2');
5002
$this->_out('/O ('.$this->_escape($this->Ovalue).')');
5003
$this->_out('/U ('.$this->_escape($this->Uvalue).')');
5004
$this->_out('/P '.$this->Pvalue);
5008
* Returns the input text exrypted using RC4 algorithm and the specified key.
5009
* RC4 is the standard encryption algorithm used in PDF format
5010
* @param string $key encryption key
5011
* @param String $text input text to be encrypted
5012
* @return String encrypted text
5013
* @since 2.0.000 (2008-01-02)
5014
* @author Klemen Vodopivec
5016
protected function _RC4($key, $text) {
5017
if ($this->last_rc4_key != $key) {
5018
$k = str_repeat($key, 256/strlen($key)+1);
5019
$rc4 = range(0,255);
5021
for ($i=0; $i<256; $i++) {
5023
$j = ($j + $t + ord($k{$i})) % 256;
5024
$rc4[$i] = $rc4[$j];
5027
$this->last_rc4_key = $key;
5028
$this->last_rc4_key_c = $rc4;
5030
$rc4 = $this->last_rc4_key_c;
5032
$len = strlen($text);
5036
for ($i=0; $i<$len; $i++) {
5040
$rc4[$a] = $rc4[$b];
5042
$k = $rc4[($rc4[$a]+$rc4[$b])%256];
5043
$out.=chr(ord($text{$i}) ^ $k);
5049
* Encrypts a string using MD5 and returns it's value as a binary string.
5050
* @param string $str input string
5051
* @return String MD5 encrypted binary string
5052
* @since 2.0.000 (2008-01-02)
5053
* @author Klemen Vodopivec
5055
protected function _md5_16($str) {
5056
return pack('H*',md5($str));
5060
* Compute O value (used for RC4 encryption)
5061
* @param String $user_pass user password
5062
* @param String $owner_pass user password
5063
* @return String O value
5064
* @since 2.0.000 (2008-01-02)
5065
* @author Klemen Vodopivec
5067
protected function _Ovalue($user_pass, $owner_pass) {
5068
$tmp = $this->_md5_16($owner_pass);
5069
$owner_RC4_key = substr($tmp,0,5);
5070
return $this->_RC4($owner_RC4_key, $user_pass);
5074
* Compute U value (used for RC4 encryption)
5075
* @return String U value
5076
* @since 2.0.000 (2008-01-02)
5077
* @author Klemen Vodopivec
5079
protected function _Uvalue() {
5080
return $this->_RC4($this->encryption_key, $this->padding);
5084
* Compute encryption key
5085
* @param String $user_pass user password
5086
* @param String $owner_pass user password
5087
* @param String $protection protection type
5088
* @since 2.0.000 (2008-01-02)
5089
* @author Klemen Vodopivec
5091
protected function _generateencryptionkey($user_pass, $owner_pass, $protection) {
5093
$user_pass = substr($user_pass.$this->padding,0,32);
5094
$owner_pass = substr($owner_pass.$this->padding,0,32);
5096
$this->Ovalue = $this->_Ovalue($user_pass,$owner_pass);
5097
// Compute encyption key
5098
$tmp = $this->_md5_16($user_pass.$this->Ovalue.chr($protection)."\xFF\xFF\xFF");
5099
$this->encryption_key = substr($tmp,0,5);
5101
$this->Uvalue = $this->_Uvalue();
5103
$this->Pvalue = -(($protection^255)+1);
5107
* Set document protection
5108
* The permission array is composed of values taken from the following ones:
5109
* - copy: copy text and images to the clipboard
5110
* - print: print the document
5111
* - modify: modify it (except for annotations and forms)
5112
* - annot-forms: add annotations and forms
5113
* Remark: the protection against modification is for people who have the full Acrobat product.
5114
* If you don't set any password, the document will open as usual. If you set a user password, the PDF viewer will ask for it before displaying the document. The master password, if different from the user one, can be used to get full access.
5115
* Note: protecting a document requires to encrypt it, which increases the processing time a lot. This can cause a PHP time-out in some cases, especially if the document contains images or fonts.
5116
* @param Array $permissions the set of permissions. Empty by default (only viewing is allowed). (print, modify, copy, annot-forms)
5117
* @param String $user_pass user password. Empty by default.
5118
* @param String $owner_pass owner password. If not specified, a random value is used.
5119
* @since 2.0.000 (2008-01-02)
5120
* @author Klemen Vodopivec
5122
public function SetProtection($permissions=array(),$user_pass='',$owner_pass=null) {
5123
$options = array('print' => 4, 'modify' => 8, 'copy' => 16, 'annot-forms' => 32);
5125
foreach($permissions as $permission) {
5126
if (!isset($options[$permission])) {
5127
$this->Error('Incorrect permission: '.$permission);
5129
$protection += $options[$permission];
5131
if ($owner_pass === null) {
5132
$owner_pass = uniqid(rand());
5134
$this->encrypted = true;
5135
$this->_generateencryptionkey($user_pass, $owner_pass, $protection);
5138
// END OF ENCRYPTION FUNCTIONS -------------------------
5140
// START TRANSFORMATIONS SECTION -----------------------
5141
// authors: Moritz Wagner, Andreas Wurmser, Nicola Asuni
5144
* Starts a 2D tranformation saving current graphic state.
5145
* This function must be called before scaling, mirroring, translation, rotation and skewing.
5146
* Use StartTransform() before, and StopTransform() after the transformations to restore the normal behavior.
5147
* @since 2.1.000 (2008-01-07)
5148
* @see StartTransform(), StopTransform()
5150
public function StartTransform() {
5155
* Stops a 2D tranformation restoring previous graphic state.
5156
* This function must be called after scaling, mirroring, translation, rotation and skewing.
5157
* Use StartTransform() before, and StopTransform() after the transformations to restore the normal behavior.
5158
* @since 2.1.000 (2008-01-07)
5159
* @see StartTransform(), StopTransform()
5161
public function StopTransform() {
5165
* Horizontal Scaling.
5166
* @param float $s_x scaling factor for width as percent. 0 is not allowed.
5167
* @param int $x abscissa of the scaling center. Default is current x position
5168
* @param int $y ordinate of the scaling center. Default is current y position
5169
* @since 2.1.000 (2008-01-07)
5170
* @see StartTransform(), StopTransform()
5172
public function ScaleX($s_x, $x='', $y=''){
5173
$this->Scale($s_x, 100, $x, $y);
5178
* @param float $s_y scaling factor for height as percent. 0 is not allowed.
5179
* @param int $x abscissa of the scaling center. Default is current x position
5180
* @param int $y ordinate of the scaling center. Default is current y position
5181
* @since 2.1.000 (2008-01-07)
5182
* @see StartTransform(), StopTransform()
5184
public function ScaleY($s_y, $x='', $y=''){
5185
$this->Scale(100, $s_y, $x, $y);
5189
* Vertical and horizontal proportional Scaling.
5190
* @param float $s scaling factor for width and height as percent. 0 is not allowed.
5191
* @param int $x abscissa of the scaling center. Default is current x position
5192
* @param int $y ordinate of the scaling center. Default is current y position
5193
* @since 2.1.000 (2008-01-07)
5194
* @see StartTransform(), StopTransform()
5196
public function ScaleXY($s, $x='', $y=''){
5197
$this->Scale($s, $s, $x, $y);
5201
* Vertical and horizontal non-proportional Scaling.
5202
* @param float $s_x scaling factor for width as percent. 0 is not allowed.
5203
* @param float $s_y scaling factor for height as percent. 0 is not allowed.
5204
* @param int $x abscissa of the scaling center. Default is current x position
5205
* @param int $y ordinate of the scaling center. Default is current y position
5206
* @since 2.1.000 (2008-01-07)
5207
* @see StartTransform(), StopTransform()
5209
public function Scale($s_x, $s_y, $x='', $y=''){
5219
if($s_x == 0 OR $s_y == 0)
5220
$this->Error('Please use values unequal to zero for Scaling');
5221
$y=($this->h-$y)*$this->k;
5223
//calculate elements of transformation matrix
5232
//scale the coordinate system
5233
$this->Transform($tm);
5237
* Horizontal Mirroring.
5238
* @param int $x abscissa of the point. Default is current x position
5239
* @since 2.1.000 (2008-01-07)
5240
* @see StartTransform(), StopTransform()
5242
public function MirrorH($x=''){
5243
$this->Scale(-100, 100, $x);
5247
* Verical Mirroring.
5248
* @param int $y ordinate of the point. Default is current y position
5249
* @since 2.1.000 (2008-01-07)
5250
* @see StartTransform(), StopTransform()
5252
public function MirrorV($y=''){
5253
$this->Scale(100, -100, '', $y);
5257
* Point reflection mirroring.
5258
* @param int $x abscissa of the point. Default is current x position
5259
* @param int $y ordinate of the point. Default is current y position
5260
* @since 2.1.000 (2008-01-07)
5261
* @see StartTransform(), StopTransform()
5263
public function MirrorP($x='',$y=''){
5264
$this->Scale(-100, -100, $x, $y);
5268
* Reflection against a straight line through point (x, y) with the gradient angle (angle).
5269
* @param float $angle gradient angle of the straight line. Default is 0 (horizontal line).
5270
* @param int $x abscissa of the point. Default is current x position
5271
* @param int $y ordinate of the point. Default is current y position
5272
* @since 2.1.000 (2008-01-07)
5273
* @see StartTransform(), StopTransform()
5275
public function MirrorL($angle=0, $x='',$y=''){
5276
$this->Scale(-100, 100, $x, $y);
5277
$this->Rotate(-2*($angle-90),$x,$y);
5281
* Translate graphic object horizontally.
5282
* @param int $t_x movement to the right
5283
* @since 2.1.000 (2008-01-07)
5284
* @see StartTransform(), StopTransform()
5286
public function TranslateX($t_x){
5287
$this->Translate($t_x, 0);
5291
* Translate graphic object vertically.
5292
* @param int $t_y movement to the bottom
5293
* @since 2.1.000 (2008-01-07)
5294
* @see StartTransform(), StopTransform()
5296
public function TranslateY($t_y){
5297
$this->Translate(0, $t_y, $x, $y);
5301
* Translate graphic object horizontally and vertically.
5302
* @param int $t_x movement to the right
5303
* @param int $t_y movement to the bottom
5304
* @since 2.1.000 (2008-01-07)
5305
* @see StartTransform(), StopTransform()
5307
public function Translate($t_x, $t_y){
5311
//calculate elements of transformation matrix
5316
$tm[4]=$t_x*$this->k;
5317
$tm[5]=-$t_y*$this->k;
5318
//translate the coordinate system
5319
$this->Transform($tm);
5324
* @param float $angle angle in degrees for counter-clockwise rotation
5325
* @param int $x abscissa of the rotation center. Default is current x position
5326
* @param int $y ordinate of the rotation center. Default is current y position
5327
* @since 2.1.000 (2008-01-07)
5328
* @see StartTransform(), StopTransform()
5330
public function Rotate($angle, $x='', $y=''){
5341
$y=($this->h-$y)*$this->k;
5343
//calculate elements of transformation matrix
5344
$tm[0]=cos(deg2rad($angle));
5345
$tm[1]=sin(deg2rad($angle));
5348
$tm[4]=$x+$tm[1]*$y-$tm[0]*$x;
5349
$tm[5]=$y-$tm[0]*$y-$tm[1]*$x;
5350
//rotate the coordinate system around ($x,$y)
5351
$this->Transform($tm);
5355
* Skew horizontally.
5356
* @param float $angle_x angle in degrees between -90 (skew to the left) and 90 (skew to the right)
5357
* @param int $x abscissa of the skewing center. default is current x position
5358
* @param int $y ordinate of the skewing center. default is current y position
5359
* @since 2.1.000 (2008-01-07)
5360
* @see StartTransform(), StopTransform()
5362
public function SkewX($angle_x, $x='', $y=''){
5363
$this->Skew($angle_x, 0, $x, $y);
5368
* @param float $angle_y angle in degrees between -90 (skew to the bottom) and 90 (skew to the top)
5369
* @param int $x abscissa of the skewing center. default is current x position
5370
* @param int $y ordinate of the skewing center. default is current y position
5371
* @since 2.1.000 (2008-01-07)
5372
* @see StartTransform(), StopTransform()
5374
public function SkewY($angle_y, $x='', $y=''){
5375
$this->Skew(0, $angle_y, $x, $y);
5380
* @param float $angle_x angle in degrees between -90 (skew to the left) and 90 (skew to the right)
5381
* @param float $angle_y angle in degrees between -90 (skew to the bottom) and 90 (skew to the top)
5382
* @param int $x abscissa of the skewing center. default is current x position
5383
* @param int $y ordinate of the skewing center. default is current y position
5384
* @since 2.1.000 (2008-01-07)
5385
* @see StartTransform(), StopTransform()
5387
public function Skew($angle_x, $angle_y, $x='', $y=''){
5396
$angle_x = -$angle_x;
5398
if($angle_x <= -90 OR $angle_x >= 90 OR $angle_y <= -90 OR $angle_y >= 90)
5399
$this->Error('Please use values between -90� and 90� for skewing');
5401
$y=($this->h-$y)*$this->k;
5402
//calculate elements of transformation matrix
5404
$tm[1]=tan(deg2rad($angle_y));
5405
$tm[2]=tan(deg2rad($angle_x));
5409
//skew the coordinate system
5410
$this->Transform($tm);
5414
* Apply graphic transformations.
5415
* @since 2.1.000 (2008-01-07)
5416
* @see StartTransform(), StopTransform()
5418
protected function Transform($tm){
5419
$this->_out(sprintf('%.3f %.3f %.3f %.3f %.3f %.3f cm', $tm[0],$tm[1],$tm[2],$tm[3],$tm[4],$tm[5]));
5422
// END TRANSFORMATIONS SECTION -------------------------
5425
// START GRAPHIC FUNCTIONS SECTION ---------------------
5426
// The following section is based on the code provided by David Hernandez Sanz
5429
* Defines the line width. By default, the value equals 0.2 mm. The method can be called before the first page is created and the value is retained from page to page.
5430
* @param float $width The width.
5432
* @see Line(), Rect(), Cell(), MultiCell()
5434
public function SetLineWidth($width) {
5436
$this->LineWidth=$width;
5438
$this->_out(sprintf('%.2f w',$width*$this->k));
5443
* Returns the current the line width.
5444
* @return int Line width
5445
* @since 2.1.000 (2008-01-07)
5446
* @see Line(), SetLineWidth()
5448
public function GetLineWidth() {
5449
return $this->LineWidth;
5455
* @param array $style Line style. Array with keys among the following:
5457
* <li>width (float): Width of the line in user units.</li>
5458
* <li>cap (string): Type of cap to put on the line. Possible values are:
5459
* butt, round, square. The difference between "square" and "butt" is that
5460
* "square" projects a flat end past the end of the line.</li>
5461
* <li>join (string): Type of join. Possible values are: miter, round,
5463
* <li>dash (mixed): Dash pattern. Is 0 (without dash) or string with
5464
* series of length values, which are the lengths of the on and off dashes.
5465
* For example: "2" represents 2 on, 2 off, 2 on, 2 off, ...; "2,1" is 2 on,
5466
* 1 off, 2 on, 1 off, ...</li>
5467
* <li>phase (integer): Modifier on the dash pattern which is used to shift
5468
* the point at which the pattern starts.</li>
5469
* <li>color (array): Draw color. Format: array(red, green, blue).</li>
5472
* @since 2.1.000 (2008-01-08)
5474
public function SetLineStyle($style) {
5476
if (isset($width)) {
5477
$width_prev = $this->LineWidth;
5478
$this->SetLineWidth($width);
5479
$this->LineWidth = $width_prev;
5482
$ca = array("butt" => 0, "round"=> 1, "square" => 2);
5483
if (isset($ca[$cap])) {
5484
$this->_out($ca[$cap] . " J");
5488
$ja = array("miter" => 0, "round" => 1, "bevel" => 2);
5489
if (isset($ja[$join])) {
5490
$this->_out($ja[$join] . " j");
5496
// phpMyAdmin change
5497
if (preg_match("/^.+,/", $dash)) {
5498
$tab = explode(",", $dash);
5500
$tab = array($dash);
5503
foreach ($tab as $i => $v) {
5505
$dash_string .= " ";
5507
$dash_string .= sprintf("%.2f", $v);
5510
if (!isset($phase) OR !$dash) {
5513
$this->_out(sprintf("[%s] %.2f d", $dash_string, $phase));
5515
if (isset($color)) {
5516
list($r, $g, $b) = $color;
5517
$this->SetDrawColor($r, $g, $b);
5523
* @param float $x Abscissa of point.
5524
* @param float $y Ordinate of point.
5526
* @since 2.1.000 (2008-01-08)
5528
protected function _outPoint($x, $y) {
5532
$this->_out(sprintf("%.2f %.2f m", $x * $this->k, ($this->h - $y) * $this->k));
5536
* Draws a line from last draw point.
5537
* @param float $x Abscissa of end point.
5538
* @param float $y Ordinate of end point.
5540
* @since 2.1.000 (2008-01-08)
5542
protected function _outLine($x, $y) {
5546
$this->_out(sprintf("%.2f %.2f l", $x * $this->k, ($this->h - $y) * $this->k));
5550
* Draws a rectangle.
5551
* @param float $x Abscissa of upper-left corner (or upper-right corner for RTL language).
5552
* @param float $y Ordinate of upper-left corner (or upper-right corner for RTL language).
5553
* @param float $w Width.
5554
* @param float $h Height.
5555
* @param string $op options
5557
* @since 2.1.000 (2008-01-08)
5559
protected function _outRect($x, $y, $w, $h, $op) {
5561
$x = $this->w - $x - $w;
5563
$this->_out(sprintf('%.2f %.2f %.2f %.2f re %s',$x*$this->k,($this->h-$y)*$this->k,$w*$this->k,-$h*$this->k,$op));
5567
* Draws a Bezier curve from last draw point.
5568
* The Bezier curve is a tangent to the line between the control points at either end of the curve.
5569
* @param float $x1 Abscissa of control point 1.
5570
* @param float $y1 Ordinate of control point 1.
5571
* @param float $x2 Abscissa of control point 2.
5572
* @param float $y2 Ordinate of control point 2.
5573
* @param float $x3 Abscissa of end point.
5574
* @param float $y3 Ordinate of end point.
5576
* @since 2.1.000 (2008-01-08)
5578
protected function _outCurve($x1, $y1, $x2, $y2, $x3, $y3) {
5580
$x1 = $this->w - $x1;
5581
$x2 = $this->w - $x2;
5582
$x3 = $this->w - $x3;
5584
$this->_out(sprintf("%.2f %.2f %.2f %.2f %.2f %.2f c", $x1 * $this->k, ($this->h - $y1) * $this->k, $x2 * $this->k, ($this->h - $y2) * $this->k, $x3 * $this->k, ($this->h - $y3) * $this->k));
5588
* Draws a line between two points.
5589
* @param float $x1 Abscissa of first point.
5590
* @param float $y1 Ordinate of first point.
5591
* @param float $x2 Abscissa of second point.
5592
* @param float $y2 Ordinate of second point.
5593
* @param array $style Line style. Array like for {@link SetLineStyle SetLineStyle}. Default value: default line style (empty array).
5596
* @see SetLineWidth(), SetDrawColor(), SetLineStyle()
5598
public function Line($x1, $y1, $x2, $y2, $style = array()) {
5600
$this->SetLineStyle($style);
5602
$this->_outPoint($x1, $y1);
5603
$this->_outLine($x2, $y2);
5608
* Draws a rectangle.
5609
* @param float $x Abscissa of upper-left corner (or upper-right corner for RTL language).
5610
* @param float $y Ordinate of upper-left corner (or upper-right corner for RTL language).
5611
* @param float $w Width.
5612
* @param float $h Height.
5613
* @param string $style Style of rendering. Possible values are:
5615
* <li>D or empty string: Draw (default).</li>
5617
* <li>DF or FD: Draw and fill.</li>
5619
* @param array $border_style Border style of rectangle. Array with keys among the following:
5621
* <li>all: Line style of all borders. Array like for {@link SetLineStyle SetLineStyle}.</li>
5622
* <li>L, T, R, B or combinations: Line style of left, top, right or bottom border. Array like for {@link SetLineStyle SetLineStyle}.</li>
5624
* If a key is not present or is null, not draws the border. Default value: default line style (empty array).
5625
* @param array $fill_color Fill color. Format: array(red, green, blue). Default value: default color (empty array).
5628
* @see SetLineStyle()
5630
public function Rect($x, $y, $w, $h, $style='', $border_style = array(), $fill_color = array()) {
5631
if (!(false === strpos($style, "F")) AND $fill_color) {
5632
list($r, $g, $b) = $fill_color;
5633
$this->SetFillColor($r, $g, $b);
5638
$border_style = array();
5639
$this->_outRect($x, $y, $w, $h, $op);
5644
if (!$border_style OR isset($border_style["all"])) {
5646
if (isset($border_style["all"])) {
5647
$this->SetLineStyle($border_style["all"]);
5648
$border_style = array();
5653
$this->_outRect($x, $y, $w, $h, $op);
5658
if (!$border_style OR isset($border_style["all"])) {
5659
if (isset($border_style["all"]) && $border_style["all"]) {
5660
$this->SetLineStyle($border_style["all"]);
5661
$border_style = array();
5663
$this->_outRect($x, $y, $w, $h, $op);
5668
if ($border_style) {
5669
$border_style2 = array();
5670
foreach ($border_style as $line => $value) {
5671
$lenght = strlen($line);
5672
for ($i = 0; $i < $lenght; $i++) {
5673
$border_style2[$line[$i]] = $value;
5676
$border_style = $border_style2;
5677
if (isset($border_style["L"]) && $border_style["L"]) {
5678
$this->Line($x, $y, $x, $y + $h, $border_style["L"]);
5680
if (isset($border_style["T"]) && $border_style["T"]) {
5681
$this->Line($x, $y, $x + $w, $y, $border_style["T"]);
5683
if (isset($border_style["R"]) && $border_style["R"]) {
5684
$this->Line($x + $w, $y, $x + $w, $y + $h, $border_style["R"]);
5686
if (isset($border_style["B"]) && $border_style["B"]) {
5687
$this->Line($x, $y + $h, $x + $w, $y + $h, $border_style["B"]);
5694
* Draws a Bezier curve.
5695
* The Bezier curve is a tangent to the line between the control points at
5696
* either end of the curve.
5697
* @param float $x0 Abscissa of start point.
5698
* @param float $y0 Ordinate of start point.
5699
* @param float $x1 Abscissa of control point 1.
5700
* @param float $y1 Ordinate of control point 1.
5701
* @param float $x2 Abscissa of control point 2.
5702
* @param float $y2 Ordinate of control point 2.
5703
* @param float $x3 Abscissa of end point.
5704
* @param float $y3 Ordinate of end point.
5705
* @param string $style Style of rendering. Possible values are:
5707
* <li>D or empty string: Draw (default).</li>
5709
* <li>DF or FD: Draw and fill.</li>
5711
* @param array $line_style Line style of curve. Array like for {@link SetLineStyle SetLineStyle}. Default value: default line style (empty array).
5712
* @param array $fill_color Fill color. Format: array(red, green, blue). Default value: default color (empty array).
5714
* @see SetLineStyle()
5715
* @since 2.1.000 (2008-01-08)
5717
public function Curve($x0, $y0, $x1, $y1, $x2, $y2, $x3, $y3, $style = "", $line_style = array(), $fill_color = array()) {
5718
if (!(false === strpos($style, "F")) AND $fill_color) {
5719
list($r, $g, $b) = $fill_color;
5720
$this->SetFillColor($r, $g, $b);
5725
$line_style = array();
5739
$this->SetLineStyle($line_style);
5741
$this->_outPoint($x0, $y0);
5742
$this->_outCurve($x1, $y1, $x2, $y2, $x3, $y3);
5748
* An ellipse is formed from n Bezier curves.
5749
* @param float $x0 Abscissa of center point.
5750
* @param float $y0 Ordinate of center point.
5751
* @param float $rx Horizontal radius.
5752
* @param float $ry Vertical radius (if ry = 0 then is a circle, see {@link Circle Circle}). Default value: 0.
5753
* @param float $angle: Angle oriented (anti-clockwise). Default value: 0.
5754
* @param float $astart: Angle start of draw line. Default value: 0.
5755
* @param float $afinish: Angle finish of draw line. Default value: 360.
5756
* @param string $style Style of rendering. Possible values are:
5758
* <li>D or empty string: Draw (default).</li>
5760
* <li>DF or FD: Draw and fill.</li>
5761
* <li>C: Draw close.</li>
5763
* @param array $line_style Line style of ellipse. Array like for {@link SetLineStyle SetLineStyle}. Default value: default line style (empty array).
5764
* @param array $fill_color Fill color. Format: array(red, green, blue). Default value: default color (empty array).
5765
* @param integer $nc Number of curves used in ellipse. Default value: 8.
5767
* @since 2.1.000 (2008-01-08)
5769
public function Ellipse($x0, $y0, $rx, $ry = 0, $angle = 0, $astart = 0, $afinish = 360, $style = "", $line_style = array(), $fill_color = array(), $nc = 8) {
5771
$this->StartTransform();
5772
$this->Rotate($angle, $x0, $y0);
5773
$this->Ellipse($x0, $y0, $rx, $ry, 0, $astart, $afinish, $style, $line_style, $fill_color, $nc);
5774
$this->StopTransform();
5778
if (!(false === strpos($style, "F")) AND $fill_color) {
5779
list($r, $g, $b) = $fill_color;
5780
$this->SetFillColor($r, $g, $b);
5785
$line_style = array();
5794
$op = "s"; // Small "s" signifies closing the path as well
5803
$this->SetLineStyle($line_style);
5813
$astart = deg2rad((float) $astart);
5814
$afinish = deg2rad((float) $afinish);
5815
$total_angle = $afinish - $astart;
5816
$dt = $total_angle / $nc;
5819
$y0 = ($this->h - $y0) * $this->k;
5821
$a0 = $x0 + ($rx * cos($t1));
5822
$b0 = $y0 + ($ry * sin($t1));
5823
$c0 = -$rx * sin($t1);
5824
$d0 = $ry * cos($t1);
5825
$this->_outPoint($a0 / $this->k, $this->h - ($b0 / $this->k));
5826
for ($i = 1; $i <= $nc; $i++) {
5827
// Draw this bit of the total curve
5828
$t1 = ($i * $dt) + $astart;
5829
$a1 = $x0 + ($rx * cos($t1));
5830
$b1 = $y0 + ($ry * sin($t1));
5831
$c1 = -$rx * sin($t1);
5832
$d1 = $ry * cos($t1);
5833
$this->_outCurve(($a0 + ($c0 * $dtm)) / $this->k, $this->h - (($b0 + ($d0 * $dtm)) / $this->k), ($a1 - ($c1 * $dtm)) / $this->k, $this->h - (($b1 - ($d1 * $dtm)) / $this->k), $a1 / $this->k, $this->h - ($b1 / $this->k));
5845
* A circle is formed from n Bezier curves.
5846
* @param float $x0 Abscissa of center point.
5847
* @param float $y0 Ordinate of center point.
5848
* @param float $r Radius.
5849
* @param float $astart: Angle start of draw line. Default value: 0.
5850
* @param float $afinish: Angle finish of draw line. Default value: 360.
5851
* @param string $style Style of rendering. Possible values are:
5853
* <li>D or empty string: Draw (default).</li>
5855
* <li>DF or FD: Draw and fill.</li>
5856
* <li>C: Draw close.</li>
5858
* @param array $line_style Line style of circle. Array like for {@link SetLineStyle SetLineStyle}. Default value: default line style (empty array).
5859
* @param array $fill_color Fill color. Format: array(red, green, blue). Default value: default color (empty array).
5860
* @param integer $nc Number of curves used in circle. Default value: 8.
5862
* @since 2.1.000 (2008-01-08)
5864
public function Circle($x0, $y0, $r, $astart = 0, $afinish = 360, $style = "", $line_style = array(), $fill_color = array(), $nc = 8) {
5865
$this->Ellipse($x0, $y0, $r, 0, 0, $astart, $afinish, $style, $line_style, $fill_color, $nc);
5870
* @param array $p Points 0 to ($np - 1). Array with values (x0, y0, x1, y1,..., x(np-1), y(np - 1))
5871
* @param string $style Style of rendering. Possible values are:
5873
* <li>D or empty string: Draw (default).</li>
5875
* <li>DF or FD: Draw and fill.</li>
5877
* @param array $line_style Line style of polygon. Array with keys among the following:
5879
* <li>all: Line style of all lines. Array like for {@link SetLineStyle SetLineStyle}.</li>
5880
* <li>0 to ($np - 1): Line style of each line. Array like for {@link SetLineStyle SetLineStyle}.</li>
5882
* If a key is not present or is null, not draws the line. Default value is default line style (empty array).
5883
* @param array $fill_color Fill color. Format: array(red, green, blue). Default value: default color (empty array).
5885
* @since 2.1.000 (2008-01-08)
5887
public function Polygon($p, $style = "", $line_style = array(), $fill_color = array()) {
5888
$np = count($p) / 2;
5889
if (!(false === strpos($style, "F")) AND $fill_color) {
5890
list($r, $g, $b) = $fill_color;
5891
$this->SetFillColor($r, $g, $b);
5895
$line_style = array();
5911
if (isset($line_style["all"])) {
5912
$this->SetLineStyle($line_style["all"]);
5914
else { // 0 .. (np - 1), op = {B, S}
5918
$this->_outPoint($p[0], $p[1]);
5919
for ($i = 2; $i < ($np * 2); $i = $i + 2) {
5920
$this->_outLine($p[$i], $p[$i + 1]);
5922
$this->_outLine($p[0], $p[1]);
5925
$p[$np * 2] = $p[0];
5926
$p[($np * 2) + 1] = $p[1];
5927
for ($i = 0; $i < $np; $i++) {
5928
if (isset($line_style[$i])) {
5929
$this->Line($p[$i * 2], $p[($i * 2) + 1], $p[($i * 2) + 2], $p[($i * 2) + 3], $line_style[$i]);
5935
$this->_outPoint($p[0], $p[1]);
5936
for ($i = 2; $i < ($np * 2); $i = $i + 2) {
5937
$this->_outLine($p[$i], $p[$i + 1]);
5939
$this->_outLine($p[0], $p[1]);
5945
* Draws a regular polygon.
5946
* @param float $x0 Abscissa of center point.
5947
* @param float $y0 Ordinate of center point.
5948
* @param float $r: Radius of inscribed circle.
5949
* @param integer $ns Number of sides.
5950
* @param float $angle Angle oriented (anti-clockwise). Default value: 0.
5951
* @param boolean $draw_circle Draw inscribed circle or not. Default value: false.
5952
* @param string $style Style of rendering. Possible values are:
5954
* <li>D or empty string: Draw (default).</li>
5956
* <li>DF or FD: Draw and fill.</li>
5958
* @param array $line_style Line style of polygon sides. Array with keys among the following:
5960
* <li>all: Line style of all sides. Array like for {@link SetLineStyle SetLineStyle}.</li>
5961
* <li>0 to ($ns - 1): Line style of each side. Array like for {@link SetLineStyle SetLineStyle}.</li>
5963
* If a key is not present or is null, not draws the side. Default value is default line style (empty array).
5964
* @param array $fill_color Fill color. Format: array(red, green, blue). Default value: default color (empty array).
5965
* @param string $circle_style Style of rendering of inscribed circle (if draws). Possible values are:
5967
* <li>D or empty string: Draw (default).</li>
5969
* <li>DF or FD: Draw and fill.</li>
5971
* @param array $circle_outLine_style Line style of inscribed circle (if draws). Array like for {@link SetLineStyle SetLineStyle}. Default value: default line style (empty array).
5972
* @param array $circle_fill_color Fill color of inscribed circle (if draws). Format: array(red, green, blue). Default value: default color (empty array).
5974
* @since 2.1.000 (2008-01-08)
5976
public function RegularPolygon($x0, $y0, $r, $ns, $angle = 0, $draw_circle = false, $style = "", $line_style = array(), $fill_color = array(), $circle_style = "", $circle_outLine_style = array(), $circle_fill_color = array()) {
5981
$this->Circle($x0, $y0, $r, 0, 360, $circle_style, $circle_outLine_style, $circle_fill_color);
5984
for ($i = 0; $i < $ns; $i++) {
5985
$a = $angle + ($i * 360 / $ns);
5986
$a_rad = deg2rad((float) $a);
5987
$p[] = $x0 + ($r * sin($a_rad));
5988
$p[] = $y0 + ($r * cos($a_rad));
5990
$this->Polygon($p, $style, $line_style, $fill_color);
5994
* Draws a star polygon
5995
* @param float $x0 Abscissa of center point.
5996
* @param float $y0 Ordinate of center point.
5997
* @param float $r Radius of inscribed circle.
5998
* @param integer $nv Number of vertices.
5999
* @param integer $ng Number of gap (if ($ng % $nv = 1) then is a regular polygon).
6000
* @param float $angle: Angle oriented (anti-clockwise). Default value: 0.
6001
* @param boolean $draw_circle: Draw inscribed circle or not. Default value is false.
6002
* @param string $style Style of rendering. Possible values are:
6004
* <li>D or empty string: Draw (default).</li>
6006
* <li>DF or FD: Draw and fill.</li>
6008
* @param array $line_style Line style of polygon sides. Array with keys among the following:
6010
* <li>all: Line style of all sides. Array like for
6011
* {@link SetLineStyle SetLineStyle}.</li>
6012
* <li>0 to (n - 1): Line style of each side. Array like for {@link SetLineStyle SetLineStyle}.</li>
6014
* If a key is not present or is null, not draws the side. Default value is default line style (empty array).
6015
* @param array $fill_color Fill color. Format: array(red, green, blue). Default value: default color (empty array).
6016
* @param string $circle_style Style of rendering of inscribed circle (if draws). Possible values are:
6018
* <li>D or empty string: Draw (default).</li>
6020
* <li>DF or FD: Draw and fill.</li>
6022
* @param array $circle_outLine_style Line style of inscribed circle (if draws). Array like for {@link SetLineStyle SetLineStyle}. Default value: default line style (empty array).
6023
* @param array $circle_fill_color Fill color of inscribed circle (if draws). Format: array(red, green, blue). Default value: default color (empty array).
6025
* @since 2.1.000 (2008-01-08)
6027
public function StarPolygon($x0, $y0, $r, $nv, $ng, $angle = 0, $draw_circle = false, $style = "", $line_style = array(), $fill_color = array(), $circle_style = "", $circle_outLine_style = array(), $circle_fill_color = array()) {
6032
$this->Circle($x0, $y0, $r, 0, 360, $circle_style, $circle_outLine_style, $circle_fill_color);
6036
for ($i = 0; $i < $nv; $i++) {
6037
$a = $angle + ($i * 360 / $nv);
6038
$a_rad = deg2rad((float) $a);
6039
$p2[] = $x0 + ($r * sin($a_rad));
6040
$p2[] = $y0 + ($r * cos($a_rad));
6047
$p[] = $p2[($i * 2) + 1];
6048
$visited[$i] = true;
6051
} while (!$visited[$i]);
6052
$this->Polygon($p, $style, $line_style, $fill_color);
6056
* Draws a rounded rectangle.
6057
* @param float $x Abscissa of upper-left corner.
6058
* @param float $y Ordinate of upper-left corner.
6059
* @param float $w Width.
6060
* @param float $h Height.
6061
* @param float $r Radius of the rounded corners.
6062
* @param string $round_corner Draws rounded corner or not. String with a 0 (not rounded i-corner) or 1 (rounded i-corner) in i-position. Positions are, in order and begin to 0: top left, top right, bottom right and bottom left. Default value: all rounded corner ("1111").
6063
* @param string $style Style of rendering. Possible values are:
6065
* <li>D or empty string: Draw (default).</li>
6067
* <li>DF or FD: Draw and fill.</li>
6069
* @param array $border_style Border style of rectangle. Array like for {@link SetLineStyle SetLineStyle}. Default value: default line style (empty array).
6070
* @param array $fill_color Fill color. Format: array(red, green, blue). Default value: default color (empty array).
6072
* @since 2.1.000 (2008-01-08)
6074
public function RoundedRect($x, $y, $w, $h, $r, $round_corner = "1111", $style = "", $border_style = array(), $fill_color = array()) {
6075
if ("0000" == $round_corner) { // Not rounded
6076
$this->Rect($x, $y, $w, $h, $style, $border_style, $fill_color);
6078
if (!(false === strpos($style, "F")) AND $fill_color) {
6079
list($red, $g, $b) = $fill_color;
6080
$this->SetFillColor($red, $g, $b);
6084
$border_style = array();
6098
if ($border_style) {
6099
$this->SetLineStyle($border_style);
6101
$MyArc = 4 / 3 * (sqrt(2) - 1);
6102
$this->_outPoint($x + $r, $y);
6105
$this->_outLine($xc, $y);
6106
if ($round_corner[0]) {
6107
$this->_outCurve($xc + ($r * $MyArc), $yc - $r, $xc + $r, $yc - ($r * $MyArc), $xc + $r, $yc);
6109
$this->_outLine($x + $w, $y);
6113
$this->_outLine($x + $w, $yc);
6114
if ($round_corner[1]) {
6115
$this->_outCurve($xc + $r, $yc + ($r * $MyArc), $xc + ($r * $MyArc), $yc + $r, $xc, $yc + $r);
6117
$this->_outLine($x + $w, $y + $h);
6121
$this->_outLine($xc, $y + $h);
6122
if ($round_corner[2]) {
6123
$this->_outCurve($xc - ($r * $MyArc), $yc + $r, $xc - $r, $yc + ($r * $MyArc), $xc - $r, $yc);
6125
$this->_outLine($x, $y + $h);
6129
$this->_outLine($x, $yc);
6130
if ($round_corner[3]) {
6131
$this->_outCurve($xc - $r, $yc - ($r * $MyArc), $xc - ($r * $MyArc), $yc - $r, $xc, $yc - $r);
6133
$this->_outLine($x, $y);
6134
$this->_outLine($x + $r, $y);
6140
// END GRAPHIC FUNCTIONS SECTION -----------------------
6142
// BIDIRECTIONAL TEXT SECTION --------------------------
6145
* Reverse the RLT substrings using the Bidirectional Algorithm (http://unicode.org/reports/tr9/).
6146
* @param string $str string to manipulate.
6147
* @param bool $forcertl if 'R' forces RTL, if 'L' forces LTR
6149
* @author Nicola Asuni
6150
* @since 2.1.000 (2008-01-08)
6152
protected function utf8StrRev($str, $setbom=false, $forcertl=false) {
6153
global $unicode,$unicode_mirror, $unicode_arlet;
6154
require_once(dirname(__FILE__).'/unicode_data.php');
6156
// paragraph embedding level
6161
// check if string contains arabic text
6162
if (preg_match(K_RE_PATTERN_ARABIC, $str)) {
6168
// check if string contains RTL text
6169
if (!($forcertl OR $arabic OR preg_match(K_RE_PATTERN_RTL, $str))) {
6170
return $this->UTF8ToUTF16BE($str, false);
6173
// convert string to array of unicode chars
6174
$ta = $this->UTF8StringToArray($str);
6175
// get number of chars
6176
$numchars = count($ta);
6178
if ($forcertl == 'R') {
6180
} elseif ($forcertl == 'L') {
6183
// P2. In each paragraph, find the first character of type L, AL, or R.
6184
// P3. If a character is found in P2 and it is of type AL or R, then set the paragraph embedding level to one; otherwise, set it to zero.
6185
for ($i=0; $i < $numchars; $i++) {
6186
$type = $unicode[$ta[$i]];
6190
} elseif (($type == 'AL') OR ($type == 'R')) {
6197
// Current Embedding Level
6199
// directional override status
6201
$remember = array();
6202
// start-of-level-run
6203
$sor = $pel % 2 ? 'R' : 'L';
6206
//$levels = array(array('level' => $cel, 'sor' => $sor, 'eor' => '', 'chars' => array()));
6207
//$current_level = &$levels[count( $levels )-1];
6209
// Array of characters data
6210
$chardata = Array();
6212
// X1. Begin by setting the current embedding level to the paragraph embedding level. Set the directional override status to neutral. Process each character iteratively, applying rules X2 through X9. Only embedding levels from 0 to 61 are valid in this phase.
6213
// In the resolution of levels in rules I1 and I2, the maximum embedding level of 62 can be reached.
6214
for ($i=0; $i < $numchars; $i++) {
6215
if ($ta[$i] == K_RLE) {
6216
// X2. With each RLE, compute the least greater odd embedding level.
6217
// a. If this new level would be valid, then this embedding code is valid. Remember (push) the current embedding level and override status. Reset the current level to this new level, and reset the override status to neutral.
6218
// b. If the new level would not be valid, then this code is invalid. Do not change the current level or override status.
6219
$next_level = $cel + ($cel % 2) + 1;
6220
if ($next_level < 62) {
6221
$remember[] = array('num' => K_RLE, 'cel' => $cel, 'dos' => $dos);
6225
$eor = $cel % 2 ? 'R' : 'L';
6227
} elseif ($ta[$i] == K_LRE) {
6228
// X3. With each LRE, compute the least greater even embedding level.
6229
// a. If this new level would be valid, then this embedding code is valid. Remember (push) the current embedding level and override status. Reset the current level to this new level, and reset the override status to neutral.
6230
// b. If the new level would not be valid, then this code is invalid. Do not change the current level or override status.
6231
$next_level = $cel + 2 - ($cel % 2);
6232
if ( $next_level < 62 ) {
6233
$remember[] = array('num' => K_LRE, 'cel' => $cel, 'dos' => $dos);
6237
$eor = $cel % 2 ? 'R' : 'L';
6239
} elseif ($ta[$i] == K_RLO) {
6240
// X4. With each RLO, compute the least greater odd embedding level.
6241
// a. If this new level would be valid, then this embedding code is valid. Remember (push) the current embedding level and override status. Reset the current level to this new level, and reset the override status to right-to-left.
6242
// b. If the new level would not be valid, then this code is invalid. Do not change the current level or override status.
6243
$next_level = $cel + ($cel % 2) + 1;
6244
if ($next_level < 62) {
6245
$remember[] = array('num' => K_RLO, 'cel' => $cel, 'dos' => $dos);
6249
$eor = $cel % 2 ? 'R' : 'L';
6251
} elseif ($ta[$i] == K_LRO) {
6252
// X5. With each LRO, compute the least greater even embedding level.
6253
// a. If this new level would be valid, then this embedding code is valid. Remember (push) the current embedding level and override status. Reset the current level to this new level, and reset the override status to left-to-right.
6254
// b. If the new level would not be valid, then this code is invalid. Do not change the current level or override status.
6255
$next_level = $cel + 2 - ($cel % 2);
6256
if ( $next_level < 62 ) {
6257
$remember[] = array('num' => K_LRO, 'cel' => $cel, 'dos' => $dos);
6261
$eor = $cel % 2 ? 'R' : 'L';
6263
} elseif ($ta[$i] == K_PDF) {
6264
// X7. With each PDF, determine the matching embedding or override code. If there was a valid matching code, restore (pop) the last remembered (pushed) embedding level and directional override.
6265
if (count($remember)) {
6266
$last = count($remember ) - 1;
6267
if (($remember[$last]['num'] == K_RLE) OR
6268
($remember[$last]['num'] == K_LRE) OR
6269
($remember[$last]['num'] == K_RLO) OR
6270
($remember[$last]['num'] == K_LRO)) {
6271
$match = array_pop($remember);
6272
$cel = $match['cel'];
6273
$dos = $match['dos'];
6275
$eor = ($cel > $match['cel'] ? $cel : $match['cel']) % 2 ? 'R' : 'L';
6278
} elseif (($ta[$i] != K_RLE) AND
6279
($ta[$i] != K_LRE) AND
6280
($ta[$i] != K_RLO) AND
6281
($ta[$i] != K_LRO) AND
6282
($ta[$i] != K_PDF)) {
6283
// X6. For all types besides RLE, LRE, RLO, LRO, and PDF:
6284
// a. Set the level of the current character to the current embedding level.
6285
// b. Whenever the directional override status is not neutral, reset the current character type to the directional override status.
6289
$chardir = $unicode[$ta[$i]];
6291
// stores string characters and other information
6292
$chardata[] = array('char' => $ta[$i], 'level' => $cel, 'type' => $chardir, 'sor' => $sor, 'eor' => $eor);
6294
} // end for each char
6296
// X8. All explicit directional embeddings and overrides are completely terminated at the end of each paragraph. Paragraph separators are not included in the embedding.
6297
// X9. Remove all RLE, LRE, RLO, LRO, PDF, and BN codes.
6298
// X10. The remaining rules are applied to each run of characters at the same level. For each run, determine the start-of-level-run (sor) and end-of-level-run (eor) type, either L or R. This depends on the higher of the two levels on either side of the boundary (at the start or end of the paragraph, the level of the �other� run is the base embedding level). If the higher level is odd, the type is R; otherwise, it is L.
6300
// 3.3.3 Resolving Weak Types
6301
// Weak types are now resolved one level run at a time. At level run boundaries where the type of the character on the other side of the boundary is required, the type assigned to sor or eor is used.
6302
// Nonspacing marks are now resolved based on the previous characters.
6303
$numchars = count($chardata);
6305
// W1. Examine each nonspacing mark (NSM) in the level run, and change the type of the NSM to the type of the previous character. If the NSM is at the start of the level run, it will get the type of sor.
6306
$prevlevel = -1; // track level changes
6307
$levcount = 0; // counts consecutive chars at the same level
6308
for ($i=0; $i < $numchars; $i++) {
6309
if ($chardata[$i]['type'] == 'NSM') {
6311
$chardata[$i]['type'] = $chardata[$i]['sor'];
6313
$chardata[$i]['type'] = $chardata[($i-1)]['type'];
6316
if ($chardata[$i]['level'] != $prevlevel) {
6321
$prevlevel = $chardata[$i]['level'];
6324
// W2. Search backward from each instance of a European number until the first strong type (R, L, AL, or sor) is found. If an AL is found, change the type of the European number to Arabic number.
6327
for ($i=0; $i < $numchars; $i++) {
6328
if ($chardata[$i]['char'] == 'EN') {
6329
for ($j=$levcount; $j >= 0; $j--) {
6330
if ($chardata[$j]['type'] == 'AL') {
6331
$chardata[$i]['type'] = 'AN';
6332
} elseif (($chardata[$j]['type'] == 'L') OR ($chardata[$j]['type'] == 'R')) {
6337
if ($chardata[$i]['level'] != $prevlevel) {
6342
$prevlevel = $chardata[$i]['level'];
6345
// W3. Change all ALs to R.
6346
for ($i=0; $i < $numchars; $i++) {
6347
if ($chardata[$i]['type'] == 'AL') {
6348
$chardata[$i]['type'] = 'R';
6352
// W4. A single European separator between two European numbers changes to a European number. A single common separator between two numbers of the same type changes to that type.
6355
for ($i=0; $i < $numchars; $i++) {
6356
if (($levcount > 0) AND (($i+1) < $numchars) AND ($chardata[($i+1)]['level'] == $prevlevel)) {
6357
if (($chardata[$i]['type'] == 'ES') AND ($chardata[($i-1)]['type'] == 'EN') AND ($chardata[($i+1)]['type'] == 'EN')) {
6358
$chardata[$i]['type'] = 'EN';
6359
} elseif (($chardata[$i]['type'] == 'CS') AND ($chardata[($i-1)]['type'] == 'EN') AND ($chardata[($i+1)]['type'] == 'EN')) {
6360
$chardata[$i]['type'] = 'EN';
6361
} elseif (($chardata[$i]['type'] == 'CS') AND ($chardata[($i-1)]['type'] == 'AN') AND ($chardata[($i+1)]['type'] == 'AN')) {
6362
$chardata[$i]['type'] = 'AN';
6365
if ($chardata[$i]['level'] != $prevlevel) {
6370
$prevlevel = $chardata[$i]['level'];
6373
// W5. A sequence of European terminators adjacent to European numbers changes to all European numbers.
6376
for ($i=0; $i < $numchars; $i++) {
6377
if($chardata[$i]['type'] == 'ET') {
6378
if (($levcount > 0) AND ($chardata[($i-1)]['type'] == 'EN')) {
6379
$chardata[$i]['type'] = 'EN';
6382
while (($j < $numchars) AND ($chardata[$j]['level'] == $prevlevel)) {
6383
if ($chardata[$j]['type'] == 'EN') {
6384
$chardata[$i]['type'] = 'EN';
6386
} elseif ($chardata[$j]['type'] != 'ET') {
6393
if ($chardata[$i]['level'] != $prevlevel) {
6398
$prevlevel = $chardata[$i]['level'];
6401
// W6. Otherwise, separators and terminators change to Other Neutral.
6404
for ($i=0; $i < $numchars; $i++) {
6405
if (($chardata[$i]['type'] == 'ET') OR ($chardata[$i]['type'] == 'ES') OR ($chardata[$i]['type'] == 'CS')) {
6406
$chardata[$i]['type'] = 'ON';
6408
if ($chardata[$i]['level'] != $prevlevel) {
6413
$prevlevel = $chardata[$i]['level'];
6416
//W7. Search backward from each instance of a European number until the first strong type (R, L, or sor) is found. If an L is found, then change the type of the European number to L.
6419
for ($i=0; $i < $numchars; $i++) {
6420
if ($chardata[$i]['char'] == 'EN') {
6421
for ($j=$levcount; $j >= 0; $j--) {
6422
if ($chardata[$j]['type'] == 'L') {
6423
$chardata[$i]['type'] = 'L';
6424
} elseif ($chardata[$j]['type'] == 'R') {
6429
if ($chardata[$i]['level'] != $prevlevel) {
6434
$prevlevel = $chardata[$i]['level'];
6437
// N1. A sequence of neutrals takes the direction of the surrounding strong text if the text on both sides has the same direction. European and Arabic numbers act as if they were R in terms of their influence on neutrals. Start-of-level-run (sor) and end-of-level-run (eor) are used at level run boundaries.
6440
for ($i=0; $i < $numchars; $i++) {
6441
if (($levcount > 0) AND (($i+1) < $numchars) AND ($chardata[($i+1)]['level'] == $prevlevel)) {
6442
if (($chardata[$i]['type'] == 'N') AND ($chardata[($i-1)]['type'] == 'L') AND ($chardata[($i+1)]['type'] == 'L')) {
6443
$chardata[$i]['type'] = 'L';
6444
} elseif (($chardata[$i]['type'] == 'N') AND
6445
(($chardata[($i-1)]['type'] == 'R') OR ($chardata[($i-1)]['type'] == 'EN') OR ($chardata[($i-1)]['type'] == 'AN')) AND
6446
(($chardata[($i+1)]['type'] == 'R') OR ($chardata[($i+1)]['type'] == 'EN') OR ($chardata[($i+1)]['type'] == 'AN'))) {
6447
$chardata[$i]['type'] = 'R';
6448
} elseif ($chardata[$i]['type'] == 'N') {
6449
// N2. Any remaining neutrals take the embedding direction
6450
$chardata[$i]['type'] = $chardata[$i]['sor'];
6452
} elseif (($levcount == 0) AND (($i+1) < $numchars) AND ($chardata[($i+1)]['level'] == $prevlevel)) {
6454
if (($chardata[$i]['type'] == 'N') AND ($chardata[$i]['sor'] == 'L') AND ($chardata[($i+1)]['type'] == 'L')) {
6455
$chardata[$i]['type'] = 'L';
6456
} elseif (($chardata[$i]['type'] == 'N') AND
6457
(($chardata[$i]['sor'] == 'R') OR ($chardata[$i]['sor'] == 'EN') OR ($chardata[$i]['sor'] == 'AN')) AND
6458
(($chardata[($i+1)]['type'] == 'R') OR ($chardata[($i+1)]['type'] == 'EN') OR ($chardata[($i+1)]['type'] == 'AN'))) {
6459
$chardata[$i]['type'] = 'R';
6460
} elseif ($chardata[$i]['type'] == 'N') {
6461
// N2. Any remaining neutrals take the embedding direction
6462
$chardata[$i]['type'] = $chardata[$i]['sor'];
6464
} elseif (($levcount > 0) AND ((($i+1) == $numchars) OR (($i+1) < $numchars) AND ($chardata[($i+1)]['level'] != $prevlevel))) {
6466
if (($chardata[$i]['type'] == 'N') AND ($chardata[($i-1)]['type'] == 'L') AND ($chardata[$i]['eor'] == 'L')) {
6467
$chardata[$i]['type'] = 'L';
6468
} elseif (($chardata[$i]['type'] == 'N') AND
6469
(($chardata[($i-1)]['type'] == 'R') OR ($chardata[($i-1)]['type'] == 'EN') OR ($chardata[($i-1)]['type'] == 'AN')) AND
6470
(($chardata[$i]['eor'] == 'R') OR ($chardata[$i]['eor'] == 'EN') OR ($chardata[$i]['eor'] == 'AN'))) {
6471
$chardata[$i]['type'] = 'R';
6472
} elseif ($chardata[$i]['type'] == 'N') {
6473
// N2. Any remaining neutrals take the embedding direction
6474
$chardata[$i]['type'] = $chardata[$i]['sor'];
6476
} elseif ($chardata[$i]['type'] == 'N') {
6477
// N2. Any remaining neutrals take the embedding direction
6478
$chardata[$i]['type'] = $chardata[$i]['sor'];
6480
if ($chardata[$i]['level'] != $prevlevel) {
6485
$prevlevel = $chardata[$i]['level'];
6488
// I1. For all characters with an even (left-to-right) embedding direction, those of type R go up one level and those of type AN or EN go up two levels.
6489
// I2. For all characters with an odd (right-to-left) embedding direction, those of type L, EN or AN go up one level.
6490
for ($i=0; $i < $numchars; $i++) {
6491
$odd = $chardata[$i]['level'] % 2;
6493
if (($chardata[$i]['type'] == 'L') OR ($chardata[$i]['type'] == 'AN') OR ($chardata[$i]['type'] == 'EN')){
6494
$chardata[$i]['level'] += 1;
6497
if ($chardata[$i]['type'] == 'R') {
6498
$chardata[$i]['level'] += 1;
6499
} elseif (($chardata[$i]['type'] == 'AN') OR ($chardata[$i]['type'] == 'EN')){
6500
$chardata[$i]['level'] += 2;
6503
$maxlevel = max($chardata[$i]['level'],$maxlevel);
6506
// L1. On each line, reset the embedding level of the following characters to the paragraph embedding level:
6507
// 1. Segment separators,
6508
// 2. Paragraph separators,
6509
// 3. Any sequence of whitespace characters preceding a segment separator or paragraph separator, and
6510
// 4. Any sequence of white space characters at the end of the line.
6511
for ($i=0; $i < $numchars; $i++) {
6512
if (($chardata[$i]['type'] == 'B') OR ($chardata[$i]['type'] == 'S')) {
6513
$chardata[$i]['level'] = $pel;
6514
} elseif ($chardata[$i]['type'] == 'WS') {
6516
while ($j < $numchars) {
6517
if ((($chardata[$j]['type'] == 'B') OR ($chardata[$j]['type'] == 'S')) OR
6518
(($j == ($numchars-1)) AND ($chardata[$j]['type'] == 'WS'))) {
6519
$chardata[$i]['level'] = $pel;;
6521
} elseif ($chardata[$j]['type'] != 'WS') {
6530
// Cursively connected scripts, such as Arabic or Syriac, require the selection of positional character shapes that depend on adjacent characters. Shaping is logically applied after the Bidirectional Algorithm is used and is limited to characters within the same directional run.
6532
for ($i=0; $i < $numchars; $i++) {
6533
if ($unicode[$chardata[$i]['char']] == 'AL') {
6534
if (($i > 0) AND (($i+1) < $numchars) AND
6535
($unicode[$chardata[($i-1)]['char']] == 'AL') AND
6536
($unicode[$chardata[($i+1)]['char']] == 'AL') AND
6537
($chardata[($i-1)]['type'] == $chardata[$i]['type']) AND
6538
($chardata[($i+1)]['type'] == $chardata[$i]['type'])) {
6540
if (isset($unicode_arlet[$chardata[$i]['char']][3])) {
6541
$chardata[$i]['char'] = $unicode_arlet[$chardata[$i]['char']][3];
6543
} elseif ((($i+1) < $numchars) AND
6544
($unicode[$chardata[($i+1)]['char']] == 'AL') AND
6545
($chardata[($i+1)]['type'] == $chardata[$i]['type'])) {
6547
if (isset($unicode_arlet[$chardata[$i]['char']][2])) {
6548
$chardata[$i]['char'] = $unicode_arlet[$chardata[$i]['char']][2];
6550
} elseif (($i > 0) AND
6551
($unicode[$chardata[($i-1)]['char']] == 'AL') AND
6552
($chardata[($i-1)]['type'] == $chardata[$i]['type'])) {
6554
if (isset($unicode_arlet[$chardata[$i]['char']][1])) {
6555
$chardata[$i]['char'] = $unicode_arlet[$chardata[$i]['char']][1];
6557
} elseif (isset($unicode_arlet[$chardata[$i]['char']][0])) {
6559
$chardata[$i]['char'] = $unicode_arlet[$chardata[$i]['char']][0];
6565
// L2. From the highest level found in the text to the lowest odd level on each line, including intermediate levels not actually present in the text, reverse any contiguous sequence of characters that are at that level or higher.
6566
for ($j=$maxlevel; $j > 0; $j--) {
6567
$ordarray = Array();
6570
for ($i=0; $i < $numchars; $i++) {
6571
if ($chardata[$i]['level'] >= $j) {
6573
if (isset($unicode_mirror[$chardata[$i]['char']])) {
6574
// L4. A character is depicted by a mirrored glyph if and only if (a) the resolved directionality of that character is R, and (b) the Bidi_Mirrored property value of that character is true.
6575
$chardata[$i]['char'] = $unicode_mirror[$chardata[$i]['char']];
6577
$revarr[] = $chardata[$i];
6580
$revarr = array_reverse($revarr);
6581
$ordarray = array_merge($ordarray, $revarr);
6585
$ordarray[] = $chardata[$i];
6589
$revarr = array_reverse($revarr);
6590
$ordarray = array_merge($ordarray, $revarr);
6592
$chardata = $ordarray;
6595
$ordarray = array();
6596
for ($i=0; $i < $numchars; $i++) {
6597
$ordarray[] = $chardata[$i]['char'];
6600
return $this->arrUTF8ToUTF16BE($ordarray, $setbom);
6603
// END OF BIDIRECTIONAL TEXT SECTION -------------------
6607
* @param string $txt bookmark description.
6608
* @param int $level bookmark level.
6609
* @param float $y Ordinate of the boorkmark position (default = -1 = current position).
6611
* @author Olivier Plathey, Nicola Asuni
6612
* @since 2.1.002 (2008-02-12)
6614
public function Bookmark($txt, $level=0, $y=-1) {
6618
$this->outlines[]=array('t'=>$txt,'l'=>$level,'y'=>$y,'p'=>$this->PageNo());
6622
* Create a bookmark PDF string.
6624
* @author Olivier Plathey, Nicola Asuni
6625
* @since 2.1.002 (2008-02-12)
6627
private function _putbookmarks() {
6628
$nb = count($this->outlines);
6634
foreach($this->outlines as $i=>$o) {
6636
$parent = $lru[$o['l'] - 1];
6637
//Set parent and last pointers
6638
$this->outlines[$i]['parent'] = $parent;
6639
$this->outlines[$parent]['last'] = $i;
6640
if($o['l'] > $level) {
6641
//Level increasing: set first pointer
6642
$this->outlines[$parent]['first'] = $i;
6645
$this->outlines[$i]['parent']=$nb;
6647
if($o['l']<=$level and $i>0) {
6648
//Set prev and next pointers
6649
$prev = $lru[$o['l']];
6650
$this->outlines[$prev]['next'] = $i;
6651
$this->outlines[$i]['prev'] = $prev;
6658
foreach($this->outlines as $i=>$o) {
6660
$this->_out('<</Title '.$this->_textstring($o['t']));
6661
$this->_out('/Parent '.($n+$o['parent']).' 0 R');
6662
if(isset($o['prev']))
6663
$this->_out('/Prev '.($n+$o['prev']).' 0 R');
6664
if(isset($o['next']))
6665
$this->_out('/Next '.($n+$o['next']).' 0 R');
6666
if(isset($o['first']))
6667
$this->_out('/First '.($n+$o['first']).' 0 R');
6668
if(isset($o['last']))
6669
$this->_out('/Last '.($n+$o['last']).' 0 R');
6670
$this->_out(sprintf('/Dest [%d 0 R /XYZ 0 %.2f null]',1+2*$o['p'],($this->h-$o['y'])*$this->k));
6671
$this->_out('/Count 0>>');
6672
$this->_out('endobj');
6676
$this->OutlineRoot=$this->n;
6677
$this->_out('<</Type /Outlines /First '.$n.' 0 R');
6678
$this->_out('/Last '.($n+$lru[0]).' 0 R>>');
6679
$this->_out('endobj');
6683
// --- JAVASCRIPT - FORMS ------------------------------
6688
* @author Johannes G�ntert, Nicola Asuni
6689
* @since 2.1.002 (2008-02-12)
6691
public function IncludeJS($script) {
6692
$this->javascript .= $script;
6696
* Create a javascript PDF string.
6698
* @author Johannes G�ntert, Nicola Asuni
6699
* @since 2.1.002 (2008-02-12)
6701
private function _putjavascript() {
6702
if (empty($this->javascript)) {
6706
$this->n_js = $this->n;
6708
$this->_out('/Names [(EmbeddedJS) '.($this->n+1).' 0 R ]');
6710
$this->_out('endobj');
6713
$this->_out('/S /JavaScript');
6714
$this->_out('/JS '.$this->_textstring($this->javascript));
6716
$this->_out('endobj');
6720
* Convert color to javascript color.
6721
* @param string $color color name or #RRGGBB
6723
* @author Denis Van Nuffelen, Nicola Asuni
6724
* @since 2.1.002 (2008-02-12)
6726
private function _JScolor($color) {
6727
static $aColors = array('transparent','black','white','red','green','blue','cyan','magenta','yellow','dkGray','gray','ltGray');
6728
if(substr($color,0,1) == '#') {
6729
return sprintf("['RGB',%.3f,%.3f,%.3f]", hexdec(substr($color,1,2))/255, hexdec(substr($color,3,2))/255, hexdec(substr($color,5,2))/255);
6731
if(!in_array($color,$aColors)) {
6732
$this->Error('Invalid color: '.$color);
6734
return 'color.'.$color;
6738
* Adds a javascript form field.
6739
* @param string $type field type
6740
* @param string $name field name
6741
* @param int $x horizontal position
6742
* @param int $y vertical position
6743
* @param int $w width
6744
* @param int $h height
6745
* @param string $prop properties
6747
* @author Denis Van Nuffelen, Nicola Asuni
6748
* @since 2.1.002 (2008-02-12)
6750
private function _addfield($type, $name, $x, $y, $w, $h, $prop) {
6752
$this->javascript .= sprintf("f=addField('%s','%s',%d,[%.2f,%.2f,%.2f,%.2f]);",$name,$type,$this->PageNo()-1,$x*$k,($this->h-$y)*$k+1,($x+$w)*$k,($this->h-$y-$h)*$k+1);
6753
$this->javascript .= 'f.textSize='.$this->FontSizePt.';';
6754
if(isset($prop['value'])) {
6755
$this->javascript .= "f.value='".addslashes($prop['value'])."';";
6757
if(isset($prop['TextColor'])) {
6758
$this->javascript .= 'f.textColor='.$this->_JScolor($prop['TextColor']).';';
6760
if(isset($prop['FillColor'])) {
6761
$this->javascript .= 'f.fillColor='.$this->_JScolor($prop['FillColor']).';';
6763
if(isset($prop['BorderColor'])) {
6764
$this->javascript .= 'f.strokeColor='.$this->_JScolor($prop['BorderColor']).';';
6766
if(isset($prop['BorderStyle'])) {
6767
$this->javascript .= "f.borderStyle='".$prop['BorderStyle']."';";
6773
* Creates a text field
6774
* @param string $name field name
6775
* @param int $w width
6776
* @param int $h height
6777
* @param string $prop properties. The value property allows to set the initial value. The multiline property allows to define the field as multiline.
6779
* @author Denis Van Nuffelen, Nicola Asuni
6780
* @since 2.1.002 (2008-02-12)
6782
public function TextField($name, $w, $h, $prop=array()) {
6783
$this->_addfield('text',$name,$this->x,$this->y,$w,$h,$prop);
6784
if(isset($prop['multiline']) AND $prop['multiline']) {
6785
$this->javascript .= 'f.multiline=true;';
6790
* Creates a Combo-box field
6791
* @param string $name field name
6792
* @param int $w width
6793
* @param int $h height
6794
* @param array $values array containing the list of values.
6795
* @param string $prop properties.
6797
* @author Denis Van Nuffelen, Nicola Asuni
6798
* @since 2.1.002 (2008-02-12)
6800
public function ComboBox($name, $w, $h, $values, $prop=array()) {
6801
$this->_addfield('combobox',$name,$this->x,$this->y,$w,$h,$prop);
6803
foreach($values as $value) {
6804
$s .= "'".addslashes($value)."',";
6806
$this->javascript .= 'f.setItems(['.substr($s,0,-1).']);';
6810
* Creates a CheckBox field
6811
* @param string $name field name
6812
* @param int $w width
6813
* @param boolean $checked define the initial state (default = false).
6814
* @param string $prop properties.
6816
* @author Denis Van Nuffelen, Nicola Asuni
6817
* @since 2.1.002 (2008-02-12)
6819
public function CheckBox($name, $w, $checked=false, $prop=array()) {
6820
$prop['value'] = ($checked ? 'Yes' : 'Off');
6821
if(!isset($prop['BorderColor'])) {
6822
$prop['BorderColor']='black';
6824
$this->_addfield('checkbox',$name,$this->x,$this->y,$w,$w,$prop);
6828
* Creates a button field
6829
* @param string $name field name
6830
* @param int $w width
6831
* @param int $h height
6832
* @param string $caption caption.
6833
* @param string $action action triggered by the button (JavaScript code).
6834
* @param string $prop properties.
6836
* @author Denis Van Nuffelen, Nicola Asuni
6837
* @since 2.1.002 (2008-02-12)
6839
public function Button($name, $w, $h, $caption, $action, $prop=array()) {
6840
if(!isset($prop['BorderColor'])) {
6841
$prop['BorderColor']='black';
6843
$prop['BorderStyle']='beveled';
6844
$this->_addfield('button',$name,$this->x,$this->y,$w,$h,$prop);
6845
$this->javascript .= "f.buttonSetCaption('".addslashes($caption)."');";
6846
$this->javascript .= "f.setAction('MouseUp','".addslashes($action)."');";
6847
$this->javascript .= "f.highlight='push';";
6848
$this->javascript .= 'f.print=false;';
6851
// END JAVASCRIPT - FORMS ------------------------------
6853
} // END OF TCPDF CLASS
4128
6855
//Handle special IE contype request
4129
6856
if(isset($_SERVER['HTTP_USER_AGENT']) AND ($_SERVER['HTTP_USER_AGENT']=='contype')) {