<?php
require('fpdf.php');
class PDF_Gradients extends FPDF{
protected $gradients = array();
function LinearGradient($x, $y, $w, $h, $col1=array(), $col2=array(), $coords=array(0,0,1,0)){
$this->Clip($x,$y,$w,$h);
$this->Gradient(2,$col1,$col2,$coords);
}
function RadialGradient($x, $y, $w, $h, $col1=array(), $col2=array(), $coords=array(0.5,0.5,0.5,0.5,1)){
$this->Clip($x,$y,$w,$h);
$this->Gradient(3,$col1,$col2,$coords);
}
function CoonsPatchMesh($x, $y, $w, $h, $col1=array(), $col2=array(), $col3=array(), $col4=array(), $coords=array(0.00,0.0,0.33,0.00,0.67,0.00,1.00,0.00,1.00,0.33,1.00,0.67,1.00,1.00,0.67,1.00,0.33,1.00,0.00,1.00,0.00,0.67,0.00,0.33), $coords_min=0, $coords_max=1){
$this->Clip($x,$y,$w,$h);
$n = count($this->gradients)+1;
$this->gradients[$n]['type']=6; //coons patch mesh
//check the coords array if it is the simple array or the multi patch array
if(!isset($coords[0]['f'])){
//simple array -> convert to multi patch array
if(!isset($col1[1]))
$col1[1]=$col1[2]=$col1[0];
if(!isset($col2[1]))
$col2[1]=$col2[2]=$col2[0];
if(!isset($col3[1]))
$col3[1]=$col3[2]=$col3[0];
if(!isset($col4[1]))
$col4[1]=$col4[2]=$col4[0];
$patch_array[0]['f']=0;
$patch_array[0]['points']=$coords;
$patch_array[0]['colors'][0]['r']=$col1[0];
$patch_array[0]['colors'][0]['g']=$col1[1];
$patch_array[0]['colors'][0]['b']=$col1[2];
$patch_array[0]['colors'][1]['r']=$col2[0];
$patch_array[0]['colors'][1]['g']=$col2[1];
$patch_array[0]['colors'][1]['b']=$col2[2];
$patch_array[0]['colors'][2]['r']=$col3[0];
$patch_array[0]['colors'][2]['g']=$col3[1];
$patch_array[0]['colors'][2]['b']=$col3[2];
$patch_array[0]['colors'][3]['r']=$col4[0];
$patch_array[0]['colors'][3]['g']=$col4[1];
$patch_array[0]['colors'][3]['b']=$col4[2];
}
else{
//multi patch array
$patch_array=$coords;
}
$bpcd=65535; //16 BitsPerCoordinate
//build the data stream
$this->gradients[$n]['stream']='';
for($i=0;$i<count($patch_array);$i++){
$this->gradients[$n]['stream'].=chr($patch_array[$i]['f']); //start with the edge flag as 8 bit
for($j=0;$j<count($patch_array[$i]['points']);$j++){
//each point as 16 bit
$patch_array[$i]['points'][$j]=(($patch_array[$i]['points'][$j]-$coords_min)/($coords_max-$coords_min))*$bpcd;
if($patch_array[$i]['points'][$j]<0) $patch_array[$i]['points'][$j]=0;
if($patch_array[$i]['points'][$j]>$bpcd) $patch_array[$i]['points'][$j]=$bpcd;
$val=(int)floor($patch_array[$i]['points'][$j]);
$this->gradients[$n]['stream'].=chr(intdiv($val,256));
$this->gradients[$n]['stream'].=chr($val%256);
}
for($j=0;$j<count($patch_array[$i]['colors']);$j++){
//each color component as 8 bit
$this->gradients[$n]['stream'].=chr($patch_array[$i]['colors'][$j]['r']);
$this->gradients[$n]['stream'].=chr($patch_array[$i]['colors'][$j]['g']);
$this->gradients[$n]['stream'].=chr($patch_array[$i]['colors'][$j]['b']);
}
}
//paint the gradient
$this->_out('/Sh'.$n.' sh');
//restore previous Graphic State
$this->_out('Q');
}
function Clip($x,$y,$w,$h){
//save current Graphic State
$s='q';
//set clipping area
$s.=sprintf(' %.2F %.2F %.2F %.2F re W n', $x*$this->k, ($this->h-$y)*$this->k, $w*$this->k, -$h*$this->k);
//set up transformation matrix for gradient
$s.=sprintf(' %.3F 0 0 %.3F %.3F %.3F cm', $w*$this->k, $h*$this->k, $x*$this->k, ($this->h-($y+$h))*$this->k);
$this->_out($s);
}
function Gradient($type, $col1, $col2, $coords){
$n = count($this->gradients)+1;
$this->gradients[$n]['type']=$type;
if(!isset($col1[1]))
$col1[1]=$col1[2]=$col1[0];
$this->gradients[$n]['col1']=sprintf('%.3F %.3F %.3F',($col1[0]/255),($col1[1]/255),($col1[2]/255));
if(!isset($col2[1]))
$col2[1]=$col2[2]=$col2[0];
$this->gradients[$n]['col2']=sprintf('%.3F %.3F %.3F',($col2[0]/255),($col2[1]/255),($col2[2]/255));
$this->gradients[$n]['coords']=$coords;
//paint the gradient
$this->_out('/Sh'.$n.' sh');
//restore previous Graphic State
$this->_out('Q');
}
function _putshaders(){
foreach($this->gradients as $id=>$grad){
if($grad['type']==2 || $grad['type']==3){
$this->_newobj();
$this->_put('<<');
$this->_put('/FunctionType 2');
$this->_put('/Domain [0.0 1.0]');
$this->_put('/C0 ['.$grad['col1'].']');
$this->_put('/C1 ['.$grad['col2'].']');
$this->_put('/N 1');
$this->_put('>>');
$this->_put('endobj');
$f1=$this->n;
}
$this->_newobj();
$this->_put('<<');
$this->_put('/ShadingType '.$grad['type']);
$this->_put('/ColorSpace /DeviceRGB');
if($grad['type']=='2'){
$this->_put(sprintf('/Coords [%.3F %.3F %.3F %.3F]',$grad['coords'][0],$grad['coords'][1],$grad['coords'][2],$grad['coords'][3]));
$this->_put('/Function '.$f1.' 0 R');
$this->_put('/Extend [true true] ');
$this->_put('>>');
}
elseif($grad['type']==3){
//x0, y0, r0, x1, y1, r1
//at this time radius of inner circle is 0
$this->_put(sprintf('/Coords [%.3F %.3F 0 %.3F %.3F %.3F]',$grad['coords'][0],$grad['coords'][1],$grad['coords'][2],$grad['coords'][3],$grad['coords'][4]));
$this->_put('/Function '.$f1.' 0 R');
$this->_put('/Extend [true true] ');
$this->_put('>>');
}
elseif($grad['type']==6){
$this->_put('/BitsPerCoordinate 16');
$this->_put('/BitsPerComponent 8');
$this->_put('/Decode[0 1 0 1 0 1 0 1 0 1]');
$this->_put('/BitsPerFlag 8');
$this->_put('/Length '.strlen($grad['stream']));
$this->_put('>>');
$this->_putstream($grad['stream']);
}
$this->_put('endobj');
$this->gradients[$id]['id']=$this->n;
}
}
function _putresourcedict(){
parent::_putresourcedict();
$this->_put('/Shading <<');
foreach($this->gradients as $id=>$grad)
$this->_put('/Sh'.$id.' '.$grad['id'].' 0 R');
$this->_put('>>');
}
function _putresources(){
$this->_putshaders();
parent::_putresources();
}
}
?>
<?php
require('gradients.php');
$pdf = new PDF_Gradients();
//first page
$pdf->AddPage();
$pdf->SetFont('Arial','',14);
$pdf->Cell(0,5,'Page 1',0,1,'C');
$pdf->Ln();
//set colors for gradients (r,g,b) or (grey 0-255)
$red=array(255,0,0);
$blue=array(0,0,200);
$yellow=array(255,255,0);
$green=array(0,255,0);
$white=array(255);
$black=array(0);
//set the coordinates x1,y1,x2,y2 of the gradient (see linear_gradient_coords.jpg)
$coords=array(0,0,1,0);
//paint a linear gradient
$pdf->LinearGradient(20,25,80,80,$red,$blue,$coords);
//set the coordinates fx,fy,cx,cy,r of the gradient (see radial_gradient_coords.jpg)
$coords=array(0.5,0.5,1,1,1.2);
//paint a radial gradient
$pdf->RadialGradient(110,25,80,80,$white,$black,$coords);
//paint a coons patch mesh with default coordinates
$pdf->CoonsPatchMesh(20,115,80,80,$yellow,$blue,$green,$red);
//set the coordinates for the cubic Bézier points x1,y1 ... x12, y12 of the patch (see coons_patch_mesh_coords.jpg)
$coords=array(0.00,0.00, 0.33,0.20, //lower left
0.67,0.00, 1.00,0.00, 0.80,0.33, //lower right
0.80,0.67, 1.00,1.00, 0.67,0.80, //upper right
0.33,1.00, 0.00,1.00, 0.20,0.67, //upper left
0.00,0.33); //lower left
$coords_min=0; //minimum value of the coordinates
$coords_max=1; //maximum value of the coordinates
//paint a coons patch gradient with the above coordinates
$pdf->CoonsPatchMesh(110,115,80,80,$yellow,$blue,$green,$red,$coords,$coords_min,$coords_max);
//second page
$pdf->AddPage();
$pdf->Cell(0,5,'Page 2',0,1,'C');
$pdf->Ln();
//first patch: f = 0
$patch_array[0]['f']=0;
$patch_array[0]['points']=array(0.00,0.00, 0.33,0.00,
0.67,0.00, 1.00,0.00, 1.00,0.33,
0.8,0.67, 1.00,1.00, 0.67,0.8,
0.33,1.80, 0.00,1.00, 0.00,0.67,
0.00,0.33);
$patch_array[0]['colors'][0]=array('r'=>255,'g'=>255,'b'=>0);
$patch_array[0]['colors'][1]=array('r'=>0,'g'=>0,'b'=>255);
$patch_array[0]['colors'][2]=array('r'=>0,'g'=>255,'b'=>0);
$patch_array[0]['colors'][3]=array('r'=>255,'g'=>0,'b'=>0);
//second patch - above the other: f = 2
$patch_array[1]['f']=2;
$patch_array[1]['points']=array(0.00,1.33,
0.00,1.67, 0.00,2.00, 0.33,2.00,
0.67,2.00, 1.00,2.00, 1.00,1.67,
1.5,1.33);
$patch_array[1]['colors'][0]=array('r'=>0,'g'=>0,'b'=>0);
$patch_array[1]['colors'][1]=array('r'=>255,'g'=>0,'b'=>255);
//third patch - right of the above: f = 3
$patch_array[2]['f']=3;
$patch_array[2]['points']=array(1.33,0.80,
1.67,1.50, 2.00,1.00, 2.00,1.33,
2.00,1.67, 2.00,2.00, 1.67,2.00,
1.33,2.00);
$patch_array[2]['colors'][0]=array('r'=>0,'g'=>255,'b'=>255);
$patch_array[2]['colors'][1]=array('r'=>0,'g'=>0,'b'=>0);
//fourth patch - below the above, which means left(?) of the above: f = 1
$patch_array[3]['f']=1;
$patch_array[3]['points']=array(2.00,0.67,
2.00,0.33, 2.00,0.00, 1.67,0.00,
1.33,0.00, 1.00,0.00, 1.00,0.33,
0.8,0.67);
$patch_array[3]['colors'][0]=array('r'=>0,'g'=>0,'b'=>0);
$patch_array[3]['colors'][1]=array('r'=>0,'g'=>0,'b'=>255);
$coords_min=0;
$coords_max=2;
$pdf->CoonsPatchMesh(10,25,190,200,'','','','',$patch_array,$coords_min,$coords_max);
$pdf->Output();
?>
View the result