<?php

require(dirname(__FILE__) . '/fpdf.php');



class PDF_Chinese extends FPDF

{

    var $Big5_widths = array();

    var $GB_widths = array();

    function PDF_Chinese($orientation = 'P', $unit = 'mm', $format = 'A4')

    {

        FPDF::FPDF($orientation = 'P', $unit = 'mm', $format = 'A4');

        $this->Big5_widths = array(' ' => 250, '!' => 250, '"' => 408, '#' => 668, '$' => 490, '%' => 875, '&' => 698, '\'' => 250,

            '(' => 240, ')' => 240, '*' => 417, '+' => 667, ',' => 250, '-' => 313, '.' => 250, '/' => 520, '0' => 500, '1' => 500,

            '2' => 500, '3' => 500, '4' => 500, '5' => 500, '6' => 500, '7' => 500, '8' => 500, '9' => 500, ':' => 250, ';' => 250,

            '<' => 667, '=' => 667, '>' => 667, '?' => 396, '@' => 921, 'A' => 677, 'B' => 615, 'C' => 719, 'D' => 760, 'E' => 625,

            'F' => 552, 'G' => 771, 'H' => 802, 'I' => 354, 'J' => 354, 'K' => 781, 'L' => 604, 'M' => 927, 'N' => 750, 'O' => 823,

            'P' => 563, 'Q' => 823, 'R' => 729, 'S' => 542, 'T' => 698, 'U' => 771, 'V' => 729, 'W' => 948, 'X' => 771, 'Y' => 677,

            'Z' => 635, '[' => 344, '\\' => 520, ']' => 344, '^' => 469, '_' => 500, '`' => 250, 'a' => 469, 'b' => 521, 'c' => 427,

            'd' => 521, 'e' => 438, 'f' => 271, 'g' => 469, 'h' => 531, 'i' => 250, 'j' => 250, 'k' => 458, 'l' => 240, 'm' => 802,

            'n' => 531, 'o' => 500, 'p' => 521, 'q' => 521, 'r' => 365, 's' => 333, 't' => 292, 'u' => 521, 'v' => 458, 'w' => 677,

            'x' => 479, 'y' => 458, 'z' => 427, '{' => 480, '|' => 496, '}' => 480, '~' => 667);



        $this->GB_widths = array(' ' => 207, '!' => 270, '"' => 342, '#' => 467, '$' => 462, '%' => 797, '&' => 710, '\'' => 239,

            '(' => 374, ')' => 374, '*' => 423, '+' => 605, ',' => 238, '-' => 375, '.' => 238, '/' => 334, '0' => 462, '1' => 462,

            '2' => 462, '3' => 462, '4' => 462, '5' => 462, '6' => 462, '7' => 462, '8' => 462, '9' => 462, ':' => 238, ';' => 238,

            '<' => 605, '=' => 605, '>' => 605, '?' => 344, '@' => 748, 'A' => 684, 'B' => 560, 'C' => 695, 'D' => 739, 'E' => 563,

            'F' => 511, 'G' => 729, 'H' => 793, 'I' => 318, 'J' => 312, 'K' => 666, 'L' => 526, 'M' => 896, 'N' => 758, 'O' => 772,

            'P' => 544, 'Q' => 772, 'R' => 628, 'S' => 465, 'T' => 607, 'U' => 753, 'V' => 711, 'W' => 972, 'X' => 647, 'Y' => 620,

            'Z' => 607, '[' => 374, '\\' => 333, ']' => 374, '^' => 606, '_' => 500, '`' => 239, 'a' => 417, 'b' => 503, 'c' => 427,

            'd' => 529, 'e' => 415, 'f' => 264, 'g' => 444, 'h' => 518, 'i' => 241, 'j' => 230, 'k' => 495, 'l' => 228, 'm' => 793,

            'n' => 527, 'o' => 524, 'p' => 524, 'q' => 504, 'r' => 338, 's' => 336, 't' => 277, 'u' => 517, 'v' => 450, 'w' => 652,

            'x' => 466, 'y' => 452, 'z' => 407, '{' => 370, '|' => 258, '}' => 370, '~' => 605);

    } 

    function AddCIDFont($family, $style, $name, $cw, $CMap, $registry)

    {

        $fontkey = strtolower($family) . strtoupper($style);

        if (isset($this->fonts[$fontkey]))

            $this->Error("Font already added: $family $style");

        $i = count($this->fonts) + 1;

        $name = str_replace(' ', '', $name);

        $this->fonts[$fontkey] = array('i' => $i, 'type' => 'Type0', 'name' => $name, 'up' => -130, 'ut' => 40, 'cw' => $cw, 'CMap' => $CMap, 'registry' => $registry);

    } 



    function AddCIDFonts($family, $name, $cw, $CMap, $registry)

    {

        $this->AddCIDFont($family, '', $name, $cw, $CMap, $registry);

        $this->AddCIDFont($family, 'B', $name . ',Bold', $cw, $CMap, $registry);

        $this->AddCIDFont($family, 'I', $name . ',Italic', $cw, $CMap, $registry);

        $this->AddCIDFont($family, 'BI', $name . ',BoldItalic', $cw, $CMap, $registry);

    } 



    function AddBig5Font($family = 'Big5', $name = 'MSungStd-Light-Acro')

    { 

        // Add Big5 font with proportional Latin

        $cw = $this->Big5_widths;

        $CMap = 'ETenms-B5-H';

        $registry = array('ordering' => 'CNS1', 'supplement' => 0);

        $this->AddCIDFonts($family, $name, $cw, $CMap, $registry);

    } 



    function AddBig5hwFont($family = 'Big5-hw', $name = 'MSungStd-Light-Acro')

    { 

        // Add Big5 font with half-witdh Latin

        for($i = 32;$i <= 126;$i++)

        $cw[chr($i)] = 500;

        $CMap = 'ETen-B5-H';

        $registry = array('ordering' => 'CNS1', 'supplement' => 0);

        $this->AddCIDFonts($family, $name, $cw, $CMap, $registry);

    } 



    function AddGBFont($family = 'GB', $name = 'STSongStd-Light-Acro')

    { 

        // Add GB font with proportional Latin

        $cw = $this->GB_widths;

        $CMap = 'GBKp-EUC-H';

        $registry = array('ordering' => 'GB1', 'supplement' => 2);

        $this->AddCIDFonts($family, $name, $cw, $CMap, $registry);

    } 



    function AddGBhwFont($family = 'GB-hw', $name = 'STSongStd-Light-Acro')

    { 

        // Add GB font with half-width Latin

        for($i = 32;$i <= 126;$i++)

        $cw[chr($i)] = 500;

        $CMap = 'GBK-EUC-H';

        $registry = array('ordering' => 'GB1', 'supplement' => 2);

        $this->AddCIDFonts($family, $name, $cw, $CMap, $registry);

    } 



    function GetStringWidth($s)

    {

        if ($this->CurrentFont['type'] == 'Type0')

            return $this->GetMBStringWidth($s);

        else

            return parent::GetStringWidth($s);

    } 



    function GetMBStringWidth($s)

    { 

        // Multi-byte version of GetStringWidth()

        $l = 0;

        $cw = &$this->CurrentFont['cw'];

        $nb = strlen($s);

        $i = 0;

        while ($i < $nb)

        {

            $c = $s[$i];

            if (ord($c) < 128)

            {

                $l += $cw[$c];

                $i++;

            } 

            else

            {

                $l += 1000;

                $i += 2;

            } 

        } 

        return $l * $this->FontSize / 1000;

    } 



    function MultiCell($w, $h, $txt, $border = 0, $align = 'L', $fill = 0)

    {

        if ($this->CurrentFont['type'] == 'Type0')

            $this->MBMultiCell($w, $h, $txt, $border, $align, $fill);

        else

            parent::MultiCell($w, $h, $txt, $border, $align, $fill);

    } 



    function MBMultiCell($w, $h, $txt, $border = 0, $align = 'L', $fill = 0)

    { 

        // Multi-byte version of MultiCell()

        $cw = &$this->CurrentFont['cw'];

        if ($w == 0)

            $w = $this->w - $this->rMargin - $this->x;

        $wmax = ($w-2 * $this->cMargin) * 1000 / $this->FontSize;

        $s = str_replace("\r", '', $txt);

        $nb = strlen($s);

        if ($nb > 0 and $s[$nb-1] == "\n")

            $nb--;

        $b = 0;

        if ($border)

        {

            if ($border == 1)

            {

                $border = 'LTRB';

                $b = 'LRT';

                $b2 = 'LR';

            } 

            else

            {

                $b2 = '';

                if (is_int(strpos($border, 'L')))

                    $b2 .= 'L';

                if (is_int(strpos($border, 'R')))

                    $b2 .= 'R';

                $b = is_int(strpos($border, 'T')) ? $b2 . 'T' : $b2;

            } 

        } 

        $sep = -1;

        $i = 0;

        $j = 0;

        $l = 0;

        $nl = 1;

        while ($i < $nb)

        { 

            // Get next character

            $c = $s[$i]; 

            // Check if ASCII or MB

            $ascii = (ord($c) < 128);

            if ($c == "\n")

            { 

                // Explicit line break

                $this->Cell($w, $h, substr($s, $j, $i - $j), $b, 2, $align, $fill);

                $i++;

                $sep = -1;

                $j = $i;

                $l = 0;

                $nl++;

                if ($border and $nl == 2)

                    $b = $b2;

                continue;

            } 

            if (!$ascii)

            {

                $sep = $i;

                $ls = $l;

            } elseif ($c == ' ')

            {

                $sep = $i;

                $ls = $l;

            } 

            $l += $ascii ? $cw[$c] : 1000;

            if ($l > $wmax)

            { 

                // Automatic line break

                if ($sep == -1 or $i == $j)

                {

                    if ($i == $j)

                        $i += $ascii ? 1 : 2;

                    $this->Cell($w, $h, substr($s, $j, $i - $j), $b, 2, $align, $fill);

                } 

                else

                {

                    $this->Cell($w, $h, substr($s, $j, $sep - $j), $b, 2, $align, $fill);

                    $i = ($s[$sep] == ' ') ? $sep + 1 : $sep;

                } 

                $sep = -1;

                $j = $i;

                $l = 0;

                $nl++;

                if ($border and $nl == 2)

                    $b = $b2;

            } 

            else

                $i += $ascii ? 1 : 2;

        } 

        // Last chunk

        if ($border and is_int(strpos($border, 'B')))

            $b .= 'B';

        $this->Cell($w, $h, substr($s, $j, $i - $j), $b, 2, $align, $fill);

        $this->x = $this->lMargin;

    } 



    function Write($h, $txt, $link = '')

    {

        if ($this->CurrentFont['type'] == 'Type0')

            $this->MBWrite($h, $txt, $link);

        else

            parent::Write($h, $txt, $link);

    } 



    function MBWrite($h, $txt, $link)

    { 

        // Multi-byte version of Write()

        $cw = &$this->CurrentFont['cw'];

        $w = $this->w - $this->rMargin - $this->x;

        $wmax = ($w-2 * $this->cMargin) * 1000 / $this->FontSize;

        $s = str_replace("\r", '', $txt);

        $nb = strlen($s);

        $sep = -1;

        $i = 0;

        $j = 0;

        $l = 0;

        $nl = 1;

        while ($i < $nb)

        { 

            // Get next character

            $c = $s[$i]; 

            // Check if ASCII or MB

            $ascii = (ord($c) < 128);

            if ($c == "\n")

            { 

                // Explicit line break

                $this->Cell($w, $h, substr($s, $j, $i - $j), 0, 2, '', 0, $link);

                $i++;

                $sep = -1;

                $j = $i;

                $l = 0;

                if ($nl == 1)

                {

                    $this->x = $this->lMargin;

                    $w = $this->w - $this->rMargin - $this->x;

                    $wmax = ($w-2 * $this->cMargin) * 1000 / $this->FontSize;

                } 

                $nl++;

                continue;

            } 

            if (!$ascii or $c == ' ')

                $sep = $i;

            $l += $ascii ? $cw[$c] : 1000;

            if ($l > $wmax)

            { 

                // Automatic line break

                if ($sep == -1 or $i == $j)

                {

                    if ($this->x > $this->lMargin)

                    { 

                        // Move to next line

                        $this->x = $this->lMargin;

                        $this->y += $h;

                        $w = $this->w - $this->rMargin - $this->x;

                        $wmax = ($w-2 * $this->cMargin) * 1000 / $this->FontSize;

                        $i++;

                        $nl++;

                        continue;

                    } 

                    if ($i == $j)

                        $i += $ascii ? 1 : 2;

                    $this->Cell($w, $h, substr($s, $j, $i - $j), 0, 2, '', 0, $link);

                } 

                else

                {

                    $this->Cell($w, $h, substr($s, $j, $sep - $j), 0, 2, '', 0, $link);

                    $i = ($s[$sep] == ' ') ? $sep + 1 : $sep;

                } 

                $sep = -1;

                $j = $i;

                $l = 0;

                if ($nl == 1)

                {

                    $this->x = $this->lMargin;

                    $w = $this->w - $this->rMargin - $this->x;

                    $wmax = ($w-2 * $this->cMargin) * 1000 / $this->FontSize;

                } 

                $nl++;

            } 

            else

                $i += $ascii ? 1 : 2;

        } 

        // Last chunk

        if ($i != $j)

            $this->Cell($l / 1000 * $this->FontSize, $h, substr($s, $j, $i - $j), 0, 0, '', 0, $link);

    } 



    function _putfonts()

    {

        $nf = $this->n;

        foreach($this->diffs as $diff)

        { 

            // Encodings

            $this->_newobj();

            $this->_out('<</Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences [' . $diff . ']>>');

            $this->_out('endobj');

        } 

        $mqr = get_magic_quotes_runtime();

        set_magic_quotes_runtime(0);

        foreach($this->FontFiles as $file => $info)

        { 

            // Font file embedding

            $this->_newobj();

            $this->FontFiles[$file]['n'] = $this->n;

            if (defined('FPDF_FONTPATH'))

                $file = FPDF_FONTPATH . $file;

            $size = filesize($file);

            if (!$size)

                $this->Error('Font file not found');

            $this->_out('<</Length ' . $size);

            if (substr($file, -2) == '.z')

                $this->_out('/Filter /FlateDecode');

            $this->_out('/Length1 ' . $info['length1']);

            if (isset($info['length2']))

                $this->_out('/Length2 ' . $info['length2'] . ' /Length3 0');

            $this->_out('>>');

            $f = fopen($file, 'rb');

            $this->_putstream(fread($f, $size));

            fclose($f);

            $this->_out('endobj');

        } 

        set_magic_quotes_runtime($mqr);

        foreach($this->fonts as $k => $font)

        { 

            // Font objects

            $this->_newobj();

            $this->fonts[$k]['n'] = $this->n;

            $this->_out('<</Type /Font');

            if ($font['type'] == 'Type0')

                $this->_putType0($font);

            else

            {

                $name = $font['name'];

                $this->_out('/BaseFont /' . $name);

                if ($font['type'] == 'core')

                { 

                    // Standard font

                    $this->_out('/Subtype /Type1');

                    if ($name != 'Symbol' and $name != 'ZapfDingbats')

                        $this->_out('/Encoding /WinAnsiEncoding');

                } 

                else

                { 

                    // Additional font

                    $this->_out('/Subtype /' . $font['type']);

                    $this->_out('/FirstChar 32');

                    $this->_out('/LastChar 255');

                    $this->_out('/Widths ' . ($this->n + 1) . ' 0 R');

                    $this->_out('/FontDescriptor ' . ($this->n + 2) . ' 0 R');

                    if ($font['enc'])

                    {

                        if (isset($font['diff']))

                            $this->_out('/Encoding ' . ($nf + $font['diff']) . ' 0 R');

                        else

                            $this->_out('/Encoding /WinAnsiEncoding');

                    } 

                } 

                $this->_out('>>');

                $this->_out('endobj');

                if ($font['type'] != 'core')

                { 

                    // Widths

                    $this->_newobj();

                    $cw = &$font['cw'];

                    $s = '[';

                    for($i = 32;$i <= 255;$i++)

                    $s .= $cw[chr($i)] . ' ';

                    $this->_out($s . ']');

                    $this->_out('endobj'); 

                    // Descriptor

                    $this->_newobj();

                    $s = '<</Type /FontDescriptor /FontName /' . $name;

                    foreach($font['desc'] as $k => $v)

                    $s .= ' /' . $k . ' ' . $v;

                    $file = $font['file'];

                    if ($file)

                        $s .= ' /FontFile' . ($font['type'] == 'Type1' ? '' : '2') . ' ' . $this->FontFiles[$file]['n'] . ' 0 R';

                    $this->_out($s . '>>');

                    $this->_out('endobj');

                } 

            } 

        } 

    } 



    function _putType0($font)

    { 

        // Type0

        $this->_out('/Subtype /Type0');

        $this->_out('/BaseFont /' . $font['name'] . '-' . $font['CMap']);

        $this->_out('/Encoding /' . $font['CMap']);

        $this->_out('/DescendantFonts [' . ($this->n + 1) . ' 0 R]');

        $this->_out('>>');

        $this->_out('endobj'); 

        // CIDFont

        $this->_newobj();

        $this->_out('<</Type /Font');

        $this->_out('/Subtype /CIDFontType0');

        $this->_out('/BaseFont /' . $font['name']);

        $this->_out('/CIDSystemInfo <</Registry (Adobe) /Ordering (' . $font['registry']['ordering'] . ') /Supplement ' . $font['registry']['supplement'] . '>>');

        $this->_out('/FontDescriptor ' . ($this->n + 1) . ' 0 R');

        if ($font['CMap'] == 'ETen-B5-H')

            $W = '13648 13742 500';

        elseif ($font['CMap'] == 'GBK-EUC-H')

            $W = '814 907 500 7716 [500]';

        else

            $W = '1 [' . implode(' ', $font['cw']) . ']';

        $this->_out('/W [' . $W . ']>>');

        $this->_out('endobj'); 

        // Font descriptor

        $this->_newobj();

        $this->_out('<</Type /FontDescriptor');

        $this->_out('/FontName /' . $font['name']);

        $this->_out('/Flags 6');

        $this->_out('/FontBBox [0 -200 1000 900]');

        $this->_out('/ItalicAngle 0');

        $this->_out('/Ascent 800');

        $this->_out('/Descent -200');

        $this->_out('/CapHeight 800');

        $this->_out('/StemV 50');

        $this->_out('>>');

        $this->_out('endobj');

    } 

} 



?>

