include line break fixes from Andrea Rossato
This commit is contained in:
parent
0ef7472634
commit
9362e92c82
|
@ -9,6 +9,9 @@
|
||||||
* *
|
* *
|
||||||
* UFPDF is a modification of FPDF to support Unicode through UTF-8. *
|
* UFPDF is a modification of FPDF to support Unicode through UTF-8. *
|
||||||
* *
|
* *
|
||||||
|
* This file includes modifications from Andrea Rossato which fix line breaking *
|
||||||
|
* in Write()/MultiCell(). *
|
||||||
|
* *
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
if(!class_exists('UFPDF'))
|
if(!class_exists('UFPDF'))
|
||||||
|
@ -17,6 +20,12 @@ define('UFPDF_VERSION','0.1');
|
||||||
|
|
||||||
include_once 'fpdf.php';
|
include_once 'fpdf.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main UFPDF class for creating Unicode PDF documents
|
||||||
|
*
|
||||||
|
* derives from FPDF class
|
||||||
|
* @see FPDF
|
||||||
|
*/
|
||||||
class UFPDF extends FPDF
|
class UFPDF extends FPDF
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -34,11 +43,22 @@ function GetStringWidth($s)
|
||||||
{
|
{
|
||||||
//Get width of a string in the current font
|
//Get width of a string in the current font
|
||||||
$s = (string)$s;
|
$s = (string)$s;
|
||||||
$codepoints=$this->utf8_to_codepoints($s);
|
$codepoints=$this->utf8_to_codepoints(trim($s));
|
||||||
$cw=&$this->CurrentFont['cw'];
|
$cw=&$this->CurrentFont['cw'];
|
||||||
$w=0;
|
$w=0;
|
||||||
foreach($codepoints as $cp)
|
foreach($codepoints as $cp) {
|
||||||
|
if (isset($cw[$cp])) {
|
||||||
$w+=$cw[$cp];
|
$w+=$cw[$cp];
|
||||||
|
}
|
||||||
|
else if (isset($cw[ord($cp)])) {
|
||||||
|
$w+=$cw[ord($cp)];
|
||||||
|
}
|
||||||
|
else if (isset($cw[chr($cp)])) {
|
||||||
|
$w+=$cw[chr($cp)];
|
||||||
|
}
|
||||||
|
//-- adjust width for incorrect hebrew chars
|
||||||
|
if ($cp>1480 && $cp < 1550) $w -= $cw[$cp]/1.8;
|
||||||
|
}
|
||||||
return $w*$this->FontSize/1000;
|
return $w*$this->FontSize/1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,7 +108,7 @@ function AcceptPageBreak()
|
||||||
return $this->AutoPageBreak;
|
return $this->AutoPageBreak;
|
||||||
}
|
}
|
||||||
|
|
||||||
function Cell($w,$h=0,$txt='',$border=0,$ln=0,$align='',$fill=0,$link='')
|
function Cell($w,$h=0,$txt='',$border=0,$ln=0,$align='J',$fill=0,$link='')
|
||||||
{
|
{
|
||||||
//Output a cell
|
//Output a cell
|
||||||
$k=$this->k;
|
$k=$this->k;
|
||||||
|
@ -168,6 +188,220 @@ function Cell($w,$h=0,$txt='',$border=0,$ln=0,$align='',$fill=0,$link='')
|
||||||
$this->x+=$w;
|
$this->x+=$w;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function MultiCell($w,$h,$txt,$border=0,$align='J',$fill=0)
|
||||||
|
{
|
||||||
|
//Output text with automatic or explicit line breaks
|
||||||
|
$cw=&$this->CurrentFont['cw'];
|
||||||
|
$cp=$this->utf8_to_codepoints(trim($txt));
|
||||||
|
//print_r($cp);
|
||||||
|
if($w==0)
|
||||||
|
$w=$this->w-$this->rMargin-$this->x;
|
||||||
|
$wmax=($w-2*$this->cMargin)*1000/$this->FontSize;
|
||||||
|
//echo $w;
|
||||||
|
$s=str_replace("\r",'',$txt);
|
||||||
|
$nb=$this->strlen($s);
|
||||||
|
if($nb>0 and $s[$nb-1]=="\n")
|
||||||
|
$nb--;
|
||||||
|
$b=0;
|
||||||
|
if($border)
|
||||||
|
{
|
||||||
|
if($border==1)
|
||||||
|
{
|
||||||
|
$border='LTRB';
|
||||||
|
$b='LRT';
|
||||||
|
$b2='LR';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$b2='';
|
||||||
|
if(is_int(strpos($border,'L')))
|
||||||
|
$b2.='L';
|
||||||
|
if(is_int(strpos($border,'R')))
|
||||||
|
$b2.='R';
|
||||||
|
$b=is_int(strpos($border,'T')) ? $b2.'T' : $b2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$sep=-1;
|
||||||
|
$i=0;
|
||||||
|
$j=0;
|
||||||
|
$l=0;
|
||||||
|
$ns=0;
|
||||||
|
$nl=1;
|
||||||
|
$char = 0;
|
||||||
|
while($i<$nb)
|
||||||
|
{
|
||||||
|
//Get next character
|
||||||
|
$c = $this->code2utf($cp[$i]);
|
||||||
|
$charw = $cw[$cp[$i]];
|
||||||
|
|
||||||
|
if($c=="\n")
|
||||||
|
{
|
||||||
|
//Explicit line break
|
||||||
|
if($this->ws>0)
|
||||||
|
{
|
||||||
|
$this->ws=0;
|
||||||
|
$this->_out('0 Tw');
|
||||||
|
}
|
||||||
|
$this->Cell($w,$h,$this->utf8_substr($cp,$j,$i-$j,"UTF-8"),$b,2,$align,$fill);
|
||||||
|
$i++;
|
||||||
|
$sep=-1;
|
||||||
|
$j=$i;
|
||||||
|
$l=0;
|
||||||
|
$ns=0;
|
||||||
|
$nl++;
|
||||||
|
if($border and $nl==2)
|
||||||
|
$b=$b2;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if($c==' ')
|
||||||
|
{
|
||||||
|
$sep=$i;
|
||||||
|
$ls=$l;
|
||||||
|
$ns++;
|
||||||
|
}
|
||||||
|
$l+=$charw;
|
||||||
|
|
||||||
|
if($l>$wmax)
|
||||||
|
{
|
||||||
|
//Automatic line break
|
||||||
|
if($sep==-1)
|
||||||
|
{
|
||||||
|
if($i==$j)
|
||||||
|
$i++;
|
||||||
|
if($this->ws>0)
|
||||||
|
{
|
||||||
|
$this->ws=0;
|
||||||
|
$this->_out('0 Tw');
|
||||||
|
}
|
||||||
|
$this->Cell($w,$h,$this->utf8_substr($cp,$j,$i-$j,"UTF-8"),$b,2,$align,$fill);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if($align=='J')
|
||||||
|
{
|
||||||
|
$len_ligne = $this->GetStringWidth($this->utf8_substr($cp,$j,$sep-$j,"UTF-8"));
|
||||||
|
$nb_carac = $this->strlen($this->utf8_substr($cp,$j,$sep-$j,"UTF-8"));
|
||||||
|
$ecart = (($w-2) - $len_ligne) / $nb_carac;
|
||||||
|
$this->_out(sprintf('BT %.3f Tc ET',$ecart*$this->k));
|
||||||
|
//$this->ws=($ns>1) ? ($wmax-$ls)/1000*$this->FontSize/($ns-1) : 0;
|
||||||
|
//$this->_out(sprintf('%.3f Tw',$this->ws*$this->k));
|
||||||
|
//echo ($wmax-$ls)/1000*$this->FontSize/($ns-1)."=".($wmax-$ls)."<br>"; //$andrea = sprintf('%.3f Tw',$this->ws*$this->k);
|
||||||
|
}
|
||||||
|
$this->Cell($w,$h,$this->utf8_substr($cp,$j,$sep-$j,"UTF-8"),$b,2,$align,$fill);
|
||||||
|
$i=$sep+1;
|
||||||
|
}
|
||||||
|
$sep=-1;
|
||||||
|
$j=$i;
|
||||||
|
$l=0;
|
||||||
|
$ns=0;
|
||||||
|
$nl++;
|
||||||
|
if($border and $nl==2)
|
||||||
|
$b=$b2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
$i++;
|
||||||
|
}
|
||||||
|
//Last chunk
|
||||||
|
if($this->ws>0)
|
||||||
|
{
|
||||||
|
$this->ws=0;
|
||||||
|
$this->_out('0 Tw');
|
||||||
|
}
|
||||||
|
if($border and is_int(strpos($border,'B')))
|
||||||
|
$b.='B';
|
||||||
|
$this->Cell($w,$h,$this->utf8_substr($cp,$j,$i-$j,"UTF-8"),$b,2,$align,$fill);
|
||||||
|
$this->x=$this->lMargin;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Write($h,$txt,$link='')
|
||||||
|
{
|
||||||
|
//Output text in flowing mode
|
||||||
|
$cw=&$this->CurrentFont['cw'];
|
||||||
|
$cp=$this->utf8_to_codepoints(trim($txt));
|
||||||
|
$w=$this->w-$this->rMargin-$this->x;
|
||||||
|
$wmax=($w-2*$this->cMargin)*1000/$this->FontSize;
|
||||||
|
$s=str_replace("\r",'',$txt);
|
||||||
|
$nb=$this->strlen($s);
|
||||||
|
$sep=-1;
|
||||||
|
$i=0;
|
||||||
|
$j=0;
|
||||||
|
$l=0;
|
||||||
|
$nl=1;
|
||||||
|
while($i<$nb)
|
||||||
|
{
|
||||||
|
//Get next character
|
||||||
|
$c=$s{$i};
|
||||||
|
$charw = $cw[$cp[$i]];
|
||||||
|
if($c=="\n")
|
||||||
|
{
|
||||||
|
//Explicit line break
|
||||||
|
$this->Cell($w,$h,$this->utf8_substr($cp,$j,$i-$j,"UTF-8"),0,2,'',0,$link);
|
||||||
|
$i++;
|
||||||
|
$sep=-1;
|
||||||
|
$j=$i;
|
||||||
|
$l=0;
|
||||||
|
if($nl==1)
|
||||||
|
{
|
||||||
|
$this->x=$this->lMargin;
|
||||||
|
$w=$this->w-$this->rMargin-$this->x;
|
||||||
|
$wmax=($w-2*$this->cMargin)*1000/$this->FontSize;
|
||||||
|
}
|
||||||
|
$nl++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if($c==' ')
|
||||||
|
$sep=$i;
|
||||||
|
$l+=$charw;
|
||||||
|
if($l>$wmax)
|
||||||
|
{
|
||||||
|
//Automatic line break
|
||||||
|
if($sep==-1)
|
||||||
|
{
|
||||||
|
if($this->x>$this->lMargin)
|
||||||
|
{
|
||||||
|
//Move to next line
|
||||||
|
$this->x=$this->lMargin;
|
||||||
|
$this->y+=$h;
|
||||||
|
$w=$this->w-$this->rMargin-$this->x;
|
||||||
|
$wmax=($w-2*$this->cMargin)*1000/$this->FontSize;
|
||||||
|
$i++;
|
||||||
|
$nl++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if($i==$j)
|
||||||
|
$i++;
|
||||||
|
$this->Cell($w,$h,$this->utf8_substr($cp,$j,$i-$j,"UTF-8"),0,2,'',0,$link);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$this->Cell($w,$h,$this->utf8_substr($cp,$j,$sep-$j,"UTF-8"),0,2,'',0,$link);
|
||||||
|
$i=$sep+1;
|
||||||
|
}
|
||||||
|
$sep=-1;
|
||||||
|
$j=$i;
|
||||||
|
$l=0;
|
||||||
|
if($nl==1)
|
||||||
|
{
|
||||||
|
$this->x=$this->lMargin;
|
||||||
|
$w=$this->w-$this->rMargin-$this->x;
|
||||||
|
$wmax=($w-2*$this->cMargin)*1000/$this->FontSize;
|
||||||
|
}
|
||||||
|
$nl++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
$i++;
|
||||||
|
}
|
||||||
|
//Last chunk
|
||||||
|
if($i!=$j)
|
||||||
|
$this->Cell($l/1000*$this->FontSize,$h,$this->utf8_substr($cp,$j, "", "UTF-8"),0,0,'',0,$link);
|
||||||
|
}
|
||||||
|
|
||||||
|
function AliasNbPages($alias='{nb}')
|
||||||
|
{
|
||||||
|
//Define an alias for total number of pages
|
||||||
|
$this->AliasNbPages=$this->utf8_to_utf16be($alias,false);
|
||||||
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* *
|
* *
|
||||||
* Protected methods *
|
* Protected methods *
|
||||||
|
@ -179,7 +413,7 @@ function _puttruetypeunicode($font) {
|
||||||
$this->_newobj();
|
$this->_newobj();
|
||||||
$this->_out('<</Type /Font');
|
$this->_out('<</Type /Font');
|
||||||
$this->_out('/Subtype /Type0');
|
$this->_out('/Subtype /Type0');
|
||||||
$this->_out('/BaseFont /'. $font['name'] .'-UCS');
|
$this->_out('/BaseFont /'. $font['name'] );
|
||||||
$this->_out('/Encoding /Identity-H');
|
$this->_out('/Encoding /Identity-H');
|
||||||
$this->_out('/DescendantFonts ['. ($this->n + 1) .' 0 R]');
|
$this->_out('/DescendantFonts ['. ($this->n + 1) .' 0 R]');
|
||||||
$this->_out('>>');
|
$this->_out('>>');
|
||||||
|
@ -193,6 +427,7 @@ function _puttruetypeunicode($font) {
|
||||||
$this->_out('/CIDSystemInfo <</Registry (Adobe) /Ordering (UCS) /Supplement 0>>');
|
$this->_out('/CIDSystemInfo <</Registry (Adobe) /Ordering (UCS) /Supplement 0>>');
|
||||||
$this->_out('/FontDescriptor '. ($this->n + 1) .' 0 R');
|
$this->_out('/FontDescriptor '. ($this->n + 1) .' 0 R');
|
||||||
$c = 0;
|
$c = 0;
|
||||||
|
$widths = "";
|
||||||
foreach ($font['cw'] as $i => $w) {
|
foreach ($font['cw'] as $i => $w) {
|
||||||
$widths .= $i .' ['. $w.'] ';
|
$widths .= $i .' ['. $w.'] ';
|
||||||
}
|
}
|
||||||
|
@ -205,6 +440,7 @@ function _puttruetypeunicode($font) {
|
||||||
$this->_newobj();
|
$this->_newobj();
|
||||||
$this->_out('<</Type /FontDescriptor');
|
$this->_out('<</Type /FontDescriptor');
|
||||||
$this->_out('/FontName /'.$font['name']);
|
$this->_out('/FontName /'.$font['name']);
|
||||||
|
$s = "";
|
||||||
foreach ($font['desc'] as $k => $v) {
|
foreach ($font['desc'] as $k => $v) {
|
||||||
$s .= ' /'. $k .' '. $v;
|
$s .= ' /'. $k .' '. $v;
|
||||||
}
|
}
|
||||||
|
@ -275,10 +511,84 @@ function _putinfo()
|
||||||
$this->_out('/CreationDate '.$this->_textstring('D:'.date('YmdHis')));
|
$this->_out('/CreationDate '.$this->_textstring('D:'.date('YmdHis')));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function _putpages()
|
||||||
|
{
|
||||||
|
$nb=$this->page;
|
||||||
|
if(!empty($this->AliasNbPages))
|
||||||
|
{
|
||||||
|
$nbstr = $this->utf8_to_utf16be($nb,false);
|
||||||
|
//Replace number of pages
|
||||||
|
for($n=1;$n<=$nb;$n++) {
|
||||||
|
$this->pages[$n]=str_replace($this->AliasNbPages,$nbstr,$this->pages[$n]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if($this->DefOrientation=='P')
|
||||||
|
{
|
||||||
|
$wPt=$this->fwPt;
|
||||||
|
$hPt=$this->fhPt;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$wPt=$this->fhPt;
|
||||||
|
$hPt=$this->fwPt;
|
||||||
|
}
|
||||||
|
$filter=($this->compress) ? '/Filter /FlateDecode ' : '';
|
||||||
|
for($n=1;$n<=$nb;$n++)
|
||||||
|
{
|
||||||
|
//Page
|
||||||
|
$this->_newobj();
|
||||||
|
$this->_out('<</Type /Page');
|
||||||
|
$this->_out('/Parent 1 0 R');
|
||||||
|
if(isset($this->OrientationChanges[$n]))
|
||||||
|
$this->_out(sprintf('/MediaBox [0 0 %.2f %.2f]',$hPt,$wPt));
|
||||||
|
$this->_out('/Resources 2 0 R');
|
||||||
|
if(isset($this->PageLinks[$n]))
|
||||||
|
{
|
||||||
|
//Links
|
||||||
|
$annots='/Annots [';
|
||||||
|
foreach($this->PageLinks[$n] as $pl)
|
||||||
|
{
|
||||||
|
$rect=sprintf('%.2f %.2f %.2f %.2f',$pl[0],$pl[1],$pl[0]+$pl[2],$pl[1]-$pl[3]);
|
||||||
|
$annots.='<</Type /Annot /Subtype /Link /Rect ['.$rect.'] /Border [0 0 0] ';
|
||||||
|
if(is_string($pl[4]))
|
||||||
|
$annots.='/A <</S /URI /URI '.$this->_textstring($pl[4]).'>>>>';
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$l=$this->links[$pl[4]];
|
||||||
|
$h=isset($this->OrientationChanges[$l[0]]) ? $wPt : $hPt;
|
||||||
|
$annots.=sprintf('/Dest [%d 0 R /XYZ 0 %.2f null]>>',1+2*$l[0],$h-$l[1]*$this->k);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->_out($annots.']');
|
||||||
|
}
|
||||||
|
$this->_out('/Contents '.($this->n+1).' 0 R>>');
|
||||||
|
$this->_out('endobj');
|
||||||
|
//Page content
|
||||||
|
$p=($this->compress) ? gzcompress($this->pages[$n]) : $this->pages[$n];
|
||||||
|
$this->_newobj();
|
||||||
|
$this->_out('<<'.$filter.'/Length '.strlen($p).'>>');
|
||||||
|
$this->_putstream($p);
|
||||||
|
$this->_out('endobj');
|
||||||
|
}
|
||||||
|
//Pages root
|
||||||
|
$this->offsets[1]=strlen($this->buffer);
|
||||||
|
$this->_out('1 0 obj');
|
||||||
|
$this->_out('<</Type /Pages');
|
||||||
|
$kids='/Kids [';
|
||||||
|
for($i=0;$i<$nb;$i++)
|
||||||
|
$kids.=(3+2*$i).' 0 R ';
|
||||||
|
$this->_out($kids.']');
|
||||||
|
$this->_out('/Count '.$nb);
|
||||||
|
$this->_out(sprintf('/MediaBox [0 0 %.2f %.2f]',$wPt,$hPt));
|
||||||
|
$this->_out('>>');
|
||||||
|
$this->_out('endobj');
|
||||||
|
}
|
||||||
|
|
||||||
// UTF-8 to UTF-16BE conversion.
|
// UTF-8 to UTF-16BE conversion.
|
||||||
// Correctly handles all illegal UTF-8 sequences.
|
// Correctly handles all illegal UTF-8 sequences.
|
||||||
function utf8_to_utf16be(&$txt, $bom = true) {
|
function utf8_to_utf16be(&$txt, $bom = true) {
|
||||||
$l = strlen($txt);
|
$l = strlen($txt);
|
||||||
|
$txt .= " ";
|
||||||
$out = $bom ? "\xFE\xFF" : '';
|
$out = $bom ? "\xFE\xFF" : '';
|
||||||
for ($i = 0; $i < $l; ++$i) {
|
for ($i = 0; $i < $l; ++$i) {
|
||||||
$c = ord($txt{$i});
|
$c = ord($txt{$i});
|
||||||
|
@ -376,10 +686,38 @@ function utf8_to_utf16be(&$txt, $bom = true) {
|
||||||
return $out;
|
return $out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function code2utf($num){
|
||||||
|
if($num<128)return chr($num);
|
||||||
|
if($num<2048)return chr(($num>>6)+192).chr(($num&63)+128);
|
||||||
|
if($num<65536)return chr(($num>>12)+224).chr((($num>>6)&63)+128).chr(($num&63)+128);
|
||||||
|
if($num<2097152)return chr(($num>>18)+240).chr((($num>>12)&63)+128).chr((($num>>6)&63)+128). chr(($num&63)+128);
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function strlen($s) {
|
||||||
|
return strlen(utf8_decode($s));
|
||||||
|
}
|
||||||
|
|
||||||
|
function utf8_substr($str,$start)
|
||||||
|
{
|
||||||
|
if( func_num_args() >= 3 ) {
|
||||||
|
$end = func_get_arg( 2 );
|
||||||
|
for ($i=$start; $i < ($start+$end); $i++)
|
||||||
|
$rs .= $this->code2utf($str[$i]);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
for ($i=$start; $i < count($str); $i++)
|
||||||
|
$rs .= $this->code2utf($str[$i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $rs;
|
||||||
|
}
|
||||||
|
|
||||||
// UTF-8 to codepoint array conversion.
|
// UTF-8 to codepoint array conversion.
|
||||||
// Correctly handles all illegal UTF-8 sequences.
|
// Correctly handles all illegal UTF-8 sequences.
|
||||||
function utf8_to_codepoints(&$txt) {
|
function utf8_to_codepoints(&$txt) {
|
||||||
$l = strlen($txt);
|
$l = strlen($txt);
|
||||||
|
$txt .= " ";
|
||||||
$out = array();
|
$out = array();
|
||||||
for ($i = 0; $i < $l; ++$i) {
|
for ($i = 0; $i < $l; ++$i) {
|
||||||
$c = ord($txt{$i});
|
$c = ord($txt{$i});
|
||||||
|
|
Loading…
Reference in New Issue