382 lines
12 KiB
PHP
382 lines
12 KiB
PHP
<?php
|
|
|
|
namespace Fpdi;
|
|
|
|
/**
|
|
* 中文支持及文字图片旋转支持
|
|
*/
|
|
class CFpdf extends \Fpdi\Fpdf
|
|
{
|
|
protected $angle = 0; //旋转角度
|
|
|
|
protected $Big5_widths = array(
|
|
' ' => 250, '!' => 250, '"' => 408, '#' => 668, '$' => 490, '%' => 875, '&' => 698, '\'' => 250,
|
|
'(' => 240, ')' => 240, '*' => 417, '+' => 667, ',' => 250, '-' => 313, '.' => 250, '/' => 520, '0' => 500, '1' => 500,
|
|
'2' => 500, '3' => 500, '4' => 500, '5' => 500, '6' => 500, '7' => 500, '8' => 500, '9' => 500, ':' => 250, ';' => 250,
|
|
'<' => 667, '=' => 667, '>' => 667, '?' => 396, '@' => 921, 'A' => 677, 'B' => 615, 'C' => 719, 'D' => 760, 'E' => 625,
|
|
'F' => 552, 'G' => 771, 'H' => 802, 'I' => 354, 'J' => 354, 'K' => 781, 'L' => 604, 'M' => 927, 'N' => 750, 'O' => 823,
|
|
'P' => 563, 'Q' => 823, 'R' => 729, 'S' => 542, 'T' => 698, 'U' => 771, 'V' => 729, 'W' => 948, 'X' => 771, 'Y' => 677,
|
|
'Z' => 635, '[' => 344, '\\' => 520, ']' => 344, '^' => 469, '_' => 500, '`' => 250, 'a' => 469, 'b' => 521, 'c' => 427,
|
|
'd' => 521, 'e' => 438, 'f' => 271, 'g' => 469, 'h' => 531, 'i' => 250, 'j' => 250, 'k' => 458, 'l' => 240, 'm' => 802,
|
|
'n' => 531, 'o' => 500, 'p' => 521, 'q' => 521, 'r' => 365, 's' => 333, 't' => 292, 'u' => 521, 'v' => 458, 'w' => 677,
|
|
'x' => 479, 'y' => 458, 'z' => 427, '{' => 480, '|' => 496, '}' => 480, '~' => 667
|
|
);
|
|
|
|
protected $GB_widths = array(
|
|
' ' => 207, '!' => 270, '"' => 342, '#' => 467, '$' => 462, '%' => 797, '&' => 710, '\'' => 239,
|
|
'(' => 374, ')' => 374, '*' => 423, '+' => 605, ',' => 238, '-' => 375, '.' => 238, '/' => 334, '0' => 462, '1' => 462,
|
|
'2' => 462, '3' => 462, '4' => 462, '5' => 462, '6' => 462, '7' => 462, '8' => 462, '9' => 462, ':' => 238, ';' => 238,
|
|
'<' => 605, '=' => 605, '>' => 605, '?' => 344, '@' => 748, 'A' => 684, 'B' => 560, 'C' => 695, 'D' => 739, 'E' => 563,
|
|
'F' => 511, 'G' => 729, 'H' => 793, 'I' => 318, 'J' => 312, 'K' => 666, 'L' => 526, 'M' => 896, 'N' => 758, 'O' => 772,
|
|
'P' => 544, 'Q' => 772, 'R' => 628, 'S' => 465, 'T' => 607, 'U' => 753, 'V' => 711, 'W' => 972, 'X' => 647, 'Y' => 620,
|
|
'Z' => 607, '[' => 374, '\\' => 333, ']' => 374, '^' => 606, '_' => 500, '`' => 239, 'a' => 417, 'b' => 503, 'c' => 427,
|
|
'd' => 529, 'e' => 415, 'f' => 264, 'g' => 444, 'h' => 518, 'i' => 241, 'j' => 230, 'k' => 495, 'l' => 228, 'm' => 793,
|
|
'n' => 527, 'o' => 524, 'p' => 524, 'q' => 504, 'r' => 338, 's' => 336, 't' => 277, 'u' => 517, 'v' => 450, 'w' => 652,
|
|
'x' => 466, 'y' => 452, 'z' => 407, '{' => 370, '|' => 258, '}' => 370, '~' => 605
|
|
);
|
|
|
|
public function AddCIDFont($family, $style, $name, $cw, $CMap, $registry)
|
|
{
|
|
$fontkey = strtolower($family) . strtoupper($style);
|
|
if (isset($this->fonts[$fontkey]))
|
|
$this->Error("Font already added: $family $style");
|
|
$i = count($this->fonts) + 1;
|
|
$name = str_replace(' ', '', $name);
|
|
$this->fonts[$fontkey] = array('i' => $i, 'type' => 'Type0', 'name' => $name, 'up' => -130, 'ut' => 40, 'cw' => $cw, 'CMap' => $CMap, 'registry' => $registry);
|
|
}
|
|
|
|
public function AddCIDFonts($family, $name, $cw, $CMap, $registry)
|
|
{
|
|
$this->AddCIDFont($family, '', $name, $cw, $CMap, $registry);
|
|
$this->AddCIDFont($family, 'B', $name . ',Bold', $cw, $CMap, $registry);
|
|
$this->AddCIDFont($family, 'I', $name . ',Italic', $cw, $CMap, $registry);
|
|
$this->AddCIDFont($family, 'BI', $name . ',BoldItalic', $cw, $CMap, $registry);
|
|
}
|
|
|
|
public function AddBig5Font($family = 'Big5', $name = 'MSungStd-Light-Acro')
|
|
{
|
|
// Add Big5 font with proportional Latin
|
|
$cw = $this->Big5_widths;
|
|
$CMap = 'ETenms-B5-H';
|
|
$registry = array('ordering' => 'CNS1', 'supplement' => 0);
|
|
$this->AddCIDFonts($family, $name, $cw, $CMap, $registry);
|
|
}
|
|
|
|
public function AddBig5hwFont($family = 'Big5-hw', $name = 'MSungStd-Light-Acro')
|
|
{
|
|
// Add Big5 font with half-witdh Latin
|
|
for ($i = 32; $i <= 126; $i++)
|
|
$cw[chr($i)] = 500;
|
|
$CMap = 'ETen-B5-H';
|
|
$registry = array('ordering' => 'CNS1', 'supplement' => 0);
|
|
$this->AddCIDFonts($family, $name, $cw, $CMap, $registry);
|
|
}
|
|
|
|
public function AddGBFont($family = 'GB', $name = 'STSongStd-Light-Acro')
|
|
{
|
|
// Add GB font with proportional Latin
|
|
$cw = $this->GB_widths;
|
|
$CMap = 'GBKp-EUC-H';
|
|
$registry = array('ordering' => 'GB1', 'supplement' => 2);
|
|
$this->AddCIDFonts($family, $name, $cw, $CMap, $registry);
|
|
}
|
|
|
|
public function AddGBhwFont($family = 'GB-hw', $name = 'STSongStd-Light-Acro')
|
|
{
|
|
// Add GB font with half-width Latin
|
|
for ($i = 32; $i <= 126; $i++)
|
|
$cw[chr($i)] = 500;
|
|
$CMap = 'GBK-EUC-H';
|
|
$registry = array('ordering' => 'GB1', 'supplement' => 2);
|
|
$this->AddCIDFonts($family, $name, $cw, $CMap, $registry);
|
|
}
|
|
|
|
public function GetStringWidth($s)
|
|
{
|
|
if ($this->CurrentFont['type'] == 'Type0')
|
|
return $this->GetMBStringWidth($s);
|
|
else
|
|
return parent::GetStringWidth($s);
|
|
}
|
|
|
|
public function GetMBStringWidth($s)
|
|
{
|
|
// Multi-byte version of GetStringWidth()
|
|
$l = 0;
|
|
$cw = &$this->CurrentFont['cw'];
|
|
$nb = strlen($s);
|
|
$i = 0;
|
|
while ($i < $nb) {
|
|
$c = $s[$i];
|
|
if (ord($c) < 128) {
|
|
$l += $cw[$c];
|
|
$i++;
|
|
} else {
|
|
$l += 1000;
|
|
$i += 2;
|
|
}
|
|
}
|
|
return $l * $this->FontSize / 1000;
|
|
}
|
|
|
|
public function MultiCell($w, $h, $txt, $border = 0, $align = 'L', $fill = 0)
|
|
{
|
|
if ($this->CurrentFont['type'] == 'Type0')
|
|
$this->MBMultiCell($w, $h, $txt, $border, $align, $fill);
|
|
else
|
|
parent::MultiCell($w, $h, $txt, $border, $align, $fill);
|
|
}
|
|
|
|
private function MBMultiCell($w, $h, $txt, $border = 0, $align = 'L', $fill = 0)
|
|
{
|
|
// Multi-byte version of MultiCell()
|
|
$cw = &$this->CurrentFont['cw'];
|
|
if ($w == 0)
|
|
$w = $this->w - $this->rMargin - $this->x;
|
|
$wmax = ($w - 2 * $this->cMargin) * 1000 / $this->FontSize;
|
|
$s = str_replace("\r", '', $txt);
|
|
$nb = strlen($s);
|
|
if ($nb > 0 && $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;
|
|
$nl = 1;
|
|
while ($i < $nb) {
|
|
// Get next character
|
|
$c = $s[$i];
|
|
// Check if ASCII or MB
|
|
$ascii = (ord($c) < 128);
|
|
if ($c == "\n") {
|
|
// Explicit line break
|
|
$this->Cell($w, $h, substr($s, $j, $i - $j), $b, 2, $align, $fill);
|
|
$i++;
|
|
$sep = -1;
|
|
$j = $i;
|
|
$l = 0;
|
|
$nl++;
|
|
if ($border && $nl == 2)
|
|
$b = $b2;
|
|
continue;
|
|
}
|
|
if (!$ascii) {
|
|
$sep = $i;
|
|
$ls = $l;
|
|
} elseif ($c == ' ') {
|
|
$sep = $i;
|
|
$ls = $l;
|
|
}
|
|
$l += $ascii ? $cw[$c] : 1000;
|
|
if ($l > $wmax) {
|
|
// Automatic line break
|
|
if ($sep == -1 || $i == $j) {
|
|
if ($i == $j)
|
|
$i += $ascii ? 1 : 2;
|
|
$this->Cell($w, $h, substr($s, $j, $i - $j), $b, 2, $align, $fill);
|
|
} else {
|
|
$this->Cell($w, $h, substr($s, $j, $sep - $j), $b, 2, $align, $fill);
|
|
$i = ($s[$sep] == ' ') ? $sep + 1 : $sep;
|
|
}
|
|
$sep = -1;
|
|
$j = $i;
|
|
$l = 0;
|
|
$nl++;
|
|
if ($border && $nl == 2)
|
|
$b = $b2;
|
|
} else
|
|
$i += $ascii ? 1 : 2;
|
|
}
|
|
// Last chunk
|
|
if ($border && is_int(strpos($border, 'B')))
|
|
$b .= 'B';
|
|
$this->Cell($w, $h, substr($s, $j, $i - $j), $b, 2, $align, $fill);
|
|
$this->x = $this->lMargin;
|
|
}
|
|
|
|
public function Write($h, $txt, $link = '')
|
|
{
|
|
if ($this->CurrentFont['type'] == 'Type0')
|
|
$this->MBWrite($h, $txt, $link);
|
|
else
|
|
parent::Write($h, $txt, $link);
|
|
}
|
|
|
|
private function MBWrite($h, $txt, $link)
|
|
{
|
|
// Multi-byte version of Write()
|
|
$cw = &$this->CurrentFont['cw'];
|
|
$w = $this->w - $this->rMargin - $this->x;
|
|
$wmax = ($w - 2 * $this->cMargin) * 1000 / $this->FontSize;
|
|
$s = str_replace("\r", '', $txt);
|
|
$nb = strlen($s);
|
|
$sep = -1;
|
|
$i = 0;
|
|
$j = 0;
|
|
$l = 0;
|
|
$nl = 1;
|
|
while ($i < $nb) {
|
|
// Get next character
|
|
$c = $s[$i];
|
|
// Check if ASCII or MB
|
|
$ascii = (ord($c) < 128);
|
|
if ($c == "\n") {
|
|
// Explicit line break
|
|
$this->Cell($w, $h, substr($s, $j, $i - $j), 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 (!$ascii || $c == ' ')
|
|
$sep = $i;
|
|
$l += $ascii ? $cw[$c] : 1000;
|
|
if ($l > $wmax) {
|
|
// Automatic line break
|
|
if ($sep == -1 || $i == $j) {
|
|
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 += $ascii ? 1 : 2;
|
|
$this->Cell($w, $h, substr($s, $j, $i - $j), 0, 2, '', 0, $link);
|
|
} else {
|
|
$this->Cell($w, $h, substr($s, $j, $sep - $j), 0, 2, '', 0, $link);
|
|
$i = ($s[$sep] == ' ') ? $sep + 1 : $sep;
|
|
}
|
|
$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 += $ascii ? 1 : 2;
|
|
}
|
|
// Last chunk
|
|
if ($i != $j)
|
|
$this->Cell($l / 1000 * $this->FontSize, $h, substr($s, $j, $i - $j), 0, 0, '', 0, $link);
|
|
}
|
|
|
|
public function _putType0($font)
|
|
{
|
|
// Type0
|
|
$this->_newobj();
|
|
$this->_out('<</Type /Font');
|
|
$this->_out('/Subtype /Type0');
|
|
$this->_out('/BaseFont /' . $font['name'] . '-' . $font['CMap']);
|
|
$this->_out('/Encoding /' . $font['CMap']);
|
|
$this->_out('/DescendantFonts [' . ($this->n + 1) . ' 0 R]');
|
|
$this->_out('>>');
|
|
$this->_out('endobj');
|
|
// CIDFont
|
|
$this->_newobj();
|
|
$this->_out('<</Type /Font');
|
|
$this->_out('/Subtype /CIDFontType0');
|
|
$this->_out('/BaseFont /' . $font['name']);
|
|
$this->_out('/CIDSystemInfo <</Registry ' . $this->_textstring('Adobe') . ' /Ordering ' . $this->_textstring($font['registry']['ordering']) . ' /Supplement ' . $font['registry']['supplement'] . '>>');
|
|
$this->_out('/FontDescriptor ' . ($this->n + 1) . ' 0 R');
|
|
if ($font['CMap'] == 'ETen-B5-H')
|
|
$W = '13648 13742 500';
|
|
elseif ($font['CMap'] == 'GBK-EUC-H')
|
|
$W = '814 907 500 7716 [500]';
|
|
else
|
|
$W = '1 [' . implode(' ', $font['cw']) . ']';
|
|
$this->_out('/W [' . $W . ']>>');
|
|
$this->_out('endobj');
|
|
// Font descriptor
|
|
$this->_newobj();
|
|
$this->_out('<</Type /FontDescriptor');
|
|
$this->_out('/FontName /' . $font['name']);
|
|
$this->_out('/Flags 6');
|
|
$this->_out('/FontBBox [0 -200 1000 900]');
|
|
$this->_out('/ItalicAngle 0');
|
|
$this->_out('/Ascent 800');
|
|
$this->_out('/Descent -200');
|
|
$this->_out('/CapHeight 800');
|
|
$this->_out('/StemV 50');
|
|
$this->_out('>>');
|
|
$this->_out('endobj');
|
|
}
|
|
|
|
/**
|
|
* 旋转文字,角度为弧度
|
|
*
|
|
* @param int $angle 角度
|
|
* @return void
|
|
*/
|
|
private function Rotate($angle, $x = -1, $y = -1)
|
|
{
|
|
if ($x == -1)
|
|
$x = $this->x;
|
|
if ($y == -1)
|
|
$y = $this->y;
|
|
if ($this->angle != 0)
|
|
$this->_out('Q');
|
|
$this->angle = $angle;
|
|
if ($angle != 0) {
|
|
$angle *= M_PI / 180;
|
|
$c = cos($angle);
|
|
$s = sin($angle);
|
|
$cx = $x * $this->k;
|
|
$cy = ($this->h - $y) * $this->k;
|
|
$this->_out(sprintf('q %.5F %.5F %.5F %.5F %.2F %.2F cm 1 0 0 1 %.2F %.2F cm', $c, $s, -$s, $c, $cx, $cy, -$cx, -$cy));
|
|
}
|
|
}
|
|
public function _endpage()
|
|
{
|
|
if ($this->angle != 0) {
|
|
$this->angle = 0;
|
|
$this->_out('Q');
|
|
}
|
|
parent::_endpage();
|
|
}
|
|
public function RotatedText($x, $y, $txt, $angle)
|
|
{
|
|
//Text rotated around its origin
|
|
$this->Rotate($angle, $x, $y);
|
|
$this->Text($x, $y, $txt);
|
|
$this->Rotate(0);
|
|
}
|
|
|
|
public function RotatedImage($file, $x, $y, $w, $h, $angle)
|
|
{
|
|
//Image rotated around its upper-left corner
|
|
$this->Rotate($angle, $x, $y);
|
|
$this->Image($file, $x, $y, $w, $h);
|
|
$this->Rotate(0);
|
|
}
|
|
}
|