+ MPDF 6.1

This commit is contained in:
2020-08-11 18:04:59 +06:00
parent 11d3f0fc7a
commit c2e133debe
714 changed files with 120510 additions and 93145 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,260 @@
<?php
class bmp
{
var $mpdf = null;
public function __construct(mPDF $mpdf)
{
$this->mpdf = $mpdf;
}
function _getBMPimage($data, $file)
{
$info = array();
// Adapted from script by Valentin Schmidt
// http://staff.dasdeck.de/valentin/fpdf/fpdf_bmp/
$bfOffBits = $this->_fourbytes2int_le(substr($data, 10, 4));
$width = $this->_fourbytes2int_le(substr($data, 18, 4));
$height = $this->_fourbytes2int_le(substr($data, 22, 4));
$flip = ($height < 0);
if ($flip)
$height = -$height;
$biBitCount = $this->_twobytes2int_le(substr($data, 28, 2));
$biCompression = $this->_fourbytes2int_le(substr($data, 30, 4));
$info = array('w' => $width, 'h' => $height);
if ($biBitCount < 16) {
$info['cs'] = 'Indexed';
$info['bpc'] = $biBitCount;
$palStr = substr($data, 54, ($bfOffBits - 54));
$pal = '';
$cnt = strlen($palStr) / 4;
for ($i = 0; $i < $cnt; $i++) {
$n = 4 * $i;
$pal .= $palStr[$n + 2] . $palStr[$n + 1] . $palStr[$n];
}
$info['pal'] = $pal;
} else {
$info['cs'] = 'DeviceRGB';
$info['bpc'] = 8;
}
if ($this->mpdf->restrictColorSpace == 1 || $this->mpdf->PDFX || $this->mpdf->restrictColorSpace == 3) {
if (($this->mpdf->PDFA && !$this->mpdf->PDFAauto) || ($this->mpdf->PDFX && !$this->mpdf->PDFXauto)) {
$this->mpdf->PDFAXwarnings[] = "Image cannot be converted to suitable colour space for PDFA or PDFX file - " . $file . " - (Image replaced by 'no-image'.)";
}
return array('error' => "BMP Image cannot be converted to suitable colour space - " . $file . " - (Image replaced by 'no-image'.)");
}
$biXPelsPerMeter = $this->_fourbytes2int_le(substr($data, 38, 4)); // horizontal pixels per meter, usually set to zero
//$biYPelsPerMeter=$this->_fourbytes2int_le(substr($data,42,4)); // vertical pixels per meter, usually set to zero
$biXPelsPerMeter = round($biXPelsPerMeter / 1000 * 25.4);
//$biYPelsPerMeter=round($biYPelsPerMeter/1000 *25.4);
$info['set-dpi'] = $biXPelsPerMeter;
switch ($biCompression) {
case 0:
$str = substr($data, $bfOffBits);
break;
case 1: # BI_RLE8
$str = $this->rle8_decode(substr($data, $bfOffBits), $width);
break;
case 2: # BI_RLE4
$str = $this->rle4_decode(substr($data, $bfOffBits), $width);
break;
}
$bmpdata = '';
$padCnt = (4 - ceil(($width / (8 / $biBitCount))) % 4) % 4;
switch ($biBitCount) {
case 1:
case 4:
case 8:
$w = floor($width / (8 / $biBitCount)) + ($width % (8 / $biBitCount) ? 1 : 0);
$w_row = $w + $padCnt;
if ($flip) {
for ($y = 0; $y < $height; $y++) {
$y0 = $y * $w_row;
for ($x = 0; $x < $w; $x++)
$bmpdata .= $str[$y0 + $x];
}
} else {
for ($y = $height - 1; $y >= 0; $y--) {
$y0 = $y * $w_row;
for ($x = 0; $x < $w; $x++)
$bmpdata .= $str[$y0 + $x];
}
}
break;
case 16:
$w_row = $width * 2 + $padCnt;
if ($flip) {
for ($y = 0; $y < $height; $y++) {
$y0 = $y * $w_row;
for ($x = 0; $x < $width; $x++) {
$n = (ord($str[$y0 + 2 * $x + 1]) * 256 + ord($str[$y0 + 2 * $x]));
$b = ($n & 31) << 3;
$g = ($n & 992) >> 2;
$r = ($n & 31744) >> 7128;
$bmpdata .= chr($r) . chr($g) . chr($b);
}
}
} else {
for ($y = $height - 1; $y >= 0; $y--) {
$y0 = $y * $w_row;
for ($x = 0; $x < $width; $x++) {
$n = (ord($str[$y0 + 2 * $x + 1]) * 256 + ord($str[$y0 + 2 * $x]));
$b = ($n & 31) << 3;
$g = ($n & 992) >> 2;
$r = ($n & 31744) >> 7;
$bmpdata .= chr($r) . chr($g) . chr($b);
}
}
}
break;
case 24:
case 32:
$byteCnt = $biBitCount / 8;
$w_row = $width * $byteCnt + $padCnt;
if ($flip) {
for ($y = 0; $y < $height; $y++) {
$y0 = $y * $w_row;
for ($x = 0; $x < $width; $x++) {
$i = $y0 + $x * $byteCnt; # + 1
$bmpdata .= $str[$i + 2] . $str[$i + 1] . $str[$i];
}
}
} else {
for ($y = $height - 1; $y >= 0; $y--) {
$y0 = $y * $w_row;
for ($x = 0; $x < $width; $x++) {
$i = $y0 + $x * $byteCnt; # + 1
$bmpdata .= $str[$i + 2] . $str[$i + 1] . $str[$i];
}
}
}
break;
default:
return array('error' => 'Error parsing BMP image - Unsupported image biBitCount');
}
if ($this->mpdf->compress) {
$bmpdata = gzcompress($bmpdata);
$info['f'] = 'FlateDecode';
}
$info['data'] = $bmpdata;
$info['type'] = 'bmp';
return $info;
}
function _fourbytes2int_le($s)
{
//Read a 4-byte integer from string
return (ord($s[3]) << 24) + (ord($s[2]) << 16) + (ord($s[1]) << 8) + ord($s[0]);
}
function _twobytes2int_le($s)
{
//Read a 2-byte integer from string
return (ord(substr($s, 1, 1)) << 8) + ord(substr($s, 0, 1));
}
# Decoder for RLE8 compression in windows bitmaps
# see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/bitmaps_6x0u.asp
function rle8_decode($str, $width)
{
$lineWidth = $width + (3 - ($width - 1) % 4);
$out = '';
$cnt = strlen($str);
for ($i = 0; $i < $cnt; $i++) {
$o = ord($str[$i]);
switch ($o) {
case 0: # ESCAPE
$i++;
switch (ord($str[$i])) {
case 0: # NEW LINE
$padCnt = $lineWidth - strlen($out) % $lineWidth;
if ($padCnt < $lineWidth)
$out .= str_repeat(chr(0), $padCnt);# pad line
break;
case 1: # END OF FILE
$padCnt = $lineWidth - strlen($out) % $lineWidth;
if ($padCnt < $lineWidth)
$out .= str_repeat(chr(0), $padCnt);# pad line
break 3;
case 2: # DELTA
$i += 2;
break;
default: # ABSOLUTE MODE
$num = ord($str[$i]);
for ($j = 0; $j < $num; $j++)
$out .= $str[++$i];
if ($num % 2)
$i++;
}
break;
default:
$out .= str_repeat($str[++$i], $o);
}
}
return $out;
}
# Decoder for RLE4 compression in windows bitmaps
# see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/bitmaps_6x0u.asp
function rle4_decode($str, $width)
{
$w = floor($width / 2) + ($width % 2);
$lineWidth = $w + (3 - ( ($width - 1) / 2) % 4);
$pixels = array();
$cnt = strlen($str);
for ($i = 0; $i < $cnt; $i++) {
$o = ord($str[$i]);
switch ($o) {
case 0: # ESCAPE
$i++;
switch (ord($str[$i])) {
case 0: # NEW LINE
while (count($pixels) % $lineWidth != 0)
$pixels[] = 0;
break;
case 1: # END OF FILE
while (count($pixels) % $lineWidth != 0)
$pixels[] = 0;
break 3;
case 2: # DELTA
$i += 2;
break;
default: # ABSOLUTE MODE
$num = ord($str[$i]);
for ($j = 0; $j < $num; $j++) {
if ($j % 2 == 0) {
$c = ord($str[++$i]);
$pixels[] = ($c & 240) >> 4;
} else
$pixels[] = $c & 15;
}
if ($num % 2)
$i++;
}
break;
default:
$c = ord($str[++$i]);
for ($j = 0; $j < $o; $j++)
$pixels[] = ($j % 2 == 0 ? ($c & 240) >> 4 : $c & 15);
}
}
$out = '';
if (count($pixels) % 2)
$pixels[] = 0;
$cnt = count($pixels) / 2;
for ($i = 0; $i < $cnt; $i++)
$out .= chr(16 * $pixels[2 * $i] + $pixels[2 * $i + 1]);
return $out;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,463 @@
<?php
class directw
{
var $mpdf = null;
public function __construct(mPDF $mpdf)
{
$this->mpdf = $mpdf;
}
function Write($h, $txt, $currentx = 0, $link = '', $directionality = 'ltr', $align = '')
{
if (!$align) {
if ($directionality == 'rtl') {
$align = 'R';
} else {
$align = 'L';
}
}
if ($h == 0) {
$this->mpdf->SetLineHeight();
$h = $this->mpdf->lineheight;
}
//Output text in flowing mode
$w = $this->mpdf->w - $this->mpdf->rMargin - $this->mpdf->x;
$wmax = ($w - ($this->mpdf->cMarginL + $this->mpdf->cMarginR));
$s = str_replace("\r", '', $txt);
if ($this->mpdf->usingCoreFont) {
$nb = strlen($s);
} else {
$nb = mb_strlen($s, $this->mpdf->mb_enc);
// handle single space character
if (($nb == 1) && $s == " ") {
$this->mpdf->x += $this->mpdf->GetStringWidth($s);
return;
}
}
$sep = -1;
$i = 0;
$j = 0;
$l = 0;
$nl = 1;
if (!$this->mpdf->usingCoreFont) {
if (preg_match("/([" . $this->mpdf->pregRTLchars . "])/u", $txt)) {
$this->mpdf->biDirectional = true;
} // *RTL*
while ($i < $nb) {
//Get next character
$c = mb_substr($s, $i, 1, $this->mpdf->mb_enc);
if ($c == "\n") {
// WORD SPACING
$this->mpdf->ResetSpacing();
//Explicit line break
$tmp = rtrim(mb_substr($s, $j, $i - $j, $this->mpdf->mb_enc));
$this->mpdf->Cell($w, $h, $tmp, 0, 2, $align, $fill, $link);
$i++;
$sep = -1;
$j = $i;
$l = 0;
if ($nl == 1) {
if ($currentx != 0)
$this->mpdf->x = $currentx;
else
$this->mpdf->x = $this->mpdf->lMargin;
$w = $this->mpdf->w - $this->mpdf->rMargin - $this->mpdf->x;
$wmax = ($w - ($this->mpdf->cMarginL + $this->mpdf->cMarginR));
}
$nl++;
continue;
}
if ($c == " ") {
$sep = $i;
}
$l += $this->mpdf->GetCharWidthNonCore($c); // mPDF 5.3.04
if ($l > $wmax) {
//Automatic line break (word wrapping)
if ($sep == -1) {
// WORD SPACING
$this->mpdf->ResetSpacing();
if ($this->mpdf->x > $this->mpdf->lMargin) {
//Move to next line
if ($currentx != 0)
$this->mpdf->x = $currentx;
else
$this->mpdf->x = $this->mpdf->lMargin;
$this->mpdf->y+=$h;
$w = $this->mpdf->w - $this->mpdf->rMargin - $this->mpdf->x;
$wmax = ($w - ($this->mpdf->cMarginL + $this->mpdf->cMarginR));
$i++;
$nl++;
continue;
}
if ($i == $j) {
$i++;
}
$tmp = rtrim(mb_substr($s, $j, $i - $j, $this->mpdf->mb_enc));
$this->mpdf->Cell($w, $h, $tmp, 0, 2, $align, $fill, $link);
} else {
$tmp = rtrim(mb_substr($s, $j, $sep - $j, $this->mpdf->mb_enc));
if ($align == 'J') {
//////////////////////////////////////////
// JUSTIFY J using Unicode fonts (Word spacing doesn't work)
// WORD SPACING
// Change NON_BREAKING SPACE to spaces so they are 'spaced' properly
$tmp = str_replace(chr(194) . chr(160), chr(32), $tmp);
$len_ligne = $this->mpdf->GetStringWidth($tmp);
$nb_carac = mb_strlen($tmp, $this->mpdf->mb_enc);
$nb_spaces = mb_substr_count($tmp, ' ', $this->mpdf->mb_enc);
$inclCursive = false;
if (isset($this->mpdf->CurrentFont['useOTL']) && $this->mpdf->CurrentFont['useOTL']) {
if (preg_match("/([" . $this->mpdf->pregCURSchars . "])/u", $tmp)) {
$inclCursive = true;
}
}
list($charspacing, $ws) = $this->mpdf->GetJspacing($nb_carac, $nb_spaces, ((($w - 2) - $len_ligne) * _MPDFK), $inclCursive);
$this->mpdf->SetSpacing($charspacing, $ws);
//////////////////////////////////////////
}
$this->mpdf->Cell($w, $h, $tmp, 0, 2, $align, $fill, $link);
$i = $sep + 1;
}
$sep = -1;
$j = $i;
$l = 0;
if ($nl == 1) {
if ($currentx != 0)
$this->mpdf->x = $currentx;
else
$this->mpdf->x = $this->mpdf->lMargin;
$w = $this->mpdf->w - $this->mpdf->rMargin - $this->mpdf->x;
$wmax = ($w - ($this->mpdf->cMarginL + $this->mpdf->cMarginR));
}
$nl++;
}
else {
$i++;
}
}
//Last chunk
// WORD SPACING
$this->mpdf->ResetSpacing();
} else {
while ($i < $nb) {
//Get next character
$c = $s[$i];
if ($c == "\n") {
//Explicit line break
// WORD SPACING
$this->mpdf->ResetSpacing();
$this->mpdf->Cell($w, $h, substr($s, $j, $i - $j), 0, 2, $align, $fill, $link);
$i++;
$sep = -1;
$j = $i;
$l = 0;
if ($nl == 1) {
if ($currentx != 0)
$this->mpdf->x = $currentx;
else
$this->mpdf->x = $this->mpdf->lMargin;
$w = $this->mpdf->w - $this->mpdf->rMargin - $this->mpdf->x;
$wmax = $w - ($this->mpdf->cMarginL + $this->mpdf->cMarginR);
}
$nl++;
continue;
}
if ($c == " ") {
$sep = $i;
}
$l += $this->mpdf->GetCharWidthCore($c); // mPDF 5.3.04
if ($l > $wmax) {
//Automatic line break (word wrapping)
if ($sep == -1) {
// WORD SPACING
$this->mpdf->ResetSpacing();
if ($this->mpdf->x > $this->mpdf->lMargin) {
//Move to next line
if ($currentx != 0)
$this->mpdf->x = $currentx;
else
$this->mpdf->x = $this->mpdf->lMargin;
$this->mpdf->y+=$h;
$w = $this->mpdf->w - $this->mpdf->rMargin - $this->mpdf->x;
$wmax = $w - ($this->mpdf->cMarginL + $this->mpdf->cMarginR);
$i++;
$nl++;
continue;
}
if ($i == $j) {
$i++;
}
$this->mpdf->Cell($w, $h, substr($s, $j, $i - $j), 0, 2, $align, $fill, $link);
} else {
$tmp = substr($s, $j, $sep - $j);
if ($align == 'J') {
//////////////////////////////////////////
// JUSTIFY J using Unicode fonts
// WORD SPACING is not fully supported for complex scripts
// Change NON_BREAKING SPACE to spaces so they are 'spaced' properly
$tmp = str_replace(chr(160), chr(32), $tmp);
$len_ligne = $this->mpdf->GetStringWidth($tmp);
$nb_carac = strlen($tmp);
$nb_spaces = substr_count($tmp, ' ');
list($charspacing, $ws) = $this->mpdf->GetJspacing($nb_carac, $nb_spaces, ((($w - 2) - $len_ligne) * _MPDFK), $false);
$this->mpdf->SetSpacing($charspacing, $ws);
//////////////////////////////////////////
}
$this->mpdf->Cell($w, $h, $tmp, 0, 2, $align, $fill, $link);
$i = $sep + 1;
}
$sep = -1;
$j = $i;
$l = 0;
if ($nl == 1) {
if ($currentx != 0)
$this->mpdf->x = $currentx;
else
$this->mpdf->x = $this->mpdf->lMargin;
$w = $this->mpdf->w - $this->mpdf->rMargin - $this->mpdf->x;
$wmax = $w - ($this->mpdf->cMarginL + $this->mpdf->cMarginR);
}
$nl++;
}
else {
$i++;
}
}
// WORD SPACING
$this->mpdf->ResetSpacing();
}
//Last chunk
if ($i != $j) {
if ($currentx != 0)
$this->mpdf->x = $currentx;
else
$this->mpdf->x = $this->mpdf->lMargin;
if ($this->mpdf->usingCoreFont) {
$tmp = substr($s, $j, $i - $j);
} else {
$tmp = mb_substr($s, $j, $i - $j, $this->mpdf->mb_enc);
}
$this->mpdf->Cell($w, $h, $tmp, 0, 0, $align, $fill, $link);
}
}
function CircularText($x, $y, $r, $text, $align = 'top', $fontfamily = '', $fontsizePt = 0, $fontstyle = '', $kerning = 120, $fontwidth = 100, $divider = '')
{
if ($fontfamily || $fontstyle || $fontsizePt)
$this->mpdf->SetFont($fontfamily, $fontstyle, $fontsizePt);
$kerning/=100;
$fontwidth/=100;
if ($kerning == 0)
$this->mpdf->Error('Please use values unequal to zero for kerning (CircularText)');
if ($fontwidth == 0)
$this->mpdf->Error('Please use values unequal to zero for font width (CircularText)');
$text = str_replace("\r", '', $text);
//circumference
$u = ($r * 2) * M_PI;
$checking = true;
$autoset = false;
while ($checking) {
$t = 0;
$w = array();
if ($this->mpdf->usingCoreFont) {
$nb = strlen($text);
for ($i = 0; $i < $nb; $i++) {
$w[$i] = $this->mpdf->GetStringWidth($text[$i]);
$w[$i]*=$kerning * $fontwidth;
$t+=$w[$i];
}
} else {
$nb = mb_strlen($text, $this->mpdf->mb_enc);
$lastchar = '';
$unicode = $this->mpdf->UTF8StringToArray($text);
for ($i = 0; $i < $nb; $i++) {
$c = mb_substr($text, $i, 1, $this->mpdf->mb_enc);
$w[$i] = $this->mpdf->GetStringWidth($c);
$w[$i]*=$kerning * $fontwidth;
$char = $unicode[$i];
if ($this->mpdf->useKerning && $lastchar) {
if (isset($this->mpdf->CurrentFont['kerninfo'][$lastchar][$char])) {
$tk = $this->mpdf->CurrentFont['kerninfo'][$lastchar][$char] * ($this->mpdf->FontSize / 1000) * $kerning * $fontwidth;
$w[$i] += $tk / 2;
$w[$i - 1] += $tk / 2;
$t+=$tk;
}
}
$lastchar = $char;
$t+=$w[$i];
}
}
if ($fontsizePt >= 0 || $autoset) {
$checking = false;
} else {
$t+=$this->mpdf->GetStringWidth(' ');
if ($divider)
$t+=$this->mpdf->GetStringWidth(' ');
if ($fontsizePt == -2)
$fontsizePt = $this->mpdf->FontSizePt * 0.5 * $u / $t;
else
$fontsizePt = $this->mpdf->FontSizePt * $u / $t;
$this->mpdf->SetFontSize($fontsizePt);
$autoset = true;
}
}
//total width of string in degrees
$d = ($t / $u) * 360;
$this->mpdf->StartTransform();
// rotate matrix for the first letter to center the text
// (half of total degrees)
if ($align == 'top') {
$this->mpdf->transformRotate(-$d / 2, $x, $y);
} else {
$this->mpdf->transformRotate($d / 2, $x, $y);
}
//run through the string
for ($i = 0; $i < $nb; $i++) {
if ($align == 'top') {
//rotate matrix half of the width of current letter + half of the width of preceding letter
if ($i == 0) {
$this->mpdf->transformRotate((($w[$i] / 2) / $u) * 360, $x, $y);
} else {
$this->mpdf->transformRotate((($w[$i] / 2 + $w[$i - 1] / 2) / $u) * 360, $x, $y);
}
if ($fontwidth != 1) {
$this->mpdf->StartTransform();
$this->mpdf->transformScale($fontwidth * 100, 100, $x, $y);
}
$this->mpdf->SetXY($x - $w[$i] / 2, $y - $r);
} else {
//rotate matrix half of the width of current letter + half of the width of preceding letter
if ($i == 0) {
$this->mpdf->transformRotate(-(($w[$i] / 2) / $u) * 360, $x, $y);
} else {
$this->mpdf->transformRotate(-(($w[$i] / 2 + $w[$i - 1] / 2) / $u) * 360, $x, $y);
}
if ($fontwidth != 1) {
$this->mpdf->StartTransform();
$this->mpdf->transformScale($fontwidth * 100, 100, $x, $y);
}
$this->mpdf->SetXY($x - $w[$i] / 2, $y + $r - ($this->mpdf->FontSize));
}
if ($this->mpdf->usingCoreFont) {
$c = $text[$i];
} else {
$c = mb_substr($text, $i, 1, $this->mpdf->mb_enc);
}
$this->mpdf->Cell(($w[$i]), $this->mpdf->FontSize, $c, 0, 0, 'C'); // mPDF 5.3.53
if ($fontwidth != 1) {
$this->mpdf->StopTransform();
}
}
$this->mpdf->StopTransform();
// mPDF 5.5.23
if ($align == 'top' && $divider != '') {
$wc = $this->mpdf->GetStringWidth($divider);
$wc*=$kerning * $fontwidth;
$this->mpdf->StartTransform();
$this->mpdf->transformRotate(90, $x, $y);
$this->mpdf->SetXY($x - $wc / 2, $y - $r);
$this->mpdf->Cell(($wc), $this->mpdf->FontSize, $divider, 0, 0, 'C');
$this->mpdf->StopTransform();
$this->mpdf->StartTransform();
$this->mpdf->transformRotate(-90, $x, $y);
$this->mpdf->SetXY($x - $wc / 2, $y - $r);
$this->mpdf->Cell(($wc), $this->mpdf->FontSize, $divider, 0, 0, 'C');
$this->mpdf->StopTransform();
}
}
function Shaded_box($text, $font = '', $fontstyle = 'B', $szfont = '', $width = '70%', $style = 'DF', $radius = 2.5, $fill = '#FFFFFF', $color = '#000000', $pad = 2)
{
// F (shading - no line),S (line, no shading),DF (both)
if (!$font) {
$font = $this->mpdf->default_font;
}
if (!$szfont) {
$szfont = ($this->mpdf->default_font_size * 1.8);
}
$text = ' ' . $text . ' ';
$this->mpdf->SetFont($font, $fontstyle, $szfont, false);
$text = $this->mpdf->purify_utf8_text($text);
if ($this->mpdf->text_input_as_HTML) {
$text = $this->mpdf->all_entities_to_utf8($text);
}
if ($this->mpdf->usingCoreFont) {
$text = mb_convert_encoding($text, $this->mpdf->mb_enc, 'UTF-8');
}
// DIRECTIONALITY
if (preg_match("/([" . $this->mpdf->pregRTLchars . "])/u", $text)) {
$this->mpdf->biDirectional = true;
} // *RTL*
$textvar = 0;
$save_OTLtags = $this->mpdf->OTLtags;
$this->mpdf->OTLtags = array();
if ($this->mpdf->useKerning) {
if ($this->mpdf->CurrentFont['haskernGPOS']) {
$this->mpdf->OTLtags['Plus'] .= ' kern';
} else {
$textvar = ($textvar | FC_KERNING);
}
}
// Use OTL OpenType Table Layout - GSUB & GPOS
if (isset($this->mpdf->CurrentFont['useOTL']) && $this->mpdf->CurrentFont['useOTL']) {
$text = $this->mpdf->otl->applyOTL($text, $this->mpdf->CurrentFont['useOTL']);
$OTLdata = $this->mpdf->otl->OTLdata;
}
$this->mpdf->OTLtags = $save_OTLtags;
$this->mpdf->magic_reverse_dir($text, $this->mpdf->directionality, $OTLdata);
if (!$width) {
$width = $this->mpdf->pgwidth;
} else {
$width = $this->mpdf->ConvertSize($width, $this->mpdf->pgwidth);
}
$midpt = $this->mpdf->lMargin + ($this->mpdf->pgwidth / 2);
$r1 = $midpt - ($width / 2); //($this->mpdf->w / 2) - 40;
$r2 = $r1 + $width; //$r1 + 80;
$y1 = $this->mpdf->y;
$mid = ($r1 + $r2 ) / 2;
$loop = 0;
while ($loop == 0) {
$this->mpdf->SetFont($font, $fontstyle, $szfont, false);
$sz = $this->mpdf->GetStringWidth($text, true, $OTLdata, $textvar);
if (($r1 + $sz) > $r2)
$szfont --;
else
$loop ++;
}
$this->mpdf->SetFont($font, $fontstyle, $szfont, true, true);
$y2 = $this->mpdf->FontSize + ($pad * 2);
$this->mpdf->SetLineWidth(0.1);
$fc = $this->mpdf->ConvertColor($fill);
$tc = $this->mpdf->ConvertColor($color);
$this->mpdf->SetFColor($fc);
$this->mpdf->SetTColor($tc);
$this->mpdf->RoundedRect($r1, $y1, ($r2 - $r1), $y2, $radius, $style);
$this->mpdf->SetX($r1);
$this->mpdf->Cell($r2 - $r1, $y2, $text, 0, 1, "C", 0, '', 0, 0, 0, 'M', 0, false, $OTLdata, $textvar);
$this->mpdf->SetY($y1 + $y2 + 2); // +2 = mm margin below shaded box
$this->mpdf->Reset();
}
}

View File

@ -0,0 +1,677 @@
<?php
///////////////////////////////////////////////////////////////////////////////////////////////////
// 2009-12-22 Adapted for mPDF 4.2
///////////////////////////////////////////////////////////////////////////////////////////////////
// GIF Util - (C) 2003 Yamasoft (S/C)
// http://www.yamasoft.com
// All Rights Reserved
// This file can be freely copied, distributed, modified, updated by anyone under the only
// condition to leave the original address (Yamasoft, http://www.yamasoft.com) and this header.
///////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
// 2009-12-22 Adapted INB
// Functions calling functionname($x, $len = 0) were not working on PHP5.1.5 as pass by reference
// All edited to $len = 0; then call function.
///////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
class CGIFLZW
{
var $MAX_LZW_BITS;
var $Fresh, $CodeSize, $SetCodeSize, $MaxCode, $MaxCodeSize, $FirstCode, $OldCode;
var $ClearCode, $EndCode, $Next, $Vals, $Stack, $sp, $Buf, $CurBit, $LastBit, $Done, $LastByte;
public function __construct()
{
$this->MAX_LZW_BITS = 12;
unSet($this->Next);
unSet($this->Vals);
unSet($this->Stack);
unSet($this->Buf);
$this->Next = range(0, (1 << $this->MAX_LZW_BITS) - 1);
$this->Vals = range(0, (1 << $this->MAX_LZW_BITS) - 1);
$this->Stack = range(0, (1 << ($this->MAX_LZW_BITS + 1)) - 1);
$this->Buf = range(0, 279);
}
function deCompress($data, &$datLen)
{
$stLen = strlen($data);
$datLen = 0;
$ret = "";
$dp = 0; // data pointer
// INITIALIZATION
$this->LZWCommandInit($data, $dp);
while (($iIndex = $this->LZWCommand($data, $dp)) >= 0) {
$ret .= chr($iIndex);
}
$datLen = $dp;
if ($iIndex != -2) {
return false;
}
return $ret;
}
function LZWCommandInit(&$data, &$dp)
{
$this->SetCodeSize = ord($data[0]);
$dp += 1;
$this->CodeSize = $this->SetCodeSize + 1;
$this->ClearCode = 1 << $this->SetCodeSize;
$this->EndCode = $this->ClearCode + 1;
$this->MaxCode = $this->ClearCode + 2;
$this->MaxCodeSize = $this->ClearCode << 1;
$this->GetCodeInit($data, $dp);
$this->Fresh = 1;
for ($i = 0; $i < $this->ClearCode; $i++) {
$this->Next[$i] = 0;
$this->Vals[$i] = $i;
}
for (; $i < (1 << $this->MAX_LZW_BITS); $i++) {
$this->Next[$i] = 0;
$this->Vals[$i] = 0;
}
$this->sp = 0;
return 1;
}
function LZWCommand(&$data, &$dp)
{
if ($this->Fresh) {
$this->Fresh = 0;
do {
$this->FirstCode = $this->GetCode($data, $dp);
$this->OldCode = $this->FirstCode;
} while ($this->FirstCode == $this->ClearCode);
return $this->FirstCode;
}
if ($this->sp > 0) {
$this->sp--;
return $this->Stack[$this->sp];
}
while (($Code = $this->GetCode($data, $dp)) >= 0) {
if ($Code == $this->ClearCode) {
for ($i = 0; $i < $this->ClearCode; $i++) {
$this->Next[$i] = 0;
$this->Vals[$i] = $i;
}
for (; $i < (1 << $this->MAX_LZW_BITS); $i++) {
$this->Next[$i] = 0;
$this->Vals[$i] = 0;
}
$this->CodeSize = $this->SetCodeSize + 1;
$this->MaxCodeSize = $this->ClearCode << 1;
$this->MaxCode = $this->ClearCode + 2;
$this->sp = 0;
$this->FirstCode = $this->GetCode($data, $dp);
$this->OldCode = $this->FirstCode;
return $this->FirstCode;
}
if ($Code == $this->EndCode) {
return -2;
}
$InCode = $Code;
if ($Code >= $this->MaxCode) {
$this->Stack[$this->sp++] = $this->FirstCode;
$Code = $this->OldCode;
}
while ($Code >= $this->ClearCode) {
$this->Stack[$this->sp++] = $this->Vals[$Code];
if ($Code == $this->Next[$Code]) // Circular table entry, big GIF Error!
return -1;
$Code = $this->Next[$Code];
}
$this->FirstCode = $this->Vals[$Code];
$this->Stack[$this->sp++] = $this->FirstCode;
if (($Code = $this->MaxCode) < (1 << $this->MAX_LZW_BITS)) {
$this->Next[$Code] = $this->OldCode;
$this->Vals[$Code] = $this->FirstCode;
$this->MaxCode++;
if (($this->MaxCode >= $this->MaxCodeSize) && ($this->MaxCodeSize < (1 << $this->MAX_LZW_BITS))) {
$this->MaxCodeSize *= 2;
$this->CodeSize++;
}
}
$this->OldCode = $InCode;
if ($this->sp > 0) {
$this->sp--;
return $this->Stack[$this->sp];
}
}
return $Code;
}
function GetCodeInit(&$data, &$dp)
{
$this->CurBit = 0;
$this->LastBit = 0;
$this->Done = 0;
$this->LastByte = 2;
return 1;
}
function GetCode(&$data, &$dp)
{
if (($this->CurBit + $this->CodeSize) >= $this->LastBit) {
if ($this->Done) {
if ($this->CurBit >= $this->LastBit) {
// Ran off the end of my bits
return 0;
}
return -1;
}
$this->Buf[0] = $this->Buf[$this->LastByte - 2];
$this->Buf[1] = $this->Buf[$this->LastByte - 1];
$Count = ord($data[$dp]);
$dp += 1;
if ($Count) {
for ($i = 0; $i < $Count; $i++) {
$this->Buf[2 + $i] = ord($data[$dp + $i]);
}
$dp += $Count;
} else {
$this->Done = 1;
}
$this->LastByte = 2 + $Count;
$this->CurBit = ($this->CurBit - $this->LastBit) + 16;
$this->LastBit = (2 + $Count) << 3;
}
$iRet = 0;
for ($i = $this->CurBit, $j = 0; $j < $this->CodeSize; $i++, $j++) {
$iRet |= (($this->Buf[intval($i / 8)] & (1 << ($i % 8))) != 0) << $j;
}
$this->CurBit += $this->CodeSize;
return $iRet;
}
}
class CGIFCOLORTABLE
{
var $m_nColors;
var $m_arColors;
public function __construct()
{
unSet($this->m_nColors);
unSet($this->m_arColors);
}
function load($lpData, $num)
{
$this->m_nColors = 0;
$this->m_arColors = array();
for ($i = 0; $i < $num; $i++) {
$rgb = substr($lpData, $i * 3, 3);
if (strlen($rgb) < 3) {
return false;
}
$this->m_arColors[] = (ord($rgb[2]) << 16) + (ord($rgb[1]) << 8) + ord($rgb[0]);
$this->m_nColors++;
}
return true;
}
function toString()
{
$ret = "";
for ($i = 0; $i < $this->m_nColors; $i++) {
$ret .=
chr(($this->m_arColors[$i] & 0x000000FF)) . // R
chr(($this->m_arColors[$i] & 0x0000FF00) >> 8) . // G
chr(($this->m_arColors[$i] & 0x00FF0000) >> 16); // B
}
return $ret;
}
function colorIndex($rgb)
{
$rgb = intval($rgb) & 0xFFFFFF;
$r1 = ($rgb & 0x0000FF);
$g1 = ($rgb & 0x00FF00) >> 8;
$b1 = ($rgb & 0xFF0000) >> 16;
$idx = -1;
for ($i = 0; $i < $this->m_nColors; $i++) {
$r2 = ($this->m_arColors[$i] & 0x000000FF);
$g2 = ($this->m_arColors[$i] & 0x0000FF00) >> 8;
$b2 = ($this->m_arColors[$i] & 0x00FF0000) >> 16;
$d = abs($r2 - $r1) + abs($g2 - $g1) + abs($b2 - $b1);
if (($idx == -1) || ($d < $dif)) {
$idx = $i;
$dif = $d;
}
}
return $idx;
}
}
class CGIFFILEHEADER
{
var $m_lpVer;
var $m_nWidth;
var $m_nHeight;
var $m_bGlobalClr;
var $m_nColorRes;
var $m_bSorted;
var $m_nTableSize;
var $m_nBgColor;
var $m_nPixelRatio;
var $m_colorTable;
public function __construct()
{
unSet($this->m_lpVer);
unSet($this->m_nWidth);
unSet($this->m_nHeight);
unSet($this->m_bGlobalClr);
unSet($this->m_nColorRes);
unSet($this->m_bSorted);
unSet($this->m_nTableSize);
unSet($this->m_nBgColor);
unSet($this->m_nPixelRatio);
unSet($this->m_colorTable);
}
function load($lpData, &$hdrLen)
{
$hdrLen = 0;
$this->m_lpVer = substr($lpData, 0, 6);
if (($this->m_lpVer <> "GIF87a") && ($this->m_lpVer <> "GIF89a")) {
return false;
}
$this->m_nWidth = $this->w2i(substr($lpData, 6, 2));
$this->m_nHeight = $this->w2i(substr($lpData, 8, 2));
if (!$this->m_nWidth || !$this->m_nHeight) {
return false;
}
$b = ord(substr($lpData, 10, 1));
$this->m_bGlobalClr = ($b & 0x80) ? true : false;
$this->m_nColorRes = ($b & 0x70) >> 4;
$this->m_bSorted = ($b & 0x08) ? true : false;
$this->m_nTableSize = 2 << ($b & 0x07);
$this->m_nBgColor = ord(substr($lpData, 11, 1));
$this->m_nPixelRatio = ord(substr($lpData, 12, 1));
$hdrLen = 13;
if ($this->m_bGlobalClr) {
$this->m_colorTable = new CGIFCOLORTABLE();
if (!$this->m_colorTable->load(substr($lpData, $hdrLen), $this->m_nTableSize)) {
return false;
}
$hdrLen += 3 * $this->m_nTableSize;
}
return true;
}
function w2i($str)
{
return ord(substr($str, 0, 1)) + (ord(substr($str, 1, 1)) << 8);
}
}
class CGIFIMAGEHEADER
{
var $m_nLeft;
var $m_nTop;
var $m_nWidth;
var $m_nHeight;
var $m_bLocalClr;
var $m_bInterlace;
var $m_bSorted;
var $m_nTableSize;
var $m_colorTable;
public function __construct()
{
unSet($this->m_nLeft);
unSet($this->m_nTop);
unSet($this->m_nWidth);
unSet($this->m_nHeight);
unSet($this->m_bLocalClr);
unSet($this->m_bInterlace);
unSet($this->m_bSorted);
unSet($this->m_nTableSize);
unSet($this->m_colorTable);
}
function load($lpData, &$hdrLen)
{
$hdrLen = 0;
$this->m_nLeft = $this->w2i(substr($lpData, 0, 2));
$this->m_nTop = $this->w2i(substr($lpData, 2, 2));
$this->m_nWidth = $this->w2i(substr($lpData, 4, 2));
$this->m_nHeight = $this->w2i(substr($lpData, 6, 2));
if (!$this->m_nWidth || !$this->m_nHeight) {
return false;
}
$b = ord($lpData{8});
$this->m_bLocalClr = ($b & 0x80) ? true : false;
$this->m_bInterlace = ($b & 0x40) ? true : false;
$this->m_bSorted = ($b & 0x20) ? true : false;
$this->m_nTableSize = 2 << ($b & 0x07);
$hdrLen = 9;
if ($this->m_bLocalClr) {
$this->m_colorTable = new CGIFCOLORTABLE();
if (!$this->m_colorTable->load(substr($lpData, $hdrLen), $this->m_nTableSize)) {
return false;
}
$hdrLen += 3 * $this->m_nTableSize;
}
return true;
}
function w2i($str)
{
return ord(substr($str, 0, 1)) + (ord(substr($str, 1, 1)) << 8);
}
}
class CGIFIMAGE
{
var $m_disp;
var $m_bUser;
var $m_bTrans;
var $m_nDelay;
var $m_nTrans;
var $m_lpComm;
var $m_gih;
var $m_data;
var $m_lzw;
public function __construct()
{
unSet($this->m_disp);
unSet($this->m_bUser);
unSet($this->m_bTrans);
unSet($this->m_nDelay);
unSet($this->m_nTrans);
unSet($this->m_lpComm);
unSet($this->m_data);
$this->m_gih = new CGIFIMAGEHEADER();
$this->m_lzw = new CGIFLZW();
}
function load($data, &$datLen)
{
$datLen = 0;
while (true) {
$b = ord($data[0]);
$data = substr($data, 1);
$datLen++;
switch ($b) {
case 0x21: // Extension
$len = 0;
if (!$this->skipExt($data, $len)) {
return false;
}
$datLen += $len;
break;
case 0x2C: // Image
// LOAD HEADER & COLOR TABLE
$len = 0;
if (!$this->m_gih->load($data, $len)) {
return false;
}
$data = substr($data, $len);
$datLen += $len;
// ALLOC BUFFER
$len = 0;
if (!($this->m_data = $this->m_lzw->deCompress($data, $len))) {
return false;
}
$data = substr($data, $len);
$datLen += $len;
if ($this->m_gih->m_bInterlace) {
$this->deInterlace();
}
return true;
case 0x3B: // EOF
default:
return false;
}
}
return false;
}
function skipExt(&$data, &$extLen)
{
$extLen = 0;
$b = ord($data[0]);
$data = substr($data, 1);
$extLen++;
switch ($b) {
case 0xF9: // Graphic Control
$b = ord($data[1]);
$this->m_disp = ($b & 0x1C) >> 2;
$this->m_bUser = ($b & 0x02) ? true : false;
$this->m_bTrans = ($b & 0x01) ? true : false;
$this->m_nDelay = $this->w2i(substr($data, 2, 2));
$this->m_nTrans = ord($data[4]);
break;
case 0xFE: // Comment
$this->m_lpComm = substr($data, 1, ord($data[0]));
break;
case 0x01: // Plain text
break;
case 0xFF: // Application
break;
}
// SKIP DEFAULT AS DEFS MAY CHANGE
$b = ord($data[0]);
$data = substr($data, 1);
$extLen++;
while ($b > 0) {
$data = substr($data, $b);
$extLen += $b;
$b = ord($data[0]);
$data = substr($data, 1);
$extLen++;
}
return true;
}
function w2i($str)
{
return ord(substr($str, 0, 1)) + (ord(substr($str, 1, 1)) << 8);
}
function deInterlace()
{
$data = $this->m_data;
for ($i = 0; $i < 4; $i++) {
switch ($i) {
case 0:
$s = 8;
$y = 0;
break;
case 1:
$s = 8;
$y = 4;
break;
case 2:
$s = 4;
$y = 2;
break;
case 3:
$s = 2;
$y = 1;
break;
}
for (; $y < $this->m_gih->m_nHeight; $y += $s) {
$lne = substr($this->m_data, 0, $this->m_gih->m_nWidth);
$this->m_data = substr($this->m_data, $this->m_gih->m_nWidth);
$data = substr($data, 0, $y * $this->m_gih->m_nWidth) .
$lne .
substr($data, ($y + 1) * $this->m_gih->m_nWidth);
}
}
$this->m_data = $data;
}
}
class CGIF
{
var $m_gfh;
var $m_lpData;
var $m_img;
var $m_bLoaded;
public function __construct()
{
$this->m_gfh = new CGIFFILEHEADER();
$this->m_img = new CGIFIMAGE();
$this->m_lpData = "";
$this->m_bLoaded = false;
}
function ClearData()
{
$this->m_lpData = '';
unSet($this->m_img->m_data);
unSet($this->m_img->m_lzw->Next);
unSet($this->m_img->m_lzw->Vals);
unSet($this->m_img->m_lzw->Stack);
unSet($this->m_img->m_lzw->Buf);
}
function loadFile(&$data, $iIndex)
{
if ($iIndex < 0) {
return false;
}
$this->m_lpData = $data;
// GET FILE HEADER
$len = 0;
if (!$this->m_gfh->load($this->m_lpData, $len)) {
return false;
}
$this->m_lpData = substr($this->m_lpData, $len);
do {
$imgLen = 0;
if (!$this->m_img->load($this->m_lpData, $imgLen)) {
return false;
}
$this->m_lpData = substr($this->m_lpData, $imgLen);
} while ($iIndex-- > 0);
$this->m_bLoaded = true;
return true;
}
}

View File

@ -0,0 +1,975 @@
<?php
class grad
{
var $mpdf = null;
public function __construct(mPDF $mpdf)
{
$this->mpdf = $mpdf;
}
// mPDF 5.3.A1
function CoonsPatchMesh($x, $y, $w, $h, $patch_array = array(), $x_min = 0, $x_max = 1, $y_min = 0, $y_max = 1, $colspace = 'RGB', $return = false)
{
$s = ' q ';
$s.=sprintf(' %.3F %.3F %.3F %.3F re W n ', $x * _MPDFK, ($this->mpdf->h - $y) * _MPDFK, $w * _MPDFK, -$h * _MPDFK);
$s.=sprintf(' %.3F 0 0 %.3F %.3F %.3F cm ', $w * _MPDFK, $h * _MPDFK, $x * _MPDFK, ($this->mpdf->h - ($y + $h)) * _MPDFK);
$n = count($this->mpdf->gradients) + 1;
$this->mpdf->gradients[$n]['type'] = 6; //coons patch mesh
$this->mpdf->gradients[$n]['colorspace'] = $colspace; //coons patch mesh
$bpcd = 65535; //16 BitsPerCoordinate
$trans = false;
$this->mpdf->gradients[$n]['stream'] = '';
for ($i = 0; $i < count($patch_array); $i++) {
$this->mpdf->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
if (($j % 2) == 1) { // Y coordinate (adjusted as input is From top left)
$patch_array[$i]['points'][$j] = (($patch_array[$i]['points'][$j] - $y_min) / ($y_max - $y_min)) * $bpcd;
$patch_array[$i]['points'][$j] = $bpcd - $patch_array[$i]['points'][$j];
} else {
$patch_array[$i]['points'][$j] = (($patch_array[$i]['points'][$j] - $x_min) / ($x_max - $x_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;
$this->mpdf->gradients[$n]['stream'].=chr(floor($patch_array[$i]['points'][$j] / 256));
$this->mpdf->gradients[$n]['stream'].=chr(floor($patch_array[$i]['points'][$j] % 256));
}
for ($j = 0; $j < count($patch_array[$i]['colors']); $j++) {
//each color component as 8 bit
if ($colspace == 'RGB') {
$this->mpdf->gradients[$n]['stream'].=($patch_array[$i]['colors'][$j][1]);
$this->mpdf->gradients[$n]['stream'].=($patch_array[$i]['colors'][$j][2]);
$this->mpdf->gradients[$n]['stream'].=($patch_array[$i]['colors'][$j][3]);
if (isset($patch_array[$i]['colors'][$j][4]) && ord($patch_array[$i]['colors'][$j][4]) < 100) {
$trans = true;
}
} else if ($colspace == 'CMYK') {
$this->mpdf->gradients[$n]['stream'].=chr(ord($patch_array[$i]['colors'][$j][1]) * 2.55);
$this->mpdf->gradients[$n]['stream'].=chr(ord($patch_array[$i]['colors'][$j][2]) * 2.55);
$this->mpdf->gradients[$n]['stream'].=chr(ord($patch_array[$i]['colors'][$j][3]) * 2.55);
$this->mpdf->gradients[$n]['stream'].=chr(ord($patch_array[$i]['colors'][$j][4]) * 2.55);
if (isset($patch_array[$i]['colors'][$j][5]) && ord($patch_array[$i]['colors'][$j][5]) < 100) {
$trans = true;
}
} else if ($colspace == 'Gray') {
$this->mpdf->gradients[$n]['stream'].=($patch_array[$i]['colors'][$j][1]);
if ($patch_array[$i]['colors'][$j][2] == 1) {
$trans = true;
} // transparency converted from rgba or cmyka()
}
}
}
// TRANSPARENCY
if ($trans) {
$this->mpdf->gradients[$n]['stream_trans'] = '';
for ($i = 0; $i < count($patch_array); $i++) {
$this->mpdf->gradients[$n]['stream_trans'].=chr($patch_array[$i]['f']);
for ($j = 0; $j < count($patch_array[$i]['points']); $j++) {
//each point as 16 bit
$this->mpdf->gradients[$n]['stream_trans'].=chr(floor($patch_array[$i]['points'][$j] / 256));
$this->mpdf->gradients[$n]['stream_trans'].=chr(floor($patch_array[$i]['points'][$j] % 256));
}
for ($j = 0; $j < count($patch_array[$i]['colors']); $j++) {
//each color component as 8 bit // OPACITY
if ($colspace == 'RGB') {
$this->mpdf->gradients[$n]['stream_trans'].=chr(intval(ord($patch_array[$i]['colors'][$j][4]) * 2.55));
} else if ($colspace == 'CMYK') {
$this->mpdf->gradients[$n]['stream_trans'].=chr(intval(ord($patch_array[$i]['colors'][$j][5]) * 2.55));
} else if ($colspace == 'Gray') {
$this->mpdf->gradients[$n]['stream_trans'].=chr(intval(ord($patch_array[$i]['colors'][$j][3]) * 2.55));
}
}
}
$this->mpdf->gradients[$n]['trans'] = true;
$s .= ' /TGS' . $n . ' gs ';
}
//paint the gradient
$s .= '/Sh' . $n . ' sh' . "\n";
//restore previous Graphic State
$s .= 'Q' . "\n";
if ($return) {
return $s;
} else {
$this->mpdf->_out($s);
}
}
// type = linear:2; radial: 3;
// Linear: $coords - array of the form (x1, y1, x2, y2) which defines the gradient vector (see linear_gradient_coords.jpg).
// The default value is from left to right (x1=0, y1=0, x2=1, y2=0).
// Radial: $coords - array of the form (fx, fy, cx, cy, r) where (fx, fy) is the starting point of the gradient with color1,
// (cx, cy) is the center of the circle with color2, and r is the radius of the circle (see radial_gradient_coords.jpg).
// (fx, fy) should be inside the circle, otherwise some areas will not be defined
// $col = array(R,G,B/255); or array(G/255); or array(C,M,Y,K/100)
// $stops = array('col'=>$col [, 'opacity'=>0-1] [, 'offset'=>0-1])
function Gradient($x, $y, $w, $h, $type, $stops = array(), $colorspace = 'RGB', $coords = '', $extend = '', $return = false, $is_mask = false)
{
if (strtoupper(substr($type, 0, 1)) == 'L') {
$type = 2;
} // linear
else if (strtoupper(substr($type, 0, 1)) == 'R') {
$type = 3;
} // radial
if ($colorspace != 'CMYK' && $colorspace != 'Gray') {
$colorspace = 'RGB';
}
$bboxw = $w;
$bboxh = $h;
$usex = $x;
$usey = $y;
$usew = $bboxw;
$useh = $bboxh;
if ($type < 1) {
$type = 2;
}
if ($coords[0] !== false && preg_match('/([0-9.]+(px|em|ex|pc|pt|cm|mm|in))/i', $coords[0], $m)) {
$tmp = $this->mpdf->ConvertSize($m[1], $this->mpdf->w, $this->mpdf->FontSize, false);
if ($tmp) {
$coords[0] = $tmp / $w;
}
}
if ($coords[1] !== false && preg_match('/([0-9.]+(px|em|ex|pc|pt|cm|mm|in))/i', $coords[1], $m)) {
$tmp = $this->mpdf->ConvertSize($m[1], $this->mpdf->w, $this->mpdf->FontSize, false);
if ($tmp) {
$coords[1] = 1 - ($tmp / $h);
}
}
// LINEAR
if ($type == 2) {
$angle = (isset($coords[4]) ? $coords[4] : false);
$repeat = (isset($coords[5]) ? $coords[5] : false);
// ALL POINTS SET (default for custom mPDF linear gradient) - no -moz
if ($coords[0] !== false && $coords[1] !== false && $coords[2] !== false && $coords[3] !== false) {
// do nothing - coords used as they are
}
// If both a <point> and <angle> are defined, the gradient axis starts from the point and runs along the angle. The end point is
// defined as before - in this case start points may not be in corners, and axis may not correctly fall in the right quadrant.
// NO end points (Angle defined & Start points)
else if ($angle !== false && $coords[0] !== false && $coords[1] !== false && $coords[2] === false && $coords[3] === false) {
if ($angle == 0 || $angle == 360) {
$coords[3] = $coords[1];
if ($coords[0] == 1)
$coords[2] = 2;
else
$coords[2] = 1;
}
else if ($angle == 90) {
$coords[2] = $coords[0];
$coords[3] = 1;
if ($coords[1] == 1)
$coords[3] = 2;
else
$coords[3] = 1;
}
else if ($angle == 180) {
if ($coords[4] == 0)
$coords[2] = -1;
else
$coords[2] = 0;
$coords[3] = $coords[1];
}
else if ($angle == 270) {
$coords[2] = $coords[0];
if ($coords[1] == 0)
$coords[3] = -1;
else
$coords[3] = 0;
}
else {
$endx = 1;
$endy = 1;
if ($angle <= 90) {
if ($angle <= 45) {
$endy = tan(deg2rad($angle));
} else {
$endx = tan(deg2rad(90 - $angle));
}
$b = atan2(($endy * $bboxh), ($endx * $bboxw));
$ny = 1 - $coords[1] - (tan($b) * (1 - $coords[0]));
$tx = sin($b) * cos($b) * $ny;
$ty = cos($b) * cos($b) * $ny;
$coords[2] = 1 + $tx;
$coords[3] = 1 - $ty;
} else if ($angle <= 180) {
if ($angle <= 135) {
$endx = tan(deg2rad($angle - 90));
} else {
$endy = tan(deg2rad(180 - $angle));
}
$b = atan2(($endy * $bboxh), ($endx * $bboxw));
$ny = 1 - $coords[1] - (tan($b) * ($coords[0]));
$tx = sin($b) * cos($b) * $ny;
$ty = cos($b) * cos($b) * $ny;
$coords[2] = -$tx;
$coords[3] = 1 - $ty;
} else if ($angle <= 270) {
if ($angle <= 225) {
$endy = tan(deg2rad($angle - 180));
} else {
$endx = tan(deg2rad(270 - $angle));
}
$b = atan2(($endy * $bboxh), ($endx * $bboxw));
$ny = $coords[1] - (tan($b) * ($coords[0]));
$tx = sin($b) * cos($b) * $ny;
$ty = cos($b) * cos($b) * $ny;
$coords[2] = -$tx;
$coords[3] = $ty;
} else {
if ($angle <= 315) {
$endx = tan(deg2rad($angle - 270));
} else {
$endy = tan(deg2rad(360 - $angle));
}
$b = atan2(($endy * $bboxh), ($endx * $bboxw));
$ny = $coords[1] - (tan($b) * (1 - $coords[0]));
$tx = sin($b) * cos($b) * $ny;
$ty = cos($b) * cos($b) * $ny;
$coords[2] = 1 + $tx;
$coords[3] = $ty;
}
}
}
// -moz If the first parameter is only an <angle>, the gradient axis starts from the box's corner that would ensure the
// axis goes through the box. The axis runs along the specified angle. The end point of the axis is defined such that the
// farthest corner of the box from the starting point is perpendicular to the gradient axis at that point.
// NO end points or Start points (Angle defined)
else if ($angle !== false && $coords[0] === false && $coords[1] === false) {
if ($angle == 0 || $angle == 360) {
$coords[0] = 0;
$coords[1] = 0;
$coords[2] = 1;
$coords[3] = 0;
} else if ($angle == 90) {
$coords[0] = 0;
$coords[1] = 0;
$coords[2] = 0;
$coords[3] = 1;
} else if ($angle == 180) {
$coords[0] = 1;
$coords[1] = 0;
$coords[2] = 0;
$coords[3] = 0;
} else if ($angle == 270) {
$coords[0] = 0;
$coords[1] = 1;
$coords[2] = 0;
$coords[3] = 0;
} else {
if ($angle <= 90) {
$coords[0] = 0;
$coords[1] = 0;
if ($angle <= 45) {
$endx = 1;
$endy = tan(deg2rad($angle));
} else {
$endx = tan(deg2rad(90 - $angle));
$endy = 1;
}
} else if ($angle <= 180) {
$coords[0] = 1;
$coords[1] = 0;
if ($angle <= 135) {
$endx = tan(deg2rad($angle - 90));
$endy = 1;
} else {
$endx = 1;
$endy = tan(deg2rad(180 - $angle));
}
} else if ($angle <= 270) {
$coords[0] = 1;
$coords[1] = 1;
if ($angle <= 225) {
$endx = 1;
$endy = tan(deg2rad($angle - 180));
} else {
$endx = tan(deg2rad(270 - $angle));
$endy = 1;
}
} else {
$coords[0] = 0;
$coords[1] = 1;
if ($angle <= 315) {
$endx = tan(deg2rad($angle - 270));
$endy = 1;
} else {
$endx = 1;
$endy = tan(deg2rad(360 - $angle));
}
}
$b = atan2(($endy * $bboxh), ($endx * $bboxw));
$h2 = $bboxh - ($bboxh * tan($b));
$px = $bboxh + ($h2 * sin($b) * cos($b));
$py = ($bboxh * tan($b)) + ($h2 * sin($b) * sin($b));
$x1 = $px / $bboxh;
$y1 = $py / $bboxh;
if ($angle <= 90) {
$coords[2] = $x1;
$coords[3] = $y1;
} else if ($angle <= 180) {
$coords[2] = 1 - $x1;
$coords[3] = $y1;
} else if ($angle <= 270) {
$coords[2] = 1 - $x1;
$coords[3] = 1 - $y1;
} else {
$coords[2] = $x1;
$coords[3] = 1 - $y1;
}
}
}
// -moz If the first parameter to the gradient function is only a <point>, the gradient axis starts from the specified point,
// and ends at the point you would get if you rotated the starting point by 180 degrees about the center of the box that the
// gradient is to be applied to.
// NO angle and NO end points (Start points defined)
else if ((!isset($angle) || $angle === false) && $coords[0] !== false && $coords[1] !== false) { // should have start and end defined
$coords[2] = 1 - $coords[0];
$coords[3] = 1 - $coords[1];
$angle = rad2deg(atan2($coords[3] - $coords[1], $coords[2] - $coords[0]));
if ($angle < 0) {
$angle += 360;
} else if ($angle > 360) {
$angle -= 360;
}
if ($angle != 0 && $angle != 360 && $angle != 90 && $angle != 180 && $angle != 270) {
if ($w >= $h) {
$coords[1] *= $h / $w;
$coords[3] *= $h / $w;
$usew = $useh = $bboxw;
$usey -= ($w - $h);
} else {
$coords[0] *= $w / $h;
$coords[2] *= $w / $h;
$usew = $useh = $bboxh;
}
}
}
// -moz If neither a <point> or <angle> is specified, i.e. the entire function consists of only <stop> values, the gradient
// axis starts from the top of the box and runs vertically downwards, ending at the bottom of the box.
else { // default values T2B
// All values are set in parseMozGradient - so won't appear here
$coords = array(0, 0, 1, 0); // default for original linear gradient (L2R)
}
$s = ' q';
$s .= sprintf(' %.3F %.3F %.3F %.3F re W n', $x * _MPDFK, ($this->mpdf->h - $y) * _MPDFK, $w * _MPDFK, -$h * _MPDFK) . "\n";
$s .= sprintf(' %.3F 0 0 %.3F %.3F %.3F cm', $usew * _MPDFK, $useh * _MPDFK, $usex * _MPDFK, ($this->mpdf->h - ($usey + $useh)) * _MPDFK) . "\n";
}
// RADIAL
else if ($type == 3) {
$radius = (isset($coords[4]) ? $coords[4] : false);
$angle = (isset($coords[5]) ? $coords[5] : false); // ?? no effect
$shape = (isset($coords[6]) ? $coords[6] : false);
$size = (isset($coords[7]) ? $coords[7] : false);
$repeat = (isset($coords[8]) ? $coords[8] : false);
// ALL POINTS AND RADIUS SET (default for custom mPDF radial gradient) - no -moz
if ($coords[0] !== false && $coords[1] !== false && $coords[2] !== false && $coords[3] !== false && $coords[4] !== false) {
// do nothing - coords used as they are
}
// If a <point> is defined
else if ($shape !== false && $size !== false) {
if ($coords[2] == false) {
$coords[2] = $coords[0];
}
if ($coords[3] == false) {
$coords[3] = $coords[1];
}
// ELLIPSE
if ($shape == 'ellipse') {
$corner1 = sqrt(pow($coords[0], 2) + pow($coords[1], 2));
$corner2 = sqrt(pow($coords[0], 2) + pow((1 - $coords[1]), 2));
$corner3 = sqrt(pow((1 - $coords[0]), 2) + pow($coords[1], 2));
$corner4 = sqrt(pow((1 - $coords[0]), 2) + pow((1 - $coords[1]), 2));
if ($size == 'closest-side') {
$radius = min($coords[0], $coords[1], (1 - $coords[0]), (1 - $coords[1]));
} else if ($size == 'closest-corner') {
$radius = min($corner1, $corner2, $corner3, $corner4);
} else if ($size == 'farthest-side') {
$radius = max($coords[0], $coords[1], (1 - $coords[0]), (1 - $coords[1]));
} else {
$radius = max($corner1, $corner2, $corner3, $corner4);
} // farthest corner (default)
}
// CIRCLE
else if ($shape == 'circle') {
if ($w >= $h) {
$coords[1] = $coords[3] = ($coords[1] * $h / $w);
$corner1 = sqrt(pow($coords[0], 2) + pow($coords[1], 2));
$corner2 = sqrt(pow($coords[0], 2) + pow((($h / $w) - $coords[1]), 2));
$corner3 = sqrt(pow((1 - $coords[0]), 2) + pow($coords[1], 2));
$corner4 = sqrt(pow((1 - $coords[0]), 2) + pow((($h / $w) - $coords[1]), 2));
if ($size == 'closest-side') {
$radius = min($coords[0], $coords[1], (1 - $coords[0]), (($h / $w) - $coords[1]));
} else if ($size == 'closest-corner') {
$radius = min($corner1, $corner2, $corner3, $corner4);
} else if ($size == 'farthest-side') {
$radius = max($coords[0], $coords[1], (1 - $coords[0]), (($h / $w) - $coords[1]));
} else if ($size == 'farthest-corner') {
$radius = max($corner1, $corner2, $corner3, $corner4);
} // farthest corner (default)
$usew = $useh = $bboxw;
$usey -= ($w - $h);
} else {
$coords[0] = $coords[2] = ($coords[0] * $w / $h);
$corner1 = sqrt(pow($coords[0], 2) + pow($coords[1], 2));
$corner2 = sqrt(pow($coords[0], 2) + pow((1 - $coords[1]), 2));
$corner3 = sqrt(pow((($w / $h) - $coords[0]), 2) + pow($coords[1], 2));
$corner4 = sqrt(pow((($w / $h) - $coords[0]), 2) + pow((1 - $coords[1]), 2));
if ($size == 'closest-side') {
$radius = min($coords[0], $coords[1], (($w / $h) - $coords[0]), (1 - $coords[1]));
} else if ($size == 'closest-corner') {
$radius = min($corner1, $corner2, $corner3, $corner4);
} else if ($size == 'farthest-side') {
$radius = max($coords[0], $coords[1], (($w / $h) - $coords[0]), (1 - $coords[1]));
} else if ($size == 'farthest-corner') {
$radius = max($corner1, $corner2, $corner3, $corner4);
} // farthest corner (default)
$usew = $useh = $bboxh;
}
}
if ($radius == 0) {
$radius = 0.001;
} // to prevent error
$coords[4] = $radius;
}
// -moz If entire function consists of only <stop> values
else { // default values
// All values are set in parseMozGradient - so won't appear here
$coords = array(0.5, 0.5, 0.5, 0.5); // default for radial gradient (centred)
}
$s = ' q';
$s .= sprintf(' %.3F %.3F %.3F %.3F re W n', $x * _MPDFK, ($this->mpdf->h - $y) * _MPDFK, $w * _MPDFK, -$h * _MPDFK) . "\n";
$s .= sprintf(' %.3F 0 0 %.3F %.3F %.3F cm', $usew * _MPDFK, $useh * _MPDFK, $usex * _MPDFK, ($this->mpdf->h - ($usey + $useh)) * _MPDFK) . "\n";
}
$n = count($this->mpdf->gradients) + 1;
$this->mpdf->gradients[$n]['type'] = $type;
$this->mpdf->gradients[$n]['colorspace'] = $colorspace;
$trans = false;
$this->mpdf->gradients[$n]['is_mask'] = $is_mask;
if ($is_mask) {
$trans = true;
}
if (count($stops) == 1) {
$stops[1] = $stops[0];
}
if (!isset($stops[0]['offset'])) {
$stops[0]['offset'] = 0;
}
if (!isset($stops[(count($stops) - 1)]['offset'])) {
$stops[(count($stops) - 1)]['offset'] = 1;
}
// Fix stop-offsets set as absolute lengths
if ($type == 2) {
$axisx = ($coords[2] - $coords[0]) * $usew;
$axisy = ($coords[3] - $coords[1]) * $useh;
$axis_length = sqrt(pow($axisx, 2) + pow($axisy, 2));
} else {
$axis_length = $coords[4] * $usew;
} // Absolute lengths are meaningless for an ellipse - Firefox uses Width as reference
for ($i = 0; $i < count($stops); $i++) {
if (isset($stops[$i]['offset']) && preg_match('/([0-9.]+(px|em|ex|pc|pt|cm|mm|in))/i', $stops[$i]['offset'], $m)) {
$tmp = $this->mpdf->ConvertSize($m[1], $this->mpdf->w, $this->mpdf->FontSize, false);
$stops[$i]['offset'] = $tmp / $axis_length;
}
}
if (isset($stops[0]['offset']) && $stops[0]['offset'] > 0) {
$firststop = $stops[0];
$firststop['offset'] = 0;
array_unshift($stops, $firststop);
}
if (!$repeat && isset($stops[(count($stops) - 1)]['offset']) && $stops[(count($stops) - 1)]['offset'] < 1) {
$endstop = $stops[(count($stops) - 1)];
$endstop['offset'] = 1;
$stops[] = $endstop;
}
if ($stops[0]['offset'] > $stops[(count($stops) - 1)]['offset']) {
$stops[0]['offset'] = 0;
$stops[(count($stops) - 1)]['offset'] = 1;
}
for ($i = 0; $i < count($stops); $i++) {
// mPDF 5.3.74
if ($colorspace == 'CMYK') {
$this->mpdf->gradients[$n]['stops'][$i]['col'] = sprintf('%.3F %.3F %.3F %.3F', (ord($stops[$i]['col']{1}) / 100), (ord($stops[$i]['col']{2}) / 100), (ord($stops[$i]['col']{3}) / 100), (ord($stops[$i]['col']{4}) / 100));
} else if ($colorspace == 'Gray') {
$this->mpdf->gradients[$n]['stops'][$i]['col'] = sprintf('%.3F', (ord($stops[$i]['col']{1}) / 255));
} else {
$this->mpdf->gradients[$n]['stops'][$i]['col'] = sprintf('%.3F %.3F %.3F', (ord($stops[$i]['col']{1}) / 255), (ord($stops[$i]['col']{2}) / 255), (ord($stops[$i]['col']{3}) / 255));
}
if (!isset($stops[$i]['opacity'])) {
$stops[$i]['opacity'] = 1;
} else if ($stops[$i]['opacity'] > 1 || $stops[$i]['opacity'] < 0) {
$stops[$i]['opacity'] = 1;
} else if ($stops[$i]['opacity'] < 1) {
$trans = true;
}
$this->mpdf->gradients[$n]['stops'][$i]['opacity'] = $stops[$i]['opacity'];
// OFFSET
if ($i > 0 && $i < (count($stops) - 1)) {
if (!isset($stops[$i]['offset']) || (isset($stops[$i + 1]['offset']) && $stops[$i]['offset'] > $stops[$i + 1]['offset']) || $stops[$i]['offset'] < $stops[$i - 1]['offset']) {
if (isset($stops[$i - 1]['offset']) && isset($stops[$i + 1]['offset'])) {
$stops[$i]['offset'] = ($stops[$i - 1]['offset'] + $stops[$i + 1]['offset']) / 2;
} else {
for ($j = ($i + 1); $j < count($stops); $j++) {
if (isset($stops[$j]['offset'])) {
break;
}
}
$int = ($stops[$j]['offset'] - $stops[($i - 1)]['offset']) / ($j - $i + 1);
for ($f = 0; $f < ($j - $i - 1); $f++) {
$stops[($i + $f)]['offset'] = $stops[($i + $f - 1)]['offset'] + ($int);
}
}
}
}
$this->mpdf->gradients[$n]['stops'][$i]['offset'] = $stops[$i]['offset'];
$this->mpdf->gradients[$n]['stops'][$i]['offset'] = $stops[$i]['offset'];
}
if ($repeat) {
$ns = count($this->mpdf->gradients[$n]['stops']);
$offs = array();
for ($i = 0; $i < $ns; $i++) {
$offs[$i] = $this->mpdf->gradients[$n]['stops'][$i]['offset'];
}
$gp = 0;
$inside = true;
while ($inside) {
$gp++;
for ($i = 0; $i < $ns; $i++) {
$this->mpdf->gradients[$n]['stops'][(($ns * $gp) + $i)] = $this->mpdf->gradients[$n]['stops'][(($ns * ($gp - 1)) + $i)];
$tmp = $this->mpdf->gradients[$n]['stops'][(($ns * ($gp - 1)) + ($ns - 1))]['offset'] + $offs[$i];
if ($tmp < 1) {
$this->mpdf->gradients[$n]['stops'][(($ns * $gp) + $i)]['offset'] = $tmp;
} else {
$this->mpdf->gradients[$n]['stops'][(($ns * $gp) + $i)]['offset'] = 1;
$inside = false;
break(2);
}
}
}
}
if ($trans) {
$this->mpdf->gradients[$n]['trans'] = true;
$s .= ' /TGS' . $n . ' gs ';
}
if (!is_array($extend) || count($extend) < 1) {
$extend = array('true', 'true'); // These are supposed to be quoted - appear in PDF file as text
}
$this->mpdf->gradients[$n]['coords'] = $coords;
$this->mpdf->gradients[$n]['extend'] = $extend;
//paint the gradient
$s .= '/Sh' . $n . ' sh ' . "\n";
//restore previous Graphic State
$s .= ' Q ' . "\n";
if ($return) {
return $s;
} else {
$this->mpdf->_out($s);
}
}
function parseMozGradient($bg)
{
// background[-image]: -moz-linear-gradient(left, #c7Fdde 20%, #FF0000 );
// background[-image]: linear-gradient(left, #c7Fdde 20%, #FF0000 ); // CSS3
if (preg_match('/repeating-/', $bg)) {
$repeat = true;
} else {
$repeat = false;
}
if (preg_match('/linear-gradient\((.*)\)/', $bg, $m)) {
$g = array();
$g['type'] = 2;
$g['colorspace'] = 'RGB';
$g['extend'] = array('true', 'true');
$v = trim($m[1]);
// Change commas inside e.g. rgb(x,x,x)
while (preg_match('/(\([^\)]*?),/', $v)) {
$v = preg_replace('/(\([^\)]*?),/', '\\1@', $v);
}
// Remove spaces inside e.g. rgb(x, x, x)
while (preg_match('/(\([^\)]*?)[ ]/', $v)) {
$v = preg_replace('/(\([^\)]*?)[ ]/', '\\1', $v);
}
$bgr = preg_split('/\s*,\s*/', $v);
for ($i = 0; $i < count($bgr); $i++) {
$bgr[$i] = preg_replace('/@/', ',', $bgr[$i]);
}
// Is first part $bgr[0] a valid point/angle?
$first = preg_split('/\s+/', trim($bgr[0]));
if (preg_match('/(left|center|right|bottom|top|deg|grad|rad)/i', $bgr[0]) && !preg_match('/(<#|rgb|rgba|hsl|hsla)/i', $bgr[0])) {
$startStops = 1;
} else if (trim($first[(count($first) - 1)]) === "0") {
$startStops = 1;
} else {
$check = $this->mpdf->ConvertColor($first[0]);
if ($check)
$startStops = 0;
else
$startStops = 1;
}
// first part a valid point/angle?
if ($startStops == 1) { // default values
// [<point> || <angle>,] = [<% em px left center right bottom top> || <deg grad rad 0>,]
if (preg_match('/([\-]*[0-9\.]+)(deg|grad|rad)/i', $bgr[0], $m)) {
$angle = $m[1] + 0;
if (strtolower($m[2]) == 'deg') {
$angle = $angle;
} else if (strtolower($m[2]) == 'grad') {
$angle *= (360 / 400);
} else if (strtolower($m[2]) == 'rad') {
$angle = rad2deg($angle);
}
while ($angle < 0) {
$angle += 360;
}
$angle = ($angle % 360);
} else if (trim($first[(count($first) - 1)]) === "0") {
$angle = 0;
}
if (preg_match('/left/i', $bgr[0])) {
$startx = 0;
} else if (preg_match('/right/i', $bgr[0])) {
$startx = 1;
}
if (preg_match('/top/i', $bgr[0])) {
$starty = 1;
} else if (preg_match('/bottom/i', $bgr[0])) {
$starty = 0;
}
// Check for %? ?% or %%
if (preg_match('/(\d+)[%]/i', $first[0], $m)) {
$startx = $m[1] / 100;
} else if (!isset($startx) && preg_match('/([0-9.]+(px|em|ex|pc|pt|cm|mm|in))/i', $first[0], $m)) {
$tmp = $this->mpdf->ConvertSize($m[1], $this->mpdf->w, $this->mpdf->FontSize, false);
if ($tmp) {
$startx = $m[1];
}
}
if (isset($first[1]) && preg_match('/(\d+)[%]/i', $first[1], $m)) {
$starty = 1 - ($m[1] / 100);
} else if (!isset($starty) && isset($first[1]) && preg_match('/([0-9.]+(px|em|ex|pc|pt|cm|mm|in))/i', $first[1], $m)) {
$tmp = $this->mpdf->ConvertSize($m[1], $this->mpdf->w, $this->mpdf->FontSize, false);
if ($tmp) {
$starty = $m[1];
}
}
if (isset($startx) && !isset($starty)) {
$starty = 0.5;
}
if (!isset($startx) && isset($starty)) {
$startx = 0.5;
}
}
// If neither a <point> or <angle> is specified, i.e. the entire function consists of only <stop> values, the gradient axis starts from the top of the box and runs vertically downwards, ending at the bottom of the box.
else { // default values T2B
$starty = 1;
$startx = 0.5;
$endy = 0;
$endx = 0.5;
}
$coords = array();
if (!isset($startx)) {
$startx = false;
}
if (!isset($starty)) {
$starty = false;
}
if (!isset($endx)) {
$endx = false;
}
if (!isset($endy)) {
$endy = false;
}
if (!isset($angle)) {
$angle = false;
}
$g['coords'] = array($startx, $starty, $endx, $endy, $angle, $repeat);
$g['stops'] = array();
for ($i = $startStops; $i < count($bgr); $i++) {
$stop = array();
// parse stops
$el = preg_split('/\s+/', trim($bgr[$i]));
// mPDF 5.3.74
$col = $this->mpdf->ConvertColor($el[0]);
if ($col) {
$stop['col'] = $col;
} else {
$stop['col'] = $col = $this->mpdf->ConvertColor(255);
}
if ($col{0} == 1)
$g['colorspace'] = 'Gray';
else if ($col{0} == 4 || $col{0} == 6)
$g['colorspace'] = 'CMYK';
if ($col{0} == 5) {
$stop['opacity'] = ord($col{4}) / 100;
} // transparency from rgba()
else if ($col{0} == 6) {
$stop['opacity'] = ord($col{5}) / 100;
} // transparency from cmyka()
else if ($col{0} == 1 && $col{2} == 1) {
$stop['opacity'] = ord($col{3}) / 100;
} // transparency converted from rgba or cmyka()
if (isset($el[1]) && preg_match('/(\d+)[%]/', $el[1], $m)) {
$stop['offset'] = $m[1] / 100;
if ($stop['offset'] > 1) {
unset($stop['offset']);
}
} else if (isset($el[1]) && preg_match('/([0-9.]+(px|em|ex|pc|pt|cm|mm|in))/i', $el[1], $m)) {
$tmp = $this->mpdf->ConvertSize($m[1], $this->mpdf->w, $this->mpdf->FontSize, false);
if ($tmp) {
$stop['offset'] = $m[1];
}
}
$g['stops'][] = $stop;
}
if (count($g['stops'])) {
return $g;
}
} else if (preg_match('/radial-gradient\((.*)\)/', $bg, $m)) {
$g = array();
$g['type'] = 3;
$g['colorspace'] = 'RGB';
$g['extend'] = array('true', 'true');
$v = trim($m[1]);
// Change commas inside e.g. rgb(x,x,x)
while (preg_match('/(\([^\)]*?),/', $v)) {
$v = preg_replace('/(\([^\)]*?),/', '\\1@', $v);
}
// Remove spaces inside e.g. rgb(x, x, x)
while (preg_match('/(\([^\)]*?)[ ]/', $v)) {
$v = preg_replace('/(\([^\)]*?)[ ]/', '\\1', $v);
}
$bgr = preg_split('/\s*,\s*/', $v);
for ($i = 0; $i < count($bgr); $i++) {
$bgr[$i] = preg_replace('/@/', ',', $bgr[$i]);
}
// Is first part $bgr[0] a valid point/angle?
$startStops = 0;
$pos_angle = false;
$shape_size = false;
$first = preg_split('/\s+/', trim($bgr[0]));
$checkCol = $this->mpdf->ConvertColor($first[0]);
if (preg_match('/(left|center|right|bottom|top|deg|grad|rad)/i', $bgr[0]) && !preg_match('/(<#|rgb|rgba|hsl|hsla)/i', $bgr[0])) {
$startStops = 1;
$pos_angle = $bgr[0];
} else if (trim($first[(count($first) - 1)]) === "0") {
$startStops = 1;
$pos_angle = $bgr[0];
} else if (preg_match('/(circle|ellipse|closest-side|closest-corner|farthest-side|farthest-corner|contain|cover)/i', $bgr[0])) {
$startStops = 1;
$shape_size = $bgr[0];
} else if (!$checkCol) {
$startStops = 1;
$pos_angle = $bgr[0];
}
if (preg_match('/(circle|ellipse|closest-side|closest-corner|farthest-side|farthest-corner|contain|cover)/i', $bgr[1])) {
$startStops = 2;
$shape_size = $bgr[1];
}
// If valid point/angle?
if ($pos_angle) { // default values
// [<point> || <angle>,] = [<% em px left center right bottom top> || <deg grad rad 0>,]
if (preg_match('/left/i', $pos_angle)) {
$startx = 0;
} else if (preg_match('/right/i', $pos_angle)) {
$startx = 1;
}
if (preg_match('/top/i', $pos_angle)) {
$starty = 1;
} else if (preg_match('/bottom/i', $pos_angle)) {
$starty = 0;
}
// Check for %? ?% or %%
if (preg_match('/(\d+)[%]/i', $first[0], $m)) {
$startx = $m[1] / 100;
} else if (!isset($startx) && preg_match('/([0-9.]+(px|em|ex|pc|pt|cm|mm|in))/i', $first[0], $m)) {
$tmp = $this->mpdf->ConvertSize($m[1], $this->mpdf->w, $this->mpdf->FontSize, false);
if ($tmp) {
$startx = $m[1];
}
}
if (isset($first[1]) && preg_match('/(\d+)[%]/i', $first[1], $m)) {
$starty = 1 - ($m[1] / 100);
} else if (!isset($starty) && isset($first[1]) && preg_match('/([0-9.]+(px|em|ex|pc|pt|cm|mm|in))/i', $first[1], $m)) {
$tmp = $this->mpdf->ConvertSize($m[1], $this->mpdf->w, $this->mpdf->FontSize, false);
if ($tmp) {
$starty = $m[1];
}
}
/*
// ?? Angle has no effect in radial gradient (does not exist in CSS3 spec.)
if (preg_match('/([\-]*[0-9\.]+)(deg|grad|rad)/i',$pos_angle,$m)) {
$angle = $m[1] + 0;
if (strtolower($m[2])=='deg') { $angle = $angle; }
else if (strtolower($m[2])=='grad') { $angle *= (360/400); }
else if (strtolower($m[2])=='rad') { $angle = rad2deg($angle); }
while($angle < 0) { $angle += 360; }
$angle = ($angle % 360);
}
*/
if (!isset($starty)) {
$starty = 0.5;
}
if (!isset($startx)) {
$startx = 0.5;
}
}
// If neither a <point> or <angle> is specified, i.e. the entire function consists of only <stop> values, the gradient axis starts from the top of the box and runs vertically downwards, ending at the bottom of the box.
else { // default values Center
$starty = 0.5;
$startx = 0.5;
$endy = 0.5;
$endx = 0.5;
}
// If valid shape/size?
$shape = 'ellipse'; // default
$size = 'farthest-corner'; // default
if ($shape_size) { // default values
if (preg_match('/(circle|ellipse)/i', $shape_size, $m)) {
$shape = $m[1];
}
if (preg_match('/(closest-side|closest-corner|farthest-side|farthest-corner|contain|cover)/i', $shape_size, $m)) {
$size = $m[1];
if ($size == 'contain') {
$size = 'closest-side';
} else if ($size == 'cover') {
$size = 'farthest-corner';
}
}
}
$coords = array();
if (!isset($startx)) {
$startx = false;
}
if (!isset($starty)) {
$starty = false;
}
if (!isset($endx)) {
$endx = false;
}
if (!isset($endy)) {
$endy = false;
}
if (!isset($radius)) {
$radius = false;
}
if (!isset($angle)) {
$angle = 0;
}
$g['coords'] = array($startx, $starty, $endx, $endy, $radius, $angle, $shape, $size, $repeat);
$g['stops'] = array();
for ($i = $startStops; $i < count($bgr); $i++) {
$stop = array();
// parse stops
$el = preg_split('/\s+/', trim($bgr[$i]));
// mPDF 5.3.74
$col = $this->mpdf->ConvertColor($el[0]);
if ($col) {
$stop['col'] = $col;
} else {
$stop['col'] = $col = $this->mpdf->ConvertColor(255);
}
if ($col{0} == 1)
$g['colorspace'] = 'Gray';
else if ($col{0} == 4 || $col{0} == 6)
$g['colorspace'] = 'CMYK';
if ($col{0} == 5) {
$stop['opacity'] = ord($col{4}) / 100;
} // transparency from rgba()
else if ($col{0} == 6) {
$stop['opacity'] = ord($col{5}) / 100;
} // transparency from cmyka()
else if ($col{0} == 1 && $col{2} == 1) {
$stop['opacity'] = ord($col{3}) / 100;
} // transparency converted from rgba or cmyka()
if (isset($el[1]) && preg_match('/(\d+)[%]/', $el[1], $m)) {
$stop['offset'] = $m[1] / 100;
if ($stop['offset'] > 1) {
unset($stop['offset']);
}
} else if (isset($el[1]) && preg_match('/([0-9.]+(px|em|ex|pc|pt|cm|mm|in))/i', $el[1], $m)) {
$tmp = $this->mpdf->ConvertSize($m[1], $this->mpdf->w, $this->mpdf->FontSize, false);
$stop['offset'] = $el[1];
}
$g['stops'][] = $stop;
}
if (count($g['stops'])) {
return $g;
}
}
return array();
}
function parseBackgroundGradient($bg)
{
// background-gradient: linear #00FFFF #FFFF00 0 0.5 1 0.5; or
// background-gradient: radial #00FFFF #FFFF00 0.5 0.5 1 1 1.2;
$v = trim($bg);
$bgr = preg_split('/\s+/', $v);
$g = array();
if (count($bgr) > 6) {
if (strtoupper(substr($bgr[0], 0, 1)) == 'L' && count($bgr) == 7) { // linear
$g['type'] = 2;
//$coords = array(0,0,1,1 ); // 0 0 1 0 or 0 1 1 1 is L 2 R; 1,1,0,1 is R2L; 1,1,1,0 is T2B; 1,0,1,1 is B2T
// Linear: $coords - array of the form (x1, y1, x2, y2) which defines the gradient vector (see linear_gradient_coords.jpg).
// The default value is from left to right (x1=0, y1=0, x2=1, y2=0).
$g['coords'] = array($bgr[3], $bgr[4], $bgr[5], $bgr[6]);
} else if (count($bgr) == 8) { // radial
$g['type'] = 3;
// Radial: $coords - array of the form (fx, fy, cx, cy, r) where (fx, fy) is the starting point of the gradient with color1,
// (cx, cy) is the center of the circle with color2, and r is the radius of the circle (see radial_gradient_coords.jpg).
// (fx, fy) should be inside the circle, otherwise some areas will not be defined
$g['coords'] = array($bgr[3], $bgr[4], $bgr[5], $bgr[6], $bgr[7]);
}
$g['colorspace'] = 'RGB';
// mPDF 5.3.74
$cor = $this->mpdf->ConvertColor($bgr[1]);
if ($cor{0} == 1)
$g['colorspace'] = 'Gray';
else if ($cor{0} == 4 || $cor{0} == 6)
$g['colorspace'] = 'CMYK';
if ($cor) {
$g['col'] = $cor;
} else {
$g['col'] = $this->mpdf->ConvertColor(255);
}
$cor = $this->mpdf->ConvertColor($bgr[2]);
if ($cor) {
$g['col2'] = $cor;
} else {
$g['col2'] = $this->mpdf->ConvertColor(255);
}
$g['extend'] = array('true', 'true');
$g['stops'] = array(array('col' => $g['col'], 'opacity' => 1, 'offset' => 0), array('col' => $g['col2'], 'opacity' => 1, 'offset' => 1));
return $g;
}
return false;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,292 @@
<?php
class meter
{
function __construct()
{
}
function makeSVG($tag, $type, $value, $max, $min, $optimum, $low, $high)
{
$svg = '';
if ($tag == 'meter') {
if ($type == '2') {
/////////////////////////////////////////////////////////////////////////////////////
///////// CUSTOM <meter type="2">
/////////////////////////////////////////////////////////////////////////////////////
$h = 10;
$w = 160;
$border_radius = 0.143; // Factor of Height
$svg = '<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="' . $w . 'px" height="' . $h . 'px" viewBox="0 0 ' . $w . ' ' . $h . '" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" ><g>
<defs>
<linearGradient id="GrGRAY" x1="0" y1="0" x2="0" y2="1" gradientUnits="boundingBox">
<stop offset="0%" stop-color="rgb(222, 222, 222)" />
<stop offset="20%" stop-color="rgb(232, 232, 232)" />
<stop offset="25%" stop-color="rgb(232, 232, 232)" />
<stop offset="100%" stop-color="rgb(182, 182, 182)" />
</linearGradient>
</defs>
';
$svg .= '<rect x="0" y="0" width="' . $w . '" height="' . $h . '" fill="#f4f4f4" stroke="none" />';
// LOW to HIGH region
//if ($low && $high && ($low != $min || $high != $max)) {
if ($low && $high) {
$barx = (($low - $min) / ($max - $min) ) * $w;
$barw = (($high - $low) / ($max - $min) ) * $w;
$svg .= '<rect x="' . $barx . '" y="0" width="' . $barw . '" height="' . $h . '" fill="url(#GrGRAY)" stroke="#888888" stroke-width="0.5px" />';
}
// OPTIMUM Marker (? AVERAGE)
if ($optimum) {
$barx = (($optimum - $min) / ($max - $min) ) * $w;
$barw = $h / 2;
$barcol = '#888888';
$svg .= '<rect x="' . $barx . '" y="0" rx="' . ($h * $border_radius) . 'px" ry="' . ($h * $border_radius) . 'px" width="' . $barw . '" height="' . $h . '" fill="' . $barcol . '" stroke="none" />';
}
// VALUE Marker
if ($value) {
if ($min != $low && $value < $low) {
$col = 'orange';
} else if ($max != $high && $value > $high) {
$col = 'orange';
} else {
$col = '#008800';
}
$cx = (($value - $min) / ($max - $min) ) * $w;
$cy = $h / 2;
$rx = $h / 3.5;
$ry = $h / 2.2;
$svg .= '<ellipse fill="' . $col . '" stroke="#000000" stroke-width="0.5px" cx="' . $cx . '" cy="' . $cy . '" rx="' . $rx . '" ry="' . $ry . '"/>';
}
// BoRDER
$svg .= '<rect x="0" y="0" width="' . $w . '" height="' . $h . '" fill="none" stroke="#888888" stroke-width="0.5px" />';
$svg .= '</g></svg>';
} else if ($type == '3') {
/////////////////////////////////////////////////////////////////////////////////////
///////// CUSTOM <meter type="2">
/////////////////////////////////////////////////////////////////////////////////////
$h = 10;
$w = 100;
$border_radius = 0.143; // Factor of Height
$svg = '<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="' . $w . 'px" height="' . $h . 'px" viewBox="0 0 ' . $w . ' ' . $h . '" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" ><g>
<defs>
<linearGradient id="GrGRAY" x1="0" y1="0" x2="0" y2="1" gradientUnits="boundingBox">
<stop offset="0%" stop-color="rgb(222, 222, 222)" />
<stop offset="20%" stop-color="rgb(232, 232, 232)" />
<stop offset="25%" stop-color="rgb(232, 232, 232)" />
<stop offset="100%" stop-color="rgb(182, 182, 182)" />
</linearGradient>
</defs>
';
$svg .= '<rect x="0" y="0" width="' . $w . '" height="' . $h . '" fill="#f4f4f4" stroke="none" />';
// LOW to HIGH region
if ($low && $high && ($low != $min || $high != $max)) {
//if ($low && $high) {
$barx = (($low - $min) / ($max - $min) ) * $w;
$barw = (($high - $low) / ($max - $min) ) * $w;
$svg .= '<rect x="' . $barx . '" y="0" width="' . $barw . '" height="' . $h . '" fill="url(#GrGRAY)" stroke="#888888" stroke-width="0.5px" />';
}
// OPTIMUM Marker (? AVERAGE)
if ($optimum) {
$barx = (($optimum - $min) / ($max - $min) ) * $w;
$barw = $h / 2;
$barcol = '#888888';
$svg .= '<rect x="' . $barx . '" y="0" rx="' . ($h * $border_radius) . 'px" ry="' . ($h * $border_radius) . 'px" width="' . $barw . '" height="' . $h . '" fill="' . $barcol . '" stroke="none" />';
}
// VALUE Marker
if ($value) {
if ($min != $low && $value < $low) {
$col = 'orange';
} else if ($max != $high && $value > $high) {
$col = 'orange';
} else {
$col = 'orange';
}
$cx = (($value - $min) / ($max - $min) ) * $w;
$cy = $h / 2;
$rx = $h / 2.2;
$ry = $h / 2.2;
$svg .= '<ellipse fill="' . $col . '" stroke="#000000" stroke-width="0.5px" cx="' . $cx . '" cy="' . $cy . '" rx="' . $rx . '" ry="' . $ry . '"/>';
}
// BoRDER
$svg .= '<rect x="0" y="0" width="' . $w . '" height="' . $h . '" fill="none" stroke="#888888" stroke-width="0.5px" />';
$svg .= '</g></svg>';
} else {
/////////////////////////////////////////////////////////////////////////////////////
///////// DEFAULT <meter>
/////////////////////////////////////////////////////////////////////////////////////
$h = 10;
$w = 50;
$border_radius = 0.143; // Factor of Height
$svg = '<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="' . $w . 'px" height="' . $h . 'px" viewBox="0 0 ' . $w . ' ' . $h . '" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" ><g>
<defs>
<linearGradient id="GrGRAY" x1="0" y1="0" x2="0" y2="1" gradientUnits="boundingBox">
<stop offset="0%" stop-color="rgb(222, 222, 222)" />
<stop offset="20%" stop-color="rgb(232, 232, 232)" />
<stop offset="25%" stop-color="rgb(232, 232, 232)" />
<stop offset="100%" stop-color="rgb(182, 182, 182)" />
</linearGradient>
<linearGradient id="GrRED" x1="0" y1="0" x2="0" y2="1" gradientUnits="boundingBox">
<stop offset="0%" stop-color="rgb(255, 162, 162)" />
<stop offset="20%" stop-color="rgb(255, 218, 218)" />
<stop offset="25%" stop-color="rgb(255, 218, 218)" />
<stop offset="100%" stop-color="rgb(255, 0, 0)" />
</linearGradient>
<linearGradient id="GrGREEN" x1="0" y1="0" x2="0" y2="1" gradientUnits="boundingBox">
<stop offset="0%" stop-color="rgb(102, 230, 102)" />
<stop offset="20%" stop-color="rgb(218, 255, 218)" />
<stop offset="25%" stop-color="rgb(218, 255, 218)" />
<stop offset="100%" stop-color="rgb(0, 148, 0)" />
</linearGradient>
<linearGradient id="GrBLUE" x1="0" y1="0" x2="0" y2="1" gradientUnits="boundingBox">
<stop offset="0%" stop-color="rgb(102, 102, 230)" />
<stop offset="20%" stop-color="rgb(238, 238, 238)" />
<stop offset="25%" stop-color="rgb(238, 238, 238)" />
<stop offset="100%" stop-color="rgb(0, 0, 128)" />
</linearGradient>
<linearGradient id="GrORANGE" x1="0" y1="0" x2="0" y2="1" gradientUnits="boundingBox">
<stop offset="0%" stop-color="rgb(255, 186, 0)" />
<stop offset="20%" stop-color="rgb(255, 238, 168)" />
<stop offset="25%" stop-color="rgb(255, 238, 168)" />
<stop offset="100%" stop-color="rgb(255, 155, 0)" />
</linearGradient>
</defs>
<rect x="0" y="0" rx="' . ($h * $border_radius) . 'px" ry="' . ($h * $border_radius) . 'px" width="' . $w . '" height="' . $h . '" fill="url(#GrGRAY)" stroke="none" />
';
if ($value) {
$barw = (($value - $min) / ($max - $min) ) * $w;
if ($optimum < $low) {
if ($value < $low) {
$barcol = 'url(#GrGREEN)';
} else if ($value > $high) {
$barcol = 'url(#GrRED)';
} else {
$barcol = 'url(#GrORANGE)';
}
} else if ($optimum > $high) {
if ($value < $low) {
$barcol = 'url(#GrRED)';
} else if ($value > $high) {
$barcol = 'url(#GrGREEN)';
} else {
$barcol = 'url(#GrORANGE)';
}
} else {
if ($value < $low) {
$barcol = 'url(#GrORANGE)';
} else if ($value > $high) {
$barcol = 'url(#GrORANGE)';
} else {
$barcol = 'url(#GrGREEN)';
}
}
$svg .= '<rect x="0" y="0" rx="' . ($h * $border_radius) . 'px" ry="' . ($h * $border_radius) . 'px" width="' . $barw . '" height="' . $h . '" fill="' . $barcol . '" stroke="none" />';
}
// Borders
//$svg .= '<rect x="0" y="0" rx="'.($h*$border_radius).'px" ry="'.($h*$border_radius).'px" width="'.$w.'" height="'.$h.'" fill="none" stroke="#888888" stroke-width="0.5px" />';
if ($value) {
// $svg .= '<rect x="0" y="0" rx="'.($h*$border_radius).'px" ry="'.($h*$border_radius).'px" width="'.$barw.'" height="'.$h.'" fill="none" stroke="#888888" stroke-width="0.5px" />';
}
$svg .= '</g></svg>';
}
} else { // $tag == 'progress'
if ($type == '2') {
/////////////////////////////////////////////////////////////////////////////////////
///////// CUSTOM <progress type="2">
/////////////////////////////////////////////////////////////////////////////////////
} else {
/////////////////////////////////////////////////////////////////////////////////////
///////// DEFAULT <progress>
/////////////////////////////////////////////////////////////////////////////////////
$h = 10;
$w = 100;
$border_radius = 0.143; // Factor of Height
if ($value or $value === '0') {
$fill = 'url(#GrGRAY)';
} else {
$fill = '#f8f8f8';
}
$svg = '<svg width="' . $w . 'px" height="' . $h . 'px" viewBox="0 0 ' . $w . ' ' . $h . '"><g>
<defs>
<linearGradient id="GrGRAY" x1="0" y1="0" x2="0" y2="1" gradientUnits="boundingBox">
<stop offset="0%" stop-color="rgb(222, 222, 222)" />
<stop offset="20%" stop-color="rgb(232, 232, 232)" />
<stop offset="25%" stop-color="rgb(232, 232, 232)" />
<stop offset="100%" stop-color="rgb(182, 182, 182)" />
</linearGradient>
<linearGradient id="GrGREEN" x1="0" y1="0" x2="0" y2="1" gradientUnits="boundingBox">
<stop offset="0%" stop-color="rgb(102, 230, 102)" />
<stop offset="20%" stop-color="rgb(218, 255, 218)" />
<stop offset="25%" stop-color="rgb(218, 255, 218)" />
<stop offset="100%" stop-color="rgb(0, 148, 0)" />
</linearGradient>
</defs>
<rect x="0" y="0" rx="' . ($h * $border_radius) . 'px" ry="' . ($h * $border_radius) . 'px" width="' . $w . '" height="' . $h . '" fill="' . $fill . '" stroke="none" />
';
if ($value) {
$barw = (($value - $min) / ($max - $min) ) * $w;
$barcol = 'url(#GrGREEN)';
$svg .= '<rect x="0" y="0" rx="' . ($h * $border_radius) . 'px" ry="' . ($h * $border_radius) . 'px" width="' . $barw . '" height="' . $h . '" fill="' . $barcol . '" stroke="none" />';
}
// Borders
$svg .= '<rect x="0" y="0" rx="' . ($h * $border_radius) . 'px" ry="' . ($h * $border_radius) . 'px" width="' . $w . '" height="' . $h . '" fill="none" stroke="#888888" stroke-width="0.5px" />';
if ($value) {
// $svg .= '<rect x="0" y="0" rx="'.($h*$border_radius).'px" ry="'.($h*$border_radius).'px" width="'.$barw.'" height="'.$h.'" fill="none" stroke="#888888" stroke-width="0.5px" />';
}
$svg .= '</g></svg>';
}
}
return $svg;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,484 @@
<?php
class MYANMAR
{
/* FROM hb-ot-shape-complex-indic-private.hh */
// indic_category
const OT_X = 0;
const OT_C = 1;
const OT_V = 2;
const OT_N = 3;
const OT_H = 4;
const OT_ZWNJ = 5;
const OT_ZWJ = 6;
const OT_M = 7; /* Matra or Dependent Vowel */
const OT_SM = 8;
const OT_VD = 9;
const OT_A = 10;
const OT_NBSP = 11;
const OT_DOTTEDCIRCLE = 12; /* Not in the spec, but special in Uniscribe. /Very very/ special! */
const OT_RS = 13; /* Register Shifter, used in Khmer OT spec */
const OT_Coeng = 14;
const OT_Repha = 15;
const OT_Ra = 16; /* Not explicitly listed in the OT spec, but used in the grammar. */
const OT_CM = 17;
/* FROM hb-ot-shape-complex-myanmar.hh */
// myanmar_category
const OT_DB = 3; // same as INDIC::OT_N; /* Dot below */
const OT_GB = 12; // same as INDIC::OT_DOTTEDCIRCLE;
const OT_As = 18; /* Asat */
const OT_D = 19; /* Digits except zero */
const OT_D0 = 20; /* Digit zero */
const OT_MH = 21; /* Various consonant medial types */
const OT_MR = 22; /* Various consonant medial types */
const OT_MW = 23; /* Various consonant medial types */
const OT_MY = 24; /* Various consonant medial types */
const OT_PT = 25; /* Pwo and other tones */
const OT_VAbv = 26;
const OT_VBlw = 27;
const OT_VPre = 28;
const OT_VPst = 29;
const OT_VS = 30; /* Variation selectors */
// Based on myanmar_category used to make string to find syllables
// OT_ to string character (using e.g. OT_C from MYANMAR) hb-ot-shape-complex-myanmar-private.hh
public static $myanmar_category_char = array(
'x',
'C',
'V',
'N',
'H',
'Z',
'J',
'x',
'S',
'x',
'A',
'x',
'D',
'x',
'x',
'x',
'R',
'x',
'a', /* As Asat */
'd', /* Digits except zero */
'o', /* Digit zero */
'k', /* Medial types */
'l', /* Medial types */
'm', /* Medial types */
'n', /* Medial types */
'p', /* Pwo and other tones */
'v', /* Vowel aboVe */
'b', /* Vowel Below */
'e', /* Vowel prE */
't', /* Vowel posT */
's', /* variation Selector */
);
/* Visual positions in a syllable from left to right. */
/* FROM hb-ot-shape-complex-myanmar-private.hh */
// myanmar_position
const POS_START = 0;
const POS_RA_TO_BECOME_REPH = 1;
const POS_PRE_M = 2;
const POS_PRE_C = 3;
const POS_BASE_C = 4;
const POS_AFTER_MAIN = 5;
const POS_ABOVE_C = 6;
const POS_BEFORE_SUB = 7;
const POS_BELOW_C = 8;
const POS_AFTER_SUB = 9;
const POS_BEFORE_POST = 10;
const POS_POST_C = 11;
const POS_AFTER_POST = 12;
const POS_FINAL_C = 13;
const POS_SMVD = 14;
const POS_END = 15;
public static function set_myanmar_properties(&$info)
{
$u = $info['uni'];
$type = self::myanmar_get_categories($u);
$cat = ($type & 0x7F);
$pos = ($type >> 8);
/*
* Re-assign category
* http://www.microsoft.com/typography/OpenTypeDev/myanmar/intro.htm#analyze
*/
if (self::in_range($u, 0xFE00, 0xFE0F))
$cat = self::OT_VS;
else if ($u == 0x200C)
$cat = self::OT_ZWNJ;
else if ($u == 0x200D)
$cat = self::OT_ZWJ;
switch ($u) {
case 0x002D: case 0x00A0: case 0x00D7: case 0x2012:
case 0x2013: case 0x2014: case 0x2015: case 0x2022:
case 0x25CC: case 0x25FB: case 0x25FC: case 0x25FD:
case 0x25FE:
$cat = self::OT_GB;
break;
case 0x1004: case 0x101B: case 0x105A:
$cat = self::OT_Ra;
break;
case 0x1032: case 0x1036:
$cat = self::OT_A;
break;
case 0x103A:
$cat = self::OT_As;
break;
case 0x1041: case 0x1042: case 0x1043: case 0x1044:
case 0x1045: case 0x1046: case 0x1047: case 0x1048:
case 0x1049: case 0x1090: case 0x1091: case 0x1092:
case 0x1093: case 0x1094: case 0x1095: case 0x1096:
case 0x1097: case 0x1098: case 0x1099:
$cat = self::OT_D;
break;
case 0x1040:
$cat = self::OT_D; /* XXX The spec says D0, but Uniscribe doesn't seem to do. */
break;
case 0x103E: case 0x1060:
$cat = self::OT_MH;
break;
case 0x103C:
$cat = self::OT_MR;
break;
case 0x103D: case 0x1082:
$cat = self::OT_MW;
break;
case 0x103B: case 0x105E: case 0x105F:
$cat = self::OT_MY;
break;
case 0x1063: case 0x1064: case 0x1069: case 0x106A:
case 0x106B: case 0x106C: case 0x106D: case 0xAA7B:
$cat = self::OT_PT;
break;
case 0x1038: case 0x1087: case 0x1088: case 0x1089:
case 0x108A: case 0x108B: case 0x108C: case 0x108D:
case 0x108F: case 0x109A: case 0x109B: case 0x109C:
$cat = self::OT_SM;
break;
}
if ($cat == self::OT_M) {
switch ($pos) {
case self::POS_PRE_C:
$cat = self::OT_VPre;
$pos = self::POS_PRE_M;
break;
case self::POS_ABOVE_C: $cat = self::OT_VAbv;
break;
case self::POS_BELOW_C: $cat = self::OT_VBlw;
break;
case self::POS_POST_C: $cat = self::OT_VPst;
break;
}
}
$info['myanmar_category'] = $cat;
$info['myanmar_position'] = $pos;
}
// syllable_type
const CONSONANT_SYLLABLE = 0;
const BROKEN_CLUSTER = 3;
const NON_MYANMAR_CLUSTER = 4;
public static function set_syllables(&$o, $s, &$broken_syllables)
{
$ptr = 0;
$syllable_serial = 1;
$broken_syllables = false;
while ($ptr < strlen($s)) {
$match = '';
$syllable_length = 1;
$syllable_type = self::NON_MYANMAR_CLUSTER;
// CONSONANT_SYLLABLE Consonant syllable
// From OT spec:
if (preg_match('/^(RaH)?([C|R]|V|d|D)[s]?(H([C|R|V])[s]?)*(H|[a]*[n]?[l]?((m[k]?|k)[a]?)?[e]*[v]*[b]*[A]*(N[a]?)?(t[k]?[a]*[v]*[A]*(N[a]?)?)*(p[A]*(N[a]?)?)*S*[J|Z]?)/', substr($s, $ptr), $ma)) {
$syllable_length = strlen($ma[0]);
$syllable_type = self::CONSONANT_SYLLABLE;
}
// BROKEN_CLUSTER syllable
else if (preg_match('/^(RaH)?s?(H|[a]*[n]?[l]?((m[k]?|k)[a]?)?[e]*[v]*[b]*[A]*(N[a]?)?(t[k]?[a]*[v]*[A]*(N[a]?)?)*(p[A]*(N[a]?)?)*S*[J|Z]?)/', substr($s, $ptr), $ma)) {
if (strlen($ma[0])) { // May match blank
$syllable_length = strlen($ma[0]);
$syllable_type = self::BROKEN_CLUSTER;
$broken_syllables = true;
}
}
for ($i = $ptr; $i < $ptr + $syllable_length; $i++) {
$o[$i]['syllable'] = ($syllable_serial << 4) | $syllable_type;
}
$ptr += $syllable_length;
$syllable_serial++;
if ($syllable_serial == 16)
$syllable_serial = 1;
}
}
public static function reordering(&$info, $GSUBdata, $broken_syllables, $dottedcircle)
{
if ($broken_syllables && $dottedcircle) {
self::insert_dotted_circles($info, $dottedcircle);
}
$count = count($info);
if (!$count)
return;
$last = 0;
$last_syllable = $info[0]['syllable'];
for ($i = 1; $i < $count; $i++) {
if ($last_syllable != $info[$i]['syllable']) {
self::reordering_syllable($info, $GSUBdata, $last, $i);
$last = $i;
$last_syllable = $info[$last]['syllable'];
}
}
self::reordering_syllable($info, $GSUBdata, $last, $count);
}
public static function insert_dotted_circles(&$info, $dottedcircle)
{
$idx = 0;
$last_syllable = 0;
while ($idx < count($info)) {
$syllable = $info[$idx]['syllable'];
$syllable_type = ($syllable & 0x0F);
if ($last_syllable != $syllable && $syllable_type == self::BROKEN_CLUSTER) {
$last_syllable = $syllable;
$dottedcircle[0]['syllable'] = $info[$idx]['syllable'];
array_splice($info, $idx, 0, $dottedcircle);
} else
$idx++;
}
// In case of final bloken cluster...
$syllable = $info[$idx]['syllable'];
$syllable_type = ($syllable & 0x0F);
if ($last_syllable != $syllable && $syllable_type == self::BROKEN_CLUSTER) {
$dottedcircle[0]['syllable'] = $info[$idx]['syllable'];
array_splice($info, $idx, 0, $dottedcircle);
}
}
/* Rules from:
* https://www.microsoft.com/typography/otfntdev/devanot/shaping.aspx */
public static function reordering_syllable(&$info, $GSUBdata, $start, $end)
{
/* vowel_syllable: We made the vowels look like consonants. So uses the consonant logic! */
/* broken_cluster: We already inserted dotted-circles, so just call the standalone_cluster. */
$syllable_type = ($info[$start]['syllable'] & 0x0F);
if ($syllable_type == self::NON_MYANMAR_CLUSTER) {
return;
}
if ($syllable_type == self::BROKEN_CLUSTER) {
//if ($uniscribe_bug_compatible) {
/* For dotted-circle, this is what Uniscribe does:
* If dotted-circle is the last glyph, it just does nothing.
* i.e. It doesn't form Reph. */
if ($info[$end - 1]['myanmar_category'] == self::OT_DOTTEDCIRCLE) {
return;
}
}
$base = $end;
$has_reph = false;
$limit = $start;
if (($start + 3 <= $end) &&
$info[$start]['myanmar_category'] == self::OT_Ra &&
$info[$start + 1]['myanmar_category'] == self::OT_As &&
$info[$start + 2]['myanmar_category'] == self::OT_H) {
$limit += 3;
$base = $start;
$has_reph = true;
}
if (!$has_reph)
$base = $limit;
for ($i = $limit; $i < $end; $i++) {
if (self::is_consonant($info[$i])) {
$base = $i;
break;
}
}
/* Reorder! */
$i = $start;
for (; $i < $start + ($has_reph ? 3 : 0); $i++)
$info[$i]['myanmar_position'] = self::POS_AFTER_MAIN;
for (; $i < $base; $i++)
$info[$i]['myanmar_position'] = self::POS_PRE_C;
if ($i < $end) {
$info[$i]['myanmar_position'] = self::POS_BASE_C;
$i++;
}
$pos = self::POS_AFTER_MAIN;
/* The following loop may be ugly, but it implements all of
* Myanmar reordering! */
for (; $i < $end; $i++) {
if ($info[$i]['myanmar_category'] == self::OT_MR) /* Pre-base reordering */ {
$info[$i]['myanmar_position'] = self::POS_PRE_C;
continue;
}
if ($info[$i]['myanmar_position'] < self::POS_BASE_C) /* Left matra */ {
continue;
}
if ($pos == self::POS_AFTER_MAIN && $info[$i]['myanmar_category'] == self::OT_VBlw) {
$pos = self::POS_BELOW_C;
$info[$i]['myanmar_position'] = $pos;
continue;
}
if ($pos == self::POS_BELOW_C && $info[$i]['myanmar_category'] == self::OT_A) {
$info[$i]['myanmar_position'] = self::POS_BEFORE_SUB;
continue;
}
if ($pos == self::POS_BELOW_C && $info[$i]['myanmar_category'] == self::OT_VBlw) {
$info[$i]['myanmar_position'] = $pos;
continue;
}
if ($pos == self::POS_BELOW_C && $info[$i]['myanmar_category'] != self::OT_A) {
$pos = self::POS_AFTER_SUB;
$info[$i]['myanmar_position'] = $pos;
continue;
}
$info[$i]['myanmar_position'] = $pos;
}
/* Sit tight, rock 'n roll! */
self::bubble_sort($info, $start, $end - $start);
}
public static function is_one_of($info, $flags)
{
if (isset($info['is_ligature']) && $info['is_ligature'])
return false; /* If it ligated, all bets are off. */
return !!(self::FLAG($info['myanmar_category']) & $flags);
}
/* Vowels and placeholders treated as if they were consonants. */
public static function is_consonant($info)
{
return self::is_one_of($info, (self::FLAG(self::OT_C) | self::FLAG(self::OT_CM) | self::FLAG(self::OT_Ra) | self::FLAG(self::OT_V) | self::FLAG(self::OT_NBSP) | self::FLAG(self::OT_GB)));
}
// From hb-private.hh
public static function in_range($u, $lo, $hi)
{
if ((($lo ^ $hi) & $lo) == 0 && (($lo ^ $hi) & $hi) == ($lo ^ $hi) && (($lo ^ $hi) & (($lo ^ $hi) + 1)) == 0)
return ($u & ~($lo ^ $hi)) == $lo;
else
return $lo <= $u && $u <= $hi;
}
// From hb-private.hh
public static function FLAG($x)
{
return (1 << ($x));
}
public static function FLAG_RANGE($x, $y)
{
self::FLAG(y + 1) - self::FLAG(x);
}
// BELOW from hb-ot-shape-complex-indic.cc
// see INDIC for details
public static $myanmar_table = array(
/* Myanmar (1000..109F) */
/* 1000 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
/* 1008 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
/* 1010 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
/* 1018 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
/* 1020 */ 3841, 3842, 3842, 3842, 3842, 3842, 3842, 3842,
/* 1028 */ 3842, 3842, 3842, 2823, 2823, 1543, 1543, 2055,
/* 1030 */ 2055, 775, 1543, 1543, 1543, 1543, 3848, 3843,
/* 1038 */ 3848, 3844, 1540, 3857, 3857, 3857, 3857, 3841,
/* 1040 */ 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840,
/* 1048 */ 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840,
/* 1050 */ 3841, 3841, 3842, 3842, 3842, 3842, 2823, 2823,
/* 1058 */ 2055, 2055, 3841, 3841, 3841, 3841, 3857, 3857,
/* 1060 */ 3857, 3841, 2823, 3843, 3843, 3841, 3841, 2823,
/* 1068 */ 2823, 3843, 3843, 3843, 3843, 3843, 3841, 3841,
/* 1070 */ 3841, 1543, 1543, 1543, 1543, 3841, 3841, 3841,
/* 1078 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
/* 1080 */ 3841, 3841, 3857, 2823, 775, 1543, 1543, 3843,
/* 1088 */ 3843, 3843, 3843, 3843, 3843, 3843, 3841, 3843,
/* 1090 */ 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840,
/* 1098 */ 3840, 3840, 3843, 3843, 2823, 1543, 3840, 3840,
/* Myanmar Extended-A (AA60..AA7F) */
/* AA60 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
/* AA68 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
/* AA70 */ 3840, 3841, 3841, 3841, 3840, 3840, 3840, 3840,
/* AA78 */ 3840, 3840, 3841, 3843, 3840, 3840, 3840, 3840,
);
// from "hb-ot-shape-complex-indic-table.cc"
public static function myanmar_get_categories($u)
{
if (0x1000 <= $u && $u <= 0x109F)
return self::$myanmar_table[$u - 0x1000 + 0]; // offset 0 for Most "myanmar"
if (0xAA60 <= $u && $u <= 0xAA7F)
return self::$myanmar_table[$u - 0xAA60 + 160]; // offset for extensions
if ($u == 0x00A0)
return 3851; // (ISC_CP | (IMC_x << 8))
if ($u == 0x25CC)
return 3851; // (ISC_CP | (IMC_x << 8))
return 3840; // (ISC_x | (IMC_x << 8))
}
public static function bubble_sort(&$arr, $start, $len)
{
if ($len < 2) {
return;
}
$k = $start + $len - 2;
while ($k >= $start) {
for ($j = $start; $j <= $k; $j++) {
if ($arr[$j]['myanmar_position'] > $arr[$j + 1]['myanmar_position']) {
$t = $arr[$j];
$arr[$j] = $arr[$j + 1];
$arr[$j + 1] = $t;
}
}
$k--;
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,383 @@
<?php
class SEA
{
// South East Asian shaper
// sea_category
const OT_X = 0;
const OT_C = 1;
const OT_IV = 2; # Independent Vowel
const OT_T = 3; # Tone Marks
const OT_H = 4; # Halant
const OT_A = 10; # Anusvara
const OT_GB = 12; # Generic Base (OT_DOTTEDCIRCLE in Indic)
const OT_CM = 17; # Consonant Medial
const OT_MR = 22; # Medial Ra
const OT_VAbv = 26;
const OT_VBlw = 27;
const OT_VPre = 28;
const OT_VPst = 29;
// ? From Indic categories
const OT_ZWNJ = 5;
const OT_ZWJ = 6;
const OT_M = 7;
const OT_SM = 8;
const OT_VD = 9;
const OT_NBSP = 11;
const OT_RS = 13;
const OT_Coeng = 14;
const OT_Repha = 15;
const OT_Ra = 16;
// Based on sea_category used to make string to find syllables
// OT_ to string character (using e.g. OT_C from INDIC) hb-ot-shape-complex-sea-private.hh
public static $sea_category_char = array(
'x',
'C',
'V',
'T',
'H',
'x',
'x',
'x',
'x',
'x',
'A',
'x',
'G',
'x',
'x',
'x',
'x',
'M',
'x',
'x',
'x',
'x',
'R',
'x',
'x',
'x',
'a',
'b',
'p',
't',
);
/* Visual positions in a syllable from left to right. */
// sea_position
const POS_START = 0;
const POS_RA_TO_BECOME_REPH = 1;
const POS_PRE_M = 2;
const POS_PRE_C = 3;
const POS_BASE_C = 4;
const POS_AFTER_MAIN = 5;
const POS_ABOVE_C = 6;
const POS_BEFORE_SUB = 7;
const POS_BELOW_C = 8;
const POS_AFTER_SUB = 9;
const POS_BEFORE_POST = 10;
const POS_POST_C = 11;
const POS_AFTER_POST = 12;
const POS_FINAL_C = 13;
const POS_SMVD = 14;
const POS_END = 15;
public static function set_sea_properties(&$info, $scriptblock)
{
$u = $info['uni'];
$type = self::sea_get_categories($u);
$cat = ($type & 0x7F);
$pos = ($type >> 8);
/*
* Re-assign category
*/
// Medial Ra
if ($u == 0x1A55 || $u == 0xAA34) {
$cat = self::OT_MR;
}
/*
* Re-assign position.
*/
if ($cat == self::OT_M) { // definitely "OT_M" in HarfBuzz - although this does not seem to have been defined ? should be OT_MR
switch ($pos) {
case self::POS_PRE_C: $cat = self::OT_VPre;
break;
case self::POS_ABOVE_C: $cat = self::OT_VAbv;
break;
case self::POS_BELOW_C: $cat = self::OT_VBlw;
break;
case self::POS_POST_C: $cat = self::OT_VPst;
break;
}
}
$info['sea_category'] = $cat;
$info['sea_position'] = $pos;
}
// syllable_type
const CONSONANT_SYLLABLE = 0;
const BROKEN_CLUSTER = 1;
const NON_SEA_CLUSTER = 2;
public static function set_syllables(&$o, $s, &$broken_syllables)
{
$ptr = 0;
$syllable_serial = 1;
$broken_syllables = false;
while ($ptr < strlen($s)) {
$match = '';
$syllable_length = 1;
$syllable_type = self::NON_SEA_CLUSTER;
// CONSONANT_SYLLABLE Consonant syllable
if (preg_match('/^(C|V|G)(p|a|b|t|HC|M|R|T|A)*/', substr($s, $ptr), $ma)) {
$syllable_length = strlen($ma[0]);
$syllable_type = self::CONSONANT_SYLLABLE;
}
// BROKEN_CLUSTER syllable
else if (preg_match('/^(p|a|b|t|HC|M|R|T|A)+/', substr($s, $ptr), $ma)) {
$syllable_length = strlen($ma[0]);
$syllable_type = self::BROKEN_CLUSTER;
$broken_syllables = true;
}
for ($i = $ptr; $i < $ptr + $syllable_length; $i++) {
$o[$i]['syllable'] = ($syllable_serial << 4) | $syllable_type;
}
$ptr += $syllable_length;
$syllable_serial++;
if ($syllable_serial == 16)
$syllable_serial = 1;
}
}
public static function initial_reordering(&$info, $GSUBdata, $broken_syllables, $scriptblock, $dottedcircle)
{
if ($broken_syllables && $dottedcircle) {
self::insert_dotted_circles($info, $dottedcircle);
}
$count = count($info);
if (!$count)
return;
$last = 0;
$last_syllable = $info[0]['syllable'];
for ($i = 1; $i < $count; $i++) {
if ($last_syllable != $info[$i]['syllable']) {
self::initial_reordering_syllable($info, $GSUBdata, $scriptblock, $last, $i);
$last = $i;
$last_syllable = $info[$last]['syllable'];
}
}
self::initial_reordering_syllable($info, $GSUBdata, $scriptblock, $last, $count);
}
public static function insert_dotted_circles(&$info, $dottedcircle)
{
$idx = 0;
$last_syllable = 0;
while ($idx < count($info)) {
$syllable = $info[$idx]['syllable'];
$syllable_type = ($syllable & 0x0F);
if ($last_syllable != $syllable && $syllable_type == self::BROKEN_CLUSTER) {
$last_syllable = $syllable;
$dottedcircle[0]['syllable'] = $info[$idx]['syllable'];
array_splice($info, $idx, 0, $dottedcircle);
} else
$idx++;
}
}
public static function initial_reordering_syllable(&$info, $GSUBdata, $scriptblock, $start, $end)
{
/* broken_cluster: We already inserted dotted-circles, so just call the standalone_cluster. */
$syllable_type = ($info[$start]['syllable'] & 0x0F);
if ($syllable_type == self::NON_SEA_CLUSTER) {
return;
}
if ($syllable_type == self::BROKEN_CLUSTER) {
/* For dotted-circle, this is what Uniscribe does:
* If dotted-circle is the last glyph, it just does nothing. */
if ($info[$end - 1]['sea_category'] == self::OT_GB) {
return;
}
}
$base = $start;
$i = $start;
for (; $i < $base; $i++)
$info[$i]['sea_position'] = self::POS_PRE_C;
if ($i < $end) {
$info[$i]['sea_position'] = self::POS_BASE_C;
$i++;
}
for (; $i < $end; $i++) {
if (isset($info[$i]['sea_category']) && $info[$i]['sea_category'] == self::OT_MR) { /* Pre-base reordering */
$info[$i]['sea_position'] = self::POS_PRE_C;
continue;
}
if (isset($info[$i]['sea_category']) && $info[$i]['sea_category'] == self::OT_VPre) { /* Left matra */
$info[$i]['sea_position'] = self::POS_PRE_M;
continue;
}
$info[$i]['sea_position'] = self::POS_AFTER_MAIN;
}
/* Sit tight, rock 'n roll! */
self::bubble_sort($info, $start, $end - $start);
}
public static function final_reordering(&$info, $GSUBdata, $scriptblock)
{
$count = count($info);
if (!$count)
return;
$last = 0;
$last_syllable = $info[0]['syllable'];
for ($i = 1; $i < $count; $i++) {
if ($last_syllable != $info[$i]['syllable']) {
self::final_reordering_syllable($info, $GSUBdata, $scriptblock, $last, $i);
$last = $i;
$last_syllable = $info[$last]['syllable'];
}
}
self::final_reordering_syllable($info, $GSUBdata, $scriptblock, $last, $count);
}
public static function final_reordering_syllable(&$info, $GSUBdata, $scriptblock, $start, $end)
{
/*
* Nothing to do here at present!
*/
}
public static $sea_table = array(
/* New Tai Lue (1980..19DF) */
/* 1980 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
/* 1988 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
/* 1990 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
/* 1998 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
/* 19A0 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
/* 19A8 */ 3841, 3841, 3841, 3841, 3840, 3840, 3840, 3840,
/* 19B0 */ 2823, 2823, 2823, 2823, 2823, 775, 775, 775,
/* 19B8 */ 2823, 2823, 775, 2823, 2823, 2823, 2823, 2823,
/* 19C0 */ 2823, 3857, 3857, 3857, 3857, 3857, 3857, 3857,
/* 19C8 */ 3843, 3843, 3840, 3840, 3840, 3840, 3840, 3840,
/* 19D0 */ 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840,
/* 19D8 */ 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840,
/* Tai Tham (1A20..1AAF) */
/* 1A20 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
/* 1A28 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
/* 1A30 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
/* 1A38 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
/* 1A40 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
/* 1A48 */ 3841, 3841, 3841, 3841, 3841, 3842, 3842, 3842,
/* 1A50 */ 3842, 3842, 3842, 3841, 3841, 3857, 3857, 3857,
/* 1A58 */ 3857, 3857, 3857, 3857, 3857, 3857, 3857, 3840,
/* 1A60 */ 3844, 2823, 1543, 2823, 2823, 1543, 1543, 1543,
/* 1A68 */ 1543, 2055, 2055, 1543, 2055, 2823, 775, 775,
/* 1A70 */ 775, 775, 775, 1543, 1543, 3843, 3843, 3843,
/* 1A78 */ 3843, 3843, 3840, 3840, 3840, 3840, 3840, 3840,
/* 1A80 */ 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840,
/* 1A88 */ 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840,
/* 1A90 */ 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840,
/* 1A98 */ 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840,
/* 1AA0 */ 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840,
/* 1AA8 */ 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840,
/* Cham (AA00..AA5F) */
/* AA00 */ 3842, 3842, 3842, 3842, 3842, 3842, 3841, 3841,
/* AA08 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
/* AA10 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
/* AA18 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
/* AA20 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
/* AA28 */ 3841, 1543, 1543, 1543, 1543, 2055, 1543, 775,
/* AA30 */ 775, 1543, 2055, 3857, 3857, 3857, 3857, 3840,
/* AA38 */ 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840,
/* AA40 */ 3857, 3857, 3857, 3857, 3857, 3857, 3857, 3857,
/* AA48 */ 3857, 3857, 3857, 3857, 3857, 3857, 3840, 3840,
/* AA50 */ 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840,
/* AA58 */ 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840,
);
public static function sea_get_categories($u)
{
if (0x1980 <= $u && $u <= 0x19DF)
return self::$sea_table[$u - 0x1980]; // offset 0 for New Tai Lue
if (0x1A20 <= $u && $u <= 0x1AAF)
return self::$sea_table[$u - 0x1A20 + 96]; // offset for Tai Tham
if (0xAA00 <= $u && $u <= 0xAA5F)
return self::$sea_table[$u - 0xAA00 + 96 + 144]; // Cham
if ($u == 0x00A0)
return 3851; // (ISC_CP | (IMC_x << 8))
if ($u == 0x25CC)
return 3851; // (ISC_CP | (IMC_x << 8))
return 3840; // (ISC_x | (IMC_x << 8))
}
public static function bubble_sort(&$arr, $start, $len)
{
if ($len < 2) {
return;
}
$k = $start + $len - 2;
while ($k >= $start) {
for ($j = $start; $j <= $k; $j++) {
if ($arr[$j]['sea_position'] > $arr[$j + 1]['sea_position']) {
$t = $arr[$j];
$arr[$j] = $arr[$j + 1];
$arr[$j + 1] = $t;
}
}
$k--;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,778 @@
<?php
class tocontents
{
var $mpdf = null;
var $_toc;
var $TOCmark;
var $TOCoutdent; // mPDF 5.6.31
var $TOCpreHTML;
var $TOCpostHTML;
var $TOCbookmarkText;
var $TOCusePaging;
var $TOCuseLinking;
var $TOCorientation;
var $TOC_margin_left;
var $TOC_margin_right;
var $TOC_margin_top;
var $TOC_margin_bottom;
var $TOC_margin_header;
var $TOC_margin_footer;
var $TOC_odd_header_name;
var $TOC_even_header_name;
var $TOC_odd_footer_name;
var $TOC_even_footer_name;
var $TOC_odd_header_value;
var $TOC_even_header_value;
var $TOC_odd_footer_value;
var $TOC_even_footer_value;
var $TOC_page_selector;
var $TOC_resetpagenum; // mPDF 6
var $TOC_pagenumstyle; // mPDF 6
var $TOC_suppress; // mPDF 6
var $m_TOC;
public function __construct(mPDF $mpdf)
{
$this->mpdf = $mpdf;
$this->_toc = array();
$this->TOCmark = 0;
$this->m_TOC = array();
}
function TOCpagebreak($tocfont = '', $tocfontsize = '', $tocindent = '', $TOCusePaging = true, $TOCuseLinking = '', $toc_orientation = '', $toc_mgl = '', $toc_mgr = '', $toc_mgt = '', $toc_mgb = '', $toc_mgh = '', $toc_mgf = '', $toc_ohname = '', $toc_ehname = '', $toc_ofname = '', $toc_efname = '', $toc_ohvalue = 0, $toc_ehvalue = 0, $toc_ofvalue = 0, $toc_efvalue = 0, $toc_preHTML = '', $toc_postHTML = '', $toc_bookmarkText = '', $resetpagenum = '', $pagenumstyle = '', $suppress = '', $orientation = '', $mgl = '', $mgr = '', $mgt = '', $mgb = '', $mgh = '', $mgf = '', $ohname = '', $ehname = '', $ofname = '', $efname = '', $ohvalue = 0, $ehvalue = 0, $ofvalue = 0, $efvalue = 0, $toc_id = 0, $pagesel = '', $toc_pagesel = '', $sheetsize = '', $toc_sheetsize = '', $tocoutdent = '', $toc_resetpagenum = '', $toc_pagenumstyle = '', $toc_suppress = '')
{ // mPDF 5.6.19 // mPDF 6
if (strtoupper($toc_id) == 'ALL') {
$toc_id = '_mpdf_all';
} else if (!$toc_id) {
$toc_id = 0;
} else {
$toc_id = strtolower($toc_id);
}
if ($TOCusePaging === false || strtolower($TOCusePaging) == "off" || $TOCusePaging === 0 || $TOCusePaging === "0" || $TOCusePaging === "") {
$TOCusePaging = false;
} else {
$TOCusePaging = true;
}
if (!$TOCuseLinking) {
$TOCuseLinking = false;
}
if ($toc_id) {
$this->m_TOC[$toc_id]['TOCmark'] = $this->mpdf->page;
$this->m_TOC[$toc_id]['TOCoutdent'] = $tocoutdent;
$this->m_TOC[$toc_id]['TOCorientation'] = $toc_orientation;
$this->m_TOC[$toc_id]['TOCuseLinking'] = $TOCuseLinking;
$this->m_TOC[$toc_id]['TOCusePaging'] = $TOCusePaging;
if ($toc_preHTML) {
$this->m_TOC[$toc_id]['TOCpreHTML'] = $toc_preHTML;
}
if ($toc_postHTML) {
$this->m_TOC[$toc_id]['TOCpostHTML'] = $toc_postHTML;
}
if ($toc_bookmarkText) {
$this->m_TOC[$toc_id]['TOCbookmarkText'] = $toc_bookmarkText;
}
$this->m_TOC[$toc_id]['TOC_margin_left'] = $toc_mgl;
$this->m_TOC[$toc_id]['TOC_margin_right'] = $toc_mgr;
$this->m_TOC[$toc_id]['TOC_margin_top'] = $toc_mgt;
$this->m_TOC[$toc_id]['TOC_margin_bottom'] = $toc_mgb;
$this->m_TOC[$toc_id]['TOC_margin_header'] = $toc_mgh;
$this->m_TOC[$toc_id]['TOC_margin_footer'] = $toc_mgf;
$this->m_TOC[$toc_id]['TOC_odd_header_name'] = $toc_ohname;
$this->m_TOC[$toc_id]['TOC_even_header_name'] = $toc_ehname;
$this->m_TOC[$toc_id]['TOC_odd_footer_name'] = $toc_ofname;
$this->m_TOC[$toc_id]['TOC_even_footer_name'] = $toc_efname;
$this->m_TOC[$toc_id]['TOC_odd_header_value'] = $toc_ohvalue;
$this->m_TOC[$toc_id]['TOC_even_header_value'] = $toc_ehvalue;
$this->m_TOC[$toc_id]['TOC_odd_footer_value'] = $toc_ofvalue;
$this->m_TOC[$toc_id]['TOC_even_footer_value'] = $toc_efvalue;
$this->m_TOC[$toc_id]['TOC_page_selector'] = $toc_pagesel;
$this->m_TOC[$toc_id]['TOC_resetpagenum'] = $toc_resetpagenum; // mPDF 6
$this->m_TOC[$toc_id]['TOC_pagenumstyle'] = $toc_pagenumstyle; // mPDF 6
$this->m_TOC[$toc_id]['TOC_suppress'] = $toc_suppress; // mPDF 6
$this->m_TOC[$toc_id]['TOCsheetsize'] = $toc_sheetsize;
} else {
$this->TOCmark = $this->mpdf->page;
$this->TOCoutdent = $tocoutdent;
$this->TOCorientation = $toc_orientation;
$this->TOCuseLinking = $TOCuseLinking;
$this->TOCusePaging = $TOCusePaging;
if ($toc_preHTML) {
$this->TOCpreHTML = $toc_preHTML;
}
if ($toc_postHTML) {
$this->TOCpostHTML = $toc_postHTML;
}
if ($toc_bookmarkText) {
$this->TOCbookmarkText = $toc_bookmarkText;
}
$this->TOC_margin_left = $toc_mgl;
$this->TOC_margin_right = $toc_mgr;
$this->TOC_margin_top = $toc_mgt;
$this->TOC_margin_bottom = $toc_mgb;
$this->TOC_margin_header = $toc_mgh;
$this->TOC_margin_footer = $toc_mgf;
$this->TOC_odd_header_name = $toc_ohname;
$this->TOC_even_header_name = $toc_ehname;
$this->TOC_odd_footer_name = $toc_ofname;
$this->TOC_even_footer_name = $toc_efname;
$this->TOC_odd_header_value = $toc_ohvalue;
$this->TOC_even_header_value = $toc_ehvalue;
$this->TOC_odd_footer_value = $toc_ofvalue;
$this->TOC_even_footer_value = $toc_efvalue;
$this->TOC_page_selector = $toc_pagesel;
$this->TOC_resetpagenum = $toc_resetpagenum; // mPDF 6
$this->TOC_pagenumstyle = $toc_pagenumstyle; // mPDF 6
$this->TOC_suppress = $toc_suppress; // mPDF 6
$this->TOCsheetsize = $toc_sheetsize;
}
}
// Initiate, and Mark a place for the Table of Contents to be inserted
function TOC($tocfont = '', $tocfontsize = 0, $tocindent = 0, $resetpagenum = '', $pagenumstyle = '', $suppress = '', $toc_orientation = '', $TOCusePaging = true, $TOCuseLinking = false, $toc_id = 0, $tocoutdent = '', $toc_resetpagenum = '', $toc_pagenumstyle = '', $toc_suppress = '')
{ // mPDF 5.6.19 // mPDF 6
if (strtoupper($toc_id) == 'ALL') {
$toc_id = '_mpdf_all';
} else if (!$toc_id) {
$toc_id = 0;
} else {
$toc_id = strtolower($toc_id);
}
// To use odd and even pages
// Cannot start table of contents on an even page
if (($this->mpdf->mirrorMargins) && (($this->mpdf->page) % 2 == 0)) { // EVEN
if ($this->mpdf->ColActive) {
if (count($this->mpdf->columnbuffer)) {
$this->mpdf->printcolumnbuffer();
}
}
$this->mpdf->AddPage($this->mpdf->CurOrientation, '', $resetpagenum, $pagenumstyle, $suppress);
} else {
$this->mpdf->PageNumSubstitutions[] = array('from' => $this->mpdf->page, 'reset' => $resetpagenum, 'type' => $pagenumstyle, 'suppress' => $suppress);
}
if ($toc_id) {
$this->m_TOC[$toc_id]['TOCmark'] = $this->mpdf->page;
$this->m_TOC[$toc_id]['TOCoutdent'] = $tocoutdent;
$this->m_TOC[$toc_id]['TOCorientation'] = $toc_orientation;
$this->m_TOC[$toc_id]['TOCuseLinking'] = $TOCuseLinking;
$this->m_TOC[$toc_id]['TOCusePaging'] = $TOCusePaging;
$this->m_TOC[$toc_id]['TOC_resetpagenum'] = $toc_resetpagenum; // mPDF 6
$this->m_TOC[$toc_id]['TOC_pagenumstyle'] = $toc_pagenumstyle; // mPDF 6
$this->m_TOC[$toc_id]['TOC_suppress'] = $toc_suppress; // mPDF 6
} else {
$this->TOCmark = $this->mpdf->page;
$this->TOCoutdent = $tocoutdent;
$this->TOCorientation = $toc_orientation;
$this->TOCuseLinking = $TOCuseLinking;
$this->TOCusePaging = $TOCusePaging;
$this->TOC_resetpagenum = $toc_resetpagenum; // mPDF 6
$this->TOC_pagenumstyle = $toc_pagenumstyle; // mPDF 6
$this->TOC_suppress = $toc_suppress; // mPDF 6
}
}
function insertTOC()
{
$notocs = 0;
if ($this->TOCmark) {
$notocs = 1;
}
$notocs += count($this->m_TOC);
if ($notocs == 0) {
return;
}
if (count($this->m_TOC)) {
reset($this->m_TOC);
}
$added_toc_pages = 0;
if ($this->mpdf->ColActive) {
$this->mpdf->SetColumns(0);
}
if (($this->mpdf->mirrorMargins) && (($this->mpdf->page) % 2 == 1)) { // ODD
$this->mpdf->AddPage($this->mpdf->CurOrientation);
$extrapage = true;
} else {
$extrapage = false;
}
for ($toci = 0; $toci < $notocs; $toci++) {
if ($toci == 0 && $this->TOCmark) {
$toc_id = 0;
$toc_page = $this->TOCmark;
$tocoutdent = $this->TOCoutdent;
$toc_orientation = $this->TOCorientation;
$TOCuseLinking = $this->TOCuseLinking;
$TOCusePaging = $this->TOCusePaging;
$toc_preHTML = $this->TOCpreHTML;
$toc_postHTML = $this->TOCpostHTML;
$toc_bookmarkText = $this->TOCbookmarkText;
$toc_mgl = $this->TOC_margin_left;
$toc_mgr = $this->TOC_margin_right;
$toc_mgt = $this->TOC_margin_top;
$toc_mgb = $this->TOC_margin_bottom;
$toc_mgh = $this->TOC_margin_header;
$toc_mgf = $this->TOC_margin_footer;
$toc_ohname = $this->TOC_odd_header_name;
$toc_ehname = $this->TOC_even_header_name;
$toc_ofname = $this->TOC_odd_footer_name;
$toc_efname = $this->TOC_even_footer_name;
$toc_ohvalue = $this->TOC_odd_header_value;
$toc_ehvalue = $this->TOC_even_header_value;
$toc_ofvalue = $this->TOC_odd_footer_value;
$toc_efvalue = $this->TOC_even_footer_value;
$toc_page_selector = $this->TOC_page_selector;
$toc_resetpagenum = $this->TOC_resetpagenum; // mPDF 6
$toc_pagenumstyle = $this->TOC_pagenumstyle; // mPDF 6
$toc_suppress = $this->TOC_suppress; // mPDF 6
$toc_sheet_size = (isset($this->TOCsheetsize) ? $this->TOCsheetsize : '');
} else {
$arr = current($this->m_TOC);
$toc_id = key($this->m_TOC);
$toc_page = $this->m_TOC[$toc_id]['TOCmark'];
$tocoutdent = $this->m_TOC[$toc_id]['TOCoutdent'];
$toc_orientation = $this->m_TOC[$toc_id]['TOCorientation'];
$TOCuseLinking = $this->m_TOC[$toc_id]['TOCuseLinking'];
$TOCusePaging = $this->m_TOC[$toc_id]['TOCusePaging'];
if (isset($this->m_TOC[$toc_id]['TOCpreHTML'])) {
$toc_preHTML = $this->m_TOC[$toc_id]['TOCpreHTML'];
} else {
$toc_preHTML = '';
}
if (isset($this->m_TOC[$toc_id]['TOCpostHTML'])) {
$toc_postHTML = $this->m_TOC[$toc_id]['TOCpostHTML'];
} else {
$toc_postHTML = '';
}
if (isset($this->m_TOC[$toc_id]['TOCbookmarkText'])) {
$toc_bookmarkText = $this->m_TOC[$toc_id]['TOCbookmarkText'];
} else {
$toc_bookmarkText = '';
} // *BOOKMARKS*
$toc_mgl = $this->m_TOC[$toc_id]['TOC_margin_left'];
$toc_mgr = $this->m_TOC[$toc_id]['TOC_margin_right'];
$toc_mgt = $this->m_TOC[$toc_id]['TOC_margin_top'];
$toc_mgb = $this->m_TOC[$toc_id]['TOC_margin_bottom'];
$toc_mgh = $this->m_TOC[$toc_id]['TOC_margin_header'];
$toc_mgf = $this->m_TOC[$toc_id]['TOC_margin_footer'];
$toc_ohname = $this->m_TOC[$toc_id]['TOC_odd_header_name'];
$toc_ehname = $this->m_TOC[$toc_id]['TOC_even_header_name'];
$toc_ofname = $this->m_TOC[$toc_id]['TOC_odd_footer_name'];
$toc_efname = $this->m_TOC[$toc_id]['TOC_even_footer_name'];
$toc_ohvalue = $this->m_TOC[$toc_id]['TOC_odd_header_value'];
$toc_ehvalue = $this->m_TOC[$toc_id]['TOC_even_header_value'];
$toc_ofvalue = $this->m_TOC[$toc_id]['TOC_odd_footer_value'];
$toc_efvalue = $this->m_TOC[$toc_id]['TOC_even_footer_value'];
$toc_page_selector = $this->m_TOC[$toc_id]['TOC_page_selector'];
$toc_resetpagenum = $this->m_TOC[$toc_id]['TOC_resetpagenum']; // mPDF 6
$toc_pagenumstyle = $this->m_TOC[$toc_id]['TOC_pagenumstyle']; // mPDF 6
$toc_suppress = $this->m_TOC[$toc_id]['TOC_suppress']; // mPDF 6
$toc_sheet_size = (isset($this->m_TOC[$toc_id]['TOCsheetsize']) ? $this->m_TOC[$toc_id]['TOCsheetsize'] : '');
next($this->m_TOC);
}
// mPDF 5.6.31
if (!$toc_orientation) {
$toc_orientation = $this->mpdf->DefOrientation;
}
// mPDF 6 number style and suppress now picked up from section preceding ToC
list($tp_pagenumstyle, $tp_suppress, $tp_reset) = $this->mpdf->docPageSettings($toc_page - 1);
if ($toc_resetpagenum)
$tp_reset = $toc_resetpagenum; // mPDF 6
if ($toc_pagenumstyle)
$tp_pagenumstyle = $toc_pagenumstyle; // mPDF 6
if ($toc_suppress || $toc_suppress === '0')
$tp_suppress = $toc_suppress; // mPDF 6
$this->mpdf->AddPage($toc_orientation, '', $tp_reset, $tp_pagenumstyle, $tp_suppress, $toc_mgl, $toc_mgr, $toc_mgt, $toc_mgb, $toc_mgh, $toc_mgf, $toc_ohname, $toc_ehname, $toc_ofname, $toc_efname, $toc_ohvalue, $toc_ehvalue, $toc_ofvalue, $toc_efvalue, $toc_page_selector, $toc_sheet_size); // mPDF 6
$this->mpdf->writingToC = true; // mPDF 5.6.38
// mPDF 5.6.31
$tocstart = count($this->mpdf->pages);
if (isset($toc_preHTML) && $toc_preHTML) {
$this->mpdf->WriteHTML($toc_preHTML);
}
// mPDF 5.6.19
$html = '<div class="mpdf_toc" id="mpdf_toc_' . $toc_id . '">';
foreach ($this->_toc as $t) {
if ($t['toc_id'] === '_mpdf_all' || $t['toc_id'] === $toc_id) {
$html .= '<div class="mpdf_toc_level_' . $t['l'] . '">';
if ($TOCuseLinking) {
$html .= '<a class="mpdf_toc_a" href="#__mpdfinternallink_' . $t['link'] . '">';
}
$html .= '<span class="mpdf_toc_t_level_' . $t['l'] . '">' . $t['t'] . '</span>';
if ($TOCuseLinking) {
$html .= '</a>';
}
if (!$tocoutdent) {
$tocoutdent = '0';
}
if ($TOCusePaging) {
$html .= ' <dottab outdent="' . $tocoutdent . '" /> ';
if ($TOCuseLinking) {
$html .= '<a class="mpdf_toc_a" href="#__mpdfinternallink_' . $t['link'] . '">';
}
$html .= '<span class="mpdf_toc_p_level_' . $t['l'] . '">' . $this->mpdf->docPageNum($t['p']) . '</span>';
if ($TOCuseLinking) {
$html .= '</a>';
}
}
$html .= '</div>';
}
}
$html .= '</div>';
$this->mpdf->WriteHTML($html);
if (isset($toc_postHTML) && $toc_postHTML) {
$this->mpdf->WriteHTML($toc_postHTML);
}
$this->mpdf->writingToC = false; // mPDF 5.6.38
$this->mpdf->AddPage($toc_orientation, 'E');
$n_toc = $this->mpdf->page - $tocstart + 1;
if ($toci == 0 && $this->TOCmark) {
$TOC_start = $tocstart;
$TOC_end = $this->mpdf->page;
$TOC_npages = $n_toc;
} else {
$this->m_TOC[$toc_id]['start'] = $tocstart;
$this->m_TOC[$toc_id]['end'] = $this->mpdf->page;
$this->m_TOC[$toc_id]['npages'] = $n_toc;
}
}
$s = '';
$s .= $this->mpdf->PrintBodyBackgrounds();
$s .= $this->mpdf->PrintPageBackgrounds();
$this->mpdf->pages[$this->mpdf->page] = preg_replace('/(___BACKGROUND___PATTERNS' . $this->mpdf->uniqstr . ')/', "\n" . $s . "\n" . '\\1', $this->mpdf->pages[$this->mpdf->page]);
$this->mpdf->pageBackgrounds = array();
//Page footer
$this->mpdf->InFooter = true;
$this->mpdf->Footer();
$this->mpdf->InFooter = false;
// 2nd time through to move pages etc.
$added_toc_pages = 0;
if (count($this->m_TOC)) {
reset($this->m_TOC);
}
for ($toci = 0; $toci < $notocs; $toci++) {
if ($toci == 0 && $this->TOCmark) {
$toc_id = 0;
$toc_page = $this->TOCmark + $added_toc_pages;
$toc_orientation = $this->TOCorientation;
$TOCuseLinking = $this->TOCuseLinking;
$TOCusePaging = $this->TOCusePaging;
$toc_bookmarkText = $this->TOCbookmarkText; // *BOOKMARKS*
$tocstart = $TOC_start;
$tocend = $n = $TOC_end;
$n_toc = $TOC_npages;
} else {
$arr = current($this->m_TOC);
$toc_id = key($this->m_TOC);
$toc_page = $this->m_TOC[$toc_id]['TOCmark'] + $added_toc_pages;
$toc_orientation = $this->m_TOC[$toc_id]['TOCorientation'];
$TOCuseLinking = $this->m_TOC[$toc_id]['TOCuseLinking'];
$TOCusePaging = $this->m_TOC[$toc_id]['TOCusePaging'];
$toc_bookmarkText = $this->m_TOC[$toc_id]['TOCbookmarkText']; // *BOOKMARKS*
$tocstart = $this->m_TOC[$toc_id]['start'];
$tocend = $n = $this->m_TOC[$toc_id]['end'];
$n_toc = $this->m_TOC[$toc_id]['npages'];
next($this->m_TOC);
}
// Now pages moved
$added_toc_pages += $n_toc;
$this->mpdf->MovePages($toc_page, $tocstart, $tocend);
$this->mpdf->pgsIns[$toc_page] = $tocend - $tocstart + 1;
/* -- BOOKMARKS -- */
// Insert new Bookmark for Bookmark
if ($toc_bookmarkText) {
$insert = -1;
foreach ($this->mpdf->BMoutlines as $i => $o) {
if ($o['p'] < $toc_page) { // i.e. before point of insertion
$insert = $i;
}
}
$txt = $this->mpdf->purify_utf8_text($toc_bookmarkText);
if ($this->mpdf->text_input_as_HTML) {
$txt = $this->mpdf->all_entities_to_utf8($txt);
}
$newBookmark[0] = array('t' => $txt, 'l' => 0, 'y' => 0, 'p' => $toc_page);
array_splice($this->mpdf->BMoutlines, ($insert + 1), 0, $newBookmark);
}
/* -- END BOOKMARKS -- */
}
// Delete empty page that was inserted earlier
if ($extrapage) {
unset($this->mpdf->pages[count($this->mpdf->pages)]);
$this->mpdf->page--; // Reset page pointer
}
}
function openTagTOC($attr)
{
if (isset($attr['OUTDENT']) && $attr['OUTDENT']) {
$tocoutdent = $attr['OUTDENT'];
} else {
$tocoutdent = '';
} // mPDF 5.6.19
if (isset($attr['RESETPAGENUM']) && $attr['RESETPAGENUM']) {
$resetpagenum = $attr['RESETPAGENUM'];
} else {
$resetpagenum = '';
}
if (isset($attr['PAGENUMSTYLE']) && $attr['PAGENUMSTYLE']) {
$pagenumstyle = $attr['PAGENUMSTYLE'];
} else {
$pagenumstyle = '';
}
if (isset($attr['SUPPRESS']) && $attr['SUPPRESS']) {
$suppress = $attr['SUPPRESS'];
} else {
$suppress = '';
}
if (isset($attr['TOC-ORIENTATION']) && $attr['TOC-ORIENTATION']) {
$toc_orientation = $attr['TOC-ORIENTATION'];
} else {
$toc_orientation = '';
}
if (isset($attr['PAGING']) && (strtoupper($attr['PAGING']) == 'OFF' || $attr['PAGING'] === '0')) {
$paging = false;
} else {
$paging = true;
}
if (isset($attr['LINKS']) && (strtoupper($attr['LINKS']) == 'ON' || $attr['LINKS'] == 1)) {
$links = true;
} else {
$links = false;
}
if (isset($attr['NAME']) && $attr['NAME']) {
$toc_id = strtolower($attr['NAME']);
} else {
$toc_id = 0;
}
$this->TOC('', 0, 0, $resetpagenum, $pagenumstyle, $suppress, $toc_orientation, $paging, $links, $toc_id, $tocoutdent); // mPDF 5.6.19 5.6.31
}
function openTagTOCPAGEBREAK($attr)
{
if (isset($attr['NAME']) && $attr['NAME']) {
$toc_id = strtolower($attr['NAME']);
} else {
$toc_id = 0;
}
if ($toc_id) {
if (isset($attr['OUTDENT']) && $attr['OUTDENT']) {
$this->m_TOC[$toc_id]['TOCoutdent'] = $attr['OUTDENT'];
} else {
$this->m_TOC[$toc_id]['TOCoutdent'] = '';
} // mPDF 5.6.19
if (isset($attr['TOC-ORIENTATION']) && $attr['TOC-ORIENTATION']) {
$this->m_TOC[$toc_id]['TOCorientation'] = $attr['TOC-ORIENTATION'];
} else {
$this->m_TOC[$toc_id]['TOCorientation'] = '';
}
if (isset($attr['PAGING']) && (strtoupper($attr['PAGING']) == 'OFF' || $attr['PAGING'] === '0')) {
$this->m_TOC[$toc_id]['TOCusePaging'] = false;
} else {
$this->m_TOC[$toc_id]['TOCusePaging'] = true;
}
if (isset($attr['LINKS']) && (strtoupper($attr['LINKS']) == 'ON' || $attr['LINKS'] == 1)) {
$this->m_TOC[$toc_id]['TOCuseLinking'] = true;
} else {
$this->m_TOC[$toc_id]['TOCuseLinking'] = false;
}
$this->m_TOC[$toc_id]['TOC_margin_left'] = $this->m_TOC[$toc_id]['TOC_margin_right'] = $this->m_TOC[$toc_id]['TOC_margin_top'] = $this->m_TOC[$toc_id]['TOC_margin_bottom'] = $this->m_TOC[$toc_id]['TOC_margin_header'] = $this->m_TOC[$toc_id]['TOC_margin_footer'] = '';
if (isset($attr['TOC-MARGIN-RIGHT'])) {
$this->m_TOC[$toc_id]['TOC_margin_right'] = $this->mpdf->ConvertSize($attr['TOC-MARGIN-RIGHT'], $this->mpdf->w, $this->mpdf->FontSize, false);
}
if (isset($attr['TOC-MARGIN-LEFT'])) {
$this->m_TOC[$toc_id]['TOC_margin_left'] = $this->mpdf->ConvertSize($attr['TOC-MARGIN-LEFT'], $this->mpdf->w, $this->mpdf->FontSize, false);
}
if (isset($attr['TOC-MARGIN-TOP'])) {
$this->m_TOC[$toc_id]['TOC_margin_top'] = $this->mpdf->ConvertSize($attr['TOC-MARGIN-TOP'], $this->mpdf->w, $this->mpdf->FontSize, false);
}
if (isset($attr['TOC-MARGIN-BOTTOM'])) {
$this->m_TOC[$toc_id]['TOC_margin_bottom'] = $this->mpdf->ConvertSize($attr['TOC-MARGIN-BOTTOM'], $this->mpdf->w, $this->mpdf->FontSize, false);
}
if (isset($attr['TOC-MARGIN-HEADER'])) {
$this->m_TOC[$toc_id]['TOC_margin_header'] = $this->mpdf->ConvertSize($attr['TOC-MARGIN-HEADER'], $this->mpdf->w, $this->mpdf->FontSize, false);
}
if (isset($attr['TOC-MARGIN-FOOTER'])) {
$this->m_TOC[$toc_id]['TOC_margin_footer'] = $this->mpdf->ConvertSize($attr['TOC-MARGIN-FOOTER'], $this->mpdf->w, $this->mpdf->FontSize, false);
}
$this->m_TOC[$toc_id]['TOC_odd_header_name'] = $this->m_TOC[$toc_id]['TOC_even_header_name'] = $this->m_TOC[$toc_id]['TOC_odd_footer_name'] = $this->m_TOC[$toc_id]['TOC_even_footer_name'] = '';
if (isset($attr['TOC-ODD-HEADER-NAME']) && $attr['TOC-ODD-HEADER-NAME']) {
$this->m_TOC[$toc_id]['TOC_odd_header_name'] = $attr['TOC-ODD-HEADER-NAME'];
}
if (isset($attr['TOC-EVEN-HEADER-NAME']) && $attr['TOC-EVEN-HEADER-NAME']) {
$this->m_TOC[$toc_id]['TOC_even_header_name'] = $attr['TOC-EVEN-HEADER-NAME'];
}
if (isset($attr['TOC-ODD-FOOTER-NAME']) && $attr['TOC-ODD-FOOTER-NAME']) {
$this->m_TOC[$toc_id]['TOC_odd_footer_name'] = $attr['TOC-ODD-FOOTER-NAME'];
}
if (isset($attr['TOC-EVEN-FOOTER-NAME']) && $attr['TOC-EVEN-FOOTER-NAME']) {
$this->m_TOC[$toc_id]['TOC_even_footer_name'] = $attr['TOC-EVEN-FOOTER-NAME'];
}
$this->m_TOC[$toc_id]['TOC_odd_header_value'] = $this->m_TOC[$toc_id]['TOC_even_header_value'] = $this->m_TOC[$toc_id]['TOC_odd_footer_value'] = $this->m_TOC[$toc_id]['TOC_even_footer_value'] = 0;
if (isset($attr['TOC-ODD-HEADER-VALUE']) && ($attr['TOC-ODD-HEADER-VALUE'] == '1' || strtoupper($attr['TOC-ODD-HEADER-VALUE']) == 'ON')) {
$this->m_TOC[$toc_id]['TOC_odd_header_value'] = 1;
} else if (isset($attr['TOC-ODD-HEADER-VALUE']) && ($attr['TOC-ODD-HEADER-VALUE'] == '-1' || strtoupper($attr['TOC-ODD-HEADER-VALUE']) == 'OFF')) {
$this->m_TOC[$toc_id]['TOC_odd_header_value'] = -1;
}
if (isset($attr['TOC-EVEN-HEADER-VALUE']) && ($attr['TOC-EVEN-HEADER-VALUE'] == '1' || strtoupper($attr['TOC-EVEN-HEADER-VALUE']) == 'ON')) {
$this->m_TOC[$toc_id]['TOC_even_header_value'] = 1;
} else if (isset($attr['TOC-EVEN-HEADER-VALUE']) && ($attr['TOC-EVEN-HEADER-VALUE'] == '-1' || strtoupper($attr['TOC-EVEN-HEADER-VALUE']) == 'OFF')) {
$this->m_TOC[$toc_id]['TOC_even_header_value'] = -1;
}
if (isset($attr['TOC-ODD-FOOTER-VALUE']) && ($attr['TOC-ODD-FOOTER-VALUE'] == '1' || strtoupper($attr['TOC-ODD-FOOTER-VALUE']) == 'ON')) {
$this->m_TOC[$toc_id]['TOC_odd_footer_value'] = 1;
} else if (isset($attr['TOC-ODD-FOOTER-VALUE']) && ($attr['TOC-ODD-FOOTER-VALUE'] == '-1' || strtoupper($attr['TOC-ODD-FOOTER-VALUE']) == 'OFF')) {
$this->m_TOC[$toc_id]['TOC_odd_footer_value'] = -1;
}
if (isset($attr['TOC-EVEN-FOOTER-VALUE']) && ($attr['TOC-EVEN-FOOTER-VALUE'] == '1' || strtoupper($attr['TOC-EVEN-FOOTER-VALUE']) == 'ON')) {
$this->m_TOC[$toc_id]['TOC_even_footer_value'] = 1;
} else if (isset($attr['TOC-EVEN-FOOTER-VALUE']) && ($attr['TOC-EVEN-FOOTER-VALUE'] == '-1' || strtoupper($attr['TOC-EVEN-FOOTER-VALUE']) == 'OFF')) {
$this->m_TOC[$toc_id]['TOC_even_footer_value'] = -1;
}
if (isset($attr['TOC-RESETPAGENUM']) && $attr['TOC-RESETPAGENUM']) {
$this->m_TOC[$toc_id]['TOC_resetpagenum'] = $attr['TOC-RESETPAGENUM'];
} else {
$this->m_TOC[$toc_id]['TOC_resetpagenum'] = '';
} // mPDF 6
if (isset($attr['TOC-PAGENUMSTYLE']) && $attr['TOC-PAGENUMSTYLE']) {
$this->m_TOC[$toc_id]['TOC_pagenumstyle'] = $attr['TOC-PAGENUMSTYLE'];
} else {
$this->m_TOC[$toc_id]['TOC_pagenumstyle'] = '';
} // mPDF 6
if (isset($attr['TOC-SUPPRESS']) && ($attr['TOC-SUPPRESS'] || $attr['TOC-SUPPRESS'] === '0')) {
$this->m_TOC[$toc_id]['TOC_suppress'] = $attr['TOC-SUPPRESS'];
} else {
$this->m_TOC[$toc_id]['TOC_suppress'] = '';
} // mPDF 6
if (isset($attr['TOC-PAGE-SELECTOR']) && $attr['TOC-PAGE-SELECTOR']) {
$this->m_TOC[$toc_id]['TOC_page_selector'] = $attr['TOC-PAGE-SELECTOR'];
} else {
$this->m_TOC[$toc_id]['TOC_page_selector'] = '';
}
if (isset($attr['TOC-SHEET-SIZE']) && $attr['TOC-SHEET-SIZE']) {
$this->m_TOC[$toc_id]['TOCsheetsize'] = $attr['TOC-SHEET-SIZE'];
} else {
$this->m_TOC[$toc_id]['TOCsheetsize'] = '';
}
if (isset($attr['TOC-PREHTML']) && $attr['TOC-PREHTML']) {
$this->m_TOC[$toc_id]['TOCpreHTML'] = htmlspecialchars_decode($attr['TOC-PREHTML'], ENT_QUOTES);
}
if (isset($attr['TOC-POSTHTML']) && $attr['TOC-POSTHTML']) {
$this->m_TOC[$toc_id]['TOCpostHTML'] = htmlspecialchars_decode($attr['TOC-POSTHTML'], ENT_QUOTES);
}
if (isset($attr['TOC-BOOKMARKTEXT']) && $attr['TOC-BOOKMARKTEXT']) {
$this->m_TOC[$toc_id]['TOCbookmarkText'] = htmlspecialchars_decode($attr['TOC-BOOKMARKTEXT'], ENT_QUOTES);
} // *BOOKMARKS*
} else {
if (isset($attr['OUTDENT']) && $attr['OUTDENT']) {
$this->TOCoutdent = $attr['OUTDENT'];
} else {
$this->TOCoutdent = '';
} // mPDF 5.6.19
if (isset($attr['TOC-ORIENTATION']) && $attr['TOC-ORIENTATION']) {
$this->TOCorientation = $attr['TOC-ORIENTATION'];
} else {
$this->TOCorientation = '';
}
if (isset($attr['PAGING']) && (strtoupper($attr['PAGING']) == 'OFF' || $attr['PAGING'] === '0')) {
$this->TOCusePaging = false;
} else {
$this->TOCusePaging = true;
}
if (isset($attr['LINKS']) && (strtoupper($attr['LINKS']) == 'ON' || $attr['LINKS'] == 1)) {
$this->TOCuseLinking = true;
} else {
$this->TOCuseLinking = false;
}
$this->TOC_margin_left = $this->TOC_margin_right = $this->TOC_margin_top = $this->TOC_margin_bottom = $this->TOC_margin_header = $this->TOC_margin_footer = '';
if (isset($attr['TOC-MARGIN-RIGHT'])) {
$this->TOC_margin_right = $this->mpdf->ConvertSize($attr['TOC-MARGIN-RIGHT'], $this->mpdf->w, $this->mpdf->FontSize, false);
}
if (isset($attr['TOC-MARGIN-LEFT'])) {
$this->TOC_margin_left = $this->mpdf->ConvertSize($attr['TOC-MARGIN-LEFT'], $this->mpdf->w, $this->mpdf->FontSize, false);
}
if (isset($attr['TOC-MARGIN-TOP'])) {
$this->TOC_margin_top = $this->mpdf->ConvertSize($attr['TOC-MARGIN-TOP'], $this->mpdf->w, $this->mpdf->FontSize, false);
}
if (isset($attr['TOC-MARGIN-BOTTOM'])) {
$this->TOC_margin_bottom = $this->mpdf->ConvertSize($attr['TOC-MARGIN-BOTTOM'], $this->mpdf->w, $this->mpdf->FontSize, false);
}
if (isset($attr['TOC-MARGIN-HEADER'])) {
$this->TOC_margin_header = $this->mpdf->ConvertSize($attr['TOC-MARGIN-HEADER'], $this->mpdf->w, $this->mpdf->FontSize, false);
}
if (isset($attr['TOC-MARGIN-FOOTER'])) {
$this->TOC_margin_footer = $this->mpdf->ConvertSize($attr['TOC-MARGIN-FOOTER'], $this->mpdf->w, $this->mpdf->FontSize, false);
}
$this->TOC_odd_header_name = $this->TOC_even_header_name = $this->TOC_odd_footer_name = $this->TOC_even_footer_name = '';
if (isset($attr['TOC-ODD-HEADER-NAME']) && $attr['TOC-ODD-HEADER-NAME']) {
$this->TOC_odd_header_name = $attr['TOC-ODD-HEADER-NAME'];
}
if (isset($attr['TOC-EVEN-HEADER-NAME']) && $attr['TOC-EVEN-HEADER-NAME']) {
$this->TOC_even_header_name = $attr['TOC-EVEN-HEADER-NAME'];
}
if (isset($attr['TOC-ODD-FOOTER-NAME']) && $attr['TOC-ODD-FOOTER-NAME']) {
$this->TOC_odd_footer_name = $attr['TOC-ODD-FOOTER-NAME'];
}
if (isset($attr['TOC-EVEN-FOOTER-NAME']) && $attr['TOC-EVEN-FOOTER-NAME']) {
$this->TOC_even_footer_name = $attr['TOC-EVEN-FOOTER-NAME'];
}
$this->TOC_odd_header_value = $this->TOC_even_header_value = $this->TOC_odd_footer_value = $this->TOC_even_footer_value = 0;
if (isset($attr['TOC-ODD-HEADER-VALUE']) && ($attr['TOC-ODD-HEADER-VALUE'] == '1' || strtoupper($attr['TOC-ODD-HEADER-VALUE']) == 'ON')) {
$this->TOC_odd_header_value = 1;
} else if (isset($attr['TOC-ODD-HEADER-VALUE']) && ($attr['TOC-ODD-HEADER-VALUE'] == '-1' || strtoupper($attr['TOC-ODD-HEADER-VALUE']) == 'OFF')) {
$this->TOC_odd_header_value = -1;
}
if (isset($attr['TOC-EVEN-HEADER-VALUE']) && ($attr['TOC-EVEN-HEADER-VALUE'] == '1' || strtoupper($attr['TOC-EVEN-HEADER-VALUE']) == 'ON')) {
$this->TOC_even_header_value = 1;
} else if (isset($attr['TOC-EVEN-HEADER-VALUE']) && ($attr['TOC-EVEN-HEADER-VALUE'] == '-1' || strtoupper($attr['TOC-EVEN-HEADER-VALUE']) == 'OFF')) {
$this->TOC_even_header_value = -1;
}
if (isset($attr['TOC-ODD-FOOTER-VALUE']) && ($attr['TOC-ODD-FOOTER-VALUE'] == '1' || strtoupper($attr['TOC-ODD-FOOTER-VALUE']) == 'ON')) {
$this->TOC_odd_footer_value = 1;
} else if (isset($attr['TOC-ODD-FOOTER-VALUE']) && ($attr['TOC-ODD-FOOTER-VALUE'] == '-1' || strtoupper($attr['TOC-ODD-FOOTER-VALUE']) == 'OFF')) {
$this->TOC_odd_footer_value = -1;
}
if (isset($attr['TOC-EVEN-FOOTER-VALUE']) && ($attr['TOC-EVEN-FOOTER-VALUE'] == '1' || strtoupper($attr['TOC-EVEN-FOOTER-VALUE']) == 'ON')) {
$this->TOC_even_footer_value = 1;
} else if (isset($attr['TOC-EVEN-FOOTER-VALUE']) && ($attr['TOC-EVEN-FOOTER-VALUE'] == '-1' || strtoupper($attr['TOC-EVEN-FOOTER-VALUE']) == 'OFF')) {
$this->TOC_even_footer_value = -1;
}
if (isset($attr['TOC-PAGE-SELECTOR']) && $attr['TOC-PAGE-SELECTOR']) {
$this->TOC_page_selector = $attr['TOC-PAGE-SELECTOR'];
} else {
$this->TOC_page_selector = '';
}
if (isset($attr['TOC-RESETPAGENUM']) && $attr['TOC-RESETPAGENUM']) {
$this->TOC_resetpagenum = $attr['TOC-RESETPAGENUM'];
} else {
$this->TOC_resetpagenum = '';
} // mPDF 6
if (isset($attr['TOC-PAGENUMSTYLE']) && $attr['TOC-PAGENUMSTYLE']) {
$this->TOC_pagenumstyle = $attr['TOC-PAGENUMSTYLE'];
} else {
$this->TOC_pagenumstyle = '';
} // mPDF 6
if (isset($attr['TOC-SUPPRESS']) && ($attr['TOC-SUPPRESS'] || $attr['TOC-SUPPRESS'] === '0')) {
$this->TOC_suppress = $attr['TOC-SUPPRESS'];
} else {
$this->TOC_suppress = '';
} // mPDF 6
if (isset($attr['TOC-SHEET-SIZE']) && $attr['TOC-SHEET-SIZE']) {
$this->TOCsheetsize = $attr['TOC-SHEET-SIZE'];
} else {
$this->TOCsheetsize = '';
}
if (isset($attr['TOC-PREHTML']) && $attr['TOC-PREHTML']) {
$this->TOCpreHTML = htmlspecialchars_decode($attr['TOC-PREHTML'], ENT_QUOTES);
}
if (isset($attr['TOC-POSTHTML']) && $attr['TOC-POSTHTML']) {
$this->TOCpostHTML = htmlspecialchars_decode($attr['TOC-POSTHTML'], ENT_QUOTES);
}
if (isset($attr['TOC-BOOKMARKTEXT']) && $attr['TOC-BOOKMARKTEXT']) {
$this->TOCbookmarkText = htmlspecialchars_decode($attr['TOC-BOOKMARKTEXT'], ENT_QUOTES);
}
}
if ($this->mpdf->y == $this->mpdf->tMargin && (!$this->mpdf->mirrorMargins || ($this->mpdf->mirrorMargins && $this->mpdf->page % 2 == 1))) {
if ($toc_id) {
$this->m_TOC[$toc_id]['TOCmark'] = $this->mpdf->page;
} else {
$this->TOCmark = $this->mpdf->page;
}
// Don't add a page
if ($this->mpdf->page == 1 && count($this->mpdf->PageNumSubstitutions) == 0) {
$resetpagenum = '';
$pagenumstyle = '';
$suppress = '';
if (isset($attr['RESETPAGENUM'])) {
$resetpagenum = $attr['RESETPAGENUM'];
}
if (isset($attr['PAGENUMSTYLE'])) {
$pagenumstyle = $attr['PAGENUMSTYLE'];
}
if (isset($attr['SUPPRESS'])) {
$suppress = $attr['SUPPRESS'];
}
if (!$suppress) {
$suppress = 'off';
}
if (!$resetpagenum) {
$resetpagenum = 1;
}
$this->mpdf->PageNumSubstitutions[] = array('from' => 1, 'reset' => $resetpagenum, 'type' => $pagenumstyle, 'suppress' => $suppress);
}
return array(true, $toc_id);
}
// No break - continues as PAGEBREAK...
return array(false, $toc_id);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,446 @@
<?php
require_once __DIR__ . '/../MpdfException.php';
require_once __DIR__ . '/ttfontsuni.php';
class TTFontFile_Analysis extends TTFontFile
{
// Used to get font information from files in directory
function extractCoreInfo($file, $TTCfontID = 0)
{
$this->filename = $file;
$this->fh = fopen($file, 'rb');
if (!$this->fh) {
return ('ERROR - Can\'t open file ' . $file);
}
$this->_pos = 0;
$this->charWidths = '';
$this->glyphPos = array();
$this->charToGlyph = array();
$this->tables = array();
$this->otables = array();
$this->ascent = 0;
$this->descent = 0;
$this->numTTCFonts = 0;
$this->TTCFonts = array();
$this->version = $version = $this->read_ulong();
$this->panose = array(); // mPDF 5.0
if ($version == 0x4F54544F) {
throw new MpdfException('ERROR - NOT ADDED as Postscript outlines are not supported - ' . $file);
}
if ($version == 0x74746366) {
if ($TTCfontID > 0) {
$this->version = $version = $this->read_ulong(); // TTC Header version now
if (!in_array($version, array(0x00010000, 0x00020000))) {
throw new MpdfException("ERROR - NOT ADDED as Error parsing TrueType Collection: version=" . $version . " - " . $file);
}
} else {
throw new MpdfException("ERROR - Error parsing TrueType Collection - " . $file);
}
$this->numTTCFonts = $this->read_ulong();
for ($i = 1; $i <= $this->numTTCFonts; $i++) {
$this->TTCFonts[$i]['offset'] = $this->read_ulong();
}
$this->seek($this->TTCFonts[$TTCfontID]['offset']);
$this->version = $version = $this->read_ulong(); // TTFont version again now
$this->readTableDirectory(false);
} else {
if (!in_array($version, array(0x00010000, 0x74727565))) {
throw new MpdfException("ERROR - NOT ADDED as Not a TrueType font: version=" . $version . " - " . $file);
}
$this->readTableDirectory(false);
}
/* Included for testing...
$cmap_offset = $this->seek_table("cmap");
$this->skip(2);
$cmapTableCount = $this->read_ushort();
$unicode_cmap_offset = 0;
for ($i=0;$i<$cmapTableCount;$i++) {
$x[$i]['platformId'] = $this->read_ushort();
$x[$i]['encodingId'] = $this->read_ushort();
$x[$i]['offset'] = $this->read_ulong();
$save_pos = $this->_pos;
$x[$i]['format'] = $this->get_ushort($cmap_offset + $x[$i]['offset'] );
$this->seek($save_pos );
}
print_r($x); exit;
*/
///////////////////////////////////
// name - Naming table
///////////////////////////////////
/* Test purposes - displays table of names
$name_offset = $this->seek_table("name");
$format = $this->read_ushort();
if ($format != 0 && $format != 1) // mPDF 5.3.73
die("Unknown name table format ".$format);
$numRecords = $this->read_ushort();
$string_data_offset = $name_offset + $this->read_ushort();
for ($i=0;$i<$numRecords; $i++) {
$x[$i]['platformId'] = $this->read_ushort();
$x[$i]['encodingId'] = $this->read_ushort();
$x[$i]['languageId'] = $this->read_ushort();
$x[$i]['nameId'] = $this->read_ushort();
$x[$i]['length'] = $this->read_ushort();
$x[$i]['offset'] = $this->read_ushort();
$N = '';
if ($x[$i]['platformId'] == 1 && $x[$i]['encodingId'] == 0 && $x[$i]['languageId'] == 0) { // Roman
$opos = $this->_pos;
$N = $this->get_chunk($string_data_offset + $x[$i]['offset'] , $x[$i]['length'] );
$this->_pos = $opos;
$this->seek($opos);
}
else { // Unicode
$opos = $this->_pos;
$this->seek($string_data_offset + $x[$i]['offset'] );
$length = $x[$i]['length'] ;
if ($length % 2 != 0)
$length -= 1;
// die("PostScript name is UTF-16BE string of odd length");
$length /= 2;
$N = '';
while ($length > 0) {
$char = $this->read_ushort();
$N .= (chr($char));
$length -= 1;
}
$this->_pos = $opos;
$this->seek($opos);
}
$x[$i]['names'][$nameId] = $N;
}
print_r($x); exit;
*/
$name_offset = $this->seek_table("name");
$format = $this->read_ushort();
if ($format != 0 && $format != 1) // mPDF 5.3.73
throw new MpdfException("ERROR - NOT ADDED as Unknown name table format " . $format . " - " . $file);
$numRecords = $this->read_ushort();
$string_data_offset = $name_offset + $this->read_ushort();
$names = array(1 => '', 2 => '', 3 => '', 4 => '', 6 => '');
$K = array_keys($names);
$nameCount = count($names);
for ($i = 0; $i < $numRecords; $i++) {
$platformId = $this->read_ushort();
$encodingId = $this->read_ushort();
$languageId = $this->read_ushort();
$nameId = $this->read_ushort();
$length = $this->read_ushort();
$offset = $this->read_ushort();
if (!in_array($nameId, $K))
continue;
$N = '';
if ($platformId == 3 && $encodingId == 1 && $languageId == 0x409) { // Microsoft, Unicode, US English, PS Name
$opos = $this->_pos;
$this->seek($string_data_offset + $offset);
if ($length % 2 != 0)
$length += 1;
$length /= 2;
$N = '';
while ($length > 0) {
$char = $this->read_ushort();
$N .= (chr($char));
$length -= 1;
}
$this->_pos = $opos;
$this->seek($opos);
} else if ($platformId == 1 && $encodingId == 0 && $languageId == 0) { // Macintosh, Roman, English, PS Name
$opos = $this->_pos;
$N = $this->get_chunk($string_data_offset + $offset, $length);
$this->_pos = $opos;
$this->seek($opos);
}
if ($N && $names[$nameId] == '') {
$names[$nameId] = $N;
$nameCount -= 1;
if ($nameCount == 0)
break;
}
}
if ($names[6])
$psName = preg_replace('/ /', '-', $names[6]);
else if ($names[4])
$psName = preg_replace('/ /', '-', $names[4]);
else if ($names[1])
$psName = preg_replace('/ /', '-', $names[1]);
else
$psName = '';
if (!$names[1] && !$psName)
throw new MpdfException("ERROR - NOT ADDED as Could not find valid font name - " . $file);
$this->name = $psName;
if ($names[1]) {
$this->familyName = $names[1];
} else {
$this->familyName = $psName;
}
if ($names[2]) {
$this->styleName = $names[2];
} else {
$this->styleName = 'Regular';
}
///////////////////////////////////
// head - Font header table
///////////////////////////////////
$this->seek_table("head");
$ver_maj = $this->read_ushort();
$ver_min = $this->read_ushort();
if ($ver_maj != 1)
throw new MpdfException('ERROR - NOT ADDED as Unknown head table version ' . $ver_maj . '.' . $ver_min . " - " . $file);
$this->fontRevision = $this->read_ushort() . $this->read_ushort();
$this->skip(4);
$magic = $this->read_ulong();
if ($magic != 0x5F0F3CF5)
throw new MpdfException('ERROR - NOT ADDED as Invalid head table magic ' . $magic . " - " . $file);
$this->skip(2);
$this->unitsPerEm = $unitsPerEm = $this->read_ushort();
$scale = 1000 / $unitsPerEm;
$this->skip(24);
$macStyle = $this->read_short();
$this->skip(4);
$indexLocFormat = $this->read_short();
///////////////////////////////////
// OS/2 - OS/2 and Windows metrics table
///////////////////////////////////
$sFamily = '';
$panose = '';
$fsSelection = '';
if (isset($this->tables["OS/2"])) {
$this->seek_table("OS/2");
$this->skip(30);
$sF = $this->read_short();
$sFamily = ($sF >> 8);
$this->_pos += 10; //PANOSE = 10 byte length
$panose = fread($this->fh, 10);
$this->panose = array();
for ($p = 0; $p < strlen($panose); $p++) {
$this->panose[] = ord($panose[$p]);
}
$this->skip(20);
$fsSelection = $this->read_short();
}
///////////////////////////////////
// post - PostScript table
///////////////////////////////////
$this->seek_table("post");
$this->skip(4);
$this->italicAngle = $this->read_short() + $this->read_ushort() / 65536.0;
$this->skip(4);
$isFixedPitch = $this->read_ulong();
///////////////////////////////////
// cmap - Character to glyph index mapping table
///////////////////////////////////
$cmap_offset = $this->seek_table("cmap");
$this->skip(2);
$cmapTableCount = $this->read_ushort();
$unicode_cmap_offset = 0;
for ($i = 0; $i < $cmapTableCount; $i++) {
$platformID = $this->read_ushort();
$encodingID = $this->read_ushort();
$offset = $this->read_ulong();
$save_pos = $this->_pos;
if (($platformID == 3 && $encodingID == 1) || $platformID == 0) { // Microsoft, Unicode
$format = $this->get_ushort($cmap_offset + $offset);
if ($format == 4) {
if (!$unicode_cmap_offset)
$unicode_cmap_offset = $cmap_offset + $offset;
}
}
else if ((($platformID == 3 && $encodingID == 10) || $platformID == 0)) { // Microsoft, Unicode Format 12 table HKCS
$format = $this->get_ushort($cmap_offset + $offset);
if ($format == 12) {
$unicode_cmap_offset = $cmap_offset + $offset;
break;
}
}
$this->seek($save_pos);
}
if (!$unicode_cmap_offset)
throw new MpdfException('ERROR - Font (' . $this->filename . ') NOT ADDED as it is not Unicode encoded, and cannot be used by mPDF');
$rtl = false;
$indic = false;
$cjk = false;
$sip = false;
$smp = false;
$pua = false;
$puaag = false;
$glyphToChar = array();
$unAGlyphs = '';
// Format 12 CMAP does characters above Unicode BMP i.e. some HKCS characters U+20000 and above
if ($format == 12) {
$this->seek($unicode_cmap_offset + 4);
$length = $this->read_ulong();
$limit = $unicode_cmap_offset + $length;
$this->skip(4);
$nGroups = $this->read_ulong();
for ($i = 0; $i < $nGroups; $i++) {
$startCharCode = $this->read_ulong();
$endCharCode = $this->read_ulong();
$startGlyphCode = $this->read_ulong();
if (($endCharCode > 0x20000 && $endCharCode < 0x2A6DF) || ($endCharCode > 0x2F800 && $endCharCode < 0x2FA1F)) {
$sip = true;
}
if ($endCharCode > 0x10000 && $endCharCode < 0x1FFFF) {
$smp = true;
}
if (($endCharCode > 0x0590 && $endCharCode < 0x077F) || ($endCharCode > 0xFE70 && $endCharCode < 0xFEFF) || ($endCharCode > 0xFB50 && $endCharCode < 0xFDFF)) {
$rtl = true;
}
if ($endCharCode > 0x0900 && $endCharCode < 0x0DFF) {
$indic = true;
}
if ($endCharCode > 0xE000 && $endCharCode < 0xF8FF) {
$pua = true;
if ($endCharCode > 0xF500 && $endCharCode < 0xF7FF) {
$puaag = true;
}
}
if (($endCharCode > 0x2E80 && $endCharCode < 0x4DC0) || ($endCharCode > 0x4E00 && $endCharCode < 0xA4CF) || ($endCharCode > 0xAC00 && $endCharCode < 0xD7AF) || ($endCharCode > 0xF900 && $endCharCode < 0xFAFF) || ($endCharCode > 0xFE30 && $endCharCode < 0xFE4F)) {
$cjk = true;
}
$offset = 0;
// Get each glyphToChar - only point if going to analyse un-mapped Arabic Glyphs
if (isset($this->tables['post'])) {
for ($unichar = $startCharCode; $unichar <= $endCharCode; $unichar++) {
$glyph = $startGlyphCode + $offset;
$offset++;
$glyphToChar[$glyph][] = $unichar;
}
}
}
} else { // Format 4 CMap
$this->seek($unicode_cmap_offset + 2);
$length = $this->read_ushort();
$limit = $unicode_cmap_offset + $length;
$this->skip(2);
$segCount = $this->read_ushort() / 2;
$this->skip(6);
$endCount = array();
for ($i = 0; $i < $segCount; $i++) {
$endCount[] = $this->read_ushort();
}
$this->skip(2);
$startCount = array();
for ($i = 0; $i < $segCount; $i++) {
$startCount[] = $this->read_ushort();
}
$idDelta = array();
for ($i = 0; $i < $segCount; $i++) {
$idDelta[] = $this->read_short();
}
$idRangeOffset_start = $this->_pos;
$idRangeOffset = array();
for ($i = 0; $i < $segCount; $i++) {
$idRangeOffset[] = $this->read_ushort();
}
for ($n = 0; $n < $segCount; $n++) {
if (($endCount[$n] > 0x0590 && $endCount[$n] < 0x077F) || ($endCount[$n] > 0xFE70 && $endCount[$n] < 0xFEFF) || ($endCount[$n] > 0xFB50 && $endCount[$n] < 0xFDFF)) {
$rtl = true;
}
if ($endCount[$n] > 0x0900 && $endCount[$n] < 0x0DFF) {
$indic = true;
}
if (($endCount[$n] > 0x2E80 && $endCount[$n] < 0x4DC0) || ($endCount[$n] > 0x4E00 && $endCount[$n] < 0xA4CF) || ($endCount[$n] > 0xAC00 && $endCount[$n] < 0xD7AF) || ($endCount[$n] > 0xF900 && $endCount[$n] < 0xFAFF) || ($endCount[$n] > 0xFE30 && $endCount[$n] < 0xFE4F)) {
$cjk = true;
}
if ($endCount[$n] > 0xE000 && $endCount[$n] < 0xF8FF) {
$pua = true;
if ($endCount[$n] > 0xF500 && $endCount[$n] < 0xF7FF) {
$puaag = true;
}
}
// Get each glyphToChar - only point if going to analyse un-mapped Arabic Glyphs
if (isset($this->tables['post'])) {
$endpoint = ($endCount[$n] + 1);
for ($unichar = $startCount[$n]; $unichar < $endpoint; $unichar++) {
if ($idRangeOffset[$n] == 0)
$glyph = ($unichar + $idDelta[$n]) & 0xFFFF;
else {
$offset = ($unichar - $startCount[$n]) * 2 + $idRangeOffset[$n];
$offset = $idRangeOffset_start + 2 * $n + $offset;
if ($offset >= $limit)
$glyph = 0;
else {
$glyph = $this->get_ushort($offset);
if ($glyph != 0)
$glyph = ($glyph + $idDelta[$n]) & 0xFFFF;
}
}
$glyphToChar[$glyph][] = $unichar;
}
}
}
}
$bold = false;
$italic = false;
$ftype = '';
if ($macStyle & (1 << 0)) {
$bold = true;
} // bit 0 bold
else if ($fsSelection & (1 << 5)) {
$bold = true;
} // 5 BOLD Characters are emboldened
if ($macStyle & (1 << 1)) {
$italic = true;
} // bit 1 italic
else if ($fsSelection & (1 << 0)) {
$italic = true;
} // 0 ITALIC Font contains Italic characters, otherwise they are upright
else if ($this->italicAngle <> 0) {
$italic = true;
}
if ($isFixedPitch) {
$ftype = 'mono';
} else if ($sFamily > 0 && $sFamily < 8) {
$ftype = 'serif';
} else if ($sFamily == 8) {
$ftype = 'sans';
} else if ($sFamily == 10) {
$ftype = 'cursive';
}
// Use PANOSE
if ($panose) {
$bFamilyType = ord($panose[0]);
if ($bFamilyType == 2) {
$bSerifStyle = ord($panose[1]);
if (!$ftype) {
if ($bSerifStyle > 1 && $bSerifStyle < 11) {
$ftype = 'serif';
} else if ($bSerifStyle > 10) {
$ftype = 'sans';
}
}
$bProportion = ord($panose[3]);
if ($bProportion == 9 || $bProportion == 1) {
$ftype = 'mono';
} // ==1 i.e. No Fit needed for OCR-a and -b
} else if ($bFamilyType == 3) {
$ftype = 'cursive';
}
}
fclose($this->fh);
return array($this->familyName, $bold, $italic, $ftype, $TTCfontID, $rtl, $indic, $cjk, $sip, $smp, $puaag, $pua, $unAGlyphs);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,271 @@
<?php
class wmf
{
var $mpdf = null;
var $gdiObjectArray;
public function __construct(mPDF $mpdf)
{
$this->mpdf = $mpdf;
}
function _getWMFimage($data)
{
$k = _MPDFK;
$this->gdiObjectArray = array();
$a = unpack('stest', "\1\0");
if ($a['test'] != 1)
return array(0, 'Error parsing WMF image - Big-endian architecture not supported');
// check for Aldus placeable metafile header
$key = unpack('Lmagic', substr($data, 0, 4));
$p = 18; // WMF header
if ($key['magic'] == (int) 0x9AC6CDD7) {
$p +=22;
} // Aldus header
// define some state variables
$wo = null; // window origin
$we = null; // window extent
$polyFillMode = 0;
$nullPen = false;
$nullBrush = false;
$endRecord = false;
$wmfdata = '';
while ($p < strlen($data) && !$endRecord) {
$recordInfo = unpack('Lsize/Sfunc', substr($data, $p, 6));
$p += 6;
// size of record given in WORDs (= 2 bytes)
$size = $recordInfo['size'];
// func is number of GDI function
$func = $recordInfo['func'];
if ($size > 3) {
$parms = substr($data, $p, 2 * ($size - 3));
$p += 2 * ($size - 3);
}
switch ($func) {
case 0x020b: // SetWindowOrg
// do not allow window origin to be changed
// after drawing has begun
if (!$wmfdata)
$wo = array_reverse(unpack('s2', $parms));
break;
case 0x020c: // SetWindowExt
// do not allow window extent to be changed
// after drawing has begun
if (!$wmfdata)
$we = array_reverse(unpack('s2', $parms));
break;
case 0x02fc: // CreateBrushIndirect
$brush = unpack('sstyle/Cr/Cg/Cb/Ca/Shatch', $parms);
$brush['type'] = 'B';
$this->_AddGDIObject($brush);
break;
case 0x02fa: // CreatePenIndirect
$pen = unpack('Sstyle/swidth/sdummy/Cr/Cg/Cb/Ca', $parms);
// convert width from twips to user unit
$pen['width'] /= (20 * $k);
$pen['type'] = 'P';
$this->_AddGDIObject($pen);
break;
// MUST create other GDI objects even if we don't handle them
case 0x06fe: // CreateBitmap
case 0x02fd: // CreateBitmapIndirect
case 0x00f8: // CreateBrush
case 0x02fb: // CreateFontIndirect
case 0x00f7: // CreatePalette
case 0x01f9: // CreatePatternBrush
case 0x06ff: // CreateRegion
case 0x0142: // DibCreatePatternBrush
$dummyObject = array('type' => 'D');
$this->_AddGDIObject($dummyObject);
break;
case 0x0106: // SetPolyFillMode
$polyFillMode = unpack('smode', $parms);
$polyFillMode = $polyFillMode['mode'];
break;
case 0x01f0: // DeleteObject
$idx = unpack('Sidx', $parms);
$idx = $idx['idx'];
$this->_DeleteGDIObject($idx);
break;
case 0x012d: // SelectObject
$idx = unpack('Sidx', $parms);
$idx = $idx['idx'];
$obj = $this->_GetGDIObject($idx);
switch ($obj['type']) {
case 'B':
$nullBrush = false;
if ($obj['style'] == 1) {
$nullBrush = true;
} else {
$wmfdata .= $this->mpdf->SetFColor($this->mpdf->ConvertColor('rgb(' . $obj['r'] . ',' . $obj['g'] . ',' . $obj['b'] . ')'), true) . "\n";
}
break;
case 'P':
$nullPen = false;
$dashArray = array();
// dash parameters are custom
switch ($obj['style']) {
case 0: // PS_SOLID
break;
case 1: // PS_DASH
$dashArray = array(3, 1);
break;
case 2: // PS_DOT
$dashArray = array(0.5, 0.5);
break;
case 3: // PS_DASHDOT
$dashArray = array(2, 1, 0.5, 1);
break;
case 4: // PS_DASHDOTDOT
$dashArray = array(2, 1, 0.5, 1, 0.5, 1);
break;
case 5: // PS_NULL
$nullPen = true;
break;
}
if (!$nullPen) {
$wmfdata .= $this->mpdf->SetDColor($this->mpdf->ConvertColor('rgb(' . $obj['r'] . ',' . $obj['g'] . ',' . $obj['b'] . ')'), true) . "\n";
$wmfdata .= sprintf("%.3F w\n", $obj['width'] * $k);
}
if (!empty($dashArray)) {
$s = '[';
for ($i = 0; $i < count($dashArray); $i++) {
$s .= $dashArray[$i] * $k;
if ($i != count($dashArray) - 1) {
$s .= ' ';
}
}
$s .= '] 0 d';
$wmfdata .= $s . "\n";
}
break;
}
break;
case 0x0325: // Polyline
case 0x0324: // Polygon
$coords = unpack('s' . ($size - 3), $parms);
$numpoints = $coords[1];
for ($i = $numpoints; $i > 0; $i--) {
$px = $coords[2 * $i];
$py = $coords[2 * $i + 1];
if ($i < $numpoints) {
$wmfdata .= $this->_LineTo($px, $py);
} else {
$wmfdata .= $this->_MoveTo($px, $py);
}
}
if ($func == 0x0325) {
$op = 's';
} else if ($func == 0x0324) {
if ($nullPen) {
if ($nullBrush) {
$op = 'n';
} // no op
else {
$op = 'f';
} // fill
} else {
if ($nullBrush) {
$op = 's';
} // stroke
else {
$op = 'b';
} // stroke and fill
}
if ($polyFillMode == 1 && ($op == 'b' || $op == 'f')) {
$op .= '*';
} // use even-odd fill rule
}
$wmfdata .= $op . "\n";
break;
case 0x0538: // PolyPolygon
$coords = unpack('s' . ($size - 3), $parms);
$numpolygons = $coords[1];
$adjustment = $numpolygons;
for ($j = 1; $j <= $numpolygons; $j++) {
$numpoints = $coords[$j + 1];
for ($i = $numpoints; $i > 0; $i--) {
$px = $coords[2 * $i + $adjustment];
$py = $coords[2 * $i + 1 + $adjustment];
if ($i == $numpoints) {
$wmfdata .= $this->_MoveTo($px, $py);
} else {
$wmfdata .= $this->_LineTo($px, $py);
}
}
$adjustment += $numpoints * 2;
}
if ($nullPen) {
if ($nullBrush) {
$op = 'n';
} // no op
else {
$op = 'f';
} // fill
} else {
if ($nullBrush) {
$op = 's';
} // stroke
else {
$op = 'b';
} // stroke and fill
}
if ($polyFillMode == 1 && ($op == 'b' || $op == 'f')) {
$op .= '*';
} // use even-odd fill rule
$wmfdata .= $op . "\n";
break;
case 0x0000:
$endRecord = true;
break;
}
}
return array(1, $wmfdata, $wo, $we);
}
function _MoveTo($x, $y)
{
return "$x $y m\n";
}
// a line must have been started using _MoveTo() first
function _LineTo($x, $y)
{
return "$x $y l\n";
}
function _AddGDIObject($obj)
{
// find next available slot
$idx = 0;
if (!empty($this->gdiObjectArray)) {
$empty = false;
$i = 0;
while (!$empty) {
$empty = !isset($this->gdiObjectArray[$i]);
$i++;
}
$idx = $i - 1;
}
$this->gdiObjectArray[$idx] = $obj;
}
function _GetGDIObject($idx)
{
return $this->gdiObjectArray[$idx];
}
function _DeleteGDIObject($idx)
{
unset($this->gdiObjectArray[$idx]);
}
}